summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-02 17:17:21 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-02 17:17:21 +0000
commit5d84d01d904a2e5fa3e17b8d9165e63a20351160 (patch)
treedd87a4d94ed6276dc1551cbc5d3c744eb268cebd /ppapi
parent9a80065bad1506ac11163d597ace3295ddbfa8cb (diff)
downloadchromium_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
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/ppapi.gyp25
-rw-r--r--ppapi/proxy/DEPS3
-rw-r--r--ppapi/proxy/dispatcher.cc12
-rw-r--r--ppapi/proxy/dispatcher.h13
-rw-r--r--ppapi/proxy/host_dispatcher.cc5
-rw-r--r--ppapi/proxy/host_dispatcher.h4
-rw-r--r--ppapi/proxy/interface_id.h4
-rw-r--r--ppapi/proxy/plugin_dispatcher.cc5
-rw-r--r--ppapi/proxy/plugin_dispatcher.h5
-rw-r--r--ppapi/proxy/plugin_resource.h2
-rw-r--r--ppapi/proxy/ppapi_messages.h4
-rw-r--r--ppapi/proxy/ppapi_messages_internal.h49
-rw-r--r--ppapi/proxy/ppb_audio_config_proxy.cc135
-rw-r--r--ppapi/proxy/ppb_audio_config_proxy.h46
-rw-r--r--ppapi/proxy/ppb_audio_proxy.cc285
-rw-r--r--ppapi/proxy/ppb_audio_proxy.h78
-rw-r--r--ppapi/shared_impl/DEPS4
-rw-r--r--ppapi/shared_impl/README.txt2
-rw-r--r--ppapi/shared_impl/audio_impl.cc96
-rw-r--r--ppapi/shared_impl/audio_impl.h85
20 files changed, 847 insertions, 15 deletions
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_