diff options
-rw-r--r-- | chrome/renderer/pepper_plugin_delegate_impl.cc | 26 | ||||
-rw-r--r-- | ppapi/c/dev/ppb_audio_trusted_dev.h | 40 | ||||
-rw-r--r-- | ppapi/examples/audio/audio.cc | 22 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_audio.cc | 153 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_audio.h | 32 | ||||
-rw-r--r-- | webkit/glue/plugins/pepper_plugin_delegate.h | 5 |
6 files changed, 221 insertions, 57 deletions
diff --git a/chrome/renderer/pepper_plugin_delegate_impl.cc b/chrome/renderer/pepper_plugin_delegate_impl.cc index c7aa4b0..3cf9183 100644 --- a/chrome/renderer/pepper_plugin_delegate_impl.cc +++ b/chrome/renderer/pepper_plugin_delegate_impl.cc @@ -123,10 +123,12 @@ class PlatformContext3DImpl : public pepper::PluginDelegate::PlatformContext3D { class PlatformAudioImpl : public pepper::PluginDelegate::PlatformAudio, - public AudioMessageFilter::Delegate { + public AudioMessageFilter::Delegate, + public base::RefCountedThreadSafe<PlatformAudioImpl> { public: explicit PlatformAudioImpl(scoped_refptr<AudioMessageFilter> filter) - : client_(NULL), filter_(filter), stream_id_(0) { + : client_(NULL), filter_(filter), stream_id_(0), + main_message_loop_(MessageLoop::current()) { DCHECK(filter_); } @@ -177,6 +179,8 @@ class PlatformAudioImpl // Our ID on the MessageFilter. int32 stream_id_; + MessageLoop* main_message_loop_; + DISALLOW_COPY_AND_ASSIGN(PlatformAudioImpl); }; @@ -297,7 +301,15 @@ void PlatformAudioImpl::OnLowLatencyCreated( #endif DCHECK(length); - client_->StreamCreated(handle, length, socket_handle); + if (MessageLoop::current() == main_message_loop_) { + if (client_) { + client_->StreamCreated(handle, length, socket_handle); + } + } else { + main_message_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &PlatformAudioImpl::OnLowLatencyCreated, + handle, socket_handle, length)); + } } void PlatformAudioImpl::ShutDown() { @@ -309,6 +321,10 @@ void PlatformAudioImpl::ShutDown() { filter_->RemoveDelegate(stream_id_); stream_id_ = 0; client_ = NULL; + + // Release on the IO thread so that we avoid race problems with + // OnLowLatencyCreated. + filter_->message_loop()->ReleaseSoon(FROM_HERE, this); } // Implements the VideoDecoder. @@ -560,9 +576,11 @@ void PepperPluginDelegateImpl::SelectedFindResultChanged(int identifier, pepper::PluginDelegate::PlatformAudio* PepperPluginDelegateImpl::CreateAudio( uint32_t sample_rate, uint32_t sample_count, pepper::PluginDelegate::PlatformAudio::Client* client) { - scoped_ptr<PlatformAudioImpl> audio( + scoped_refptr<PlatformAudioImpl> audio( new PlatformAudioImpl(render_view_->audio_message_filter())); if (audio->Initialize(sample_rate, sample_count, client)) { + + // Also note ReleaseSoon invoked in PlatformAudioImpl::ShutDown(). return audio.release(); } else { return NULL; diff --git a/ppapi/c/dev/ppb_audio_trusted_dev.h b/ppapi/c/dev/ppb_audio_trusted_dev.h index acb883f..4c250b6 100644 --- a/ppapi/c/dev/ppb_audio_trusted_dev.h +++ b/ppapi/c/dev/ppb_audio_trusted_dev.h @@ -5,23 +5,37 @@ #ifndef PPAPI_C_DEV_PPB_AUDIO_TRUSTED_DEV_H_ #define PPAPI_C_DEV_PPB_AUDIO_TRUSTED_DEV_H_ +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_resource.h" -#define PPB_AUDIO_TRUSTED_DEV_INTERFACE "PPB_AudioTrusted(Dev);0.1" +#define PPB_AUDIO_TRUSTED_DEV_INTERFACE "PPB_AudioTrusted(Dev);0.2" -// This interface is used to get access to the audio buffer and a socket on -// which the client can block until the audio is ready to accept more data. -// This interface should be used by NaCl to implement the Audio interface. +// This interface is to be used by proxy implementations. All +// functions should be called from the main thread only. The +// resource returned is an Audio resource; most of the PPB_Audio_Dev +// interface is also usable on this resource. struct PPB_AudioTrusted_Dev { - // Returns a Buffer object that has the audio buffer. - PP_Resource (*GetBuffer)(PP_Resource audio); - - // Returns a select()-able/Wait()-able OS-specific descriptor. The browser - // will put a byte on the socket each time the buffer is ready to be filled. - // The plugin can then implement its own audio thread using select()/poll() to - // block until the browser is ready to receive data. - int (*GetOSDescriptor)(PP_Resource audio); + // Returns an audio resource. + PP_Resource (*CreateTrusted)(PP_Instance instance); + + // Opens a paused audio interface, used by trusted side of proxy. + // Returns PP_ERROR_WOULD_BLOCK on success, and invokes + // the |create_callback| asynchronously to complete. + // As this function should always be invoked from the main thread, + // do not use the blocking variant of PP_CompletionCallback. + int32_t (*Open)(PP_Resource audio, PP_Resource config, + struct PP_CompletionCallback create_callback); + + // Get the sync socket. Use once Open has completed. + // Returns PP_OK on success. + int32_t (*GetSyncSocket)(PP_Resource audio, int* sync_socket); + + // Get the shared memory interface. Use once Open has completed. + // Returns PP_OK on success. + int32_t (*GetSharedMemory)(PP_Resource audio, + int* shm_handle, + int32_t* shm_size); }; #endif // PPAPI_C_DEV_PPB_AUDIO_TRUSTED_DEV_H_ - diff --git a/ppapi/examples/audio/audio.cc b/ppapi/examples/audio/audio.cc index 8f80ba4..fcef2b1 100644 --- a/ppapi/examples/audio/audio.cc +++ b/ppapi/examples/audio/audio.cc @@ -6,6 +6,7 @@ #include <limits> #include "ppapi/cpp/dev/audio_dev.h" +#include "ppapi/cpp/dev/audio_config_dev.h" #include "ppapi/cpp/instance.h" #include "ppapi/cpp/module.h" @@ -17,6 +18,7 @@ const double frequency_r = 1000; // This sample frequency is guaranteed to work. const PP_AudioSampleRate_Dev sample_frequency = PP_AUDIOSAMPLERATE_44100; const uint32_t sample_count = 4096; +uint32_t obtained_sample_count = 0; class MyInstance : public pp::Instance { public: @@ -26,16 +28,16 @@ class MyInstance : public pp::Instance { } virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { - audio_ = pp::Audio_Dev( - *this, pp::AudioConfig_Dev(sample_frequency, sample_count), - SineWaveCallback, this); + pp::AudioConfig_Dev config; + obtained_sample_count = pp::AudioConfig_Dev::RecommendSampleFrameCount( + sample_count); + config = pp::AudioConfig_Dev(sample_frequency, obtained_sample_count); + audio_ = pp::Audio_Dev(*this, config, SineWaveCallback, this); return audio_.StartPlayback(); } private: - static void SineWaveCallback(void* samples, - size_t buffer_size_in_bytes, - void* thiz) { + static void SineWaveCallback(void* samples, size_t num_bytes, void* thiz) { const double th_l = 2 * 3.141592653589 * frequency_l / sample_frequency; const double th_r = 2 * 3.141592653589 * frequency_r / sample_frequency; @@ -43,12 +45,10 @@ class MyInstance : public pp::Instance { size_t t = reinterpret_cast<MyInstance*>(thiz)->audio_time_; uint16_t* buf = reinterpret_cast<uint16_t*>(samples); - for (size_t buffer_index = 0u; - buffer_index < buffer_size_in_bytes; - buffer_index += 2) { - *buf++ = static_cast<uint16_t>(std::sin(th_l * t) + for (size_t sample = 0; sample < obtained_sample_count; ++sample) { + *buf++ = static_cast<uint16_t>(sin(th_l * t) * std::numeric_limits<uint16_t>::max()); - *buf++ = static_cast<uint16_t>(std::sin(th_r * t++) + *buf++ = static_cast<uint16_t>(sin(th_r * t++) * std::numeric_limits<uint16_t>::max()); } reinterpret_cast<MyInstance*>(thiz)->audio_time_ = t; diff --git a/webkit/glue/plugins/pepper_audio.cc b/webkit/glue/plugins/pepper_audio.cc index d98ef1b..1731d8a 100644 --- a/webkit/glue/plugins/pepper_audio.cc +++ b/webkit/glue/plugins/pepper_audio.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "ppapi/c/dev/ppb_audio_dev.h" #include "ppapi/c/dev/ppb_audio_trusted_dev.h" +#include "ppapi/c/pp_completion_callback.h" #include "webkit/glue/plugins/pepper_common.h" namespace pepper { @@ -77,13 +78,15 @@ const PPB_AudioConfig_Dev ppb_audioconfig = { // PPB_Audio ------------------------------------------------------------------- PP_Resource Create(PP_Instance instance_id, PP_Resource config_id, - PPB_Audio_Callback callback, void* user_data) { + PPB_Audio_Callback user_callback, void* user_data) { PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); if (!instance) return 0; - // TODO(neb): Require callback to be present for untrusted plugins. - scoped_refptr<Audio> audio(new Audio(instance->module())); - if (!audio->Init(instance->delegate(), config_id, callback, user_data)) + if (!user_callback) + return 0; + scoped_refptr<Audio> audio(new Audio(instance->module(), instance_id)); + if (!audio->Init(instance->delegate(), config_id, + user_callback, user_data)) return 0; return audio->GetReference(); } @@ -118,19 +121,50 @@ const PPB_Audio_Dev ppb_audio = { // PPB_AudioTrusted ------------------------------------------------------------ -PP_Resource GetBuffer(PP_Resource audio_id) { - // TODO(neb): Implement me! - return 0; +PP_Resource CreateTrusted(PP_Instance instance_id) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + scoped_refptr<Audio> audio(new Audio(instance->module(), instance_id)); + return audio->GetReference(); +} + +int32_t Open(PP_Resource audio_id, + PP_Resource config_id, + PP_CompletionCallback created) { + scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); + if (!audio) + return PP_ERROR_BADRESOURCE; + if (!created.func) + return PP_ERROR_BADARGUMENT; + PP_Instance instance_id = audio->pp_instance(); + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return PP_ERROR_FAILED; + return audio->Open(instance->delegate(), config_id, created); +} + +int32_t GetSyncSocket(PP_Resource audio_id, int* sync_socket) { + scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); + if (audio) + return audio->GetSyncSocket(sync_socket); + return PP_ERROR_BADRESOURCE; } -int GetOSDescriptor(PP_Resource audio_id) { - // TODO(neb): Implement me! - return -1; +int32_t GetSharedMemory(PP_Resource audio_id, + int* shm_handle, + int32_t* shm_size) { + scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); + if (audio) + return audio->GetSharedMemory(shm_handle, shm_size); + return PP_ERROR_BADRESOURCE; } const PPB_AudioTrusted_Dev ppb_audiotrusted = { - &GetBuffer, - &GetOSDescriptor + &CreateTrusted, + &Open, + &GetSyncSocket, + &GetSharedMemory, }; } // namespace @@ -165,25 +199,38 @@ AudioConfig* AudioConfig::AsAudioConfig() { // Audio ----------------------------------------------------------------------- -Audio::Audio(PluginModule* module) +Audio::Audio(PluginModule* module, PP_Instance instance_id) : Resource(module), playing_(false), + pp_instance_(instance_id), + audio_(NULL), socket_(NULL), shared_memory_(NULL), shared_memory_size_(0), callback_(NULL), - user_data_(NULL) { + user_data_(NULL), + create_callback_pending_(false) { + create_callback_ = PP_MakeCompletionCallback(NULL, NULL); } Audio::~Audio() { // Calling ShutDown() makes sure StreamCreated cannot be called anymore. audio_->ShutDown(); + audio_ = NULL; + // Closing the socket causes the thread to exit - wait for it. socket_->Close(); if (audio_thread_.get()) { audio_thread_->Join(); audio_thread_.reset(); } + + // If the completion callback hasn't fired yet, do so here + // with an error condition. + if (create_callback_pending_) { + PP_RunCompletionCallback(&create_callback_, PP_ERROR_ABORTED); + create_callback_pending_ = false; + } // Shared memory destructor will unmap the memory automatically. } @@ -199,19 +246,73 @@ Audio* Audio::AsAudio() { return this; } -bool Audio::Init(PluginDelegate* plugin_delegate, PP_Resource config_id, +bool Audio::Init(PluginDelegate* plugin_delegate, + PP_Resource config_id, PPB_Audio_Callback callback, void* user_data) { - CHECK(!audio_.get()); + CHECK(!audio_); config_ = Resource::GetAs<AudioConfig>(config_id); if (!config_) return false; callback_ = callback; user_data_ = user_data; - // When the stream is created, we'll get called back in StreamCreated(). - audio_.reset(plugin_delegate->CreateAudio(config_->sample_rate(), - config_->sample_frame_count(), - this)); - return audio_.get() != NULL; + + // When the stream is created, we'll get called back on StreamCreated(). + audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), + config_->sample_frame_count(), + this); + return audio_ != NULL; +} + +int32_t Audio::Open(PluginDelegate* plugin_delegate, + PP_Resource config_id, + PP_CompletionCallback create_callback) { + DCHECK(!audio_); + config_ = Resource::GetAs<AudioConfig>(config_id); + if (!config_) + return PP_ERROR_BADRESOURCE; + + // When the stream is created, we'll get called back on StreamCreated(). + audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), + config_->sample_frame_count(), + this); + if (!audio_) + return PP_ERROR_FAILED; + + // At this point, we are guaranteeing ownership of the completion + // callback. Audio promises to fire the completion callback + // once and only once. + create_callback_ = create_callback; + create_callback_pending_ = true; + return PP_ERROR_WOULDBLOCK; +} + +int32_t Audio::GetSyncSocket(int* sync_socket) { + if (socket_ != NULL) { +#if defined(OS_POSIX) + *sync_socket = socket_->handle(); +#elif defined(OS_WIN) + *sync_socket = reinterpret_cast<int>(socket_->handle()); +#else + #error "Platform not supported." +#endif + return PP_OK; + } + return PP_ERROR_FAILED; +} + +int32_t Audio::GetSharedMemory(int* shm_handle, int32_t* shm_size) { + if (shared_memory_ != NULL) { +#if defined(OS_POSIX) + *shm_handle = shared_memory_->handle().fd; +#elif defined(OS_WIN) + *shm_handle = reinterpret_cast<int>(shared_memory_->handle()); +#else + #error "Platform not supported." +#endif + *shm_size = shared_memory_size_; + return PP_OK; + } + return PP_ERROR_FAILED; } bool Audio::StartPlayback() { @@ -250,8 +351,17 @@ void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle, shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); shared_memory_size_ = shared_memory_size; + // Trusted side of proxy can specify a callback to recieve handles. + if (create_callback_pending_) { + PP_RunCompletionCallback(&create_callback_, 0); + create_callback_pending_ = false; + } + + // Trusted, non-proxy audio will invoke buffer filling callback on a + // dedicated thread, see Audio::Run() below. if (callback_) { shared_memory_->Map(shared_memory_size_); + // In common case StartPlayback() was called before StreamCreated(). if (playing_) { audio_thread_.reset(new base::DelegateSimpleThread(this, @@ -277,4 +387,3 @@ void Audio::Run() { } } // namespace pepper - diff --git a/webkit/glue/plugins/pepper_audio.h b/webkit/glue/plugins/pepper_audio.h index ccba021..8c14666 100644 --- a/webkit/glue/plugins/pepper_audio.h +++ b/webkit/glue/plugins/pepper_audio.h @@ -13,6 +13,7 @@ #include "ppapi/c/dev/ppb_audio_dev.h" #include "ppapi/c/dev/ppb_audio_config_dev.h" #include "ppapi/c/dev/ppb_audio_trusted_dev.h" +#include "ppapi/c/pp_completion_callback.h" #include "webkit/glue/plugins/pepper_plugin_delegate.h" #include "webkit/glue/plugins/pepper_plugin_instance.h" #include "webkit/glue/plugins/pepper_plugin_module.h" @@ -46,19 +47,32 @@ class Audio : public Resource, public PluginDelegate::PlatformAudio::Client, public base::DelegateSimpleThread::Delegate { public: - explicit Audio(PluginModule* module); + explicit Audio(PluginModule* module, PP_Instance instance_id); virtual ~Audio(); static const PPB_Audio_Dev* GetInterface(); static const PPB_AudioTrusted_Dev* GetTrustedInterface(); - bool Init(PluginDelegate* plugin_delegate, PP_Resource config_id, - PPB_Audio_Callback callback, void* user_data); + bool Init(PluginDelegate* plugin_delegate, + PP_Resource config_id, + PPB_Audio_Callback user_callback, void* user_data); + + int32_t Open(PluginDelegate* plugin_delegate, + PP_Resource config_id, + PP_CompletionCallback create_callback); PP_Resource GetCurrentConfiguration() { return config_->GetReference(); } + PP_Instance pp_instance() { + return pp_instance_; + } + + int32_t GetSyncSocket(int* sync_socket); + + int32_t GetSharedMemory(int* shm_handle, int32_t* shm_size); + bool StartPlayback(); bool StopPlayback(); @@ -83,8 +97,11 @@ class Audio : public Resource, // AudioConfig used for creating this Audio object. scoped_refptr<AudioConfig> config_; + // Instance id + PP_Instance pp_instance_; + // PluginDelegate audio object that we delegate audio IPC through. - scoped_ptr<PluginDelegate::PlatformAudio> audio_; + PluginDelegate::PlatformAudio* audio_; // Socket used to notify us when audio is ready to accept new samples. This // pointer is created in StreamCreated(). @@ -106,9 +123,14 @@ class Audio : public Resource, // User data pointer passed verbatim to the callback function. void* user_data_; + + // Is a create callback pending to fire? + bool create_callback_pending_; + + // Trusted callback invoked from StreamCreated. + PP_CompletionCallback create_callback_; }; } // namespace pepper #endif // WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_ - diff --git a/webkit/glue/plugins/pepper_plugin_delegate.h b/webkit/glue/plugins/pepper_plugin_delegate.h index 97f775a..7032c2c 100644 --- a/webkit/glue/plugins/pepper_plugin_delegate.h +++ b/webkit/glue/plugins/pepper_plugin_delegate.h @@ -129,8 +129,6 @@ class PluginDelegate { base::SyncSocket::Handle socket) = 0; }; - virtual ~PlatformAudio() {} - // Starts the playback. Returns false on error or if called before the // stream is created or after the stream is closed. virtual bool StartPlayback() = 0; @@ -142,6 +140,9 @@ class PluginDelegate { // Closes the stream. Make sure to call this before the object is // destructed. virtual void ShutDown() = 0; + + protected: + virtual ~PlatformAudio() {} }; class PlatformVideoDecoder { |