blob: 22ddddd3feb23eb55a4657a19c6285c92d162201 [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"
[email protected]55cdf6052011-05-13 19:22:5310#include "ppapi/c/ppb_audio_config.h"
11#include "ppapi/c/ppb_var.h"
[email protected]b9a59842011-01-15 01:04:0012#include "ppapi/c/trusted/ppb_audio_trusted.h"
[email protected]cd910b92011-06-01 07:19:3113#include "ppapi/proxy/enter_proxy.h"
[email protected]5d84d012010-12-02 17:17:2114#include "ppapi/proxy/interface_id.h"
15#include "ppapi/proxy/plugin_dispatcher.h"
16#include "ppapi/proxy/plugin_resource.h"
17#include "ppapi/proxy/ppapi_messages.h"
18#include "ppapi/shared_impl/audio_impl.h"
[email protected]55cdf6052011-05-13 19:22:5319#include "ppapi/thunk/ppb_audio_config_api.h"
20#include "ppapi/thunk/ppb_audio_trusted_api.h"
21#include "ppapi/thunk/enter.h"
22#include "ppapi/thunk/resource_creation_api.h"
23#include "ppapi/thunk/thunk.h"
[email protected]5d84d012010-12-02 17:17:2124
[email protected]cd910b92011-06-01 07:19:3125using ::ppapi::thunk::PPB_Audio_API;
26
[email protected]5d84d012010-12-02 17:17:2127namespace pp {
28namespace proxy {
29
[email protected]55cdf6052011-05-13 19:22:5330class Audio : public PluginResource, public ppapi::AudioImpl {
[email protected]5d84d012010-12-02 17:17:2131 public:
[email protected]f24448db2011-01-27 20:40:3932 Audio(const HostResource& audio_id,
[email protected]4614f192011-01-21 00:26:4333 PP_Resource config_id,
34 PPB_Audio_Callback callback,
[email protected]55cdf6052011-05-13 19:22:5335 void* user_data);
36 virtual ~Audio();
[email protected]5d84d012010-12-02 17:17:2137
[email protected]55cdf6052011-05-13 19:22:5338 // ResourceObjectBase overrides.
[email protected]cd910b92011-06-01 07:19:3139 virtual PPB_Audio_API* AsPPB_Audio_API();
[email protected]5d84d012010-12-02 17:17:2140
[email protected]55cdf6052011-05-13 19:22:5341 // PPB_Audio_API implementation.
42 virtual PP_Resource GetCurrentConfig() OVERRIDE;
43 virtual PP_Bool StartPlayback() OVERRIDE;
44 virtual PP_Bool StopPlayback() OVERRIDE;
[email protected]5d84d012010-12-02 17:17:2145
46 private:
[email protected]55cdf6052011-05-13 19:22:5347 // Owning reference to the current config object. This isn't actually used,
48 // we just dish it out as requested by the plugin.
[email protected]5d84d012010-12-02 17:17:2149 PP_Resource config_;
50
51 DISALLOW_COPY_AND_ASSIGN(Audio);
52};
53
[email protected]55cdf6052011-05-13 19:22:5354Audio::Audio(const HostResource& audio_id,
55 PP_Resource config_id,
56 PPB_Audio_Callback callback,
57 void* user_data)
58 : PluginResource(audio_id),
59 config_(config_id) {
60 SetCallback(callback, user_data);
61 PluginResourceTracker::GetInstance()->AddRefResource(config_);
62}
63
64Audio::~Audio() {
65 PluginResourceTracker::GetInstance()->ReleaseResource(config_);
66}
67
[email protected]cd910b92011-06-01 07:19:3168PPB_Audio_API* Audio::AsPPB_Audio_API() {
[email protected]55cdf6052011-05-13 19:22:5369 return this;
70}
71
72PP_Resource Audio::GetCurrentConfig() {
73 // AddRef for the caller.
74 PluginResourceTracker::GetInstance()->AddRefResource(config_);
75 return config_;
76}
77
78PP_Bool Audio::StartPlayback() {
79 if (playing())
80 return PP_TRUE;
81 SetStartPlaybackState();
82 PluginDispatcher::GetForInstance(instance())->Send(
83 new PpapiHostMsg_PPBAudio_StartOrStop(
84 INTERFACE_ID_PPB_AUDIO, host_resource(), true));
85 return PP_TRUE;
86}
87
88PP_Bool Audio::StopPlayback() {
89 if (!playing())
90 return PP_TRUE;
91 PluginDispatcher::GetForInstance(instance())->Send(
92 new PpapiHostMsg_PPBAudio_StartOrStop(
93 INTERFACE_ID_PPB_AUDIO, host_resource(), false));
94 SetStopPlaybackState();
95 return PP_TRUE;
96}
97
[email protected]5d84d012010-12-02 17:17:2198namespace {
99
[email protected]465faa22011-02-08 16:31:46100InterfaceProxy* CreateAudioProxy(Dispatcher* dispatcher,
101 const void* target_interface) {
102 return new PPB_Audio_Proxy(dispatcher, target_interface);
103}
104
[email protected]db0f57f52011-02-25 03:54:54105base::PlatformFile IntToPlatformFile(int32_t handle) {
106 // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle,
107 // those casts are ugly.
108#if defined(OS_WIN)
109 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
110#elif defined(OS_POSIX)
111 return handle;
112#else
113 #error Not implemented.
114#endif
115}
116
[email protected]5d84d012010-12-02 17:17:21117} // namespace
118
119PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher,
120 const void* target_interface)
121 : InterfaceProxy(dispatcher, target_interface),
122 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
129const InterfaceProxy::Info* PPB_Audio_Proxy::GetInfo() {
130 static const Info info = {
[email protected]55cdf6052011-05-13 19:22:53131 ppapi::thunk::GetPPB_Audio_Thunk(),
[email protected]465faa22011-02-08 16:31:46132 PPB_AUDIO_INTERFACE,
133 INTERFACE_ID_PPB_AUDIO,
134 false,
135 &CreateAudioProxy,
136 };
137 return &info;
[email protected]5d84d012010-12-02 17:17:21138}
139
[email protected]55cdf6052011-05-13 19:22:53140// static
141PP_Resource PPB_Audio_Proxy::CreateProxyResource(
142 PP_Instance instance_id,
143 PP_Resource config_id,
144 PPB_Audio_Callback audio_callback,
145 void* user_data) {
146 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id);
147 if (!dispatcher)
148 return 0;
149
150 ::ppapi::thunk::EnterResourceNoLock< ::ppapi::thunk::PPB_AudioConfig_API>
151 config(config_id, true);
152 if (config.failed())
153 return 0;
154
155 HostResource result;
156 dispatcher->Send(new PpapiHostMsg_PPBAudio_Create(
157 INTERFACE_ID_PPB_AUDIO, instance_id,
158 config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(),
159 &result));
160 if (result.is_null())
161 return 0;
162
163 linked_ptr<Audio> object(new Audio(result, config_id,
164 audio_callback, user_data));
165 return PluginResourceTracker::GetInstance()->AddResource(object);
166}
167
[email protected]a95986a82010-12-24 06:19:28168bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) {
169 bool handled = true;
[email protected]5d84d012010-12-02 17:17:21170 IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg)
171 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate)
172 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop,
173 OnMsgStartOrStop)
[email protected]5d84d012010-12-02 17:17:21174 IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
175 OnMsgNotifyAudioStreamCreated)
[email protected]a95986a82010-12-24 06:19:28176 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]5d84d012010-12-02 17:17:21177 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28178 return handled;
[email protected]5d84d012010-12-02 17:17:21179}
180
181void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id,
[email protected]55cdf6052011-05-13 19:22:53182 int32_t sample_rate,
183 uint32_t sample_frame_count,
[email protected]f24448db2011-01-27 20:40:39184 HostResource* result) {
[email protected]55cdf6052011-05-13 19:22:53185 ::ppapi::thunk::EnterFunction< ::ppapi::thunk::ResourceCreationAPI>
186 resource_creation(instance_id, true);
187 if (resource_creation.failed())
[email protected]5d84d012010-12-02 17:17:21188 return;
[email protected]5d84d012010-12-02 17:17:21189
[email protected]55cdf6052011-05-13 19:22:53190 // Make the resource and get the API pointer to its trusted interface.
191 result->SetHostResource(
192 instance_id,
193 resource_creation.functions()->CreateAudioTrusted(instance_id));
[email protected]f24448db2011-01-27 20:40:39194 if (result->is_null())
[email protected]5d84d012010-12-02 17:17:21195 return;
[email protected]55cdf6052011-05-13 19:22:53196 ::ppapi::thunk::EnterResourceNoLock< ::ppapi::thunk::PPB_AudioTrusted_API>
197 trusted_audio(result->host_resource(), false);
198 if (trusted_audio.failed())
199 return;
[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);
206 if (!audio_config_res)
207 return;
208
209 // Initiate opening the audio object.
[email protected]5d84d012010-12-02 17:17:21210 CompletionCallback callback = callback_factory_.NewCallback(
211 &PPB_Audio_Proxy::AudioChannelConnected, *result);
[email protected]55cdf6052011-05-13 19:22:53212 int32_t open_error = trusted_audio.object()->OpenTrusted(
213 audio_config_res, callback.pp_completion_callback());
[email protected]996bdbd2011-04-11 22:46:44214 if (open_error != PP_OK_COMPLETIONPENDING)
[email protected]5d84d012010-12-02 17:17:21215 callback.Run(open_error);
[email protected]55cdf6052011-05-13 19:22:53216
217 // Clean up the temporary audio config resource we made.
218 const PPB_Core* core = static_cast<const PPB_Core*>(
219 dispatcher()->GetLocalInterface(PPB_CORE_INTERFACE));
220 core->ReleaseResource(audio_config_res);
[email protected]5d84d012010-12-02 17:17:21221}
222
[email protected]f24448db2011-01-27 20:40:39223void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id,
224 bool play) {
[email protected]5d84d012010-12-02 17:17:21225 if (play)
[email protected]f24448db2011-01-27 20:40:39226 ppb_audio_target()->StartPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21227 else
[email protected]f24448db2011-01-27 20:40:39228 ppb_audio_target()->StopPlayback(audio_id.host_resource());
[email protected]5d84d012010-12-02 17:17:21229}
230
[email protected]f24448db2011-01-27 20:40:39231// Processed in the plugin (message from host).
[email protected]5d84d012010-12-02 17:17:21232void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16233 const HostResource& audio_id,
234 int32_t result_code,
235 IPC::PlatformFileForTransit socket_handle,
236 base::SharedMemoryHandle handle,
237 uint32_t length) {
[email protected]cd910b92011-06-01 07:19:31238 EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id);
[email protected]55cdf6052011-05-13 19:22:53239 if (enter.failed() || result_code != PP_OK) {
[email protected]5d84d012010-12-02 17:17:21240 // The caller may still have given us these handles in the failure case.
241 // The easiest way to clean these up is to just put them in the objects
242 // and then close them. This failure case is not performance critical.
243 base::SyncSocket temp_socket(
[email protected]2031aeb2011-01-28 20:01:16244 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
245 base::SharedMemory temp_mem(handle, false);
[email protected]cd910b92011-06-01 07:19:31246 } else {
247 static_cast<Audio*>(enter.object())->SetStreamInfo(
248 handle, length,
249 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]5d84d012010-12-02 17:17:21250 }
[email protected]5d84d012010-12-02 17:17:21251}
252
[email protected]f24448db2011-01-27 20:40:39253void PPB_Audio_Proxy::AudioChannelConnected(
254 int32_t result,
255 const HostResource& resource) {
[email protected]5d84d012010-12-02 17:17:21256 IPC::PlatformFileForTransit socket_handle =
257 IPC::InvalidPlatformFileForTransit();
[email protected]db0f57f52011-02-25 03:54:54258 base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit();
[email protected]5d84d012010-12-02 17:17:21259 uint32_t shared_memory_length = 0;
260
261 int32_t result_code = result;
262 if (result_code == PP_OK) {
263 result_code = GetAudioConnectedHandles(resource, &socket_handle,
264 &shared_memory,
265 &shared_memory_length);
266 }
267
268 // Send all the values, even on error. This simplifies some of our cleanup
269 // code since the handles will be in the other process and could be
270 // inconvenient to clean up. Our IPC code will automatically handle this for
271 // us, as long as the remote side always closes the handles it receives
272 // (in OnMsgNotifyAudioStreamCreated), even in the failure case.
273 dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated(
[email protected]2031aeb2011-01-28 20:01:16274 INTERFACE_ID_PPB_AUDIO, resource, result_code, socket_handle,
275 shared_memory, shared_memory_length));
[email protected]5d84d012010-12-02 17:17:21276}
277
278int32_t PPB_Audio_Proxy::GetAudioConnectedHandles(
[email protected]f24448db2011-01-27 20:40:39279 const HostResource& resource,
[email protected]5d84d012010-12-02 17:17:21280 IPC::PlatformFileForTransit* foreign_socket_handle,
281 base::SharedMemoryHandle* foreign_shared_memory_handle,
282 uint32_t* shared_memory_length) {
283 // Get the trusted audio interface which will give us the handles.
[email protected]55cdf6052011-05-13 19:22:53284 ::ppapi::thunk::EnterResourceNoLock< ::ppapi::thunk::PPB_AudioTrusted_API>
285 trusted_audio(resource.host_resource(), false);
286 if (trusted_audio.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]55cdf6052011-05-13 19:22:53291 int32_t result = trusted_audio.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]55cdf6052011-05-13 19:22:53303 result = trusted_audio.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
318} // namespace pp