blob: 380bc39069c577eea37b0476c91962d389eee933 [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)
[email protected]771fc8d2012-05-19 01:39:05160// Don't build host side into NaCl IRT.
161#if !defined(OS_NACL)
[email protected]5d84d012010-12-02 17:17:21162 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
163 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
164 OnMsgStartOrStop)
[email protected]771fc8d2012-05-19 01:39:05165#endif
[email protected]5d84d012010-12-02 17:17:21166 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
167 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28168 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21169 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28170 return handled;
[email protected]5d84d012010-12-02 17:17:21171}
172
[email protected]771fc8d2012-05-19 01:39:05173#if !defined(OS_NACL)
[email protected]5d84d012010-12-02 17:17:21174void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53175 int32_t sample_rate,
176 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39177 HostResource* result) {
[email protected]4f2006122012-04-30 05:13:17178 thunk::EnterResourceCreation resource_creation(instance_id);
[email protected]55cdf6052011-05-13 19:22:53179 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21180 return;
[email protected]5d84d012010-12-02 17:17:21181
[email protected]55cdf6052011-05-13 19:22:53182 // Make the resource and get the API pointer to its trusted interface.
183 result->SetHostResource(
184 instance_id,
185 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39186 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21187 return;
[email protected]79d23c72011-08-08 19:40:40188
189 // At this point, we've set the result resource, and this is a sync request.
190 // Anything below this point must issue the AudioChannelConnected callback
191 // to the browser. Since that's an async message, it will be issued back to
192 // the plugin after the Create function returns (which is good because it
193 // would be weird to get a connected message with a failure code for a
194 // resource you haven't finished creating yet).
195 //
196 // The ...ForceCallback class will help ensure the callback is always called.
197 // All error cases must call SetResult on this class.
198 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
199 *result, callback_factory_,
200 &PPB_Audio_Proxy::AudioChannelConnected, *result);
201 if (enter.failed())
202 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21203
[email protected]55cdf6052011-05-13 19:22:53204 // Make an audio config object.
205 PP_Resource audio_config_res =
206 resource_creation.functions()->CreateAudioConfig(
207 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
208 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40209 if (!audio_config_res) {
210 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53211 return;
[email protected]79d23c72011-08-08 19:40:40212 }
[email protected]55cdf6052011-05-13 19:22:53213
214 // Initiate opening the audio object.
[email protected]79d23c72011-08-08 19:40:40215 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
216 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53217
218 // Clean up the temporary audio config resource we made.
219 const PPB_Core* core = static_cast<const PPB_Core*>(
[email protected]5c966022011-09-13 18:09:37220 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
[email protected]55cdf6052011-05-13 19:22:53221 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21222}
223
[email protected]f24448db2011-01-27 20:40:39224void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
225 bool play) {
[email protected]5c966022011-09-13 18:09:37226 EnterHostFromHostResource<PPB_Audio_API> enter(audio_id);
227 if (enter.failed())
228 return;
[email protected]5d84d012010-12-02 17:17:21229 if (play)
[email protected]5c966022011-09-13 18:09:37230 enter.object()->StartPlayback();
[email protected]5d84d012010-12-02 17:17:21231 else
[email protected]5c966022011-09-13 18:09:37232 enter.object()->StopPlayback();
[email protected]5d84d012010-12-02 17:17:21233}
234
[email protected]f24448db2011-01-27 20:40:39235void PPB_Audio_Proxy::AudioChannelConnected(
236 int32_t result,
237 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21238 IPC::PlatformFileForTransit socket_handle =
239 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54240 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21241 uint32_t shared_memory_length = 0;
242
243 int32_t result_code = result;
244 if (result_code == PP_OK) {
245 result_code = GetAudioConnectedHandles(resource, &socket_handle,
246 &shared_memory,
247 &shared_memory_length);
248 }
249
250 // Send all the values, even on error. This simplifies some of our cleanup
251 // code since the handles will be in the other process and could be
252 // inconvenient to clean up. Our IPC code will automatically handle this for
253 // us, as long as the remote side always closes the handles it receives
254 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
255 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]ac4b54d2011-10-20 23:09:28256 API_ID_PPB_AUDIO, resource, result_code, socket_handle,
[email protected]2031aeb2011-01-28 20:01:16257 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21258}
259
260int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39261 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21262 IPC::PlatformFileForTransit* foreign_socket_handle,
263 base::SharedMemoryHandle* foreign_shared_memory_handle,
264 uint32_t* shared_memory_length) {
[email protected]79d23c72011-08-08 19:40:40265 // Get the audio interface which will give us the handles.
[email protected]5c966022011-09-13 18:09:37266 EnterHostFromHostResource<PPB_Audio_API> enter(resource);
[email protected]79d23c72011-08-08 19:40:40267 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21268 return PP_ERROR_NOINTERFACE;
269
270 // Get the socket handle for signaling.
271 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40272 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21273 if (result != PP_OK)
274 return result;
275
[email protected]db0f57f52011-02-25 03:54:54276 // socket_handle doesn't belong to us: don't close it.
277 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
278 IntToPlatformFile(socket_handle), false);
279 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
280 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21281
282 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21283 int shared_memory_handle;
[email protected]79d23c72011-08-08 19:40:40284 result = enter.object()->GetSharedMemory(&shared_memory_handle,
285 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21286 if (result != PP_OK)
287 return result;
288
[email protected]db0f57f52011-02-25 03:54:54289 // shared_memory_handle doesn't belong to us: don't close it.
290 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
291 IntToPlatformFile(shared_memory_handle), false);
292 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21293 return PP_ERROR_FAILED;
294
295 return PP_OK;
296}
[email protected]771fc8d2012-05-19 01:39:05297#endif // !defined(OS_NACL)
298
299// Processed in the plugin (message from host).
300void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
301 const HostResource& audio_id,
302 int32_t result_code,
303 IPC::PlatformFileForTransit socket_handle,
304 base::SharedMemoryHandle handle,
305 uint32_t length) {
306 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
307 if (enter.failed() || result_code != PP_OK) {
308 // The caller may still have given us these handles in the failure case.
309 // The easiest way to clean these up is to just put them in the objects
310 // and then close them. This failure case is not performance critical.
311 base::SyncSocket temp_socket(
312 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
313 base::SharedMemory temp_mem(handle, false);
314 } else {
315 static_cast<Audio*>(enter.object())->SetStreamInfo(
316 enter.resource()->pp_instance(), handle, length,
317 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
318 }
319}
[email protected]5d84d012010-12-02 17:17:21320
321} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02322} // namespace ppapi