blob: aa3c42e7fbc9780287c449776e717b56daf73a02 [file] [log] [blame]
[email protected]f24448db2011-01-27 20:40:391// Copyright (c) 2011 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/interface_id.h"
16#include "ppapi/proxy/plugin_dispatcher.h"
[email protected]5d84d012010-12-02 17:17:2117#include "ppapi/proxy/ppapi_messages.h"
18#include "ppapi/shared_impl/audio_impl.h"
[email protected]7f8b26b2011-08-18 15:41:0119#include "ppapi/shared_impl/resource.h"
[email protected]55cdf6052011-05-13 19:22:5320#include "ppapi/thunk/ppb_audio_config_api.h"
[email protected]55cdf6052011-05-13 19:22:5321#include "ppapi/thunk/enter.h"
22#include "ppapi/thunk/resource_creation_api.h"
23#include "ppapi/thunk/thunk.h"
[email protected]5d84d012010-12-02 17:17:2124
[email protected]79d23c72011-08-08 19:40:4025using ppapi::thunk::EnterResourceNoLock;
26using ppapi::thunk::PPB_Audio_API;
27using ppapi::thunk::PPB_AudioConfig_API;
[email protected]cd910b92011-06-01 07:19:3128
[email protected]4d2efd22011-08-18 21:58:0229namespace ppapi {
[email protected]5d84d012010-12-02 17:17:2130namespace proxy {
31
[email protected]4d2efd22011-08-18 21:58:0232class Audio : public Resource, public AudioImpl {
[email protected]5d84d012010-12-02 17:17:2133 public:
[email protected]f24448db2011-01-27 20:40:3934 Audio(const HostResource& audio_id,
[email protected]4614f192011-01-21 00:26:4335 PP_Resource config_id,
36 PPB_Audio_Callback callback,
[email protected]55cdf6052011-05-13 19:22:5337 void* user_data);
38 virtual ~Audio();
[email protected]5d84d012010-12-02 17:17:2139
[email protected]7f8b26b2011-08-18 15:41:0140 // Resource overrides.
[email protected]cd910b92011-06-01 07:19:3141 virtual PPB_Audio_API* AsPPB_Audio_API();
[email protected]5d84d012010-12-02 17:17:2142
[email protected]55cdf6052011-05-13 19:22:5343 // PPB_Audio_API implementation.
44 virtual PP_Resource GetCurrentConfig() OVERRIDE;
45 virtual PP_Bool StartPlayback() OVERRIDE;
46 virtual PP_Bool StopPlayback() OVERRIDE;
[email protected]79d23c72011-08-08 19:40:4047 virtual int32_t OpenTrusted(PP_Resource config_id,
48 PP_CompletionCallback create_callback) OVERRIDE;
49 virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
50 virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
[email protected]5d84d012010-12-02 17:17:2151
52 private:
[email protected]55cdf6052011-05-13 19:22:5353 // Owning reference to the current config object. This isn't actually used,
54 // we just dish it out as requested by the plugin.
[email protected]5d84d012010-12-02 17:17:2155 PP_Resource config_;
56
57 DISALLOW_COPY_AND_ASSIGN(Audio);
58};
59
[email protected]55cdf6052011-05-13 19:22:5360Audio::Audio(const HostResource& audio_id,
61 PP_Resource config_id,
62 PPB_Audio_Callback callback,
63 void* user_data)
[email protected]7f8b26b2011-08-18 15:41:0164 : Resource(audio_id),
[email protected]55cdf6052011-05-13 19:22:5365 config_(config_id) {
66 SetCallback(callback, user_data);
67 PluginResourceTracker::GetInstance()->AddRefResource(config_);
68}
69
70Audio::~Audio() {
71 PluginResourceTracker::GetInstance()->ReleaseResource(config_);
72}
73
[email protected]cd910b92011-06-01 07:19:3174PPB_Audio_API* Audio::AsPPB_Audio_API() {
[email protected]55cdf6052011-05-13 19:22:5375 return this;
76}
77
78PP_Resource Audio::GetCurrentConfig() {
79 // AddRef for the caller.
80 PluginResourceTracker::GetInstance()->AddRefResource(config_);
81 return config_;
82}
83
84PP_Bool Audio::StartPlayback() {
85 if (playing())
86 return PP_TRUE;
87 SetStartPlaybackState();
[email protected]7f8b26b2011-08-18 15:41:0188 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:5389 new PpapiHostMsg_PPBAudio_StartOrStop(
90 INTERFACE_ID_PPB_AUDIO, host_resource(), true));
91 return PP_TRUE;
92}
93
94PP_Bool Audio::StopPlayback() {
95 if (!playing())
96 return PP_TRUE;
[email protected]7f8b26b2011-08-18 15:41:0197 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:5398 new PpapiHostMsg_PPBAudio_StartOrStop(
99 INTERFACE_ID_PPB_AUDIO, host_resource(), false));
100 SetStopPlaybackState();
101 return PP_TRUE;
102}
103
[email protected]79d23c72011-08-08 19:40:40104int32_t Audio::OpenTrusted(PP_Resource config_id,
105 PP_CompletionCallback create_callback) {
106 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
107}
108
109int32_t Audio::GetSyncSocket(int* sync_socket) {
110 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
111}
112
113int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) {
114 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
115}
116
[email protected]5d84d012010-12-02 17:17:21117namespace {
118
[email protected]465faa22011-02-08 16:31:46119InterfaceProxy* CreateAudioProxy(Dispatcher* dispatcher,
120 const void* target_interface) {
121 return new PPB_Audio_Proxy(dispatcher, target_interface);
122}
123
[email protected]db0f57f52011-02-25 03:54:54124base::PlatformFile IntToPlatformFile(int32_t handle) {
125 // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle,
126 // those casts are ugly.
127#if defined(OS_WIN)
128 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
129#elif defined(OS_POSIX)
130 return handle;
131#else
132 #error Not implemented.
133#endif
134}
135
[email protected]5d84d012010-12-02 17:17:21136} // namespace
137
138PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher,
139 const void* target_interface)
140 : InterfaceProxy(dispatcher, target_interface),
141 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
142}
143
144PPB_Audio_Proxy::~PPB_Audio_Proxy() {
145}
146
[email protected]465faa22011-02-08 16:31:46147// static
148const InterfaceProxy::Info* PPB_Audio_Proxy::GetInfo() {
149 static const Info info = {
[email protected]4d2efd22011-08-18 21:58:02150 thunk::GetPPB_Audio_Thunk(),
[email protected]465faa22011-02-08 16:31:46151 PPB_AUDIO_INTERFACE,
152 INTERFACE_ID_PPB_AUDIO,
153 false,
154 &CreateAudioProxy,
155 };
156 return &info;
[email protected]5d84d012010-12-02 17:17:21157}
158
[email protected]55cdf6052011-05-13 19:22:53159// static
160PP_Resource PPB_Audio_Proxy::CreateProxyResource(
161 PP_Instance instance_id,
162 PP_Resource config_id,
163 PPB_Audio_Callback audio_callback,
164 void* user_data) {
165 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
166 if (!dispatcher)
167 return 0;
168
[email protected]79d23c72011-08-08 19:40:40169 EnterResourceNoLock<PPB_AudioConfig_API> config(config_id, true);
[email protected]55cdf6052011-05-13 19:22:53170 if (config.failed())
171 return 0;
172
173 HostResource result;
174 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
175 INTERFACE_ID_PPB_AUDIO, instance_id,
176 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
177 &result));
178 if (result.is_null())
179 return 0;
180
[email protected]4d2efd22011-08-18 21:58:02181 return (new Audio(result, config_id, audio_callback, user_data))->
182 GetReference();
[email protected]55cdf6052011-05-13 19:22:53183}
184
[email protected]a95986a82010-12-24 06:19:28185bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
186 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21187 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
188 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
189 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
190 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21191 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
192 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28193 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21194 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28195 return handled;
[email protected]5d84d012010-12-02 17:17:21196}
197
198void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53199 int32_t sample_rate,
200 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39201 HostResource* result) {
[email protected]4d2efd22011-08-18 21:58:02202 thunk::EnterFunction<thunk::ResourceCreationAPI> resource_creation(
203 instance_id, true);
[email protected]55cdf6052011-05-13 19:22:53204 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21205 return;
[email protected]5d84d012010-12-02 17:17:21206
[email protected]55cdf6052011-05-13 19:22:53207 // Make the resource and get the API pointer to its trusted interface.
208 result->SetHostResource(
209 instance_id,
210 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39211 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21212 return;
[email protected]79d23c72011-08-08 19:40:40213
214 // At this point, we've set the result resource, and this is a sync request.
215 // Anything below this point must issue the AudioChannelConnected callback
216 // to the browser. Since that's an async message, it will be issued back to
217 // the plugin after the Create function returns (which is good because it
218 // would be weird to get a connected message with a failure code for a
219 // resource you haven't finished creating yet).
220 //
221 // The ...ForceCallback class will help ensure the callback is always called.
222 // All error cases must call SetResult on this class.
223 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
224 *result, callback_factory_,
225 &PPB_Audio_Proxy::AudioChannelConnected, *result);
226 if (enter.failed())
227 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21228
[email protected]55cdf6052011-05-13 19:22:53229 // Make an audio config object.
230 PP_Resource audio_config_res =
231 resource_creation.functions()->CreateAudioConfig(
232 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
233 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40234 if (!audio_config_res) {
235 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53236 return;
[email protected]79d23c72011-08-08 19:40:40237 }
[email protected]55cdf6052011-05-13 19:22:53238
239 // Initiate opening the audio object.
[email protected]79d23c72011-08-08 19:40:40240 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
241 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53242
243 // Clean up the temporary audio config resource we made.
244 const PPB_Core* core = static_cast<const PPB_Core*>(
245 dispatcher()->GetLocalInterface(PPB_CORE_INTERFACE));
246 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21247}
248
[email protected]f24448db2011-01-27 20:40:39249void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
250 bool play) {
[email protected]5d84d012010-12-02 17:17:21251 if (play)
[email protected]f24448db2011-01-27 20:40:39252 ppb_audio_target()->StartPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21253 else
[email protected]f24448db2011-01-27 20:40:39254 ppb_audio_target()->StopPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21255}
256
[email protected]f24448db2011-01-27 20:40:39257// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21258void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16259 const HostResource& audio_id,
260 int32_t result_code,
261 IPC::PlatformFileForTransit socket_handle,
262 base::SharedMemoryHandle handle,
263 uint32_t length) {
[email protected]cd910b92011-06-01 07:19:31264 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
[email protected]55cdf6052011-05-13 19:22:53265 if (enter.failed() || result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21266 // The caller may still have given us these handles in the failure case.
267 // The easiest way to clean these up is to just put them in the objects
268 // and then close them. This failure case is not performance critical.
269 base::SyncSocket temp_socket(
[email protected]2031aeb2011-01-28 20:01:16270 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
271 base::SharedMemory temp_mem(handle, false);
[email protected]cd910b92011-06-01 07:19:31272 } else {
273 static_cast<Audio*>(enter.object())->SetStreamInfo(
274 handle, length,
275 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]5d84d012010-12-02 17:17:21276 }
[email protected]5d84d012010-12-02 17:17:21277}
278
[email protected]f24448db2011-01-27 20:40:39279void PPB_Audio_Proxy::AudioChannelConnected(
280 int32_t result,
281 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21282 IPC::PlatformFileForTransit socket_handle =
283 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54284 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21285 uint32_t shared_memory_length = 0;
286
287 int32_t result_code = result;
288 if (result_code == PP_OK) {
289 result_code = GetAudioConnectedHandles(resource, &socket_handle,
290 &shared_memory,
291 &shared_memory_length);
292 }
293
294 // Send all the values, even on error. This simplifies some of our cleanup
295 // code since the handles will be in the other process and could be
296 // inconvenient to clean up. Our IPC code will automatically handle this for
297 // us, as long as the remote side always closes the handles it receives
298 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
299 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16300 INTERFACE_ID_PPB_AUDIO, resource, result_code, socket_handle,
301 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21302}
303
304int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39305 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21306 IPC::PlatformFileForTransit* foreign_socket_handle,
307 base::SharedMemoryHandle* foreign_shared_memory_handle,
308 uint32_t* shared_memory_length) {
[email protected]79d23c72011-08-08 19:40:40309 // Get the audio interface which will give us the handles.
310 EnterResourceNoLock<PPB_Audio_API> enter(resource.host_resource(), false);
311 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21312 return PP_ERROR_NOINTERFACE;
313
314 // Get the socket handle for signaling.
315 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40316 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21317 if (result != PP_OK)
318 return result;
319
[email protected]db0f57f52011-02-25 03:54:54320 // socket_handle doesn't belong to us: don't close it.
321 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
322 IntToPlatformFile(socket_handle), false);
323 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
324 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21325
326 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21327 int shared_memory_handle;
[email protected]79d23c72011-08-08 19:40:40328 result = enter.object()->GetSharedMemory(&shared_memory_handle,
329 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21330 if (result != PP_OK)
331 return result;
332
[email protected]db0f57f52011-02-25 03:54:54333 // shared_memory_handle doesn't belong to us: don't close it.
334 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
335 IntToPlatformFile(shared_memory_handle), false);
336 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21337 return PP_ERROR_FAILED;
338
339 return PP_OK;
340}
341
342} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02343} // namespace ppapi