blob: f1aedf7109142c78ae0e23a65a799b2ccb1e9a11 [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]794d83cd2011-10-20 19:09:2019#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]7f8b26b2011-08-18 15:41:0120#include "ppapi/shared_impl/resource.h"
[email protected]55cdf6052011-05-13 19:22:5321#include "ppapi/thunk/ppb_audio_config_api.h"
[email protected]55cdf6052011-05-13 19:22:5322#include "ppapi/thunk/enter.h"
23#include "ppapi/thunk/resource_creation_api.h"
24#include "ppapi/thunk/thunk.h"
[email protected]5d84d012010-12-02 17:17:2125
[email protected]79d23c72011-08-08 19:40:4026using ppapi::thunk::EnterResourceNoLock;
27using ppapi::thunk::PPB_Audio_API;
28using ppapi::thunk::PPB_AudioConfig_API;
[email protected]cd910b92011-06-01 07:19:3129
[email protected]4d2efd22011-08-18 21:58:0230namespace ppapi {
[email protected]5d84d012010-12-02 17:17:2131namespace proxy {
32
[email protected]4d2efd22011-08-18 21:58:0233class Audio : public Resource, public AudioImpl {
[email protected]5d84d012010-12-02 17:17:2134 public:
[email protected]f24448db2011-01-27 20:40:3935 Audio(const HostResource& audio_id,
[email protected]4614f192011-01-21 00:26:4336 PP_Resource config_id,
37 PPB_Audio_Callback callback,
[email protected]55cdf6052011-05-13 19:22:5338 void* user_data);
39 virtual ~Audio();
[email protected]5d84d012010-12-02 17:17:2140
[email protected]7f8b26b2011-08-18 15:41:0141 // Resource overrides.
[email protected]cd910b92011-06-01 07:19:3142 virtual PPB_Audio_API* AsPPB_Audio_API();
[email protected]5d84d012010-12-02 17:17:2143
[email protected]55cdf6052011-05-13 19:22:5344 // PPB_Audio_API implementation.
45 virtual PP_Resource GetCurrentConfig() OVERRIDE;
46 virtual PP_Bool StartPlayback() OVERRIDE;
47 virtual PP_Bool StopPlayback() OVERRIDE;
[email protected]79d23c72011-08-08 19:40:4048 virtual int32_t OpenTrusted(PP_Resource config_id,
49 PP_CompletionCallback create_callback) OVERRIDE;
50 virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
51 virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
[email protected]5d84d012010-12-02 17:17:2152
53 private:
[email protected]55cdf6052011-05-13 19:22:5354 // Owning reference to the current config object. This isn't actually used,
55 // we just dish it out as requested by the plugin.
[email protected]5d84d012010-12-02 17:17:2156 PP_Resource config_;
57
58 DISALLOW_COPY_AND_ASSIGN(Audio);
59};
60
[email protected]55cdf6052011-05-13 19:22:5361Audio::Audio(const HostResource& audio_id,
62 PP_Resource config_id,
63 PPB_Audio_Callback callback,
64 void* user_data)
[email protected]7f8b26b2011-08-18 15:41:0165 : Resource(audio_id),
[email protected]55cdf6052011-05-13 19:22:5366 config_(config_id) {
67 SetCallback(callback, user_data);
[email protected]794d83cd2011-10-20 19:09:2068 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5369}
70
71Audio::~Audio() {
[email protected]794d83cd2011-10-20 19:09:2072 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(config_);
[email protected]55cdf6052011-05-13 19:22:5373}
74
[email protected]cd910b92011-06-01 07:19:3175PPB_Audio_API* Audio::AsPPB_Audio_API() {
[email protected]55cdf6052011-05-13 19:22:5376 return this;
77}
78
79PP_Resource Audio::GetCurrentConfig() {
80 // AddRef for the caller.
[email protected]794d83cd2011-10-20 19:09:2081 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5382 return config_;
83}
84
85PP_Bool Audio::StartPlayback() {
86 if (playing())
87 return PP_TRUE;
88 SetStartPlaybackState();
[email protected]7f8b26b2011-08-18 15:41:0189 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:5390 new PpapiHostMsg_PPBAudio_StartOrStop(
91 INTERFACE_ID_PPB_AUDIO, host_resource(), true));
92 return PP_TRUE;
93}
94
95PP_Bool Audio::StopPlayback() {
96 if (!playing())
97 return PP_TRUE;
[email protected]7f8b26b2011-08-18 15:41:0198 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:5399 new PpapiHostMsg_PPBAudio_StartOrStop(
100 INTERFACE_ID_PPB_AUDIO, host_resource(), false));
101 SetStopPlaybackState();
102 return PP_TRUE;
103}
104
[email protected]79d23c72011-08-08 19:40:40105int32_t Audio::OpenTrusted(PP_Resource config_id,
106 PP_CompletionCallback create_callback) {
107 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
108}
109
110int32_t Audio::GetSyncSocket(int* sync_socket) {
111 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
112}
113
114int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) {
115 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
116}
117
[email protected]5d84d012010-12-02 17:17:21118namespace {
119
[email protected]db0f57f52011-02-25 03:54:54120base::PlatformFile IntToPlatformFile(int32_t handle) {
121 // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle,
122 // those casts are ugly.
123#if defined(OS_WIN)
124 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
125#elif defined(OS_POSIX)
126 return handle;
127#else
128 #error Not implemented.
129#endif
130}
131
[email protected]5d84d012010-12-02 17:17:21132} // namespace
133
[email protected]5c966022011-09-13 18:09:37134PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher)
135 : InterfaceProxy(dispatcher),
[email protected]5d84d012010-12-02 17:17:21136 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
137}
138
139PPB_Audio_Proxy::~PPB_Audio_Proxy() {
140}
141
[email protected]465faa22011-02-08 16:31:46142// static
[email protected]55cdf6052011-05-13 19:22:53143PP_Resource PPB_Audio_Proxy::CreateProxyResource(
144 PP_Instance instance_id,
145 PP_Resource config_id,
146 PPB_Audio_Callback audio_callback,
147 void* user_data) {
148 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
149 if (!dispatcher)
150 return 0;
151
[email protected]79d23c72011-08-08 19:40:40152 EnterResourceNoLock<PPB_AudioConfig_API> config(config_id, true);
[email protected]55cdf6052011-05-13 19:22:53153 if (config.failed())
154 return 0;
155
156 HostResource result;
157 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
158 INTERFACE_ID_PPB_AUDIO, instance_id,
159 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
160 &result));
161 if (result.is_null())
162 return 0;
163
[email protected]bab65ef2011-08-20 04:53:22164 return (new Audio(result, config_id,
165 audio_callback, user_data))->GetReference();
[email protected]55cdf6052011-05-13 19:22:53166}
167
[email protected]a95986a82010-12-24 06:19:28168bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
169 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21170 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
171 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
172 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
173 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21174 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
175 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28176 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21177 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28178 return handled;
[email protected]5d84d012010-12-02 17:17:21179}
180
181void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53182 int32_t sample_rate,
183 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39184 HostResource* result) {
[email protected]4d2efd22011-08-18 21:58:02185 thunk::EnterFunction<thunk::ResourceCreationAPI> resource_creation(
186 instance_id, true);
[email protected]55cdf6052011-05-13 19:22:53187 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21188 return;
[email protected]5d84d012010-12-02 17:17:21189
[email protected]55cdf6052011-05-13 19:22:53190 // Make the resource and get the API pointer to its trusted interface.
191 result->SetHostResource(
192 instance_id,
193 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39194 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21195 return;
[email protected]79d23c72011-08-08 19:40:40196
197 // At this point, we've set the result resource, and this is a sync request.
198 // Anything below this point must issue the AudioChannelConnected callback
199 // to the browser. Since that's an async message, it will be issued back to
200 // the plugin after the Create function returns (which is good because it
201 // would be weird to get a connected message with a failure code for a
202 // resource you haven't finished creating yet).
203 //
204 // The ...ForceCallback class will help ensure the callback is always called.
205 // All error cases must call SetResult on this class.
206 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
207 *result, callback_factory_,
208 &PPB_Audio_Proxy::AudioChannelConnected, *result);
209 if (enter.failed())
210 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21211
[email protected]55cdf6052011-05-13 19:22:53212 // Make an audio config object.
213 PP_Resource audio_config_res =
214 resource_creation.functions()->CreateAudioConfig(
215 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
216 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40217 if (!audio_config_res) {
218 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53219 return;
[email protected]79d23c72011-08-08 19:40:40220 }
[email protected]55cdf6052011-05-13 19:22:53221
222 // Initiate opening the audio object.
[email protected]79d23c72011-08-08 19:40:40223 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
224 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53225
226 // Clean up the temporary audio config resource we made.
227 const PPB_Core* core = static_cast<const PPB_Core*>(
[email protected]5c966022011-09-13 18:09:37228 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
[email protected]55cdf6052011-05-13 19:22:53229 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21230}
231
[email protected]f24448db2011-01-27 20:40:39232void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
233 bool play) {
[email protected]5c966022011-09-13 18:09:37234 EnterHostFromHostResource<PPB_Audio_API> enter(audio_id);
235 if (enter.failed())
236 return;
[email protected]5d84d012010-12-02 17:17:21237 if (play)
[email protected]5c966022011-09-13 18:09:37238 enter.object()->StartPlayback();
[email protected]5d84d012010-12-02 17:17:21239 else
[email protected]5c966022011-09-13 18:09:37240 enter.object()->StopPlayback();
[email protected]5d84d012010-12-02 17:17:21241}
242
[email protected]f24448db2011-01-27 20:40:39243// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21244void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16245 const HostResource& audio_id,
246 int32_t result_code,
247 IPC::PlatformFileForTransit socket_handle,
248 base::SharedMemoryHandle handle,
249 uint32_t length) {
[email protected]cd910b92011-06-01 07:19:31250 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
[email protected]55cdf6052011-05-13 19:22:53251 if (enter.failed() || result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21252 // The caller may still have given us these handles in the failure case.
253 // The easiest way to clean these up is to just put them in the objects
254 // and then close them. This failure case is not performance critical.
255 base::SyncSocket temp_socket(
[email protected]2031aeb2011-01-28 20:01:16256 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
257 base::SharedMemory temp_mem(handle, false);
[email protected]cd910b92011-06-01 07:19:31258 } else {
259 static_cast<Audio*>(enter.object())->SetStreamInfo(
260 handle, length,
261 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]5d84d012010-12-02 17:17:21262 }
[email protected]5d84d012010-12-02 17:17:21263}
264
[email protected]f24448db2011-01-27 20:40:39265void PPB_Audio_Proxy::AudioChannelConnected(
266 int32_t result,
267 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21268 IPC::PlatformFileForTransit socket_handle =
269 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54270 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21271 uint32_t shared_memory_length = 0;
272
273 int32_t result_code = result;
274 if (result_code == PP_OK) {
275 result_code = GetAudioConnectedHandles(resource, &socket_handle,
276 &shared_memory,
277 &shared_memory_length);
278 }
279
280 // Send all the values, even on error. This simplifies some of our cleanup
281 // code since the handles will be in the other process and could be
282 // inconvenient to clean up. Our IPC code will automatically handle this for
283 // us, as long as the remote side always closes the handles it receives
284 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
285 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16286 INTERFACE_ID_PPB_AUDIO, resource, result_code, socket_handle,
287 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21288}
289
290int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39291 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21292 IPC::PlatformFileForTransit* foreign_socket_handle,
293 base::SharedMemoryHandle* foreign_shared_memory_handle,
294 uint32_t* shared_memory_length) {
[email protected]79d23c72011-08-08 19:40:40295 // Get the audio interface which will give us the handles.
[email protected]5c966022011-09-13 18:09:37296 EnterHostFromHostResource<PPB_Audio_API> enter(resource);
[email protected]79d23c72011-08-08 19:40:40297 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21298 return PP_ERROR_NOINTERFACE;
299
300 // Get the socket handle for signaling.
301 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40302 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21303 if (result != PP_OK)
304 return result;
305
[email protected]db0f57f52011-02-25 03:54:54306 // socket_handle doesn't belong to us: don't close it.
307 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
308 IntToPlatformFile(socket_handle), false);
309 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
310 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21311
312 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21313 int shared_memory_handle;
[email protected]79d23c72011-08-08 19:40:40314 result = enter.object()->GetSharedMemory(&shared_memory_handle,
315 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21316 if (result != PP_OK)
317 return result;
318
[email protected]db0f57f52011-02-25 03:54:54319 // shared_memory_handle doesn't belong to us: don't close it.
320 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
321 IntToPlatformFile(shared_memory_handle), false);
322 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21323 return PP_ERROR_FAILED;
324
325 return PP_OK;
326}
327
328} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02329} // namespace ppapi