diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 17:17:21 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 17:17:21 +0000 |
commit | 5d84d01d904a2e5fa3e17b8d9165e63a20351160 (patch) | |
tree | dd87a4d94ed6276dc1551cbc5d3c744eb268cebd | |
parent | 9a80065bad1506ac11163d597ace3295ddbfa8cb (diff) | |
download | chromium_src-5d84d01d904a2e5fa3e17b8d9165e63a20351160.zip chromium_src-5d84d01d904a2e5fa3e17b8d9165e63a20351160.tar.gz chromium_src-5d84d01d904a2e5fa3e17b8d9165e63a20351160.tar.bz2 |
Implement audio proxy for Pepper.
In addition to the basic proxying, this required some changes to the dispatcher
and process infrastructure to get the handles of the processes available when
I need them so I can duplicate the shared memory handles properly into the
different processes.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/4985001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68026 0039d316-1c4b-4281-b951-d872f2087c98
34 files changed, 999 insertions, 180 deletions
diff --git a/chrome/browser/browser_child_process_host.cc b/chrome/browser/browser_child_process_host.cc index a317f26..5cfd536 100644 --- a/chrome/browser/browser_child_process_host.cc +++ b/chrome/browser/browser_child_process_host.cc @@ -117,6 +117,14 @@ void BrowserChildProcessHost::Launch( &client_)); } +base::ProcessHandle BrowserChildProcessHost::GetChildProcessHandle() const { + DCHECK(child_process_.get()) + << "Requesting a child process handle before launching."; + DCHECK(child_process_->GetHandle()) + << "Requesting a child process handle before launch has completed OK."; + return child_process_->GetHandle(); +} + bool BrowserChildProcessHost::Send(IPC::Message* msg) { return SendOnChannel(msg); } diff --git a/chrome/browser/browser_child_process_host.h b/chrome/browser/browser_child_process_host.h index cf30973..f70c035 100644 --- a/chrome/browser/browser_child_process_host.h +++ b/chrome/browser/browser_child_process_host.h @@ -73,6 +73,10 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver, #endif CommandLine* cmd_line); + // Returns the handle of the child process. This must be called only after + // OnProcessLaunched is called or it will be invalid and may crash. + base::ProcessHandle GetChildProcessHandle() const; + // ChildProcessLauncher::Client implementation. virtual void OnProcessLaunched() { } diff --git a/chrome/browser/ppapi_plugin_process_host.cc b/chrome/browser/ppapi_plugin_process_host.cc index ba47b86..ded8964 100644 --- a/chrome/browser/ppapi_plugin_process_host.cc +++ b/chrome/browser/ppapi_plugin_process_host.cc @@ -29,7 +29,7 @@ void PpapiPluginProcessHost::Init(const FilePath& path, reply_msg_.reset(reply_msg); if (!CreateChannel()) { - ReplyToRenderer(IPC::ChannelHandle()); + ReplyToRenderer(NULL, IPC::ChannelHandle()); return; } @@ -39,7 +39,7 @@ void PpapiPluginProcessHost::Init(const FilePath& path, FilePath exe_path = ChildProcessHost::GetChildPath(plugin_launcher.empty()); if (exe_path.empty()) { - ReplyToRenderer(IPC::ChannelHandle()); + ReplyToRenderer(NULL, IPC::ChannelHandle()); return; } @@ -80,25 +80,49 @@ void PpapiPluginProcessHost::OnMessageReceived(const IPC::Message& msg) { } void PpapiPluginProcessHost::OnChannelConnected(int32 peer_pid) { - PpapiMsg_LoadPlugin* msg = new PpapiMsg_LoadPlugin(plugin_path_, +#if defined(OS_WIN) + base::ProcessHandle plugins_renderer_handle = NULL; + ::DuplicateHandle(::GetCurrentProcess(), filter_->handle(), + GetChildProcessHandle(), &plugins_renderer_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS); +#elif defined(OS_POSIX) + base::ProcessHandle plugins_renderer_handle = filter_->handle(); +#endif + + PpapiMsg_LoadPlugin* msg = new PpapiMsg_LoadPlugin(plugins_renderer_handle, + plugin_path_, filter_->id()); if (!Send(msg)) // Just send an empty handle on failure. - ReplyToRenderer(IPC::ChannelHandle()); + ReplyToRenderer(NULL, IPC::ChannelHandle()); // This function will result in OnChannelCreated getting called to finish. } void PpapiPluginProcessHost::OnChannelError() { if (reply_msg_.get()) - ReplyToRenderer(IPC::ChannelHandle()); + ReplyToRenderer(NULL, IPC::ChannelHandle()); } -void PpapiPluginProcessHost::OnPluginLoaded(const IPC::ChannelHandle& handle) { - ReplyToRenderer(handle); +void PpapiPluginProcessHost::OnPluginLoaded( + const IPC::ChannelHandle& channel_handle) { + base::ProcessHandle plugin_process = GetChildProcessHandle(); +#if defined(OS_WIN) + base::ProcessHandle renderers_plugin_handle = NULL; + ::DuplicateHandle(::GetCurrentProcess(), plugin_process, + filter_->handle(), &renderers_plugin_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS); +#elif defined(OS_POSIX) + // Don't need to duplicate anything on POSIX since it's just a PID. + base::ProcessHandle renderers_plugin_handle = plugin_process; +#endif + ReplyToRenderer(renderers_plugin_handle, channel_handle); } -void PpapiPluginProcessHost::ReplyToRenderer(const IPC::ChannelHandle& handle) { +void PpapiPluginProcessHost::ReplyToRenderer( + base::ProcessHandle plugin_handle, + const IPC::ChannelHandle& channel_handle) { DCHECK(reply_msg_.get()); ViewHostMsg_OpenChannelToPepperPlugin::WriteReplyParams(reply_msg_.get(), - handle); + plugin_handle, + channel_handle); filter_->Send(reply_msg_.release()); } diff --git a/chrome/browser/ppapi_plugin_process_host.h b/chrome/browser/ppapi_plugin_process_host.h index 956148c..dd71b14 100644 --- a/chrome/browser/ppapi_plugin_process_host.h +++ b/chrome/browser/ppapi_plugin_process_host.h @@ -39,7 +39,8 @@ class PpapiPluginProcessHost : public BrowserChildProcessHost { void OnPluginLoaded(const IPC::ChannelHandle& handle); // Sends the reply_msg_ to the renderer with the given channel info. - void ReplyToRenderer(const IPC::ChannelHandle& handle); + void ReplyToRenderer(base::ProcessHandle plugin_handle, + const IPC::ChannelHandle& channel_handle); ResourceMessageFilter* filter_; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 34b5bf0..cf9e44f 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1579,15 +1579,16 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_OpenChannelToPlugin, GURL /* url */, std::string /* mime_type */, - IPC::ChannelHandle /* handle to channel */, + IPC::ChannelHandle /* channel_handle */, WebPluginInfo /* info */) // A renderer sends this to the browser process when it wants to // create a pepper plugin. The browser will create the plugin process if // necessary, and will return a handle to the channel on success. // On error an empty string is returned. - IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_OpenChannelToPepperPlugin, + IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_OpenChannelToPepperPlugin, FilePath /* path */, + base::ProcessHandle /* plugin_process_handle */, IPC::ChannelHandle /* handle to channel */) // A renderer sends this to the browser process when it wants to diff --git a/chrome/ppapi_plugin/ppapi_thread.cc b/chrome/ppapi_plugin/ppapi_thread.cc index 36ea9f6..8c4da88 100644 --- a/chrome/ppapi_plugin/ppapi_thread.cc +++ b/chrome/ppapi_plugin/ppapi_thread.cc @@ -47,9 +47,11 @@ void PpapiThread::OnMessageReceived(const IPC::Message& msg) { IPC_END_MESSAGE_MAP() } -void PpapiThread::OnLoadPlugin(const FilePath& path, int renderer_id) { +void PpapiThread::OnLoadPlugin(base::ProcessHandle host_process_handle, + const FilePath& path, + int renderer_id) { IPC::ChannelHandle channel_handle; - if (!LoadPluginLib(path) || + if (!LoadPluginLib(host_process_handle, path) || !SetupRendererChannel(renderer_id, &channel_handle)) { // An empty channel handle indicates error. Send(new PpapiHostMsg_PluginLoaded(IPC::ChannelHandle())); @@ -59,7 +61,8 @@ void PpapiThread::OnLoadPlugin(const FilePath& path, int renderer_id) { Send(new PpapiHostMsg_PluginLoaded(channel_handle)); } -bool PpapiThread::LoadPluginLib(const FilePath& path) { +bool PpapiThread::LoadPluginLib(base::ProcessHandle host_process_handle, + const FilePath& path) { base::ScopedNativeLibrary library(base::LoadNativeLibrary(path)); if (!library.is_valid()) return false; @@ -88,8 +91,8 @@ bool PpapiThread::LoadPluginLib(const FilePath& path) { library.GetFunctionPointer("PPP_ShutdownModule")); library_.Reset(library.Release()); - dispatcher_.reset(new pp::proxy::PluginDispatcher(get_interface, init_module, - shutdown_module)); + dispatcher_.reset(new pp::proxy::PluginDispatcher( + host_process_handle, get_interface, init_module, shutdown_module)); pp::proxy::PluginDispatcher::SetGlobal(dispatcher_.get()); return true; } diff --git a/chrome/ppapi_plugin/ppapi_thread.h b/chrome/ppapi_plugin/ppapi_thread.h index ed7b024..cf49c8b 100644 --- a/chrome/ppapi_plugin/ppapi_thread.h +++ b/chrome/ppapi_plugin/ppapi_thread.h @@ -7,6 +7,7 @@ #pragma once #include "base/basictypes.h" +#include "base/process.h" #include "base/scoped_native_library.h" #include "base/scoped_ptr.h" #include "build/build_config.h" @@ -34,9 +35,12 @@ class PpapiThread : public ChildThread { virtual void OnMessageReceived(const IPC::Message& msg); // Message handlers. - void OnLoadPlugin(const FilePath& path, int renderer_id); + void OnLoadPlugin(base::ProcessHandle renderer_handle, + const FilePath& path, + int renderer_id); - bool LoadPluginLib(const FilePath& path); + bool LoadPluginLib(base::ProcessHandle host_process_handle, + const FilePath& path); // Sets up the channel to the given renderer. On success, returns true and // fills the given ChannelHandle with the information from the new channel. diff --git a/chrome/renderer/pepper_plugin_delegate_impl.cc b/chrome/renderer/pepper_plugin_delegate_impl.cc index 3cf9183..c3a85d9 100644 --- a/chrome/renderer/pepper_plugin_delegate_impl.cc +++ b/chrome/renderer/pepper_plugin_delegate_impl.cc @@ -426,13 +426,15 @@ PepperPluginDelegateImpl::~PepperPluginDelegateImpl() { scoped_refptr<pepper::PluginModule> PepperPluginDelegateImpl::CreateOutOfProcessPepperPlugin( const FilePath& path) { + base::ProcessHandle plugin_process_handle = NULL; IPC::ChannelHandle channel_handle; render_view_->Send(new ViewHostMsg_OpenChannelToPepperPlugin( - path, &channel_handle)); + path, &plugin_process_handle, &channel_handle)); if (channel_handle.name.empty()) return scoped_refptr<pepper::PluginModule>(); // Couldn't be initialized. return pepper::PluginModule::CreateOutOfProcessModule( ChildProcess::current()->io_message_loop(), + plugin_process_handle, channel_handle, ChildProcess::current()->GetShutDownEvent()); } diff --git a/ppapi/ppapi.gyp b/ppapi/ppapi.gyp index b9fb347..b321dc6 100644 --- a/ppapi/ppapi.gyp +++ b/ppapi/ppapi.gyp @@ -495,11 +495,32 @@ # ], }, { + 'target_name': 'ppapi_shared_impl', + 'type': 'static_library', + 'dependencies': [ + 'ppapi_c', + '../base/base.gyp:base', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'shared_impl/audio_impl.cc', + 'shared_impl/audio_impl.h', + ], + 'conditions': [ + ['OS=="win"', { + 'msvs_guid': 'E7420D65-A885-41EB-B4BE-04DE0C97033B', + }], + ], + }, + { 'target_name': 'ppapi_proxy', 'type': 'static_library', 'dependencies': [ '../ipc/ipc.gyp:ipc', 'ppapi_c', + 'ppapi_shared_impl', ], 'all_dependent_settings': { 'include_dirs': [ @@ -536,6 +557,10 @@ 'proxy/ppapi_messages_internal.h', 'proxy/ppapi_param_traits.cc', 'proxy/ppapi_param_traits.h', + 'proxy/ppb_audio_config_proxy.cc', + 'proxy/ppb_audio_config_proxy.h', + 'proxy/ppb_audio_proxy.cc', + 'proxy/ppb_audio_proxy.h', 'proxy/ppb_buffer_proxy.cc', 'proxy/ppb_buffer_proxy.h', 'proxy/ppb_char_set_proxy.cc', diff --git a/ppapi/proxy/DEPS b/ppapi/proxy/DEPS index d5d2f9c..7ef8f98 100644 --- a/ppapi/proxy/DEPS +++ b/ppapi/proxy/DEPS @@ -1,4 +1,7 @@ include_rules = [ + "+base", + "+ipc", + # These files are really Chrome-only and we don't want to expose them, but # we need to use them for the proxy. Allow the code here to pull these # headers (which don't depend on anything else). diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc index b1ce1c4..df7383f 100644 --- a/ppapi/proxy/dispatcher.cc +++ b/ppapi/proxy/dispatcher.cc @@ -12,6 +12,8 @@ #include "base/logging.h" #include "ipc/ipc_message.h" #include "ipc/ipc_sync_channel.h" +#include "ppapi/c/dev/ppb_audio_config_dev.h" +#include "ppapi/c/dev/ppb_audio_dev.h" #include "ppapi/c/dev/ppb_buffer_dev.h" #include "ppapi/c/dev/ppb_char_set_dev.h" #include "ppapi/c/dev/ppb_cursor_control_dev.h" @@ -31,6 +33,8 @@ #include "ppapi/c/ppb_url_response_info.h" #include "ppapi/c/ppp_instance.h" #include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_audio_config_proxy.h" +#include "ppapi/proxy/ppb_audio_proxy.h" #include "ppapi/proxy/ppb_buffer_proxy.h" #include "ppapi/proxy/ppb_char_set_proxy.h" #include "ppapi/proxy/ppb_core_proxy.h" @@ -54,8 +58,10 @@ namespace pp { namespace proxy { -Dispatcher::Dispatcher(GetInterfaceFunc local_get_interface) +Dispatcher::Dispatcher(base::ProcessHandle remote_process_handle, + GetInterfaceFunc local_get_interface) : pp_module_(0), + remote_process_handle_(remote_process_handle), disallow_trusted_interfaces_(true), local_get_interface_(local_get_interface), declared_supported_remote_interfaces_(false), @@ -216,6 +222,10 @@ void Dispatcher::OnMsgDeclareInterfaces( InterfaceProxy* Dispatcher::CreateProxyForInterface( const std::string& interface_name, const void* interface_functions) { + if (interface_name == PPB_AUDIO_CONFIG_DEV_INTERFACE) + return new PPB_AudioConfig_Proxy(this, interface_functions); + if (interface_name == PPB_AUDIO_DEV_INTERFACE) + return new PPB_Audio_Proxy(this, interface_functions); if (interface_name == PPB_BUFFER_DEV_INTERFACE) return new PPB_Buffer_Proxy(this, interface_functions); if (interface_name == PPB_CHAR_SET_DEV_INTERFACE) diff --git a/ppapi/proxy/dispatcher.h b/ppapi/proxy/dispatcher.h index 356dbcf..deee5fc 100644 --- a/ppapi/proxy/dispatcher.h +++ b/ppapi/proxy/dispatcher.h @@ -10,6 +10,7 @@ #include <vector> #include "base/linked_ptr.h" +#include "base/process.h" #include "base/scoped_ptr.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_channel_handle.h" @@ -86,6 +87,14 @@ class Dispatcher : public IPC::Channel::Listener, // or not supported by the remote side, returns NULL. const void* GetProxiedInterface(const std::string& interface); + // Returns the remote process' handle. For the host dispatcher, this will be + // the plugin process, and for the plugin dispatcher, this will be the + // renderer process. This is used for sharing memory and such and is + // guaranteed valid (unless the remote process has suddenly died). + base::ProcessHandle remote_process_handle() const { + return remote_process_handle_; + } + // Called if the remote side is declaring to us which interfaces it supports // so we don't have to query for each one. We'll pre-create proxies for // each of the given interfaces. @@ -105,7 +114,8 @@ class Dispatcher : public IPC::Channel::Listener, } protected: - Dispatcher(GetInterfaceFunc local_get_interface); + Dispatcher(base::ProcessHandle remote_process_handle, + GetInterfaceFunc local_get_interface); // Setter for the derived classes to set the appropriate var serialization. // Takes ownership of the given pointer, which must be on the heap. @@ -154,6 +164,7 @@ class Dispatcher : public IPC::Channel::Listener, // this dispatcher. PP_Module pp_module_; + base::ProcessHandle remote_process_handle_; // See getter above. scoped_ptr<IPC::SyncChannel> channel_; bool disallow_trusted_interfaces_; diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index bb70796..a717af8 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -19,10 +19,11 @@ InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; } // namespace -HostDispatcher::HostDispatcher(const PPB_Var_Deprecated* var_interface, +HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, + const PPB_Var_Deprecated* var_interface, PP_Module module, GetInterfaceFunc local_get_interface) - : Dispatcher(local_get_interface) { + : Dispatcher(remote_process_handle, local_get_interface) { SetSerializationRules(new HostVarSerializationRules(var_interface, module)); } diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h index 94d45d2..f968652 100644 --- a/ppapi/proxy/host_dispatcher.h +++ b/ppapi/proxy/host_dispatcher.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/process.h" #include "base/scoped_ptr.h" #include "ppapi/c/pp_instance.h" #include "ppapi/proxy/dispatcher.h" @@ -36,7 +37,8 @@ class HostDispatcher : public Dispatcher { // Constructor for the renderer side. // // You must call Dispatcher::InitWithChannel after the constructor. - HostDispatcher(const PPB_Var_Deprecated* var_interface, + HostDispatcher(base::ProcessHandle host_process_handle, + const PPB_Var_Deprecated* var_interface, PP_Module module, GetInterfaceFunc local_get_interface); ~HostDispatcher(); diff --git a/ppapi/proxy/interface_id.h b/ppapi/proxy/interface_id.h index f0ae597..8d85f03 100644 --- a/ppapi/proxy/interface_id.h +++ b/ppapi/proxy/interface_id.h @@ -12,7 +12,9 @@ namespace proxy { // to route messages to the appropriate message handler. enum InterfaceID { // Zero is reserved for control messages. - INTERFACE_ID_PPB_BUFFER = 1, + INTERFACE_ID_PPB_AUDIO = 1, + INTERFACE_ID_PPB_AUDIO_CONFIG, + INTERFACE_ID_PPB_BUFFER, INTERFACE_ID_PPB_CHAR_SET, INTERFACE_ID_PPB_CORE, INTERFACE_ID_PPB_CURSORCONTROL, diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc index 085c15c..4c9adca 100644 --- a/ppapi/proxy/plugin_dispatcher.cc +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -30,10 +30,11 @@ const void* GetInterfaceFromDispatcher(const char* interface) { } // namespace -PluginDispatcher::PluginDispatcher(GetInterfaceFunc get_interface, +PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, + GetInterfaceFunc get_interface, InitModuleFunc init_module, ShutdownModuleFunc shutdown_module) - : Dispatcher(get_interface), + : Dispatcher(remote_process_handle, get_interface), init_module_(init_module), shutdown_module_(shutdown_module), plugin_resource_tracker_(new PluginResourceTracker( diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h index 0a97965..79eafb1 100644 --- a/ppapi/proxy/plugin_dispatcher.h +++ b/ppapi/proxy/plugin_dispatcher.h @@ -7,6 +7,7 @@ #include <string> +#include "base/process.h" #include "base/scoped_ptr.h" #include "ppapi/proxy/callback_tracker.h" #include "ppapi/proxy/dispatcher.h" @@ -29,7 +30,8 @@ class PluginDispatcher : public Dispatcher { // module ID will be set upon receipt of the InitializeModule message. // // You must call Dispatcher::InitWithChannel after the constructor. - PluginDispatcher(GetInterfaceFunc get_interface, + PluginDispatcher(base::ProcessHandle remote_process_handle, + GetInterfaceFunc get_interface, InitModuleFunc init_module, ShutdownModuleFunc shutdown_module); ~PluginDispatcher(); @@ -59,6 +61,7 @@ class PluginDispatcher : public Dispatcher { } private: + // IPC message handler. void OnInitializeModule(PP_Module pp_module, bool* result); InitModuleFunc init_module_; diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h index 09ed59f..52a8609 100644 --- a/ppapi/proxy/plugin_resource.h +++ b/ppapi/proxy/plugin_resource.h @@ -11,6 +11,8 @@ // If you inherit from resource, make sure you add the class name here. #define FOR_ALL_RESOURCES(F) \ + F(Audio) \ + F(AudioConfig) \ F(Buffer) \ F(Font) \ F(Graphics2D) \ diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index d0f5bed..dd2b246 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -10,8 +10,12 @@ #include <vector> #include "base/basictypes.h" +#include "base/process.h" +#include "base/shared_memory.h" #include "base/string16.h" +#include "base/sync_socket.h" #include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.h" #include "ppapi/c/pp_bool.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" diff --git a/ppapi/proxy/ppapi_messages_internal.h b/ppapi/proxy/ppapi_messages_internal.h index 22d8a52..d7f317e 100644 --- a/ppapi/proxy/ppapi_messages_internal.h +++ b/ppapi/proxy/ppapi_messages_internal.h @@ -13,7 +13,8 @@ // These are from the plugin to the renderer IPC_BEGIN_MESSAGES(Ppapi) // Loads the given plugin. - IPC_MESSAGE_CONTROL2(PpapiMsg_LoadPlugin, + IPC_MESSAGE_CONTROL3(PpapiMsg_LoadPlugin, + base::ProcessHandle /* host_process_handle */, FilePath /* path */, int /* renderer_id */) @@ -36,6 +37,27 @@ IPC_BEGIN_MESSAGES(Ppapi) uint32 /* serialized_callback */, int32 /* param */) + // PPB_Audio. + + // Notifies the result of the audio stream create call. This is called in + // both error cases and in the normal success case. These cases are + // differentiated by the result code, which is one of the standard PPAPI + // result codes. + // + // The handler of this message should always close all of the handles passed + // in, since some could be valid even in the error case. + IPC_MESSAGE_ROUTED5(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, + PP_Resource /* audio_id */, + int32_t /* result_code (will be != PP_OK on failure) */, + IPC::PlatformFileForTransit /* socket_handle */, + base::SharedMemoryHandle /* handle */, + int32_t /* length */) + + // PPB_Graphics2D. + IPC_MESSAGE_ROUTED2(PpapiMsg_PPBGraphics2D_FlushACK, + PP_Resource /* graphics_2d */, + int32_t /* pp_error */) + // PPP_Class. IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_HasProperty, int64 /* ppp_class */, @@ -88,11 +110,6 @@ IPC_BEGIN_MESSAGES(Ppapi) int64 /* ppp_class */, int64 /* object */) - // PPB_Graphics2D. - IPC_MESSAGE_ROUTED2(PpapiMsg_PPBGraphics2D_FlushACK, - PP_Resource /* graphics_2d */, - int32_t /* pp_error */) - // PPP_Instance. IPC_SYNC_MESSAGE_ROUTED3_1(PpapiMsg_PPPInstance_DidCreate, PP_Instance /* instance */, @@ -142,6 +159,26 @@ IPC_BEGIN_MESSAGES(PpapiHost) IPC_MESSAGE_CONTROL1(PpapiHostMsg_PluginLoaded, IPC::ChannelHandle /* handle */) + // PPB_Audio. + IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBAudio_Create, + PP_Instance /* instance_id */, + PP_Resource /* config_id */, + PP_Resource /* result */) + IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBAudio_StartOrStop, + PP_Resource /* audio_id */, + bool /* play */) + + // PPB_AudioConfig. + IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBAudioConfig_Create, + PP_Module /* module */, + int32_t /* sample_rate */, + uint32_t /* sample_frame_count */, + PP_Resource /* result */) + IPC_SYNC_MESSAGE_ROUTED1_1( + PpapiHostMsg_PPBAudioConfig_RecommendSampleFrameCount, + uint32_t /* requested */, + uint32_t /* result */) + // PPB_Buffer. IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBBuffer_Create, PP_Module /* module */, diff --git a/ppapi/proxy/ppb_audio_config_proxy.cc b/ppapi/proxy/ppb_audio_config_proxy.cc new file mode 100644 index 0000000..7ec3e8f --- /dev/null +++ b/ppapi/proxy/ppb_audio_config_proxy.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2010 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 "ppapi/proxy/ppb_audio_config_proxy.h" + +#include "ppapi/c/dev/ppb_audio_config_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +class AudioConfig : public PluginResource { + public: + AudioConfig(PP_AudioSampleRate_Dev sample_rate, uint32_t sample_frame_count) + : sample_rate_(sample_rate), + sample_frame_count_(sample_frame_count) { + } + virtual ~AudioConfig() {} + + // Resource overrides. + virtual AudioConfig* AsAudioConfig() { return this; } + + PP_AudioSampleRate_Dev sample_rate() const { return sample_rate_; } + uint32_t sample_frame_count() const { return sample_frame_count_; } + + private: + PP_AudioSampleRate_Dev sample_rate_; + uint32_t sample_frame_count_; + + DISALLOW_COPY_AND_ASSIGN(AudioConfig); +}; + +namespace { + +PP_Resource CreateStereo16bit(PP_Module module_id, + PP_AudioSampleRate_Dev sample_rate, + uint32_t sample_frame_count) { + PP_Resource result = 0; + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudioConfig_Create( + INTERFACE_ID_PPB_AUDIO_CONFIG, module_id, + static_cast<int32_t>(sample_rate), sample_frame_count, + &result)); + if (!result) + return 0; + + linked_ptr<AudioConfig> object( + new AudioConfig(sample_rate, sample_frame_count)); + PluginDispatcher::Get()->plugin_resource_tracker()->AddResource( + result, object); + return result; +} + +uint32_t RecommendSampleFrameCount(uint32_t requested_sample_frame_count) { + uint32_t result = 0; + PluginDispatcher::Get()->Send( + new PpapiHostMsg_PPBAudioConfig_RecommendSampleFrameCount( + INTERFACE_ID_PPB_AUDIO_CONFIG, requested_sample_frame_count, + &result)); + return result; +} + +PP_Bool IsAudioConfig(PP_Resource resource) { + AudioConfig* object = PluginResource::GetAs<AudioConfig>(resource); + return BoolToPPBool(!!object); +} + +PP_AudioSampleRate_Dev GetSampleRate(PP_Resource config_id) { + AudioConfig* object = PluginResource::GetAs<AudioConfig>(config_id); + if (!object) + return PP_AUDIOSAMPLERATE_NONE; + return object->sample_rate(); +} + +uint32_t GetSampleFrameCount(PP_Resource config_id) { + AudioConfig* object = PluginResource::GetAs<AudioConfig>(config_id); + if (!object) + return 0; + return object->sample_frame_count(); +} + +const PPB_AudioConfig_Dev audio_config_interface = { + &CreateStereo16bit, + &RecommendSampleFrameCount, + &IsAudioConfig, + &GetSampleRate, + &GetSampleFrameCount +}; + +} // namespace + +PPB_AudioConfig_Proxy::PPB_AudioConfig_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_AudioConfig_Proxy::~PPB_AudioConfig_Proxy() { +} + +const void* PPB_AudioConfig_Proxy::GetSourceInterface() const { + return &audio_config_interface; +} + +InterfaceID PPB_AudioConfig_Proxy::GetInterfaceId() const { + return INTERFACE_ID_PPB_AUDIO_CONFIG; +} + +void PPB_AudioConfig_Proxy::OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(PPB_AudioConfig_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudioConfig_Create, + OnMsgCreateStereo16Bit) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudioConfig_RecommendSampleFrameCount, + OnMsgRecommendSampleFrameCount) + IPC_END_MESSAGE_MAP() +} + +void PPB_AudioConfig_Proxy::OnMsgCreateStereo16Bit(PP_Module module, + int32_t sample_rate, + uint32_t sample_frame_count, + PP_Resource* result) { + *result = ppb_audio_config_target()->CreateStereo16Bit( + module, static_cast<PP_AudioSampleRate_Dev>(sample_rate), + sample_frame_count); +} + +void PPB_AudioConfig_Proxy::OnMsgRecommendSampleFrameCount( + uint32_t requested, + uint32_t* result) { + *result = ppb_audio_config_target()->RecommendSampleFrameCount(requested); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_audio_config_proxy.h b/ppapi/proxy/ppb_audio_config_proxy.h new file mode 100644 index 0000000..b80ea31 --- /dev/null +++ b/ppapi/proxy/ppb_audio_config_proxy.h @@ -0,0 +1,46 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_PPB_AUDIO_CONFIG_PROXY_H_ +#define PPAPI_PROXY_PPB_AUDIO_CONFIG_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_AudioConfig_Dev; + +namespace pp { +namespace proxy { + +class PPB_AudioConfig_Proxy : public InterfaceProxy { + public: + PPB_AudioConfig_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_AudioConfig_Proxy(); + + const PPB_AudioConfig_Dev* ppb_audio_config_target() const { + return static_cast<const PPB_AudioConfig_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual const void* GetSourceInterface() const; + virtual InterfaceID GetInterfaceId() const; + virtual void OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgCreateStereo16Bit(PP_Module module, + int32_t sample_rate, + uint32_t sample_frame_count, + PP_Resource* result); + void OnMsgRecommendSampleFrameCount(uint32_t requested, uint32_t* result); + + DISALLOW_COPY_AND_ASSIGN(PPB_AudioConfig_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_AUDIO_CONFIG_PROXY_H_ diff --git a/ppapi/proxy/ppb_audio_proxy.cc b/ppapi/proxy/ppb_audio_proxy.cc new file mode 100644 index 0000000..bb40693 --- /dev/null +++ b/ppapi/proxy/ppb_audio_proxy.cc @@ -0,0 +1,285 @@ +// Copyright (c) 2010 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 "ppapi/proxy/ppb_audio_proxy.h" + +#include "base/simple_thread.h" +#include "ppapi/c/dev/ppb_audio_dev.h" +#include "ppapi/c/dev/ppb_audio_trusted_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/interface_id.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/audio_impl.h" + +namespace pp { +namespace proxy { + +class Audio : public PluginResource, public pp::shared_impl::AudioImpl { + public: + Audio(PP_Resource config_id, PPB_Audio_Callback callback, void* user_data) + : config_(config_id) { + SetCallback(callback, user_data); + PluginDispatcher::Get()->plugin_resource_tracker()->AddRefResource( + config_); + } + virtual ~Audio() { + PluginDispatcher::Get()->plugin_resource_tracker()->ReleaseResource( + config_); + } + + // Resource overrides. + virtual Audio* AsAudio() { return this; } + + PP_Resource config() const { return config_; } + + void StartPlayback(PP_Resource resource) { + if (playing()) + return; + SetStartPlaybackState(); + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudio_StartOrStop( + INTERFACE_ID_PPB_AUDIO, resource, true)); + } + + void StopPlayback(PP_Resource resource) { + if (!playing()) + return; + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudio_StartOrStop( + INTERFACE_ID_PPB_AUDIO, resource, false)); + SetStopPlaybackState(); + } + + private: + PP_Resource config_; + + DISALLOW_COPY_AND_ASSIGN(Audio); +}; + +namespace { + +PP_Resource Create(PP_Instance instance_id, + PP_Resource config_id, + PPB_Audio_Callback callback, + void* user_data) { + PP_Resource result; + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudio_Create( + INTERFACE_ID_PPB_AUDIO, instance_id, config_id, &result)); + if (!result) + return 0; + + linked_ptr<Audio> object(new Audio(config_id, callback, user_data)); + PluginDispatcher::Get()->plugin_resource_tracker()->AddResource( + result, object); + return result; +} + +PP_Bool IsAudio(PP_Resource resource) { + Audio* object = PluginResource::GetAs<Audio>(resource); + return BoolToPPBool(!!object); +} + +PP_Resource GetCurrentConfiguration(PP_Resource audio_id) { + Audio* object = PluginResource::GetAs<Audio>(audio_id); + if (!object) + return 0; + PP_Resource result = object->config(); + PluginDispatcher::Get()->plugin_resource_tracker()->AddRefResource(result); + return result; +} + +PP_Bool StartPlayback(PP_Resource audio_id) { + Audio* object = PluginResource::GetAs<Audio>(audio_id); + if (!object) + return PP_FALSE; + object->StartPlayback(audio_id); + return PP_TRUE; +} + +PP_Bool StopPlayback(PP_Resource audio_id) { + Audio* object = PluginResource::GetAs<Audio>(audio_id); + if (!object) + return PP_FALSE; + object->StopPlayback(audio_id); + return PP_TRUE; +} + +const PPB_Audio_Dev audio_interface = { + &Create, + &IsAudio, + &GetCurrentConfiguration, + &StartPlayback, + &StopPlayback +}; + +} // namespace + +PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_Audio_Proxy::~PPB_Audio_Proxy() { +} + +const void* PPB_Audio_Proxy::GetSourceInterface() const { + return &audio_interface; +} + +InterfaceID PPB_Audio_Proxy::GetInterfaceId() const { + return INTERFACE_ID_PPB_AUDIO; +} + +void PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop, + OnMsgStartOrStop) + + IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, + OnMsgNotifyAudioStreamCreated) + IPC_END_MESSAGE_MAP() +} + +void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id, + PP_Resource config_id, + PP_Resource* result) { + const PPB_AudioTrusted_Dev* audio_trusted = + reinterpret_cast<const PPB_AudioTrusted_Dev*>( + dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_DEV_INTERFACE)); + if (!audio_trusted) { + *result = 0; + return; + } + + *result = audio_trusted->CreateTrusted(instance_id); + if (!result) + return; + + CompletionCallback callback = callback_factory_.NewCallback( + &PPB_Audio_Proxy::AudioChannelConnected, *result); + int32_t open_error = audio_trusted->Open(*result, config_id, + callback.pp_completion_callback()); + if (open_error != PP_ERROR_WOULDBLOCK) + callback.Run(open_error); +} + +void PPB_Audio_Proxy::OnMsgStartOrStop(PP_Resource audio_id, bool play) { + if (play) + ppb_audio_target()->StartPlayback(audio_id); + else + ppb_audio_target()->StopPlayback(audio_id); +} + +void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated( + PP_Resource audio_id, + int32_t result_code, + IPC::PlatformFileForTransit socket_handle, + base::SharedMemoryHandle handle, + uint32_t length) { + Audio* object = PluginResource::GetAs<Audio>(audio_id); + if (!object || result_code != PP_OK) { + // The caller may still have given us these handles in the failure case. + // The easiest way to clean these up is to just put them in the objects + // and then close them. This failure case is not performance critical. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); + base::SharedMemory temp_mem(handle, false); + return; + } + object->SetStreamInfo( + handle, length, IPC::PlatformFileForTransitToPlatformFile(socket_handle)); +} + +void PPB_Audio_Proxy::AudioChannelConnected(int32_t result, + PP_Resource resource) { + IPC::PlatformFileForTransit socket_handle = + IPC::InvalidPlatformFileForTransit(); +#if defined(OS_WIN) + base::SharedMemoryHandle shared_memory = NULL; +#elif defined(OS_POSIX) + base::SharedMemoryHandle shared_memory(-1, false); +#else + #error Not implemented. +#endif + uint32_t shared_memory_length = 0; + + int32_t result_code = result; + if (result_code == PP_OK) { + result_code = GetAudioConnectedHandles(resource, &socket_handle, + &shared_memory, + &shared_memory_length); + } + + // Send all the values, even on error. This simplifies some of our cleanup + // code since the handles will be in the other process and could be + // inconvenient to clean up. Our IPC code will automatically handle this for + // us, as long as the remote side always closes the handles it receives + // (in OnMsgNotifyAudioStreamCreated), even in the failure case. + dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated( + INTERFACE_ID_PPB_AUDIO, resource, result_code, shared_memory, + socket_handle, shared_memory_length)); +} + +int32_t PPB_Audio_Proxy::GetAudioConnectedHandles( + PP_Resource resource, + IPC::PlatformFileForTransit* foreign_socket_handle, + base::SharedMemoryHandle* foreign_shared_memory_handle, + uint32_t* shared_memory_length) { + // Get the trusted audio interface which will give us the handles. + const PPB_AudioTrusted_Dev* audio_trusted = + reinterpret_cast<const PPB_AudioTrusted_Dev*>( + dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_DEV_INTERFACE)); + if (!audio_trusted) + return PP_ERROR_NOINTERFACE; + + // Get the socket handle for signaling. + int32_t socket_handle; + int32_t result = audio_trusted->GetSyncSocket(resource, &socket_handle); + if (result != PP_OK) + return result; + +#if defined(OS_WIN) + // On Windows, duplicate the socket into the plugin process, this will + // automatically close the source handle. + ::DuplicateHandle( + GetCurrentProcess(), + reinterpret_cast<HANDLE>(static_cast<intptr_t>(socket_handle)), + dispatcher()->remote_process_handle(), foreign_socket_handle, + STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ | FILE_MAP_WRITE, + FALSE, DUPLICATE_CLOSE_SOURCE); +#else + // On Posix, the socket handle will be auto-duplicated when we send the + // FileDescriptor. Set AutoClose since we don't need the handle any more. + *foreign_socket_handle = base::FileDescriptor(socket_handle, true); +#endif + + // Get the shared memory for the buffer. + // TODO(brettw) remove the reinterpret cast when the interface is updated. + int shared_memory_handle; + result = audio_trusted->GetSharedMemory(resource, &shared_memory_handle, + shared_memory_length); + if (result != PP_OK) + return result; + + base::SharedMemory shared_memory( +#if defined(OS_WIN) + reinterpret_cast<HANDLE>(static_cast<intptr_t>(shared_memory_handle)), +#else + base::FileDescriptor(shared_memory_handle, false), +#endif + false); + + // Duplicate the shared memory to the plugin process. This will automatically + // close the source handle. + if (!shared_memory.GiveToProcess(dispatcher()->remote_process_handle(), + foreign_shared_memory_handle)) + return PP_ERROR_FAILED; + + return PP_OK; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_audio_proxy.h b/ppapi/proxy/ppb_audio_proxy.h new file mode 100644 index 0000000..a6d2738 --- /dev/null +++ b/ppapi/proxy/ppb_audio_proxy.h @@ -0,0 +1,78 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_PPB_AUDIO_PROXY_H_ +#define PPAPI_PROXY_PPB_AUDIO_PROXY_H_ + +#include "base/basictypes.h" +#include "base/shared_memory.h" +#include "base/sync_socket.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + +struct PPB_Audio_Dev; + +namespace pp { +namespace proxy { + +class PPB_Audio_Proxy : public InterfaceProxy { + public: + PPB_Audio_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Audio_Proxy(); + + const PPB_Audio_Dev* ppb_audio_target() const { + return static_cast<const PPB_Audio_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual const void* GetSourceInterface() const; + virtual InterfaceID GetInterfaceId() const; + virtual void OnMessageReceived(const IPC::Message& msg); + + private: + // Plugin->renderer message handlers. + void OnMsgCreate(PP_Instance instance_id, + PP_Resource config_id, + PP_Resource* result); + void OnMsgStartOrStop(PP_Resource audio_id, bool play); + + // Renderer->plugin message handlers. + void OnMsgNotifyAudioStreamCreated( + PP_Resource audio_id, + int32_t result_code, + IPC::PlatformFileForTransit socket_handle, + base::SharedMemoryHandle shared_memory_handle, + uint32_t shared_memory_length); + + void AudioChannelConnected(int32_t result, PP_Resource resource); + + // In the renderer, this is called in response to a stream created message. + // It will retrieve the shared memory and socket handles and place them into + // the given out params. The return value is a PPAPI error code. + // + // The input arguments should be initialized to 0 or -1, depending on the + // platform's default invalid handle values. On error, some of these + // arguments may be written to, and others may be untouched, depending on + // where the error occurred. + int32_t GetAudioConnectedHandles( + PP_Resource resource, + IPC::PlatformFileForTransit* foreign_socket_handle, + base::SharedMemoryHandle* foreign_shared_memory_handle, + uint32_t* shared_memory_length); + + CompletionCallbackFactory<PPB_Audio_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Audio_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_AUDIO_PROXY_H_ diff --git a/ppapi/shared_impl/DEPS b/ppapi/shared_impl/DEPS new file mode 100644 index 0000000..84fea55 --- /dev/null +++ b/ppapi/shared_impl/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+base", + "-ppapi/cpp", +] diff --git a/ppapi/shared_impl/README.txt b/ppapi/shared_impl/README.txt new file mode 100644 index 0000000..71ff8d6 --- /dev/null +++ b/ppapi/shared_impl/README.txt @@ -0,0 +1,2 @@ +This directory contains implementation code for PPAPI that needs to be shared +between the backend implemntation in the renderer and in the proxy. diff --git a/ppapi/shared_impl/audio_impl.cc b/ppapi/shared_impl/audio_impl.cc new file mode 100644 index 0000000..83b73f6 --- /dev/null +++ b/ppapi/shared_impl/audio_impl.cc @@ -0,0 +1,96 @@ +// Copyright (c) 2010 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 "ppapi/shared_impl/audio_impl.h" + +#include "base/logging.h" + +namespace pp { +namespace shared_impl { + +AudioImpl::AudioImpl() + : playing_(false), + shared_memory_size_(0), + callback_(NULL), + user_data_(NULL) { +} + +AudioImpl::~AudioImpl() { + // Closing the socket causes the thread to exit - wait for it. + socket_->Close(); + if (audio_thread_.get()) { + audio_thread_->Join(); + audio_thread_.reset(); + } +} + +void AudioImpl::SetCallback(PPB_Audio_Callback callback, void* user_data) { + callback_ = callback; + user_data_ = user_data; +} + +void AudioImpl::SetStartPlaybackState() { + DCHECK(!playing_); + DCHECK(!audio_thread_.get()); + + // If the socket doesn't exist, that means that the plugin has started before + // the browser has had a chance to create all the shared memory info and + // notify us. This is a common case. In this case, we just set the playing_ + // flag and the playback will automatically start when that data is available + // in SetStreamInfo. + if (callback_ && socket_.get()) + StartThread(); + playing_ = true; +} + +void AudioImpl::SetStopPlaybackState() { + DCHECK(playing_); + + if (audio_thread_.get()) { + audio_thread_->Join(); + audio_thread_.reset(); + } + playing_ = false; +} + +void AudioImpl::SetStreamInfo(base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size, + base::SyncSocket::Handle socket_handle) { + socket_.reset(new base::SyncSocket(socket_handle)); + shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); + shared_memory_size_ = shared_memory_size; + + if (callback_) { + shared_memory_->Map(shared_memory_size_); + + // In common case StartPlayback() was called before StreamCreated(). + if (playing_) + StartThread(); + } +} + +void AudioImpl::StartThread() { + DCHECK(callback_); + DCHECK(!audio_thread_.get()); + audio_thread_.reset(new base::DelegateSimpleThread( + this, "plugin_audio_thread")); + audio_thread_->Start(); +} + +void AudioImpl::Run() { + int pending_data; + void* buffer = shared_memory_->memory(); + + while (sizeof(pending_data) == + socket_->Receive(&pending_data, sizeof(pending_data)) && + pending_data >= 0) { + // Exit the thread on pause. + if (pending_data < 0) + return; + callback_(buffer, shared_memory_size_, user_data_); + } +} + +} // namespace shared_impl +} // namespace pp diff --git a/ppapi/shared_impl/audio_impl.h b/ppapi/shared_impl/audio_impl.h new file mode 100644 index 0000000..b4cb077 --- /dev/null +++ b/ppapi/shared_impl/audio_impl.h @@ -0,0 +1,85 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_SHARED_IMPL_AUDIO_IMPL_H_ +#define PPAPI_SHARED_IMPL_AUDIO_IMPL_H_ + +#include "base/scoped_ptr.h" +#include "base/simple_thread.h" +#include "base/shared_memory.h" +#include "base/sync_socket.h" +#include "ppapi/c/dev/ppb_audio_dev.h" + +namespace pp { +namespace shared_impl { + +// Implements the logic to map shared memory and run the audio thread signaled +// from the sync socket. Both the proxy and the renderer implementation use +// this code. +class AudioImpl : public base::DelegateSimpleThread::Delegate { + public: + AudioImpl(); + virtual ~AudioImpl(); + + bool playing() const { return playing_; } + + // Sets the callback information that the background thread will use. This + // is optional. Without a callback, the thread will not be run. This + // non-callback mode is used in the renderer with the proxy, since the proxy + // handles the callback entirely within the plugin process. + void SetCallback(PPB_Audio_Callback callback, void* user_data); + + // Configures the current state to be playing or not. The caller is + // responsible for ensuring the new state is the opposite of the current one. + // + // This is the implementation for PPB_Audio.Start/StopPlayback, except that + // it does not actually notify the audio system to stop playback, it just + // configures our object to stop generating callbacks. The actual stop + // playback request will be done in the derived classes and will be different + // from the proxy and the renderer. + void SetStartPlaybackState(); + void SetStopPlaybackState(); + + // Sets the shared memory and socket handles. This will automatically start + // playback if we're currently set to play. + void SetStreamInfo(base::SharedMemoryHandle shared_memory_handle, + size_t shared_memory_size, + base::SyncSocket::Handle socket_handle); + + private: + // Starts execution of the audio thread. + void StartThread(); + + // DelegateSimpleThread::Delegate implementation. Run on the audio thread. + void Run(); + + // True if playing the stream. + bool playing_; + + // Socket used to notify us when audio is ready to accept new samples. This + // pointer is created in StreamCreated(). + scoped_ptr<base::SyncSocket> socket_; + + // Sample buffer in shared memory. This pointer is created in + // StreamCreated(). The memory is only mapped when the audio thread is + // created. + scoped_ptr<base::SharedMemory> shared_memory_; + + // The size of the sample buffer in bytes. + size_t shared_memory_size_; + + // When the callback is set, this thread is spawned for calling it. + scoped_ptr<base::DelegateSimpleThread> audio_thread_; + + // Callback to call when audio is ready to accept new samples. + PPB_Audio_Callback callback_; + + // User data pointer passed verbatim to the callback function. + void* user_data_; +}; + +} // namespace shared_impl +} // namespace pp + +#endif // PPAPI_SHARED_IMPL_AUDIO_IMPL_H_ diff --git a/webkit/glue/plugins/pepper_audio.cc b/webkit/glue/plugins/pepper_audio.cc index 0b0999a..d18dbae 100644 --- a/webkit/glue/plugins/pepper_audio.cc +++ b/webkit/glue/plugins/pepper_audio.cc @@ -96,9 +96,9 @@ PP_Bool IsAudio(PP_Resource resource) { return BoolToPPBool(!!audio); } -PP_Resource GetCurrentConfiguration(PP_Resource audio_id) { +PP_Resource GetCurrentConfig(PP_Resource audio_id) { scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); - return audio ? audio->GetCurrentConfiguration() : 0; + return audio ? audio->GetCurrentConfig() : 0; } PP_Bool StartPlayback(PP_Resource audio_id) { @@ -114,7 +114,7 @@ PP_Bool StopPlayback(PP_Resource audio_id) { const PPB_Audio_Dev ppb_audio = { &Create, &IsAudio, - &GetCurrentConfiguration, + &GetCurrentConfig, &StartPlayback, &StopPlayback, }; @@ -201,14 +201,8 @@ AudioConfig* AudioConfig::AsAudioConfig() { 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), create_callback_pending_(false) { create_callback_ = PP_MakeCompletionCallback(NULL, NULL); } @@ -218,20 +212,12 @@ Audio::~Audio() { 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. } const PPB_Audio_Dev* Audio::GetInterface() { @@ -253,8 +239,7 @@ bool Audio::Init(PluginDelegate* plugin_delegate, config_ = Resource::GetAs<AudioConfig>(config_id); if (!config_) return false; - callback_ = callback; - user_data_ = user_data; + SetCallback(callback, user_data); // When the stream is created, we'll get called back on StreamCreated(). audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), @@ -263,6 +248,26 @@ bool Audio::Init(PluginDelegate* plugin_delegate, return audio_ != NULL; } +PP_Resource Audio::GetCurrentConfig() { + return config_->GetReference(); +} + +bool Audio::StartPlayback() { + if (playing()) + return true; + SetStartPlaybackState(); + return audio_->StartPlayback(); +} + +bool Audio::StopPlayback() { + if (!playing()) + return true; + if (!audio_->StopPlayback()) + return false; + SetStopPlaybackState(); + return true; +} + int32_t Audio::Open(PluginDelegate* plugin_delegate, PP_Resource config_id, PP_CompletionCallback create_callback) { @@ -287,11 +292,11 @@ int32_t Audio::Open(PluginDelegate* plugin_delegate, } int32_t Audio::GetSyncSocket(int* sync_socket) { - if (socket_ != NULL) { + if (socket_for_create_callback_.get()) { #if defined(OS_POSIX) - *sync_socket = socket_->handle(); + *sync_socket = socket_for_create_callback_->handle(); #elif defined(OS_WIN) - *sync_socket = reinterpret_cast<int>(socket_->handle()); + *sync_socket = reinterpret_cast<int>(socket_for_create_callback_->handle()); #else #error "Platform not supported." #endif @@ -301,88 +306,42 @@ int32_t Audio::GetSyncSocket(int* sync_socket) { } int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) { - if (shared_memory_ != NULL) { + if (shared_memory_for_create_callback_.get()) { #if defined(OS_POSIX) - *shm_handle = shared_memory_->handle().fd; + *shm_handle = shared_memory_for_create_callback_->handle().fd; #elif defined(OS_WIN) - *shm_handle = reinterpret_cast<int>(shared_memory_->handle()); + *shm_handle = reinterpret_cast<int>( + shared_memory_for_create_callback_->handle()); #else #error "Platform not supported." #endif - *shm_size = shared_memory_size_; + *shm_size = shared_memory_size_for_create_callback_; return PP_OK; } return PP_ERROR_FAILED; } -bool Audio::StartPlayback() { - if (playing_) - return true; - - CHECK(!audio_thread_.get()); - if (callback_ && socket_.get()) { - audio_thread_.reset(new base::DelegateSimpleThread(this, - "plugin_audio_thread")); - audio_thread_->Start(); - } - playing_ = true; - return audio_->StartPlayback(); -} - -bool Audio::StopPlayback() { - if (!playing_) - return true; - - if (!audio_->StopPlayback()) - return false; - - if (audio_thread_.get()) { - audio_thread_->Join(); - audio_thread_.reset(); - } - playing_ = false; - return true; -} - void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle, size_t shared_memory_size, base::SyncSocket::Handle socket_handle) { - socket_.reset(new base::SyncSocket(socket_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_) { + // Trusted side of proxy can specify a callback to recieve handles. In + // this case we don't need to map any data or start the thread since it + // will be handled by the proxy. + shared_memory_for_create_callback_.reset( + new base::SharedMemory(shared_memory_handle, false)); + shared_memory_size_for_create_callback_ = shared_memory_size; + socket_for_create_callback_.reset(new base::SyncSocket(socket_handle)); + 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, - "plugin_audio_thread")); - audio_thread_->Start(); - } - } -} -void Audio::Run() { - int pending_data; - void* buffer = shared_memory_->memory(); - size_t buffer_size_in_bytes = config_->BufferSize(); - - while (sizeof(pending_data) == - socket_->Receive(&pending_data, sizeof(pending_data)) && - pending_data >= 0) { - // Exit the thread on pause. - if (pending_data < 0) - return; - callback_(buffer, buffer_size_in_bytes, user_data_); + // Close the handles now that this process is done with them. + shared_memory_for_create_callback_.reset(); + shared_memory_size_for_create_callback_ = 0; + socket_for_create_callback_.reset(); + } else { + SetStreamInfo(shared_memory_handle, shared_memory_size, socket_handle); } } diff --git a/webkit/glue/plugins/pepper_audio.h b/webkit/glue/plugins/pepper_audio.h index 3b4a8cc..7417544 100644 --- a/webkit/glue/plugins/pepper_audio.h +++ b/webkit/glue/plugins/pepper_audio.h @@ -6,14 +6,13 @@ #define WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_ #include "base/ref_counted.h" -#include "base/scoped_ptr.h" #include "base/shared_memory.h" -#include "base/simple_thread.h" #include "base/sync_socket.h" #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 "ppapi/shared_impl/audio_impl.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" @@ -43,9 +42,11 @@ class AudioConfig : public Resource { uint32_t sample_frame_count_; }; +// Some of the backend functionality of this class is implemented by the +// AudioImpl so it can be shared with the proxy. class Audio : public Resource, - public PluginDelegate::PlatformAudio::Client, - public base::DelegateSimpleThread::Delegate { + public pp::shared_impl::AudioImpl, + public PluginDelegate::PlatformAudio::Client { public: explicit Audio(PluginModule* module, PP_Instance instance_id); virtual ~Audio(); @@ -53,30 +54,25 @@ class Audio : public Resource, static const PPB_Audio_Dev* GetInterface(); static const PPB_AudioTrusted_Dev* GetTrustedInterface(); + PP_Instance pp_instance() { + return pp_instance_; + } + + // PPB_Audio implementation. bool Init(PluginDelegate* plugin_delegate, PP_Resource config_id, PPB_Audio_Callback user_callback, void* user_data); + PP_Resource GetCurrentConfig(); + bool StartPlayback(); + bool StopPlayback(); + // PPB_Audio_Trusted implementation. 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, uint32_t* shm_size); - bool StartPlayback(); - - bool StopPlayback(); - // Resource override. virtual Audio* AsAudio(); @@ -85,50 +81,29 @@ class Audio : public Resource, virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle, size_t shared_memory_size_, base::SyncSocket::Handle socket); - // End of pepper::PluginDelegate::PlatformAudio::Client implementation. - - // Audio thread. DelegateSimpleThread::Delegate implementation. - virtual void Run(); - // End of DelegateSimpleThread::Delegate implementation. - - // True if playing the stream. - bool playing_; // AudioConfig used for creating this Audio object. scoped_refptr<AudioConfig> config_; - // Instance id + // Plugin instance that owns this audio object. PP_Instance pp_instance_; // PluginDelegate audio object that we delegate audio IPC through. PluginDelegate::PlatformAudio* audio_; - // Socket used to notify us when audio is ready to accept new samples. This - // pointer is created in StreamCreated(). - scoped_ptr<base::SyncSocket> socket_; - - // Sample buffer in shared memory. This pointer is created in - // StreamCreated(). The memory is only mapped when the audio thread is - // created. - scoped_ptr<base::SharedMemory> shared_memory_; - - // The size of the sample buffer in bytes. - size_t shared_memory_size_; - - // When the callback is set, this thread is spawned for calling it. - scoped_ptr<base::DelegateSimpleThread> audio_thread_; - - // Callback to call when audio is ready to accept new samples. - volatile PPB_Audio_Callback callback_; - - // 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_; + + // When a create callback is being issued, these will save the info for + // querying from the callback. The proxy uses this to get the handles to the + // other process instead of mapping them in the renderer. These will be + // invalid all other times. + scoped_ptr<base::SharedMemory> shared_memory_for_create_callback_; + size_t shared_memory_size_for_create_callback_; + scoped_ptr<base::SyncSocket> socket_for_create_callback_; }; } // namespace pepper diff --git a/webkit/glue/plugins/pepper_font.cc b/webkit/glue/plugins/pepper_font.cc index 553c8ed..f871e69 100644 --- a/webkit/glue/plugins/pepper_font.cc +++ b/webkit/glue/plugins/pepper_font.cc @@ -135,12 +135,12 @@ PP_Bool Describe(PP_Resource font_id, } PP_Bool DrawTextAt(PP_Resource font_id, - PP_Resource image_data, - const PP_TextRun_Dev* text, - const PP_Point* position, - uint32_t color, - const PP_Rect* clip, - PP_Bool image_data_is_opaque) { + PP_Resource image_data, + const PP_TextRun_Dev* text, + const PP_Point* position, + uint32_t color, + const PP_Rect* clip, + PP_Bool image_data_is_opaque) { scoped_refptr<Font> font(Resource::GetAs<Font>(font_id)); if (!font.get()) return PP_FALSE; diff --git a/webkit/glue/plugins/pepper_plugin_module.cc b/webkit/glue/plugins/pepper_plugin_module.cc index b7bad9f..0da663a 100644 --- a/webkit/glue/plugins/pepper_plugin_module.cc +++ b/webkit/glue/plugins/pepper_plugin_module.cc @@ -354,10 +354,12 @@ scoped_refptr<PluginModule> PluginModule::CreateInternalModule( // static scoped_refptr<PluginModule> PluginModule::CreateOutOfProcessModule( MessageLoop* ipc_message_loop, + base::ProcessHandle plugin_process_handle, const IPC::ChannelHandle& handle, base::WaitableEvent* shutdown_event) { scoped_refptr<PluginModule> lib(new PluginModule); - if (!lib->InitForOutOfProcess(ipc_message_loop, handle, shutdown_event)) + if (!lib->InitForOutOfProcess(ipc_message_loop, plugin_process_handle, + handle, shutdown_event)) return NULL; return lib; } @@ -405,13 +407,14 @@ bool PluginModule::InitFromFile(const FilePath& path) { } bool PluginModule::InitForOutOfProcess(MessageLoop* ipc_message_loop, + base::ProcessHandle remote_process, const IPC::ChannelHandle& handle, base::WaitableEvent* shutdown_event) { const PPB_Var_Deprecated* var_interface = reinterpret_cast<const PPB_Var_Deprecated*>( GetInterface(PPB_VAR_DEPRECATED_INTERFACE)); - dispatcher_.reset(new pp::proxy::HostDispatcher(var_interface, - pp_module(), &GetInterface)); + dispatcher_.reset(new pp::proxy::HostDispatcher( + remote_process, var_interface, pp_module(), &GetInterface)); #if defined(OS_POSIX) // If we received a ChannelHandle, register it now. @@ -427,7 +430,6 @@ bool PluginModule::InitForOutOfProcess(MessageLoop* ipc_message_loop, bool init_result = false; dispatcher_->Send(new PpapiMsg_InitializeModule(pp_module(), &init_result)); - if (!init_result) { // TODO(brettw) does the module get unloaded in this case? dispatcher_.reset(); diff --git a/webkit/glue/plugins/pepper_plugin_module.h b/webkit/glue/plugins/pepper_plugin_module.h index 80eccda..19e1027 100644 --- a/webkit/glue/plugins/pepper_plugin_module.h +++ b/webkit/glue/plugins/pepper_plugin_module.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/native_library.h" +#include "base/process.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/weak_ptr.h" @@ -74,6 +75,7 @@ class PluginModule : public base::RefCounted<PluginModule>, EntryPoints entry_points); static scoped_refptr<PluginModule> CreateOutOfProcessModule( MessageLoop* ipc_message_loop, + base::ProcessHandle plugin_process_handle, const IPC::ChannelHandle& handle, base::WaitableEvent* shutdown_event); @@ -122,6 +124,7 @@ class PluginModule : public base::RefCounted<PluginModule>, bool InitFromEntryPoints(const EntryPoints& entry_points); bool InitFromFile(const FilePath& path); bool InitForOutOfProcess(MessageLoop* ipc_message_loop, + base::ProcessHandle remote_process, const IPC::ChannelHandle& handle, base::WaitableEvent* shutdown_event); static bool LoadEntryPoints(const base::NativeLibrary& library, diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi index 8ed3e8b..0f9816d 100644 --- a/webkit/glue/webkit_glue.gypi +++ b/webkit/glue/webkit_glue.gypi @@ -148,6 +148,7 @@ '<(DEPTH)/gpu/gpu.gyp:gles2_implementation', '<(DEPTH)/net/net.gyp:net', '<(DEPTH)/ppapi/ppapi.gyp:ppapi_proxy', + '<(DEPTH)/ppapi/ppapi.gyp:ppapi_shared_impl', '<(DEPTH)/printing/printing.gyp:printing', '<(DEPTH)/skia/skia.gyp:skia', '<(DEPTH)/third_party/icu/icu.gyp:icui18n', |