Chromium Code Reviews| Index: content/renderer/media/mojo_audio_output_ipc.cc |
| diff --git a/content/renderer/media/mojo_audio_output_ipc.cc b/content/renderer/media/mojo_audio_output_ipc.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7e36d78d8d707a5364d62ff0b71fd26aeab90022 |
| --- /dev/null |
| +++ b/content/renderer/media/mojo_audio_output_ipc.cc |
| @@ -0,0 +1,161 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/renderer/media/mojo_audio_output_ipc.h" |
| + |
| +#include <utility> |
| + |
| +#include "content/renderer/media/audio_ipc_factory.h" |
| +#include "media/audio/audio_device_description.h" |
| +#include "mojo/public/cpp/system/platform_handle.h" |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +void TrivialAuthorizedCallback(media::OutputDeviceStatus, |
| + const media::AudioParameters&, |
| + const std::string&) {} |
| + |
| +} // namespace |
| + |
| +MojoAudioOutputIPC::MojoAudioOutputIPC(int frame_id) |
| + : frame_id_(frame_id), weak_factory_(this) { |
| + thread_checker_.DetachFromThread(); |
| +} |
| + |
| +MojoAudioOutputIPC::~MojoAudioOutputIPC() { |
| + // No thread check. |
| + // Destructing |weak_factory_| on any thread is safe since it's not used after |
| + // the final call to CloseStream. |
|
o1ka
2017/04/20 10:36:00
Could you please clarify the comment?
o1ka
2017/04/20 10:36:00
* if CloseStream() has been called. DCHECKs for th
Max Morin
2017/05/05 13:10:58
Done.
Max Morin
2017/05/05 13:10:59
Done.
|
| +} |
| + |
| +media::mojom::AudioOutputStreamProviderRequest |
| +MojoAudioOutputIPC::MakeProviderRequest( |
| + media::AudioOutputIPCDelegate* delegate) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(!stream_provider_.is_bound()); |
| + media::mojom::AudioOutputStreamProviderRequest request = |
| + mojo::MakeRequest(&stream_provider_); |
| + |
| + // Unretained is safe because |delegate| owns |this|. |
| + stream_provider_.set_connection_error_handler(base::Bind( |
| + &media::AudioOutputIPCDelegate::OnError, base::Unretained(delegate))); |
| + return request; |
| +} |
| + |
| +void MojoAudioOutputIPC::RequestDeviceAuthorization( |
| + media::AudioOutputIPCDelegate* delegate, |
| + int session_id, |
| + const std::string& device_id, |
| + const url::Origin& security_origin) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(delegate); |
| + DCHECK(!stream_provider_.is_bound()); |
| + DCHECK(!stream_.is_bound()); |
| + auto* factory = AudioIPCFactory::get()->GetRemoteFactory(frame_id_); |
| + if (!factory) { |
| + LOG(ERROR) << "No factory is registered for " << frame_id_; |
| + delegate->OnIPCClosed(); // deletes |this|. |
| + return; |
| + } |
| + |
| + // Unretained is safe because |delegate| owns |this|. |
| + factory->RequestDeviceAuthorization( |
| + MakeProviderRequest(delegate), session_id, device_id, |
| + base::Bind(&MojoAudioOutputIPC::RecievedDeviceAuthorization, |
| + weak_factory_.GetWeakPtr(), delegate)); |
| +} |
| + |
| +void MojoAudioOutputIPC::RecievedDeviceAuthorization( |
| + media::AudioOutputIPCDelegate* delegate, |
| + media::OutputDeviceStatus status, |
| + const media::AudioParameters& params, |
| + const std::string& device_id) const { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + delegate->OnDeviceAuthorized(status, params, device_id); |
| +} |
| + |
| +void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate, |
| + const media::AudioParameters& params) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(delegate); |
| + DCHECK(!stream_.is_bound()); |
| + if (!stream_provider_.is_bound()) { |
|
o1ka
2017/04/20 10:35:59
M.b. would be more readable to have AuthorizationR
Max Morin
2017/05/05 13:10:59
Done.
|
| + // No authorization requested yet. Request one for the default device. |
| + // This also means we shouldn't callback to the delegate for the reply. |
| + auto* factory = AudioIPCFactory::get()->GetRemoteFactory(frame_id_); |
| + if (!factory) { |
| + LOG(ERROR) << "No factory is registered for " << frame_id_; |
| + delegate->OnIPCClosed(); // deletes |this|. |
| + return; |
| + } |
| + |
| + factory->RequestDeviceAuthorization( |
|
o1ka
2017/04/20 10:35:59
WDYT about making a helper function and using it h
Max Morin
2017/05/05 13:10:59
Looks more complex (since it returns early if ther
|
| + MakeProviderRequest(delegate), 0, |
| + media::AudioDeviceDescription::kDefaultDeviceId, |
| + base::Bind(&TrivialAuthorizedCallback)); |
| + } |
| + |
| + // Since the callback won't fire if the binding is gone, unretained is safe. |
|
o1ka
2017/04/20 10:35:59
Which callback and which binding? It's hard for an
Max Morin
2017/05/05 13:10:58
Done.
|
| + stream_provider_->Acquire(mojo::MakeRequest(&stream_), params, |
| + base::Bind(&MojoAudioOutputIPC::StreamCreated, |
| + base::Unretained(this), delegate)); |
| + |
| + // Unretained is safe because |delegate| owns |this|. |
| + stream_.set_connection_error_handler(base::Bind( |
| + &media::AudioOutputIPCDelegate::OnError, base::Unretained(delegate))); |
| +} |
| + |
| +void MojoAudioOutputIPC::StreamCreated( |
| + media::AudioOutputIPCDelegate* delegate, |
| + mojo::ScopedSharedBufferHandle shared_memory, |
| + mojo::ScopedHandle socket) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(socket.is_valid()); |
| + DCHECK(shared_memory.is_valid()); |
| + |
| + base::PlatformFile socket_handle; |
| + mojo::UnwrapPlatformFile(std::move(socket), &socket_handle); |
| + |
| + base::SharedMemoryHandle memory_handle; |
| + bool read_only = false; |
| + size_t memory_length = 0; |
| + auto result = mojo::UnwrapSharedMemoryHandle( |
| + std::move(shared_memory), &memory_handle, &memory_length, &read_only); |
| + DCHECK_EQ(result, MOJO_RESULT_OK); |
| + DCHECK(!read_only); |
| + |
| + delegate->OnStreamCreated(memory_handle, socket_handle, memory_length); |
| +} |
| + |
| +void MojoAudioOutputIPC::PlayStream() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (stream_.is_bound()) |
| + stream_->Play(); |
| +} |
| + |
| +void MojoAudioOutputIPC::PauseStream() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (stream_.is_bound()) |
| + stream_->Pause(); |
| +} |
| + |
| +void MojoAudioOutputIPC::CloseStream() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + stream_provider_.reset(); |
| + stream_.reset(); |
| + |
| + // Make sure we don't send an authorization callback for this stream to the |
|
o1ka
2017/04/20 10:36:00
We need a comment explaining why we are never stuc
Max Morin
2017/05/05 13:10:59
In this case, the AudioOutputDevice must take care
|
| + // delegate. |
| + weak_factory_.InvalidateWeakPtrs(); |
| +} |
| + |
| +void MojoAudioOutputIPC::SetVolume(double volume) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (stream_.is_bound()) |
| + stream_->SetVolume(volume); |
| +} |
| + |
| +} // namespace content |