blob: 1000391967156fef9b49f28983f67b2f0902b059 [file] [log] [blame]
[email protected]00d320a2012-02-14 00:27:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]5d84d012010-12-02 17:17:212// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/ppb_audio_proxy.h"
6
[email protected]79d23c72011-08-08 19:40:407#include "base/compiler_specific.h"
[email protected]ac9ba8fe2010-12-30 18:08:368#include "base/threading/simple_thread.h"
[email protected]5d84d012010-12-02 17:17:219#include "ppapi/c/pp_errors.h"
[email protected]b9a59842011-01-15 01:04:0010#include "ppapi/c/ppb_audio.h"
[email protected]55cdf6052011-05-13 19:22:5311#include "ppapi/c/ppb_audio_config.h"
12#include "ppapi/c/ppb_var.h"
[email protected]b9a59842011-01-15 01:04:0013#include "ppapi/c/trusted/ppb_audio_trusted.h"
[email protected]cd910b92011-06-01 07:19:3114#include "ppapi/proxy/enter_proxy.h"
[email protected]5d84d012010-12-02 17:17:2115#include "ppapi/proxy/plugin_dispatcher.h"
[email protected]5d84d012010-12-02 17:17:2116#include "ppapi/proxy/ppapi_messages.h"
[email protected]ac4b54d2011-10-20 23:09:2817#include "ppapi/shared_impl/api_id.h"
[email protected]5a77eca2011-11-23 23:46:4618#include "ppapi/shared_impl/platform_file.h"
[email protected]794d83cd2011-10-20 19:09:2019#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]9a578392011-12-07 18:59:2720#include "ppapi/shared_impl/ppb_audio_shared.h"
[email protected]7f8b26b2011-08-18 15:41:0121#include "ppapi/shared_impl/resource.h"
[email protected]55cdf6052011-05-13 19:22:5322#include "ppapi/thunk/ppb_audio_config_api.h"
[email protected]55cdf6052011-05-13 19:22:5323#include "ppapi/thunk/enter.h"
24#include "ppapi/thunk/resource_creation_api.h"
25#include "ppapi/thunk/thunk.h"
[email protected]5d84d012010-12-02 17:17:2126
[email protected]5a77eca2011-11-23 23:46:4627using ppapi::IntToPlatformFile;
[email protected]79d23c72011-08-08 19:40:4028using ppapi::thunk::EnterResourceNoLock;
29using ppapi::thunk::PPB_Audio_API;
30using ppapi::thunk::PPB_AudioConfig_API;
[email protected]cd910b92011-06-01 07:19:3131
[email protected]4d2efd22011-08-18 21:58:0232namespace ppapi {
[email protected]5d84d012010-12-02 17:17:2133namespace proxy {
34
[email protected]9a578392011-12-07 18:59:2735class Audio : public Resource, public PPB_Audio_Shared {
[email protected]5d84d012010-12-02 17:17:2136 public:
[email protected]f24448db2011-01-27 20:40:3937 Audio(const HostResource& audio_id,
[email protected]4614f192011-01-21 00:26:4338 PP_Resource config_id,
39 PPB_Audio_Callback callback,
[email protected]55cdf6052011-05-13 19:22:5340 void* user_data);
41 virtual ~Audio();
[email protected]5d84d012010-12-02 17:17:2142
[email protected]7f8b26b2011-08-18 15:41:0143 // Resource overrides.
[email protected]cd910b92011-06-01 07:19:3144 virtual PPB_Audio_API* AsPPB_Audio_API();
[email protected]5d84d012010-12-02 17:17:2145
[email protected]55cdf6052011-05-13 19:22:5346 // PPB_Audio_API implementation.
47 virtual PP_Resource GetCurrentConfig() OVERRIDE;
48 virtual PP_Bool StartPlayback() OVERRIDE;
49 virtual PP_Bool StopPlayback() OVERRIDE;
[email protected]79d23c72011-08-08 19:40:4050 virtual int32_t OpenTrusted(PP_Resource config_id,
51 PP_CompletionCallback create_callback) OVERRIDE;
52 virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
53 virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
[email protected]5d84d012010-12-02 17:17:2154
55 private:
[email protected]55cdf6052011-05-13 19:22:5356 // Owning reference to the current config object. This isn't actually used,
57 // we just dish it out as requested by the plugin.
[email protected]5d84d012010-12-02 17:17:2158 PP_Resource config_;
59
60 DISALLOW_COPY_AND_ASSIGN(Audio);
61};
62
[email protected]55cdf6052011-05-13 19:22:5363Audio::Audio(const HostResource& audio_id,
64 PP_Resource config_id,
65 PPB_Audio_Callback callback,
66 void* user_data)
[email protected]00d320a2012-02-14 00:27:0467 : Resource(OBJECT_IS_PROXY, audio_id),
[email protected]55cdf6052011-05-13 19:22:5368 config_(config_id) {
69 SetCallback(callback, user_data);
[email protected]794d83cd2011-10-20 19:09:2070 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5371}
72
73Audio::~Audio() {
[email protected]794d83cd2011-10-20 19:09:2074 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(config_);
[email protected]55cdf6052011-05-13 19:22:5375}
76
[email protected]cd910b92011-06-01 07:19:3177PPB_Audio_API* Audio::AsPPB_Audio_API() {
[email protected]55cdf6052011-05-13 19:22:5378 return this;
79}
80
81PP_Resource Audio::GetCurrentConfig() {
82 // AddRef for the caller.
[email protected]794d83cd2011-10-20 19:09:2083 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5384 return config_;
85}
86
87PP_Bool Audio::StartPlayback() {
88 if (playing())
89 return PP_TRUE;
90 SetStartPlaybackState();
[email protected]7f8b26b2011-08-18 15:41:0191 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:5392 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]ac4b54d2011-10-20 23:09:2893 API_ID_PPB_AUDIO, host_resource(), true));
[email protected]55cdf6052011-05-13 19:22:5394 return PP_TRUE;
95}
96
97PP_Bool Audio::StopPlayback() {
98 if (!playing())
99 return PP_TRUE;
[email protected]7f8b26b2011-08-18 15:41:01100 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:53101 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]ac4b54d2011-10-20 23:09:28102 API_ID_PPB_AUDIO, host_resource(), false));
[email protected]55cdf6052011-05-13 19:22:53103 SetStopPlaybackState();
104 return PP_TRUE;
105}
106
[email protected]79d23c72011-08-08 19:40:40107int32_t Audio::OpenTrusted(PP_Resource config_id,
108 PP_CompletionCallback create_callback) {
109 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
110}
111
112int32_t Audio::GetSyncSocket(int* sync_socket) {
113 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
114}
115
116int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) {
117 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
118}
119
[email protected]5c966022011-09-13 18:09:37120PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher)
121 : InterfaceProxy(dispatcher),
[email protected]5d84d012010-12-02 17:17:21122 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
123}
124
125PPB_Audio_Proxy::~PPB_Audio_Proxy() {
126}
127
[email protected]465faa22011-02-08 16:31:46128// static
[email protected]55cdf6052011-05-13 19:22:53129PP_Resource PPB_Audio_Proxy::CreateProxyResource(
130 PP_Instance instance_id,
131 PP_Resource config_id,
132 PPB_Audio_Callback audio_callback,
133 void* user_data) {
134 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
135 if (!dispatcher)
136 return 0;
137
[email protected]79d23c72011-08-08 19:40:40138 EnterResourceNoLock<PPB_AudioConfig_API> config(config_id, true);
[email protected]55cdf6052011-05-13 19:22:53139 if (config.failed())
140 return 0;
141
[email protected]c6b2b7f2011-12-01 02:38:25142 if (!audio_callback)
143 return 0;
144
[email protected]55cdf6052011-05-13 19:22:53145 HostResource result;
146 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
[email protected]ac4b54d2011-10-20 23:09:28147 API_ID_PPB_AUDIO, instance_id,
[email protected]55cdf6052011-05-13 19:22:53148 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
149 &result));
150 if (result.is_null())
151 return 0;
152
[email protected]bab65ef2011-08-20 04:53:22153 return (new Audio(result, config_id,
154 audio_callback, user_data))->GetReference();
[email protected]55cdf6052011-05-13 19:22:53155}
156
[email protected]a95986a82010-12-24 06:19:28157bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
158 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21159 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
160 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
161 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
162 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21163 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
164 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28165 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21166 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28167 return handled;
[email protected]5d84d012010-12-02 17:17:21168}
169
170void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53171 int32_t sample_rate,
172 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39173 HostResource* result) {
[email protected]4f2006122012-04-30 05:13:17174 thunk::EnterResourceCreation resource_creation(instance_id);
[email protected]55cdf6052011-05-13 19:22:53175 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21176 return;
[email protected]5d84d012010-12-02 17:17:21177
[email protected]55cdf6052011-05-13 19:22:53178 // Make the resource and get the API pointer to its trusted interface.
179 result->SetHostResource(
180 instance_id,
181 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39182 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21183 return;
[email protected]79d23c72011-08-08 19:40:40184
185 // At this point, we've set the result resource, and this is a sync request.
186 // Anything below this point must issue the AudioChannelConnected callback
187 // to the browser. Since that's an async message, it will be issued back to
188 // the plugin after the Create function returns (which is good because it
189 // would be weird to get a connected message with a failure code for a
190 // resource you haven't finished creating yet).
191 //
192 // The ...ForceCallback class will help ensure the callback is always called.
193 // All error cases must call SetResult on this class.
194 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
195 *result, callback_factory_,
196 &PPB_Audio_Proxy::AudioChannelConnected, *result);
197 if (enter.failed())
198 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21199
[email protected]55cdf6052011-05-13 19:22:53200 // Make an audio config object.
201 PP_Resource audio_config_res =
202 resource_creation.functions()->CreateAudioConfig(
203 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
204 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40205 if (!audio_config_res) {
206 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53207 return;
[email protected]79d23c72011-08-08 19:40:40208 }
[email protected]55cdf6052011-05-13 19:22:53209
210 // Initiate opening the audio object.
[email protected]79d23c72011-08-08 19:40:40211 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
212 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53213
214 // Clean up the temporary audio config resource we made.
215 const PPB_Core* core = static_cast<const PPB_Core*>(
[email protected]5c966022011-09-13 18:09:37216 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
[email protected]55cdf6052011-05-13 19:22:53217 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21218}
219
[email protected]f24448db2011-01-27 20:40:39220void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
221 bool play) {
[email protected]5c966022011-09-13 18:09:37222 EnterHostFromHostResource<PPB_Audio_API> enter(audio_id);
223 if (enter.failed())
224 return;
[email protected]5d84d012010-12-02 17:17:21225 if (play)
[email protected]5c966022011-09-13 18:09:37226 enter.object()->StartPlayback();
[email protected]5d84d012010-12-02 17:17:21227 else
[email protected]5c966022011-09-13 18:09:37228 enter.object()->StopPlayback();
[email protected]5d84d012010-12-02 17:17:21229}
230
[email protected]f24448db2011-01-27 20:40:39231// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21232void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16233 const HostResource& audio_id,
234 int32_t result_code,
235 IPC::PlatformFileForTransit socket_handle,
236 base::SharedMemoryHandle handle,
237 uint32_t length) {
[email protected]cd910b92011-06-01 07:19:31238 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
[email protected]55cdf6052011-05-13 19:22:53239 if (enter.failed() || result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21240 // The caller may still have given us these handles in the failure case.
241 // The easiest way to clean these up is to just put them in the objects
242 // and then close them. This failure case is not performance critical.
243 base::SyncSocket temp_socket(
[email protected]2031aeb2011-01-28 20:01:16244 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
245 base::SharedMemory temp_mem(handle, false);
[email protected]cd910b92011-06-01 07:19:31246 } else {
247 static_cast<Audio*>(enter.object())->SetStreamInfo(
[email protected]96724682012-04-26 20:53:37248 enter.resource()->pp_instance(), handle, length,
[email protected]cd910b92011-06-01 07:19:31249 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]5d84d012010-12-02 17:17:21250 }
[email protected]5d84d012010-12-02 17:17:21251}
252
[email protected]f24448db2011-01-27 20:40:39253void PPB_Audio_Proxy::AudioChannelConnected(
254 int32_t result,
255 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21256 IPC::PlatformFileForTransit socket_handle =
257 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54258 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21259 uint32_t shared_memory_length = 0;
260
261 int32_t result_code = result;
262 if (result_code == PP_OK) {
263 result_code = GetAudioConnectedHandles(resource, &socket_handle,
264 &shared_memory,
265 &shared_memory_length);
266 }
267
268 // Send all the values, even on error. This simplifies some of our cleanup
269 // code since the handles will be in the other process and could be
270 // inconvenient to clean up. Our IPC code will automatically handle this for
271 // us, as long as the remote side always closes the handles it receives
272 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
273 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]ac4b54d2011-10-20 23:09:28274 API_ID_PPB_AUDIO, resource, result_code, socket_handle,
[email protected]2031aeb2011-01-28 20:01:16275 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21276}
277
278int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39279 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21280 IPC::PlatformFileForTransit* foreign_socket_handle,
281 base::SharedMemoryHandle* foreign_shared_memory_handle,
282 uint32_t* shared_memory_length) {
[email protected]79d23c72011-08-08 19:40:40283 // Get the audio interface which will give us the handles.
[email protected]5c966022011-09-13 18:09:37284 EnterHostFromHostResource<PPB_Audio_API> enter(resource);
[email protected]79d23c72011-08-08 19:40:40285 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21286 return PP_ERROR_NOINTERFACE;
287
288 // Get the socket handle for signaling.
289 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40290 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21291 if (result != PP_OK)
292 return result;
293
[email protected]db0f57f52011-02-25 03:54:54294 // socket_handle doesn't belong to us: don't close it.
295 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
296 IntToPlatformFile(socket_handle), false);
297 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
298 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21299
300 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21301 int shared_memory_handle;
[email protected]79d23c72011-08-08 19:40:40302 result = enter.object()->GetSharedMemory(&shared_memory_handle,
303 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21304 if (result != PP_OK)
305 return result;
306
[email protected]db0f57f52011-02-25 03:54:54307 // shared_memory_handle doesn't belong to us: don't close it.
308 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
309 IntToPlatformFile(shared_memory_handle), false);
310 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21311 return PP_ERROR_FAILED;
312
313 return PP_OK;
314}
315
316} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02317} // namespace ppapi