blob: 6e3467494fa9bffbe44abf147647db7e66b53555 [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]ac9ba8fe2010-12-30 18:08:367#include "base/threading/simple_thread.h"
[email protected]5d84d012010-12-02 17:17:218#include "ppapi/c/pp_errors.h"
[email protected]b9a59842011-01-15 01:04:009#include "ppapi/c/ppb_audio.h"
10#include "ppapi/c/trusted/ppb_audio_trusted.h"
[email protected]5d84d012010-12-02 17:17:2111#include "ppapi/proxy/interface_id.h"
12#include "ppapi/proxy/plugin_dispatcher.h"
13#include "ppapi/proxy/plugin_resource.h"
14#include "ppapi/proxy/ppapi_messages.h"
15#include "ppapi/shared_impl/audio_impl.h"
16
17namespace pp {
18namespace proxy {
19
20class Audio : public PluginResource, public pp::shared_impl::AudioImpl {
21 public:
[email protected]f24448db2011-01-27 20:40:3922 Audio(const HostResource& audio_id,
[email protected]4614f192011-01-21 00:26:4323 PP_Resource config_id,
24 PPB_Audio_Callback callback,
25 void* user_data)
[email protected]f24448db2011-01-27 20:40:3926 : PluginResource(audio_id),
[email protected]4614f192011-01-21 00:26:4327 config_(config_id) {
[email protected]5d84d012010-12-02 17:17:2128 SetCallback(callback, user_data);
[email protected]4614f192011-01-21 00:26:4329 PluginResourceTracker::GetInstance()->AddRefResource(config_);
[email protected]5d84d012010-12-02 17:17:2130 }
31 virtual ~Audio() {
[email protected]4614f192011-01-21 00:26:4332 PluginResourceTracker::GetInstance()->ReleaseResource(config_);
[email protected]5d84d012010-12-02 17:17:2133 }
34
35 // Resource overrides.
36 virtual Audio* AsAudio() { return this; }
37
38 PP_Resource config() const { return config_; }
39
40 void StartPlayback(PP_Resource resource) {
41 if (playing())
42 return;
43 SetStartPlaybackState();
[email protected]4614f192011-01-21 00:26:4344 PluginDispatcher::GetForInstance(instance())->Send(
45 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]f24448db2011-01-27 20:40:3946 INTERFACE_ID_PPB_AUDIO, host_resource(), true));
[email protected]5d84d012010-12-02 17:17:2147 }
48
49 void StopPlayback(PP_Resource resource) {
50 if (!playing())
51 return;
[email protected]4614f192011-01-21 00:26:4352 PluginDispatcher::GetForInstance(instance())->Send(
53 new PpapiHostMsg_PPBAudio_StartOrStop(
[email protected]f24448db2011-01-27 20:40:3954 INTERFACE_ID_PPB_AUDIO, host_resource(), false));
[email protected]5d84d012010-12-02 17:17:2155 SetStopPlaybackState();
56 }
57
58 private:
59 PP_Resource config_;
60
61 DISALLOW_COPY_AND_ASSIGN(Audio);
62};
63
64namespace {
65
66PP_Resource Create(PP_Instance instance_id,
67 PP_Resource config_id,
68 PPB_Audio_Callback callback,
69 void* user_data) {
[email protected]f24448db2011-01-27 20:40:3970 PluginResource* config = PluginResourceTracker::GetInstance()->
71 GetResourceObject(config_id);
72 if (!config)
[email protected]5d84d012010-12-02 17:17:2173 return 0;
74
[email protected]465faa22011-02-08 16:31:4675 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
76 if (!dispatcher)
77 return 0;
78
[email protected]f24448db2011-01-27 20:40:3979 HostResource result;
[email protected]465faa22011-02-08 16:31:4680 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
[email protected]f24448db2011-01-27 20:40:3981 INTERFACE_ID_PPB_AUDIO, instance_id, config->host_resource(), &result));
82 if (result.is_null())
83 return 0;
84
85 linked_ptr<Audio> object(new Audio(result, config_id, callback, user_data));
86 return PluginResourceTracker::GetInstance()->AddResource(object);
[email protected]5d84d012010-12-02 17:17:2187}
88
89PP_Bool IsAudio(PP_Resource resource) {
90 Audio* object = PluginResource::GetAs<Audio>(resource);
91 return BoolToPPBool(!!object);
92}
93
94PP_Resource GetCurrentConfiguration(PP_Resource audio_id) {
95 Audio* object = PluginResource::GetAs<Audio>(audio_id);
96 if (!object)
97 return 0;
98 PP_Resource result = object->config();
[email protected]4614f192011-01-21 00:26:4399 PluginResourceTracker::GetInstance()->AddRefResource(result);
[email protected]5d84d012010-12-02 17:17:21100 return result;
101}
102
103PP_Bool StartPlayback(PP_Resource audio_id) {
104 Audio* object = PluginResource::GetAs<Audio>(audio_id);
105 if (!object)
106 return PP_FALSE;
107 object->StartPlayback(audio_id);
108 return PP_TRUE;
109}
110
111PP_Bool StopPlayback(PP_Resource audio_id) {
112 Audio* object = PluginResource::GetAs<Audio>(audio_id);
113 if (!object)
114 return PP_FALSE;
115 object->StopPlayback(audio_id);
116 return PP_TRUE;
117}
118
[email protected]b9a59842011-01-15 01:04:00119const PPB_Audio audio_interface = {
[email protected]5d84d012010-12-02 17:17:21120 &Create,
121 &IsAudio,
122 &GetCurrentConfiguration,
123 &StartPlayback,
124 &StopPlayback
125};
126
[email protected]465faa22011-02-08 16:31:46127InterfaceProxy* CreateAudioProxy(Dispatcher* dispatcher,
128 const void* target_interface) {
129 return new PPB_Audio_Proxy(dispatcher, target_interface);
130}
131
[email protected]db0f57f52011-02-25 03:54:54132base::PlatformFile IntToPlatformFile(int32_t handle) {
133 // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle,
134 // those casts are ugly.
135#if defined(OS_WIN)
136 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
137#elif defined(OS_POSIX)
138 return handle;
139#else
140 #error Not implemented.
141#endif
142}
143
[email protected]5d84d012010-12-02 17:17:21144} // namespace
145
146PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher,
147 const void* target_interface)
148 : InterfaceProxy(dispatcher, target_interface),
149 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
150}
151
152PPB_Audio_Proxy::~PPB_Audio_Proxy() {
153}
154
[email protected]465faa22011-02-08 16:31:46155// static
156const InterfaceProxy::Info* PPB_Audio_Proxy::GetInfo() {
157 static const Info info = {
158 &audio_interface,
159 PPB_AUDIO_INTERFACE,
160 INTERFACE_ID_PPB_AUDIO,
161 false,
162 &CreateAudioProxy,
163 };
164 return &info;
[email protected]5d84d012010-12-02 17:17:21165}
166
[email protected]a95986a82010-12-24 06:19:28167bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
168 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21169 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
170 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
171 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
172 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21173 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
174 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28175 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21176 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28177 return handled;
[email protected]5d84d012010-12-02 17:17:21178}
179
180void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]f24448db2011-01-27 20:40:39181 const HostResource& config_id,
182 HostResource* result) {
[email protected]b9a59842011-01-15 01:04:00183 const PPB_AudioTrusted* audio_trusted =
184 reinterpret_cast<const PPB_AudioTrusted*>(
185 dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_INTERFACE));
[email protected]f24448db2011-01-27 20:40:39186 if (!audio_trusted)
[email protected]5d84d012010-12-02 17:17:21187 return;
[email protected]5d84d012010-12-02 17:17:21188
[email protected]f24448db2011-01-27 20:40:39189 result->SetHostResource(instance_id,
190 audio_trusted->CreateTrusted(instance_id));
191 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21192 return;
193
194 CompletionCallback callback = callback_factory_.NewCallback(
195 &PPB_Audio_Proxy::AudioChannelConnected, *result);
[email protected]f24448db2011-01-27 20:40:39196 int32_t open_error = audio_trusted->Open(result->host_resource(),
197 config_id.host_resource(),
[email protected]5d84d012010-12-02 17:17:21198 callback.pp_completion_callback());
[email protected]996bdbd2011-04-11 22:46:44199 if (open_error != PP_OK_COMPLETIONPENDING)
[email protected]5d84d012010-12-02 17:17:21200 callback.Run(open_error);
201}
202
[email protected]f24448db2011-01-27 20:40:39203void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
204 bool play) {
[email protected]5d84d012010-12-02 17:17:21205 if (play)
[email protected]f24448db2011-01-27 20:40:39206 ppb_audio_target()->StartPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21207 else
[email protected]f24448db2011-01-27 20:40:39208 ppb_audio_target()->StopPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21209}
210
[email protected]f24448db2011-01-27 20:40:39211// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21212void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16213 const HostResource& audio_id,
214 int32_t result_code,
215 IPC::PlatformFileForTransit socket_handle,
216 base::SharedMemoryHandle handle,
217 uint32_t length) {
[email protected]f24448db2011-01-27 20:40:39218 PP_Resource plugin_resource =
219 PluginResourceTracker::GetInstance()->PluginResourceForHostResource(
[email protected]2031aeb2011-01-28 20:01:16220 audio_id);
[email protected]f24448db2011-01-27 20:40:39221 Audio* object = plugin_resource ?
222 PluginResource::GetAs<Audio>(plugin_resource) : NULL;
[email protected]2031aeb2011-01-28 20:01:16223 if (!object || result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21224 // The caller may still have given us these handles in the failure case.
225 // The easiest way to clean these up is to just put them in the objects
226 // and then close them. This failure case is not performance critical.
227 base::SyncSocket temp_socket(
[email protected]2031aeb2011-01-28 20:01:16228 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
229 base::SharedMemory temp_mem(handle, false);
[email protected]5d84d012010-12-02 17:17:21230 return;
231 }
232 object->SetStreamInfo(
[email protected]2031aeb2011-01-28 20:01:16233 handle, length, IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]5d84d012010-12-02 17:17:21234}
235
[email protected]f24448db2011-01-27 20:40:39236void PPB_Audio_Proxy::AudioChannelConnected(
237 int32_t result,
238 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21239 IPC::PlatformFileForTransit socket_handle =
240 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54241 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21242 uint32_t shared_memory_length = 0;
243
244 int32_t result_code = result;
245 if (result_code == PP_OK) {
246 result_code = GetAudioConnectedHandles(resource, &socket_handle,
247 &shared_memory,
248 &shared_memory_length);
249 }
250
251 // Send all the values, even on error. This simplifies some of our cleanup
252 // code since the handles will be in the other process and could be
253 // inconvenient to clean up. Our IPC code will automatically handle this for
254 // us, as long as the remote side always closes the handles it receives
255 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
256 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16257 INTERFACE_ID_PPB_AUDIO, resource, result_code, socket_handle,
258 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21259}
260
261int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39262 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21263 IPC::PlatformFileForTransit* foreign_socket_handle,
264 base::SharedMemoryHandle* foreign_shared_memory_handle,
265 uint32_t* shared_memory_length) {
266 // Get the trusted audio interface which will give us the handles.
[email protected]b9a59842011-01-15 01:04:00267 const PPB_AudioTrusted* audio_trusted =
268 reinterpret_cast<const PPB_AudioTrusted*>(
269 dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_INTERFACE));
[email protected]5d84d012010-12-02 17:17:21270 if (!audio_trusted)
271 return PP_ERROR_NOINTERFACE;
272
273 // Get the socket handle for signaling.
274 int32_t socket_handle;
[email protected]f24448db2011-01-27 20:40:39275 int32_t result = audio_trusted->GetSyncSocket(resource.host_resource(),
276 &socket_handle);
[email protected]5d84d012010-12-02 17:17:21277 if (result != PP_OK)
278 return result;
279
[email protected]db0f57f52011-02-25 03:54:54280 // socket_handle doesn't belong to us: don't close it.
281 *foreign_socket_handle = dispatcher()->ShareHandleWithRemote(
282 IntToPlatformFile(socket_handle), false);
283 if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit())
284 return PP_ERROR_FAILED;
[email protected]5d84d012010-12-02 17:17:21285
286 // Get the shared memory for the buffer.
[email protected]5d84d012010-12-02 17:17:21287 int shared_memory_handle;
[email protected]f24448db2011-01-27 20:40:39288 result = audio_trusted->GetSharedMemory(resource.host_resource(),
289 &shared_memory_handle,
290 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21291 if (result != PP_OK)
292 return result;
293
[email protected]db0f57f52011-02-25 03:54:54294 // shared_memory_handle doesn't belong to us: don't close it.
295 *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote(
296 IntToPlatformFile(shared_memory_handle), false);
297 if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit())
[email protected]5d84d012010-12-02 17:17:21298 return PP_ERROR_FAILED;
299
300 return PP_OK;
301}
302
303} // namespace proxy
304} // namespace pp