| Index: content/renderer/pepper/pepper_platform_audio_input_impl.cc
|
| diff --git a/content/renderer/pepper/pepper_platform_audio_input_impl.cc b/content/renderer/pepper/pepper_platform_audio_input_impl.cc
|
| index 099e7d032265a6dbfb0f4705aac7b189c473e62e..f6c3244740f7a44c5a4fabeffa1bc4d4e3f27c29 100644
|
| --- a/content/renderer/pepper/pepper_platform_audio_input_impl.cc
|
| +++ b/content/renderer/pepper/pepper_platform_audio_input_impl.cc
|
| @@ -10,31 +10,41 @@
|
| #include "build/build_config.h"
|
| #include "content/common/child_process.h"
|
| #include "content/common/media/audio_messages.h"
|
| +#include "content/renderer/pepper/pepper_plugin_delegate_impl.h"
|
| #include "content/renderer/render_thread_impl.h"
|
| #include "media/audio/audio_manager_base.h"
|
|
|
| PepperPlatformAudioInputImpl::PepperPlatformAudioInputImpl()
|
| : client_(NULL),
|
| stream_id_(0),
|
| - main_message_loop_proxy_(base::MessageLoopProxy::current()) {
|
| + main_message_loop_proxy_(base::MessageLoopProxy::current()),
|
| + shutdown_called_(false) {
|
| filter_ = RenderThreadImpl::current()->audio_input_message_filter();
|
| }
|
|
|
| PepperPlatformAudioInputImpl::~PepperPlatformAudioInputImpl() {
|
| - // Make sure we have been shut down. Warning: this will usually happen on
|
| - // the I/O thread!
|
| + // Make sure we have been shut down. Warning: this may happen on the I/O
|
| + // thread!
|
| + // Although these members should be accessed on a specific thread (either the
|
| + // main thread or the I/O thread), it should be fine to examine their value
|
| + // here.
|
| DCHECK_EQ(0, stream_id_);
|
| DCHECK(!client_);
|
| + DCHECK(label_.empty());
|
| + DCHECK(shutdown_called_);
|
| }
|
|
|
| // static
|
| PepperPlatformAudioInputImpl* PepperPlatformAudioInputImpl::Create(
|
| + const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate,
|
| + const std::string& device_id,
|
| int sample_rate,
|
| int frames_per_buffer,
|
| - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) {
|
| + webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) {
|
| scoped_refptr<PepperPlatformAudioInputImpl> audio_input(
|
| new PepperPlatformAudioInputImpl);
|
| - if (audio_input->Initialize(sample_rate, frames_per_buffer, client)) {
|
| + if (audio_input->Initialize(plugin_delegate, device_id, sample_rate,
|
| + frames_per_buffer, client)) {
|
| // Balanced by Release invoked in
|
| // PepperPlatformAudioInputImpl::ShutDownOnIOThread().
|
| return audio_input.release();
|
| @@ -42,21 +52,25 @@ PepperPlatformAudioInputImpl* PepperPlatformAudioInputImpl::Create(
|
| return NULL;
|
| }
|
|
|
| -bool PepperPlatformAudioInputImpl::StartCapture() {
|
| +void PepperPlatformAudioInputImpl::StartCapture() {
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
|
| +
|
| ChildProcess::current()->io_message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this));
|
| - return true;
|
| + FROM_HERE,
|
| + base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this));
|
| }
|
|
|
| -bool PepperPlatformAudioInputImpl::StopCapture() {
|
| +void PepperPlatformAudioInputImpl::StopCapture() {
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
|
| +
|
| ChildProcess::current()->io_message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this));
|
| - return true;
|
| + FROM_HERE,
|
| + base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this));
|
| }
|
|
|
| void PepperPlatformAudioInputImpl::ShutDown() {
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
|
| +
|
| // Called on the main thread to stop all audio callbacks. We must only change
|
| // the client on the main thread, and the delegates from the I/O thread.
|
| client_ = NULL;
|
| @@ -66,51 +80,95 @@ void PepperPlatformAudioInputImpl::ShutDown() {
|
| }
|
|
|
| bool PepperPlatformAudioInputImpl::Initialize(
|
| + const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate,
|
| + const std::string& device_id,
|
| int sample_rate,
|
| int frames_per_buffer,
|
| - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) {
|
| - DCHECK(client);
|
| - // Make sure we don't call init more than once.
|
| - DCHECK_EQ(0, stream_id_);
|
| + webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) {
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
|
| +
|
| + if (!plugin_delegate || !client)
|
| + return false;
|
|
|
| + plugin_delegate_ = plugin_delegate;
|
| client_ = client;
|
|
|
| - AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
|
| - CHANNEL_LAYOUT_MONO,
|
| - sample_rate, 16, frames_per_buffer);
|
| + params_.Reset(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
|
| + sample_rate, 16, frames_per_buffer);
|
|
|
| - ChildProcess::current()->io_message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
|
| - this, params));
|
| + if (device_id.empty()) {
|
| + // Use the default device.
|
| + ChildProcess::current()->io_message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
|
| + this, 0));
|
| + } else {
|
| + // We need to open the device and obtain the label and session ID before
|
| + // initializing.
|
| + plugin_delegate_->OpenDevice(
|
| + PP_DEVICETYPE_DEV_AUDIOCAPTURE, device_id,
|
| + base::Bind(&PepperPlatformAudioInputImpl::OnDeviceOpened, this));
|
| + }
|
| return true;
|
| }
|
|
|
| -void PepperPlatformAudioInputImpl::InitializeOnIOThread(
|
| - const AudioParameters& params) {
|
| +void PepperPlatformAudioInputImpl::InitializeOnIOThread(int session_id) {
|
| + DCHECK(ChildProcess::current()->io_message_loop_proxy()->
|
| + BelongsToCurrentThread());
|
| +
|
| + if (shutdown_called_)
|
| + return;
|
| +
|
| + // Make sure we don't call init more than once.
|
| + DCHECK_EQ(0, stream_id_);
|
| stream_id_ = filter_->AddDelegate(this);
|
| - filter_->Send(new AudioInputHostMsg_CreateStream(
|
| - stream_id_, params, AudioManagerBase::kDefaultDeviceId));
|
| + DCHECK_NE(0, stream_id_);
|
| +
|
| + if (!session_id) {
|
| + // We will be notified by OnStreamCreated().
|
| + filter_->Send(new AudioInputHostMsg_CreateStream(
|
| + stream_id_, params_, AudioManagerBase::kDefaultDeviceId));
|
| + } else {
|
| + // We will be notified by OnDeviceReady().
|
| + filter_->Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id));
|
| + }
|
| }
|
|
|
| void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() {
|
| + DCHECK(ChildProcess::current()->io_message_loop_proxy()->
|
| + BelongsToCurrentThread());
|
| +
|
| if (stream_id_)
|
| filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
|
| }
|
|
|
| void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() {
|
| + DCHECK(ChildProcess::current()->io_message_loop_proxy()->
|
| + BelongsToCurrentThread());
|
| +
|
| + // TODO(yzshen): We cannot re-start capturing if the stream is closed.
|
| if (stream_id_)
|
| filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
|
| }
|
|
|
| void PepperPlatformAudioInputImpl::ShutDownOnIOThread() {
|
| + DCHECK(ChildProcess::current()->io_message_loop_proxy()->
|
| + BelongsToCurrentThread());
|
| +
|
| // Make sure we don't call shutdown more than once.
|
| - if (!stream_id_)
|
| + if (shutdown_called_)
|
| return;
|
| + shutdown_called_ = true;
|
| +
|
| + if (stream_id_) {
|
| + filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
|
| + filter_->RemoveDelegate(stream_id_);
|
| + stream_id_ = 0;
|
| + }
|
|
|
| - filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
|
| - filter_->RemoveDelegate(stream_id_);
|
| - stream_id_ = 0;
|
| + main_message_loop_proxy_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&PepperPlatformAudioInputImpl::CloseDevice, this));
|
|
|
| Release(); // Release for the delegate, balances out the reference taken in
|
| // PepperPluginDelegateImpl::CreateAudioInput.
|
| @@ -129,16 +187,24 @@ void PepperPlatformAudioInputImpl::OnStreamCreated(
|
| #endif
|
| DCHECK(length);
|
|
|
| - if (base::MessageLoopProxy::current() == main_message_loop_proxy_) {
|
| - // Must dereference the client only on the main thread. Shutdown may have
|
| - // occurred while the request was in-flight, so we need to NULL check.
|
| - if (client_)
|
| - client_->StreamCreated(handle, length, socket_handle);
|
| - } else {
|
| + if (base::MessageLoopProxy::current() != main_message_loop_proxy_) {
|
| + // No need to check |shutdown_called_| here. If shutdown has occurred,
|
| + // |client_| will be NULL and the handles will be cleaned up on the main
|
| + // thread.
|
| main_message_loop_proxy_->PostTask(
|
| FROM_HERE,
|
| base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this,
|
| handle, socket_handle, length));
|
| + } else {
|
| + // Must dereference the client only on the main thread. Shutdown may have
|
| + // occurred while the request was in-flight, so we need to NULL check.
|
| + if (client_) {
|
| + client_->StreamCreated(handle, length, socket_handle);
|
| + } else {
|
| + // Clean up the handles.
|
| + base::SyncSocket temp_socket(socket_handle);
|
| + base::SharedMemory temp_shared_memory(handle, false);
|
| + }
|
| }
|
| }
|
|
|
| @@ -148,5 +214,62 @@ void PepperPlatformAudioInputImpl::OnVolume(double volume) {
|
| void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) {
|
| }
|
|
|
| -void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string&) {
|
| +void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string& device_id) {
|
| + DCHECK(ChildProcess::current()->io_message_loop_proxy()->
|
| + BelongsToCurrentThread());
|
| +
|
| + if (shutdown_called_)
|
| + return;
|
| +
|
| + if (device_id.empty()) {
|
| + main_message_loop_proxy_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&PepperPlatformAudioInputImpl::NotifyStreamCreationFailed,
|
| + this));
|
| + } else {
|
| + // We will be notified by OnStreamCreated().
|
| + filter_->Send(new AudioInputHostMsg_CreateStream(stream_id_, params_,
|
| + device_id));
|
| + }
|
| +}
|
| +
|
| +void PepperPlatformAudioInputImpl::OnDeviceOpened(int request_id,
|
| + bool succeeded,
|
| + const std::string& label) {
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
|
| +
|
| + if (succeeded && plugin_delegate_) {
|
| + DCHECK(!label.empty());
|
| + label_ = label;
|
| +
|
| + if (client_) {
|
| + int session_id = plugin_delegate_->GetSessionID(
|
| + PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
|
| + ChildProcess::current()->io_message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
|
| + this, session_id));
|
| + } else {
|
| + // Shutdown has occurred.
|
| + CloseDevice();
|
| + }
|
| + } else {
|
| + NotifyStreamCreationFailed();
|
| + }
|
| +}
|
| +
|
| +void PepperPlatformAudioInputImpl::CloseDevice() {
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
|
| +
|
| + if (plugin_delegate_ && !label_.empty()) {
|
| + plugin_delegate_->CloseDevice(label_);
|
| + label_.clear();
|
| + }
|
| +}
|
| +
|
| +void PepperPlatformAudioInputImpl::NotifyStreamCreationFailed() {
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
|
| +
|
| + if (client_)
|
| + client_->StreamCreationFailed();
|
| }
|
|
|