blob: 2bd5c89a453f65c227b761d840e6bfdd4312349c [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]246fc492012-08-27 20:28:189#include "media/audio/shared_memory_util.h"
[email protected]5d84d012010-12-02 17:17:2110#include "ppapi/c/pp_errors.h"
[email protected]b9a59842011-01-15 01:04:0011#include "ppapi/c/ppb_audio.h"
[email protected]55cdf6052011-05-13 19:22:5312#include "ppapi/c/ppb_audio_config.h"
13#include "ppapi/c/ppb_var.h"
[email protected]b9a59842011-01-15 01:04:0014#include "ppapi/c/trusted/ppb_audio_trusted.h"
[email protected]cd910b92011-06-01 07:19:3115#include "ppapi/proxy/enter_proxy.h"
[email protected]5d84d012010-12-02 17:17:2116#include "ppapi/proxy/plugin_dispatcher.h"
[email protected]5d84d012010-12-02 17:17:2117#include "ppapi/proxy/ppapi_messages.h"
[email protected]ac4b54d2011-10-20 23:09:2818#include "ppapi/shared_impl/api_id.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]9a578392011-12-07 18:59:2721#include "ppapi/shared_impl/ppb_audio_shared.h"
[email protected]7f8b26b2011-08-18 15:41:0122#include "ppapi/shared_impl/resource.h"
[email protected]55cdf6052011-05-13 19:22:5323#include "ppapi/thunk/ppb_audio_config_api.h"
[email protected]55cdf6052011-05-13 19:22:5324#include "ppapi/thunk/enter.h"
25#include "ppapi/thunk/resource_creation_api.h"
26#include "ppapi/thunk/thunk.h"
[email protected]5d84d012010-12-02 17:17:2127
[email protected]5a77eca2011-11-23 23:46:4628using ppapi::IntToPlatformFile;
[email protected]8510d282012-08-30 19:47:3829using ppapi::proxy::SerializedHandle;
[email protected]79d23c72011-08-08 19:40:4030using ppapi::thunk::EnterResourceNoLock;
31using ppapi::thunk::PPB_Audio_API;
32using ppapi::thunk::PPB_AudioConfig_API;
[email protected]cd910b92011-06-01 07:19:3133
[email protected]4d2efd22011-08-18 21:58:0234namespace ppapi {
[email protected]5d84d012010-12-02 17:17:2135namespace proxy {
36
[email protected]9a578392011-12-07 18:59:2737class Audio : public Resource, public PPB_Audio_Shared {
[email protected]5d84d012010-12-02 17:17:2138 public:
[email protected]f24448db2011-01-27 20:40:3939 Audio(const HostResource& audio_id,
[email protected]4614f192011-01-21 00:26:4340 PP_Resource config_id,
41 PPB_Audio_Callback callback,
[email protected]55cdf6052011-05-13 19:22:5342 void* user_data);
43 virtual ~Audio();
[email protected]5d84d012010-12-02 17:17:2144
[email protected]7f8b26b2011-08-18 15:41:0145 // Resource overrides.
[email protected]cd910b92011-06-01 07:19:3146 virtual PPB_Audio_API* AsPPB_Audio_API();
[email protected]5d84d012010-12-02 17:17:2147
[email protected]55cdf6052011-05-13 19:22:5348 // PPB_Audio_API implementation.
49 virtual PP_Resource GetCurrentConfig() OVERRIDE;
50 virtual PP_Bool StartPlayback() OVERRIDE;
51 virtual PP_Bool StopPlayback() OVERRIDE;
[email protected]aed96532012-06-23 14:27:4252 virtual int32_t OpenTrusted(
53 PP_Resource config_id,
54 scoped_refptr<TrackedCallback> create_callback) OVERRIDE;
[email protected]79d23c72011-08-08 19:40:4055 virtual int32_t GetSyncSocket(int* sync_socket) OVERRIDE;
56 virtual int32_t GetSharedMemory(int* shm_handle, uint32_t* shm_size) OVERRIDE;
[email protected]5d84d012010-12-02 17:17:2157
58 private:
[email protected]55cdf6052011-05-13 19:22:5359 // Owning reference to the current config object. This isn't actually used,
60 // we just dish it out as requested by the plugin.
[email protected]5d84d012010-12-02 17:17:2161 PP_Resource config_;
62
63 DISALLOW_COPY_AND_ASSIGN(Audio);
64};
65
[email protected]55cdf6052011-05-13 19:22:5366Audio::Audio(const HostResource& audio_id,
67 PP_Resource config_id,
68 PPB_Audio_Callback callback,
69 void* user_data)
[email protected]00d320a2012-02-14 00:27:0470 : Resource(OBJECT_IS_PROXY, audio_id),
[email protected]55cdf6052011-05-13 19:22:5371 config_(config_id) {
72 SetCallback(callback, user_data);
[email protected]794d83cd2011-10-20 19:09:2073 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5374}
75
76Audio::~Audio() {
[email protected]794d83cd2011-10-20 19:09:2077 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(config_);
[email protected]55cdf6052011-05-13 19:22:5378}
79
[email protected]cd910b92011-06-01 07:19:3180PPB_Audio_API* Audio::AsPPB_Audio_API() {
[email protected]55cdf6052011-05-13 19:22:5381 return this;
82}
83
84PP_Resource Audio::GetCurrentConfig() {
85 // AddRef for the caller.
[email protected]794d83cd2011-10-20 19:09:2086 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_);
[email protected]55cdf6052011-05-13 19:22:5387 return config_;
88}
89
90PP_Bool Audio::StartPlayback() {
91 if (playing())
92 return PP_TRUE;
93 SetStartPlaybackState();
[email protected]7f8b26b2011-08-18 15:41:0194 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:5395 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]ac4b54d2011-10-20 23:09:2896 API_ID_PPB_AUDIO, host_resource(), true));
[email protected]55cdf6052011-05-13 19:22:5397 return PP_TRUE;
98}
99
100PP_Bool Audio::StopPlayback() {
101 if (!playing())
102 return PP_TRUE;
[email protected]7f8b26b2011-08-18 15:41:01103 PluginDispatcher::GetForResource(this)->Send(
[email protected]55cdf6052011-05-13 19:22:53104 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]ac4b54d2011-10-20 23:09:28105 API_ID_PPB_AUDIO, host_resource(), false));
[email protected]55cdf6052011-05-13 19:22:53106 SetStopPlaybackState();
107 return PP_TRUE;
108}
109
[email protected]79d23c72011-08-08 19:40:40110int32_t Audio::OpenTrusted(PP_Resource config_id,
[email protected]aed96532012-06-23 14:27:42111 scoped_refptr<TrackedCallback> create_callback) {
[email protected]79d23c72011-08-08 19:40:40112 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
113}
114
115int32_t Audio::GetSyncSocket(int* sync_socket) {
116 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
117}
118
119int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) {
120 return PP_ERROR_NOTSUPPORTED; // Don't proxy the trusted interface.
121}
122
[email protected]5c966022011-09-13 18:09:37123PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher)
124 : InterfaceProxy(dispatcher),
[email protected]5d84d012010-12-02 17:17:21125 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
126}
127
128PPB_Audio_Proxy::~PPB_Audio_Proxy() {
129}
130
[email protected]465faa22011-02-08 16:31:46131// static
[email protected]55cdf6052011-05-13 19:22:53132PP_Resource PPB_Audio_Proxy::CreateProxyResource(
133 PP_Instance instance_id,
134 PP_Resource config_id,
135 PPB_Audio_Callback audio_callback,
136 void* user_data) {
137 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
138 if (!dispatcher)
139 return 0;
140
[email protected]79d23c72011-08-08 19:40:40141 EnterResourceNoLock<PPB_AudioConfig_API> config(config_id, true);
[email protected]55cdf6052011-05-13 19:22:53142 if (config.failed())
143 return 0;
144
[email protected]c6b2b7f2011-12-01 02:38:25145 if (!audio_callback)
146 return 0;
147
[email protected]55cdf6052011-05-13 19:22:53148 HostResource result;
149 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
[email protected]ac4b54d2011-10-20 23:09:28150 API_ID_PPB_AUDIO, instance_id,
[email protected]55cdf6052011-05-13 19:22:53151 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
152 &result));
153 if (result.is_null())
154 return 0;
155
[email protected]bab65ef2011-08-20 04:53:22156 return (new Audio(result, config_id,
157 audio_callback, user_data))->GetReference();
[email protected]55cdf6052011-05-13 19:22:53158}
159
[email protected]a95986a82010-12-24 06:19:28160bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
161 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21162 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
[email protected]771fc8d2012-05-19 01:39:05163// Don't build host side into NaCl IRT.
164#if !defined(OS_NACL)
[email protected]5d84d012010-12-02 17:17:21165 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
166 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
167 OnMsgStartOrStop)
[email protected]771fc8d2012-05-19 01:39:05168#endif
[email protected]5d84d012010-12-02 17:17:21169 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
170 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28171 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21172 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28173 return handled;
[email protected]5d84d012010-12-02 17:17:21174}
175
176void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53177 int32_t sample_rate,
178 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39179 HostResource* result) {
[email protected]4f2006122012-04-30 05:13:17180 thunk::EnterResourceCreation resource_creation(instance_id);
[email protected]55cdf6052011-05-13 19:22:53181 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21182 return;
[email protected]5d84d012010-12-02 17:17:21183
[email protected]55cdf6052011-05-13 19:22:53184 // Make the resource and get the API pointer to its trusted interface.
185 result->SetHostResource(
186 instance_id,
187 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39188 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21189 return;
[email protected]79d23c72011-08-08 19:40:40190
191 // At this point, we've set the result resource, and this is a sync request.
192 // Anything below this point must issue the AudioChannelConnected callback
193 // to the browser. Since that's an async message, it will be issued back to
194 // the plugin after the Create function returns (which is good because it
195 // would be weird to get a connected message with a failure code for a
196 // resource you haven't finished creating yet).
197 //
198 // The ...ForceCallback class will help ensure the callback is always called.
199 // All error cases must call SetResult on this class.
200 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
201 *result, callback_factory_,
202 &PPB_Audio_Proxy::AudioChannelConnected, *result);
203 if (enter.failed())
204 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21205
[email protected]55cdf6052011-05-13 19:22:53206 // Make an audio config object.
207 PP_Resource audio_config_res =
208 resource_creation.functions()->CreateAudioConfig(
209 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
210 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40211 if (!audio_config_res) {
212 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53213 return;
[email protected]79d23c72011-08-08 19:40:40214 }
[email protected]55cdf6052011-05-13 19:22:53215
216 // Initiate opening the audio object.
[email protected]79d23c72011-08-08 19:40:40217 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
218 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53219
220 // Clean up the temporary audio config resource we made.
221 const PPB_Core* core = static_cast<const PPB_Core*>(
[email protected]5c966022011-09-13 18:09:37222 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
[email protected]55cdf6052011-05-13 19:22:53223 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21224}
225
[email protected]f24448db2011-01-27 20:40:39226void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
227 bool play) {
[email protected]5c966022011-09-13 18:09:37228 EnterHostFromHostResource<PPB_Audio_API> enter(audio_id);
229 if (enter.failed())
230 return;
[email protected]5d84d012010-12-02 17:17:21231 if (play)
[email protected]5c966022011-09-13 18:09:37232 enter.object()->StartPlayback();
[email protected]5d84d012010-12-02 17:17:21233 else
[email protected]5c966022011-09-13 18:09:37234 enter.object()->StopPlayback();
[email protected]5d84d012010-12-02 17:17:21235}
236
[email protected]f24448db2011-01-27 20:40:39237void PPB_Audio_Proxy::AudioChannelConnected(
238 int32_t result,
239 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21240 IPC::PlatformFileForTransit socket_handle =
241 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54242 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]246fc492012-08-27 20:28:18243 uint32_t audio_buffer_length = 0;
[email protected]5d84d012010-12-02 17:17:21244
245 int32_t result_code = result;
246 if (result_code == PP_OK) {
247 result_code = GetAudioConnectedHandles(resource, &socket_handle,
248 &shared_memory,
[email protected]246fc492012-08-27 20:28:18249 &audio_buffer_length);
[email protected]5d84d012010-12-02 17:17:21250 }
251
252 // Send all the values, even on error. This simplifies some of our cleanup
253 // code since the handles will be in the other process and could be
254 // inconvenient to clean up. Our IPC code will automatically handle this for
255 // us, as long as the remote side always closes the handles it receives
256 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
[email protected]8510d282012-08-30 19:47:38257 SerializedHandle fd_wrapper(SerializedHandle::SOCKET, socket_handle);
[email protected]246fc492012-08-27 20:28:18258
259 // Note that we must call TotalSharedMemorySizeInBytes because
260 // Audio allocates extra space in shared memory for book-keeping, so the
261 // actual size of the shared memory buffer is larger than audio_buffer_length.
262 // When sending to NaCl, NaClIPCAdapter expects this size to match the size
263 // of the full shared memory buffer.
[email protected]8510d282012-08-30 19:47:38264 SerializedHandle handle_wrapper(
[email protected]246fc492012-08-27 20:28:18265 shared_memory,
266 media::TotalSharedMemorySizeInBytes(audio_buffer_length));
[email protected]5d84d012010-12-02 17:17:21267 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]246fc492012-08-27 20:28:18268 API_ID_PPB_AUDIO, resource, result_code, fd_wrapper, handle_wrapper));
[email protected]5d84d012010-12-02 17:17:21269}
270
271int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39272 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21273 IPC::PlatformFileForTransit* foreign_socket_handle,
274 base::SharedMemoryHandle* foreign_shared_memory_handle,
275 uint32_t* shared_memory_length) {
[email protected]79d23c72011-08-08 19:40:40276 // Get the audio interface which will give us the handles.
[email protected]5c966022011-09-13 18:09:37277 EnterHostFromHostResource<PPB_Audio_API> enter(resource);
[email protected]79d23c72011-08-08 19:40:40278 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21279 return PP_ERROR_NOINTERFACE;
280
281 // Get the socket handle for signaling.
282 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40283 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21284 if (result != PP_OK)
285 return result;
286
[email protected]db0f57f52011-02-25 03:54:54287 // socket_handle doesn't belong to us: don't close it.
288 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
289 IntToPlatformFile(socket_handle), false);
290 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
291 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21292
293 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21294 int shared_memory_handle;
[email protected]79d23c72011-08-08 19:40:40295 result = enter.object()->GetSharedMemory(&shared_memory_handle,
296 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21297 if (result != PP_OK)
298 return result;
299
[email protected]db0f57f52011-02-25 03:54:54300 // shared_memory_handle doesn't belong to us: don't close it.
301 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
302 IntToPlatformFile(shared_memory_handle), false);
303 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21304 return PP_ERROR_FAILED;
305
306 return PP_OK;
307}
[email protected]771fc8d2012-05-19 01:39:05308
309// Processed in the plugin (message from host).
310void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
311 const HostResource& audio_id,
312 int32_t result_code,
[email protected]8510d282012-08-30 19:47:38313 SerializedHandle socket_handle,
314 SerializedHandle handle) {
[email protected]246fc492012-08-27 20:28:18315 CHECK(socket_handle.is_socket());
316 CHECK(handle.is_shmem());
[email protected]771fc8d2012-05-19 01:39:05317 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
318 if (enter.failed() || result_code != PP_OK) {
319 // The caller may still have given us these handles in the failure case.
320 // The easiest way to clean these up is to just put them in the objects
321 // and then close them. This failure case is not performance critical.
322 base::SyncSocket temp_socket(
[email protected]246fc492012-08-27 20:28:18323 IPC::PlatformFileForTransitToPlatformFile(socket_handle.descriptor()));
324 base::SharedMemory temp_mem(handle.shmem(), false);
[email protected]771fc8d2012-05-19 01:39:05325 } else {
[email protected]246fc492012-08-27 20:28:18326 // See the comment above about how we must call
327 // TotalSharedMemorySizeInBytes to get the actual size of the buffer. Here,
328 // we must call PacketSizeInBytes to get back the size of the audio buffer,
329 // excluding the bytes that audio uses for book-keeping.
[email protected]771fc8d2012-05-19 01:39:05330 static_cast<Audio*>(enter.object())->SetStreamInfo(
[email protected]246fc492012-08-27 20:28:18331 enter.resource()->pp_instance(), handle.shmem(),
332 media::PacketSizeInBytes(handle.size()),
333 IPC::PlatformFileForTransitToPlatformFile(socket_handle.descriptor()));
[email protected]771fc8d2012-05-19 01:39:05334 }
335}
[email protected]5d84d012010-12-02 17:17:21336
337} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02338} // namespace ppapi