blob: c1095cf55c5e2b1d5272ffb119d1f68986074da5 [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]f24448db2011-01-27 20:40:3975 HostResource result;
76 PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBAudio_Create(
77 INTERFACE_ID_PPB_AUDIO, instance_id, config->host_resource(), &result));
78 if (result.is_null())
79 return 0;
80
81 linked_ptr<Audio> object(new Audio(result, config_id, callback, user_data));
82 return PluginResourceTracker::GetInstance()->AddResource(object);
[email protected]5d84d012010-12-02 17:17:2183}
84
85PP_Bool IsAudio(PP_Resource resource) {
86 Audio* object = PluginResource::GetAs<Audio>(resource);
87 return BoolToPPBool(!!object);
88}
89
90PP_Resource GetCurrentConfiguration(PP_Resource audio_id) {
91 Audio* object = PluginResource::GetAs<Audio>(audio_id);
92 if (!object)
93 return 0;
94 PP_Resource result = object->config();
[email protected]4614f192011-01-21 00:26:4395 PluginResourceTracker::GetInstance()->AddRefResource(result);
[email protected]5d84d012010-12-02 17:17:2196 return result;
97}
98
99PP_Bool StartPlayback(PP_Resource audio_id) {
100 Audio* object = PluginResource::GetAs<Audio>(audio_id);
101 if (!object)
102 return PP_FALSE;
103 object->StartPlayback(audio_id);
104 return PP_TRUE;
105}
106
107PP_Bool StopPlayback(PP_Resource audio_id) {
108 Audio* object = PluginResource::GetAs<Audio>(audio_id);
109 if (!object)
110 return PP_FALSE;
111 object->StopPlayback(audio_id);
112 return PP_TRUE;
113}
114
[email protected]b9a59842011-01-15 01:04:00115const PPB_Audio audio_interface = {
[email protected]5d84d012010-12-02 17:17:21116 &Create,
117 &IsAudio,
118 &GetCurrentConfiguration,
119 &StartPlayback,
120 &StopPlayback
121};
122
123} // namespace
124
125PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher,
126 const void* target_interface)
127 : InterfaceProxy(dispatcher, target_interface),
128 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
129}
130
131PPB_Audio_Proxy::~PPB_Audio_Proxy() {
132}
133
134const void* PPB_Audio_Proxy::GetSourceInterface() const {
135 return &audio_interface;
136}
137
138InterfaceID PPB_Audio_Proxy::GetInterfaceId() const {
139 return INTERFACE_ID_PPB_AUDIO;
140}
141
[email protected]a95986a82010-12-24 06:19:28142bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
143 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21144 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
145 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
146 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
147 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21148 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
149 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28150 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21151 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28152 return handled;
[email protected]5d84d012010-12-02 17:17:21153}
154
155void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]f24448db2011-01-27 20:40:39156 const HostResource& config_id,
157 HostResource* result) {
[email protected]b9a59842011-01-15 01:04:00158 const PPB_AudioTrusted* audio_trusted =
159 reinterpret_cast<const PPB_AudioTrusted*>(
160 dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_INTERFACE));
[email protected]f24448db2011-01-27 20:40:39161 if (!audio_trusted)
[email protected]5d84d012010-12-02 17:17:21162 return;
[email protected]5d84d012010-12-02 17:17:21163
[email protected]f24448db2011-01-27 20:40:39164 result->SetHostResource(instance_id,
165 audio_trusted->CreateTrusted(instance_id));
166 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21167 return;
168
169 CompletionCallback callback = callback_factory_.NewCallback(
170 &PPB_Audio_Proxy::AudioChannelConnected, *result);
[email protected]f24448db2011-01-27 20:40:39171 int32_t open_error = audio_trusted->Open(result->host_resource(),
172 config_id.host_resource(),
[email protected]5d84d012010-12-02 17:17:21173 callback.pp_completion_callback());
174 if (open_error != PP_ERROR_WOULDBLOCK)
175 callback.Run(open_error);
176}
177
[email protected]f24448db2011-01-27 20:40:39178void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
179 bool play) {
[email protected]5d84d012010-12-02 17:17:21180 if (play)
[email protected]f24448db2011-01-27 20:40:39181 ppb_audio_target()->StartPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21182 else
[email protected]f24448db2011-01-27 20:40:39183 ppb_audio_target()->StopPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21184}
185
[email protected]f24448db2011-01-27 20:40:39186// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21187void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]f24448db2011-01-27 20:40:39188 const PPBAudio_NotifyAudioStreamCreated_Params& params) {
189 PP_Resource plugin_resource =
190 PluginResourceTracker::GetInstance()->PluginResourceForHostResource(
191 params.audio_id);
192 Audio* object = plugin_resource ?
193 PluginResource::GetAs<Audio>(plugin_resource) : NULL;
194 if (!object || params.result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21195 // The caller may still have given us these handles in the failure case.
196 // The easiest way to clean these up is to just put them in the objects
197 // and then close them. This failure case is not performance critical.
198 base::SyncSocket temp_socket(
[email protected]f24448db2011-01-27 20:40:39199 IPC::PlatformFileForTransitToPlatformFile(params.socket_handle));
200 base::SharedMemory temp_mem(params.handle, false);
[email protected]5d84d012010-12-02 17:17:21201 return;
202 }
203 object->SetStreamInfo(
[email protected]f24448db2011-01-27 20:40:39204 params.handle, params.length,
205 IPC::PlatformFileForTransitToPlatformFile(params.socket_handle));
[email protected]5d84d012010-12-02 17:17:21206}
207
[email protected]f24448db2011-01-27 20:40:39208void PPB_Audio_Proxy::AudioChannelConnected(
209 int32_t result,
210 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21211 IPC::PlatformFileForTransit socket_handle =
212 IPC::InvalidPlatformFileForTransit();
213#if defined(OS_WIN)
214 base::SharedMemoryHandle shared_memory = NULL;
215#elif defined(OS_POSIX)
216 base::SharedMemoryHandle shared_memory(-1, false);
217#else
218 #error Not implemented.
219#endif
220 uint32_t shared_memory_length = 0;
221
222 int32_t result_code = result;
223 if (result_code == PP_OK) {
224 result_code = GetAudioConnectedHandles(resource, &socket_handle,
225 &shared_memory,
226 &shared_memory_length);
227 }
228
229 // Send all the values, even on error. This simplifies some of our cleanup
230 // code since the handles will be in the other process and could be
231 // inconvenient to clean up. Our IPC code will automatically handle this for
232 // us, as long as the remote side always closes the handles it receives
233 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
[email protected]f24448db2011-01-27 20:40:39234 PPBAudio_NotifyAudioStreamCreated_Params params;
235 params.audio_id = resource;
236 params.result_code = result;
237 params.socket_handle = socket_handle;
238 params.handle = shared_memory;
239 params.length = shared_memory_length;
[email protected]5d84d012010-12-02 17:17:21240 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]f24448db2011-01-27 20:40:39241 INTERFACE_ID_PPB_AUDIO, params));
[email protected]5d84d012010-12-02 17:17:21242}
243
244int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39245 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21246 IPC::PlatformFileForTransit* foreign_socket_handle,
247 base::SharedMemoryHandle* foreign_shared_memory_handle,
248 uint32_t* shared_memory_length) {
249 // Get the trusted audio interface which will give us the handles.
[email protected]b9a59842011-01-15 01:04:00250 const PPB_AudioTrusted* audio_trusted =
251 reinterpret_cast<const PPB_AudioTrusted*>(
252 dispatcher()->GetLocalInterface(PPB_AUDIO_TRUSTED_INTERFACE));
[email protected]5d84d012010-12-02 17:17:21253 if (!audio_trusted)
254 return PP_ERROR_NOINTERFACE;
255
256 // Get the socket handle for signaling.
257 int32_t socket_handle;
[email protected]f24448db2011-01-27 20:40:39258 int32_t result = audio_trusted->GetSyncSocket(resource.host_resource(),
259 &socket_handle);
[email protected]5d84d012010-12-02 17:17:21260 if (result != PP_OK)
261 return result;
262
263#if defined(OS_WIN)
264 // On Windows, duplicate the socket into the plugin process, this will
265 // automatically close the source handle.
266 ::DuplicateHandle(
267 GetCurrentProcess(),
268 reinterpret_cast<HANDLE>(static_cast<intptr_t>(socket_handle)),
269 dispatcher()->remote_process_handle(), foreign_socket_handle,
270 STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ | FILE_MAP_WRITE,
271 FALSE, DUPLICATE_CLOSE_SOURCE);
272#else
273 // On Posix, the socket handle will be auto-duplicated when we send the
274 // FileDescriptor. Set AutoClose since we don't need the handle any more.
275 *foreign_socket_handle = base::FileDescriptor(socket_handle, true);
276#endif
277
278 // Get the shared memory for the buffer.
279 // TODO(brettw) remove the reinterpret cast when the interface is updated.
280 int shared_memory_handle;
[email protected]f24448db2011-01-27 20:40:39281 result = audio_trusted->GetSharedMemory(resource.host_resource(),
282 &shared_memory_handle,
283 shared_memory_length);
[email protected]5d84d012010-12-02 17:17:21284 if (result != PP_OK)
285 return result;
286
287 base::SharedMemory shared_memory(
288#if defined(OS_WIN)
289 reinterpret_cast<HANDLE>(static_cast<intptr_t>(shared_memory_handle)),
290#else
291 base::FileDescriptor(shared_memory_handle, false),
292#endif
293 false);
294
295 // Duplicate the shared memory to the plugin process. This will automatically
296 // close the source handle.
297 if (!shared_memory.GiveToProcess(dispatcher()->remote_process_handle(),
298 foreign_shared_memory_handle))
299 return PP_ERROR_FAILED;
300
301 return PP_OK;
302}
303
304} // namespace proxy
305} // namespace pp