blob: fe890ae381ce994d7928beebcc718652fcabfa78 [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)
160 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
161 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
162 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21163 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
164 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28165 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21166 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28167 return handled;
[email protected]5d84d012010-12-02 17:17:21168}
169
170void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53171 int32_t sample_rate,
172 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39173 HostResource* result) {
[email protected]4d2efd22011-08-18 21:58:02174 thunk::EnterFunction<thunk::ResourceCreationAPI> resource_creation(
175 instance_id, true);
[email protected]55cdf6052011-05-13 19:22:53176 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21177 return;
[email protected]5d84d012010-12-02 17:17:21178
[email protected]55cdf6052011-05-13 19:22:53179 // Make the resource and get the API pointer to its trusted interface.
180 result->SetHostResource(
181 instance_id,
182 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39183 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21184 return;
[email protected]79d23c72011-08-08 19:40:40185
186 // At this point, we've set the result resource, and this is a sync request.
187 // Anything below this point must issue the AudioChannelConnected callback
188 // to the browser. Since that's an async message, it will be issued back to
189 // the plugin after the Create function returns (which is good because it
190 // would be weird to get a connected message with a failure code for a
191 // resource you haven't finished creating yet).
192 //
193 // The ...ForceCallback class will help ensure the callback is always called.
194 // All error cases must call SetResult on this class.
195 EnterHostFromHostResourceForceCallback<PPB_Audio_API> enter(
196 *result, callback_factory_,
197 &PPB_Audio_Proxy::AudioChannelConnected, *result);
198 if (enter.failed())
199 return; // When enter fails, it will internally schedule the callback.
[email protected]5d84d012010-12-02 17:17:21200
[email protected]55cdf6052011-05-13 19:22:53201 // Make an audio config object.
202 PP_Resource audio_config_res =
203 resource_creation.functions()->CreateAudioConfig(
204 instance_id, static_cast<PP_AudioSampleRate>(sample_rate),
205 sample_frame_count);
[email protected]79d23c72011-08-08 19:40:40206 if (!audio_config_res) {
207 enter.SetResult(PP_ERROR_FAILED);
[email protected]55cdf6052011-05-13 19:22:53208 return;
[email protected]79d23c72011-08-08 19:40:40209 }
[email protected]55cdf6052011-05-13 19:22:53210
211 // Initiate opening the audio object.
[email protected]79d23c72011-08-08 19:40:40212 enter.SetResult(enter.object()->OpenTrusted(audio_config_res,
213 enter.callback()));
[email protected]55cdf6052011-05-13 19:22:53214
215 // Clean up the temporary audio config resource we made.
216 const PPB_Core* core = static_cast<const PPB_Core*>(
[email protected]5c966022011-09-13 18:09:37217 dispatcher()->local_get_interface()(PPB_CORE_INTERFACE));
[email protected]55cdf6052011-05-13 19:22:53218 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21219}
220
[email protected]f24448db2011-01-27 20:40:39221void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
222 bool play) {
[email protected]5c966022011-09-13 18:09:37223 EnterHostFromHostResource<PPB_Audio_API> enter(audio_id);
224 if (enter.failed())
225 return;
[email protected]5d84d012010-12-02 17:17:21226 if (play)
[email protected]5c966022011-09-13 18:09:37227 enter.object()->StartPlayback();
[email protected]5d84d012010-12-02 17:17:21228 else
[email protected]5c966022011-09-13 18:09:37229 enter.object()->StopPlayback();
[email protected]5d84d012010-12-02 17:17:21230}
231
[email protected]f24448db2011-01-27 20:40:39232// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21233void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16234 const HostResource& audio_id,
235 int32_t result_code,
236 IPC::PlatformFileForTransit socket_handle,
237 base::SharedMemoryHandle handle,
238 uint32_t length) {
[email protected]cd910b92011-06-01 07:19:31239 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
[email protected]55cdf6052011-05-13 19:22:53240 if (enter.failed() || result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21241 // The caller may still have given us these handles in the failure case.
242 // The easiest way to clean these up is to just put them in the objects
243 // and then close them. This failure case is not performance critical.
244 base::SyncSocket temp_socket(
[email protected]2031aeb2011-01-28 20:01:16245 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
246 base::SharedMemory temp_mem(handle, false);
[email protected]cd910b92011-06-01 07:19:31247 } else {
248 static_cast<Audio*>(enter.object())->SetStreamInfo(
249 handle, length,
250 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]5d84d012010-12-02 17:17:21251 }
[email protected]5d84d012010-12-02 17:17:21252}
253
[email protected]f24448db2011-01-27 20:40:39254void PPB_Audio_Proxy::AudioChannelConnected(
255 int32_t result,
256 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21257 IPC::PlatformFileForTransit socket_handle =
258 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54259 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21260 uint32_t shared_memory_length = 0;
261
262 int32_t result_code = result;
263 if (result_code == PP_OK) {
264 result_code = GetAudioConnectedHandles(resource, &socket_handle,
265 &shared_memory,
266 &shared_memory_length);
267 }
268
269 // Send all the values, even on error. This simplifies some of our cleanup
270 // code since the handles will be in the other process and could be
271 // inconvenient to clean up. Our IPC code will automatically handle this for
272 // us, as long as the remote side always closes the handles it receives
273 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
274 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]ac4b54d2011-10-20 23:09:28275 API_ID_PPB_AUDIO, resource, result_code, socket_handle,
[email protected]2031aeb2011-01-28 20:01:16276 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21277}
278
279int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39280 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21281 IPC::PlatformFileForTransit* foreign_socket_handle,
282 base::SharedMemoryHandle* foreign_shared_memory_handle,
283 uint32_t* shared_memory_length) {
[email protected]79d23c72011-08-08 19:40:40284 // Get the audio interface which will give us the handles.
[email protected]5c966022011-09-13 18:09:37285 EnterHostFromHostResource<PPB_Audio_API> enter(resource);
[email protected]79d23c72011-08-08 19:40:40286 if (enter.failed())
[email protected]5d84d012010-12-02 17:17:21287 return PP_ERROR_NOINTERFACE;
288
289 // Get the socket handle for signaling.
290 int32_t socket_handle;
[email protected]79d23c72011-08-08 19:40:40291 int32_t result = enter.object()->GetSyncSocket(&socket_handle);
[email protected]5d84d012010-12-02 17:17:21292 if (result != PP_OK)
293 return result;
294
[email protected]db0f57f52011-02-25 03:54:54295 // socket_handle doesn't belong to us: don't close it.
296 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
297 IntToPlatformFile(socket_handle), false);
298 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
299 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21300
301 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21302 int shared_memory_handle;
[email protected]79d23c72011-08-08 19:40:40303 result = enter.object()->GetSharedMemory(&shared_memory_handle,
304 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21305 if (result != PP_OK)
306 return result;
307
[email protected]db0f57f52011-02-25 03:54:54308 // shared_memory_handle doesn't belong to us: don't close it.
309 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
310 IntToPlatformFile(shared_memory_handle), false);
311 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21312 return PP_ERROR_FAILED;
313
314 return PP_OK;
315}
316
317} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02318} // namespace ppapi