diff options
author | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 23:43:57 +0000 |
---|---|---|
committer | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 23:43:57 +0000 |
commit | 38244d9bed99ff00c33235a27b80b28368c21cf3 (patch) | |
tree | b68e34ac9121cf548f384391fd8a303d5f2819fb /content/renderer | |
parent | 72bbaccaa082a3ad6fff9bbc1cf70d01dabd79e8 (diff) | |
download | chromium_src-38244d9bed99ff00c33235a27b80b28368c21cf3.zip chromium_src-38244d9bed99ff00c33235a27b80b28368c21cf3.tar.gz chromium_src-38244d9bed99ff00c33235a27b80b28368c21cf3.tar.bz2 |
PepperPlatformAudioInputImpl: support audio input device selection.
BUG=None
TEST=ppapi/examples/audio_input
Review URL: http://codereview.chromium.org/9705056
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@128110 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer')
7 files changed, 224 insertions, 57 deletions
diff --git a/content/renderer/media/media_stream_dispatcher.cc b/content/renderer/media/media_stream_dispatcher.cc index e87c2e2..254740a 100644 --- a/content/renderer/media/media_stream_dispatcher.cc +++ b/content/renderer/media/media_stream_dispatcher.cc @@ -233,7 +233,12 @@ void MediaStreamDispatcher::OnDeviceOpened( if (request.ipc_request == request_id) { Stream new_stream; new_stream.handler = request.handler; - new_stream.video_array.push_back(device_info); + if (device_info.stream_type == + content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE) { + new_stream.video_array.push_back(device_info); + } else { + new_stream.audio_array.push_back(device_info); + } label_stream_map_[label] = new_stream; request.handler->OnDeviceOpened(request.request_id, label, device_info); diff --git a/content/renderer/pepper/pepper_platform_audio_input_impl.cc b/content/renderer/pepper/pepper_platform_audio_input_impl.cc index 099e7d0..f6c3244 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(); } diff --git a/content/renderer/pepper/pepper_platform_audio_input_impl.h b/content/renderer/pepper/pepper_platform_audio_input_impl.h index f9f08f1..15681bb 100644 --- a/content/renderer/pepper/pepper_platform_audio_input_impl.h +++ b/content/renderer/pepper/pepper_platform_audio_input_impl.h @@ -5,14 +5,26 @@ #ifndef CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_INPUT_IMPL_H_ #define CONTENT_RENDERER_PEPPER_PEPPER_PLATFORM_AUDIO_INPUT_IMPL_H_ +#include <string> + #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "content/renderer/media/audio_input_message_filter.h" +#include "media/audio/audio_parameters.h" #include "webkit/plugins/ppapi/plugin_delegate.h" class AudioParameters; - +class PepperPluginDelegateImpl; + +// PepperPlatformAudioInputImpl is operated on two threads: the main thread (the +// thread on which objects are created) and the I/O thread. All public methods, +// except the destructor, must be called on the main thread. The notifications +// to the users of this class (via the PlatformAudioInputClient interface) are +// also sent on the main thread. Internally, this class sends audio input IPC +// messages and receives AudioInputMessageFilter::Delegate notifications on the +// I/O thread. class PepperPlatformAudioInputImpl : public webkit::ppapi::PluginDelegate::PlatformAudioInput, public AudioInputMessageFilter::Delegate, @@ -23,25 +35,29 @@ class PepperPlatformAudioInputImpl // Factory function, returns NULL on failure. StreamCreated() will be called // when the stream is created. static 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); // PlatformAudioInput implementation (called on main thread). - virtual bool StartCapture() OVERRIDE; - virtual bool StopCapture() OVERRIDE; + virtual void StartCapture() OVERRIDE; + virtual void StopCapture() OVERRIDE; virtual void ShutDown() OVERRIDE; private: PepperPlatformAudioInputImpl(); bool Initialize( + 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); // I/O thread backends to above functions. - void InitializeOnIOThread(const AudioParameters& params); + void InitializeOnIOThread(int session_id); void StartCaptureOnIOThread(); void StopCaptureOnIOThread(); void ShutDownOnIOThread(); @@ -54,9 +70,15 @@ class PepperPlatformAudioInputImpl virtual void OnStateChanged(AudioStreamState state) OVERRIDE; virtual void OnDeviceReady(const std::string&) OVERRIDE; + void OnDeviceOpened(int request_id, + bool succeeded, + const std::string& label); + void CloseDevice(); + void NotifyStreamCreationFailed(); + // The client to notify when the stream is created. THIS MUST ONLY BE // ACCESSED ON THE MAIN THREAD. - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client_; + webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client_; // MessageFilter used to send/receive IPC. THIS MUST ONLY BE ACCESSED ON THE // I/O thread except to send messages and get the message loop. @@ -68,6 +90,20 @@ class PepperPlatformAudioInputImpl base::MessageLoopProxy* main_message_loop_proxy_; + // THIS MUST ONLY BE ACCESSED ON THE MAIN THREAD. + base::WeakPtr<PepperPluginDelegateImpl> plugin_delegate_; + + // The unique ID to identify the opened device. THIS MUST ONLY BE ACCESSED ON + // THE MAIN THREAD. + std::string label_; + + // Whether ShutDownOnIOThread() has been called. THIS MUST ONLY BE ACCESSED ON + // THE I/O THREAD. + bool shutdown_called_; + + // Initialized on the main thread and accessed on the I/O thread afterwards. + AudioParameters params_; + DISALLOW_COPY_AND_ASSIGN(PepperPlatformAudioInputImpl); }; diff --git a/content/renderer/pepper/pepper_platform_audio_output_impl.cc b/content/renderer/pepper/pepper_platform_audio_output_impl.cc index 5189c7d..be636dc 100644 --- a/content/renderer/pepper/pepper_platform_audio_output_impl.cc +++ b/content/renderer/pepper/pepper_platform_audio_output_impl.cc @@ -31,7 +31,7 @@ PepperPlatformAudioOutputImpl::~PepperPlatformAudioOutputImpl() { PepperPlatformAudioOutputImpl* PepperPlatformAudioOutputImpl::Create( int sample_rate, int frames_per_buffer, - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { + webkit::ppapi::PluginDelegate::PlatformAudioOutputClient* client) { scoped_refptr<PepperPlatformAudioOutputImpl> audio_output( new PepperPlatformAudioOutputImpl); if (audio_output->Initialize(sample_rate, frames_per_buffer, client)) { @@ -76,7 +76,7 @@ void PepperPlatformAudioOutputImpl::ShutDown() { bool PepperPlatformAudioOutputImpl::Initialize( int sample_rate, int frames_per_buffer, - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { + webkit::ppapi::PluginDelegate::PlatformAudioOutputClient* client) { DCHECK(client); // Make sure we don't call init more than once. DCHECK_EQ(0, stream_id_); diff --git a/content/renderer/pepper/pepper_platform_audio_output_impl.h b/content/renderer/pepper/pepper_platform_audio_output_impl.h index cdba240..f1d5cba 100644 --- a/content/renderer/pepper/pepper_platform_audio_output_impl.h +++ b/content/renderer/pepper/pepper_platform_audio_output_impl.h @@ -28,7 +28,7 @@ class PepperPlatformAudioOutputImpl static PepperPlatformAudioOutputImpl* Create( int sample_rate, int frames_per_buffer, - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client); + webkit::ppapi::PluginDelegate::PlatformAudioOutputClient* client); // PlatformAudioOutput implementation (called on main thread). virtual bool StartPlayback() OVERRIDE; @@ -41,7 +41,7 @@ class PepperPlatformAudioOutputImpl bool Initialize( int sample_rate, int frames_per_buffer, - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client); + webkit::ppapi::PluginDelegate::PlatformAudioOutputClient* client); // I/O thread backends to above functions. void InitializeOnIOThread(const AudioParameters& params); @@ -57,7 +57,7 @@ class PepperPlatformAudioOutputImpl // The client to notify when the stream is created. THIS MUST ONLY BE // ACCESSED ON THE MAIN THREAD. - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client_; + webkit::ppapi::PluginDelegate::PlatformAudioOutputClient* client_; // MessageFilter used to send/receive IPC. THIS MUST ONLY BE ACCESSED ON THE // I/O thread except to send messages and get the message loop. diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc index a70a1f1..4d12e67 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc @@ -597,18 +597,20 @@ webkit::ppapi::PluginDelegate::PlatformAudioOutput* PepperPluginDelegateImpl::CreateAudioOutput( uint32_t sample_rate, uint32_t sample_count, - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { + webkit::ppapi::PluginDelegate::PlatformAudioOutputClient* client) { return PepperPlatformAudioOutputImpl::Create( static_cast<int>(sample_rate), static_cast<int>(sample_count), client); } webkit::ppapi::PluginDelegate::PlatformAudioInput* PepperPluginDelegateImpl::CreateAudioInput( + const std::string& device_id, uint32_t sample_rate, uint32_t sample_count, - webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { + webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) { return PepperPlatformAudioInputImpl::Create( - static_cast<int>(sample_rate), static_cast<int>(sample_count), client); + AsWeakPtr(), device_id, static_cast<int>(sample_rate), + static_cast<int>(sample_count), client); } // If a broker has not already been created for this plugin, creates one. diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.h b/content/renderer/pepper/pepper_plugin_delegate_impl.h index 08d1ed0..25cb8e2 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.h +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.h @@ -170,11 +170,12 @@ class PepperPluginDelegateImpl virtual PlatformAudioOutput* CreateAudioOutput( uint32_t sample_rate, uint32_t sample_count, - PlatformAudioCommonClient* client) OVERRIDE; + PlatformAudioOutputClient* client) OVERRIDE; virtual PlatformAudioInput* CreateAudioInput( + const std::string& device_id, uint32_t sample_rate, uint32_t sample_count, - PlatformAudioCommonClient* client) OVERRIDE; + PlatformAudioInputClient* client) OVERRIDE; virtual PlatformImage2D* CreateImage2D(int width, int height) OVERRIDE; virtual PlatformContext3D* CreateContext3D() OVERRIDE; virtual PlatformVideoCapture* CreateVideoCapture( |