blob: a5bf6682537f1133221462d11eff44f423bd6200 [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/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]5d84d012010-12-02 17:17:2118#include "ppapi/shared_impl/audio_impl.h"
[email protected]5a77eca2011-11-23 23:46:4619#include "ppapi/shared_impl/platform_file.h"
[email protected]794d83cd2011-10-20 19:09:2020#include "ppapi/shared_impl/ppapi_globals.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]4d2efd22011-08-18 21:58:0235class Audio : public Resource, public AudioImpl {
[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]7f8b26b2011-08-18 15:41:0167 : Resource(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
142 HostResource result;
143 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
[email protected]ac4b54d2011-10-20 23:09:28144 API_ID_PPB_AUDIO, instance_id,
[email protected]55cdf6052011-05-13 19:22:53145 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
146 &result));
147 if (result.is_null())
148 return 0;
149
[email protected]bab65ef2011-08-20 04:53:22150 return (new Audio(result, config_id,
151 audio_callback, user_data))->GetReference();
[email protected]55cdf6052011-05-13 19:22:53152}
153
[email protected]a95986a82010-12-24 06:19:28154bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
155 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21156 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
157 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
158 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
159 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21160 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
161 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28162 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21163 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28164 return handled;
[email protected]5d84d012010-12-02 17:17:21165}
166
167void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53168 int32_t sample_rate,
169 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39170 HostResource* result) {
[email protected]4d2efd22011-08-18 21:58:02171 thunk::EnterFunction<thunk::ResourceCreationAPI> resource_creation(
172 instance_id, true);
[email protected]55cdf6052011-05-13 19:22:53173 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21174 return;
[email protected]5d84d012010-12-02 17:17:21175
[email protected]55cdf6052011-05-13 19:22:53176 // Make the resource and get the API pointer to its trusted interface.
177 result->SetHostResource(
178 instance_id,
179 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39180 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21181 return;
[email protected]79d23c72011-08-08 19:40:40182
183 // At this point, we've set the result resource, and this is a sync request.
184 // Anything below this point must issue the AudioChannelConnected callback
185 // to the browser. Since that's an async message, it will be issued back to
186 // the plugin after the Create function returns (which is good because it
187 // would be weird to get a connected message with a failure code for a
188 // resource you haven't finished creating yet).
189 //
190 // The ...ForceCallback class will help ensure the callback is always called.
191 // All error cases must call SetResult on this class.
192 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
193 *result, callback_factory_,
194 &PPB_Audio_Proxy::AudioChannelConnected, *result);
195 if (enter.failed())
196 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21197
[email protected]55cdf6052011-05-13 19:22:53198 // Make an audio config object.
199 PP_Resource audio_config_res =
200 resource_creation.functions()->CreateAudioConfig(
201 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
202 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40203 if (!audio_config_res) {
204 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53205 return;
[email protected]79d23c72011-08-08 19:40:40206 }
[email protected]55cdf6052011-05-13 19:22:53207
208 // Initiate opening the audio object.
[email protected]79d23c72011-08-08 19:40:40209 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
210 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53211
212 // Clean up the temporary audio config resource we made.
213 const PPB_Core* core = static_cast<const PPB_Core*>(
[email protected]5c966022011-09-13 18:09:37214 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
[email protected]55cdf6052011-05-13 19:22:53215 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21216}
217
[email protected]f24448db2011-01-27 20:40:39218void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
219 bool play) {
[email protected]5c966022011-09-13 18:09:37220 EnterHostFromHostResource<PPB_Audio_API> enter(audio_id);
221 if (enter.failed())
222 return;
[email protected]5d84d012010-12-02 17:17:21223 if (play)
[email protected]5c966022011-09-13 18:09:37224 enter.object()->StartPlayback();
[email protected]5d84d012010-12-02 17:17:21225 else
[email protected]5c966022011-09-13 18:09:37226 enter.object()->StopPlayback();
[email protected]5d84d012010-12-02 17:17:21227}
228
[email protected]f24448db2011-01-27 20:40:39229// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21230void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16231 const HostResource& audio_id,
232 int32_t result_code,
233 IPC::PlatformFileForTransit socket_handle,
234 base::SharedMemoryHandle handle,
235 uint32_t length) {
[email protected]cd910b92011-06-01 07:19:31236 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
[email protected]55cdf6052011-05-13 19:22:53237 if (enter.failed() || result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21238 // The caller may still have given us these handles in the failure case.
239 // The easiest way to clean these up is to just put them in the objects
240 // and then close them. This failure case is not performance critical.
241 base::SyncSocket temp_socket(
[email protected]2031aeb2011-01-28 20:01:16242 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
243 base::SharedMemory temp_mem(handle, false);
[email protected]cd910b92011-06-01 07:19:31244 } else {
245 static_cast<Audio*>(enter.object())->SetStreamInfo(
246 handle, length,
247 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]5d84d012010-12-02 17:17:21248 }
[email protected]5d84d012010-12-02 17:17:21249}
250
[email protected]f24448db2011-01-27 20:40:39251void PPB_Audio_Proxy::AudioChannelConnected(
252 int32_t result,
253 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21254 IPC::PlatformFileForTransit socket_handle =
255 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54256 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21257 uint32_t shared_memory_length = 0;
258
259 int32_t result_code = result;
260 if (result_code == PP_OK) {
261 result_code = GetAudioConnectedHandles(resource, &socket_handle,
262 &shared_memory,
263 &shared_memory_length);
264 }
265
266 // Send all the values, even on error. This simplifies some of our cleanup
267 // code since the handles will be in the other process and could be
268 // inconvenient to clean up. Our IPC code will automatically handle this for
269 // us, as long as the remote side always closes the handles it receives
270 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
271 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]ac4b54d2011-10-20 23:09:28272 API_ID_PPB_AUDIO, resource, result_code, socket_handle,
[email protected]2031aeb2011-01-28 20:01:16273 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21274}
275
276int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39277 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21278 IPC::PlatformFileForTransit* foreign_socket_handle,
279 base::SharedMemoryHandle* foreign_shared_memory_handle,
280 uint32_t* shared_memory_length) {
[email protected]79d23c72011-08-08 19:40:40281 // Get the audio interface which will give us the handles.
[email protected]5c966022011-09-13 18:09:37282 EnterHostFromHostResource<PPB_Audio_API> enter(resource);
[email protected]79d23c72011-08-08 19:40:40283 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21284 return PP_ERROR_NOINTERFACE;
285
286 // Get the socket handle for signaling.
287 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40288 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21289 if (result != PP_OK)
290 return result;
291
[email protected]db0f57f52011-02-25 03:54:54292 // socket_handle doesn't belong to us: don't close it.
293 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
294 IntToPlatformFile(socket_handle), false);
295 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
296 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21297
298 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21299 int shared_memory_handle;
[email protected]79d23c72011-08-08 19:40:40300 result = enter.object()->GetSharedMemory(&shared_memory_handle,
301 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21302 if (result != PP_OK)
303 return result;
304
[email protected]db0f57f52011-02-25 03:54:54305 // shared_memory_handle doesn't belong to us: don't close it.
306 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
307 IntToPlatformFile(shared_memory_handle), false);
308 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21309 return PP_ERROR_FAILED;
310
311 return PP_OK;
312}
313
314} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02315} // namespace ppapi