Chromium Code Reviews| 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 596cd0694e0b8f8772ee46e2e948354f8d5c7567..80d22b590cfe23007871a55cdbfb27ef1968a07d 100644 |
| --- a/content/renderer/pepper/pepper_platform_audio_input_impl.cc |
| +++ b/content/renderer/pepper/pepper_platform_audio_input_impl.cc |
| @@ -10,13 +10,15 @@ |
| #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) { |
|
no longer working on chromium
2012/03/16 14:33:23
why do we need a new shutdown_called flag? can we
yzshen1
2012/03/17 09:32:56
ShutDown() may be called before stream_id_ is set
no longer working on chromium
2012/03/18 00:38:59
Do I miss something here? It looks to me they all
yzshen1
2012/03/19 21:47:54
OpenDevice() and OnDeviceOpened() happens on the m
|
| filter_ = RenderThreadImpl::current()->audio_input_message_filter(); |
| } |
| @@ -25,16 +27,21 @@ PepperPlatformAudioInputImpl::~PepperPlatformAudioInputImpl() { |
| // the I/O thread! |
| 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, |
| uint32_t sample_rate, |
| uint32_t sample_count, |
| - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { |
| + webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) { |
| scoped_refptr<PepperPlatformAudioInputImpl> audio_input( |
| new PepperPlatformAudioInputImpl); |
| - if (audio_input->Initialize(sample_rate, sample_count, client)) { |
| + if (audio_input->Initialize(plugin_delegate, device_id, sample_rate, |
| + sample_count, client)) { |
| // Balanced by Release invoked in |
| // PepperPlatformAudioInputImpl::ShutDownOnIOThread(). |
| return audio_input.release(); |
| @@ -43,20 +50,26 @@ PepperPlatformAudioInputImpl* PepperPlatformAudioInputImpl::Create( |
| } |
| bool PepperPlatformAudioInputImpl::StartCapture() { |
|
no longer working on chromium
2012/03/16 14:33:23
It looks like this function has no way to return f
yzshen1
2012/03/17 09:32:56
Done.
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread()); |
| + |
| ChildProcess::current()->io_message_loop()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this)); |
| + FROM_HERE, |
| + base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this)); |
| return true; |
| } |
| bool PepperPlatformAudioInputImpl::StopCapture() { |
|
no longer working on chromium
2012/03/16 14:33:23
void?
yzshen1
2012/03/17 09:32:56
Done.
|
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread()); |
| + |
| ChildProcess::current()->io_message_loop()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this)); |
| + FROM_HERE, |
| + base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this)); |
| return true; |
| } |
| 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,54 +79,98 @@ void PepperPlatformAudioInputImpl::ShutDown() { |
| } |
| bool PepperPlatformAudioInputImpl::Initialize( |
|
no longer working on chromium
2012/03/16 14:33:23
void?
yzshen1
2012/03/17 09:32:56
I changed two DCHECKs to input parameter validatio
|
| + const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate, |
| + const std::string& device_id, |
| uint32_t sample_rate, |
| uint32_t sample_count, |
| - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { |
| + webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) { |
| + DCHECK(main_message_loop_proxy_->BelongsToCurrentThread()); |
| + |
| + DCHECK(plugin_delegate); |
| DCHECK(client); |
| - // Make sure we don't call init more than once. |
| - DCHECK_EQ(0, stream_id_); |
| + plugin_delegate_ = plugin_delegate; |
| client_ = client; |
| - AudioParameters params; |
| - params.format = AudioParameters::AUDIO_PCM_LINEAR; |
| - params.channels = 1; |
| - params.sample_rate = sample_rate; |
| - params.bits_per_sample = 16; |
| - params.samples_per_packet = sample_count; |
| + params_.format = AudioParameters::AUDIO_PCM_LINEAR; |
| + params_.channels = 1; |
| + params_.sample_rate = sample_rate; |
| + params_.bits_per_sample = 16; |
| + params_.samples_per_packet = sample_count; |
| - 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_)); |
|
no longer working on chromium
2012/03/16 14:33:23
What happens if we are in the middle of starting t
yzshen1
2012/03/17 09:32:56
Thanks for pointing this out!
This class doesn't
no longer working on chromium
2012/03/18 00:38:59
Thanks for clarification.
|
| } |
| 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_)); |
|
no longer working on chromium
2012/03/16 14:33:23
same situation here, we need to do similar things
yzshen1
2012/03/17 09:32:56
Please see my comment above.
On 2012/03/16 14:33:2
|
| } |
| 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; |
| - filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); |
| - filter_->RemoveDelegate(stream_id_); |
| - stream_id_ = 0; |
| + if (stream_id_) { |
| + 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 |
|
no longer working on chromium
2012/03/16 14:33:23
What does this Release() do? We execute CloseDevic
yzshen1
2012/03/17 09:32:56
This is a ref-counted object, Release() decreases
no longer working on chromium
2012/03/18 00:38:59
True, I know it is safe due to PepperPlatformAudio
yzshen1
2012/03/19 21:47:54
I try to maintain the following order:
open device
|
| // PepperPluginDelegateImpl::CreateAudioInput. |
| @@ -135,9 +192,17 @@ void PepperPlatformAudioInputImpl::OnStreamCreated( |
| 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_) |
| + 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); |
| + } |
| } else { |
| + // 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, |
| @@ -151,5 +216,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()); |
| + |
| + succeeded = succeeded && plugin_delegate_; |
| + if (succeeded) { |
| + 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(); |
|
no longer working on chromium
2012/03/16 14:33:23
shall we still send the notification when plugin_d
yzshen1
2012/03/17 09:32:56
As long as client_ is not NULL, I think it makes s
|
| + } |
| +} |
| + |
| +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(); |
| } |