OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/glue/plugins/pepper_audio.h" | 5 #include "webkit/glue/plugins/pepper_audio.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "ppapi/c/dev/ppb_audio_dev.h" | 8 #include "ppapi/c/dev/ppb_audio_dev.h" |
9 #include "ppapi/c/dev/ppb_audio_trusted_dev.h" | 9 #include "ppapi/c/dev/ppb_audio_trusted_dev.h" |
10 #include "ppapi/c/pp_completion_callback.h" | 10 #include "ppapi/c/pp_completion_callback.h" |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 user_callback, user_data)) | 89 user_callback, user_data)) |
90 return 0; | 90 return 0; |
91 return audio->GetReference(); | 91 return audio->GetReference(); |
92 } | 92 } |
93 | 93 |
94 PP_Bool IsAudio(PP_Resource resource) { | 94 PP_Bool IsAudio(PP_Resource resource) { |
95 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(resource); | 95 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(resource); |
96 return BoolToPPBool(!!audio); | 96 return BoolToPPBool(!!audio); |
97 } | 97 } |
98 | 98 |
99 PP_Resource GetCurrentConfiguration(PP_Resource audio_id) { | 99 PP_Resource GetCurrentConfig(PP_Resource audio_id) { |
100 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); | 100 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); |
101 return audio ? audio->GetCurrentConfiguration() : 0; | 101 return audio ? audio->GetCurrentConfig() : 0; |
102 } | 102 } |
103 | 103 |
104 PP_Bool StartPlayback(PP_Resource audio_id) { | 104 PP_Bool StartPlayback(PP_Resource audio_id) { |
105 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); | 105 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); |
106 return audio ? BoolToPPBool(audio->StartPlayback()) : PP_FALSE; | 106 return audio ? BoolToPPBool(audio->StartPlayback()) : PP_FALSE; |
107 } | 107 } |
108 | 108 |
109 PP_Bool StopPlayback(PP_Resource audio_id) { | 109 PP_Bool StopPlayback(PP_Resource audio_id) { |
110 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); | 110 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); |
111 return audio ? BoolToPPBool(audio->StopPlayback()) : PP_FALSE; | 111 return audio ? BoolToPPBool(audio->StopPlayback()) : PP_FALSE; |
112 } | 112 } |
113 | 113 |
114 const PPB_Audio_Dev ppb_audio = { | 114 const PPB_Audio_Dev ppb_audio = { |
115 &Create, | 115 &Create, |
116 &IsAudio, | 116 &IsAudio, |
117 &GetCurrentConfiguration, | 117 &GetCurrentConfig, |
118 &StartPlayback, | 118 &StartPlayback, |
119 &StopPlayback, | 119 &StopPlayback, |
120 }; | 120 }; |
121 | 121 |
122 // PPB_AudioTrusted ------------------------------------------------------------ | 122 // PPB_AudioTrusted ------------------------------------------------------------ |
123 | 123 |
124 PP_Resource CreateTrusted(PP_Instance instance_id) { | 124 PP_Resource CreateTrusted(PP_Instance instance_id) { |
125 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | 125 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); |
126 if (!instance) | 126 if (!instance) |
127 return 0; | 127 return 0; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 } | 194 } |
195 | 195 |
196 AudioConfig* AudioConfig::AsAudioConfig() { | 196 AudioConfig* AudioConfig::AsAudioConfig() { |
197 return this; | 197 return this; |
198 } | 198 } |
199 | 199 |
200 // Audio ----------------------------------------------------------------------- | 200 // Audio ----------------------------------------------------------------------- |
201 | 201 |
202 Audio::Audio(PluginModule* module, PP_Instance instance_id) | 202 Audio::Audio(PluginModule* module, PP_Instance instance_id) |
203 : Resource(module), | 203 : Resource(module), |
204 playing_(false), | |
205 pp_instance_(instance_id), | 204 pp_instance_(instance_id), |
206 audio_(NULL), | 205 audio_(NULL), |
207 socket_(NULL), | |
208 shared_memory_(NULL), | |
209 shared_memory_size_(0), | |
210 callback_(NULL), | |
211 user_data_(NULL), | |
212 create_callback_pending_(false) { | 206 create_callback_pending_(false) { |
213 create_callback_ = PP_MakeCompletionCallback(NULL, NULL); | 207 create_callback_ = PP_MakeCompletionCallback(NULL, NULL); |
214 } | 208 } |
215 | 209 |
216 Audio::~Audio() { | 210 Audio::~Audio() { |
217 // Calling ShutDown() makes sure StreamCreated cannot be called anymore. | 211 // Calling ShutDown() makes sure StreamCreated cannot be called anymore. |
218 audio_->ShutDown(); | 212 audio_->ShutDown(); |
219 audio_ = NULL; | 213 audio_ = NULL; |
220 | 214 |
221 // Closing the socket causes the thread to exit - wait for it. | |
222 socket_->Close(); | |
223 if (audio_thread_.get()) { | |
224 audio_thread_->Join(); | |
225 audio_thread_.reset(); | |
226 } | |
227 | |
228 // If the completion callback hasn't fired yet, do so here | 215 // If the completion callback hasn't fired yet, do so here |
229 // with an error condition. | 216 // with an error condition. |
230 if (create_callback_pending_) { | 217 if (create_callback_pending_) { |
231 PP_RunCompletionCallback(&create_callback_, PP_ERROR_ABORTED); | 218 PP_RunCompletionCallback(&create_callback_, PP_ERROR_ABORTED); |
232 create_callback_pending_ = false; | 219 create_callback_pending_ = false; |
233 } | 220 } |
234 // Shared memory destructor will unmap the memory automatically. | |
235 } | 221 } |
236 | 222 |
237 const PPB_Audio_Dev* Audio::GetInterface() { | 223 const PPB_Audio_Dev* Audio::GetInterface() { |
238 return &ppb_audio; | 224 return &ppb_audio; |
239 } | 225 } |
240 | 226 |
241 const PPB_AudioTrusted_Dev* Audio::GetTrustedInterface() { | 227 const PPB_AudioTrusted_Dev* Audio::GetTrustedInterface() { |
242 return &ppb_audiotrusted; | 228 return &ppb_audiotrusted; |
243 } | 229 } |
244 | 230 |
245 Audio* Audio::AsAudio() { | 231 Audio* Audio::AsAudio() { |
246 return this; | 232 return this; |
247 } | 233 } |
248 | 234 |
249 bool Audio::Init(PluginDelegate* plugin_delegate, | 235 bool Audio::Init(PluginDelegate* plugin_delegate, |
250 PP_Resource config_id, | 236 PP_Resource config_id, |
251 PPB_Audio_Callback callback, void* user_data) { | 237 PPB_Audio_Callback callback, void* user_data) { |
252 CHECK(!audio_); | 238 CHECK(!audio_); |
253 config_ = Resource::GetAs<AudioConfig>(config_id); | 239 config_ = Resource::GetAs<AudioConfig>(config_id); |
254 if (!config_) | 240 if (!config_) |
255 return false; | 241 return false; |
256 callback_ = callback; | 242 SetCallback(callback, user_data); |
257 user_data_ = user_data; | |
258 | 243 |
259 // When the stream is created, we'll get called back on StreamCreated(). | 244 // When the stream is created, we'll get called back on StreamCreated(). |
260 audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), | 245 audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), |
261 config_->sample_frame_count(), | 246 config_->sample_frame_count(), |
262 this); | 247 this); |
263 return audio_ != NULL; | 248 return audio_ != NULL; |
264 } | 249 } |
265 | 250 |
| 251 PP_Resource Audio::GetCurrentConfig() { |
| 252 return config_->GetReference(); |
| 253 } |
| 254 |
| 255 bool Audio::StartPlayback() { |
| 256 if (playing()) |
| 257 return true; |
| 258 SetStartPlaybackState(); |
| 259 return audio_->StartPlayback(); |
| 260 } |
| 261 |
| 262 bool Audio::StopPlayback() { |
| 263 if (!playing()) |
| 264 return true; |
| 265 if (!audio_->StopPlayback()) |
| 266 return false; |
| 267 SetStopPlaybackState(); |
| 268 return true; |
| 269 } |
| 270 |
266 int32_t Audio::Open(PluginDelegate* plugin_delegate, | 271 int32_t Audio::Open(PluginDelegate* plugin_delegate, |
267 PP_Resource config_id, | 272 PP_Resource config_id, |
268 PP_CompletionCallback create_callback) { | 273 PP_CompletionCallback create_callback) { |
269 DCHECK(!audio_); | 274 DCHECK(!audio_); |
270 config_ = Resource::GetAs<AudioConfig>(config_id); | 275 config_ = Resource::GetAs<AudioConfig>(config_id); |
271 if (!config_) | 276 if (!config_) |
272 return PP_ERROR_BADRESOURCE; | 277 return PP_ERROR_BADRESOURCE; |
273 | 278 |
274 // When the stream is created, we'll get called back on StreamCreated(). | 279 // When the stream is created, we'll get called back on StreamCreated(). |
275 audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), | 280 audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), |
276 config_->sample_frame_count(), | 281 config_->sample_frame_count(), |
277 this); | 282 this); |
278 if (!audio_) | 283 if (!audio_) |
279 return PP_ERROR_FAILED; | 284 return PP_ERROR_FAILED; |
280 | 285 |
281 // At this point, we are guaranteeing ownership of the completion | 286 // At this point, we are guaranteeing ownership of the completion |
282 // callback. Audio promises to fire the completion callback | 287 // callback. Audio promises to fire the completion callback |
283 // once and only once. | 288 // once and only once. |
284 create_callback_ = create_callback; | 289 create_callback_ = create_callback; |
285 create_callback_pending_ = true; | 290 create_callback_pending_ = true; |
286 return PP_ERROR_WOULDBLOCK; | 291 return PP_ERROR_WOULDBLOCK; |
287 } | 292 } |
288 | 293 |
289 int32_t Audio::GetSyncSocket(int* sync_socket) { | 294 int32_t Audio::GetSyncSocket(int* sync_socket) { |
290 if (socket_ != NULL) { | 295 if (socket_for_create_callback_.get()) { |
291 #if defined(OS_POSIX) | 296 #if defined(OS_POSIX) |
292 *sync_socket = socket_->handle(); | 297 *sync_socket = socket_for_create_callback_->handle(); |
293 #elif defined(OS_WIN) | 298 #elif defined(OS_WIN) |
294 *sync_socket = reinterpret_cast<int>(socket_->handle()); | 299 *sync_socket = reinterpret_cast<int>(socket_for_create_callback_->handle()); |
295 #else | 300 #else |
296 #error "Platform not supported." | 301 #error "Platform not supported." |
297 #endif | 302 #endif |
298 return PP_OK; | 303 return PP_OK; |
299 } | 304 } |
300 return PP_ERROR_FAILED; | 305 return PP_ERROR_FAILED; |
301 } | 306 } |
302 | 307 |
303 int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) { | 308 int32_t Audio::GetSharedMemory(int* shm_handle, uint32_t* shm_size) { |
304 if (shared_memory_ != NULL) { | 309 if (shared_memory_for_create_callback_.get()) { |
305 #if defined(OS_POSIX) | 310 #if defined(OS_POSIX) |
306 *shm_handle = shared_memory_->handle().fd; | 311 *shm_handle = shared_memory_for_create_callback_->handle().fd; |
307 #elif defined(OS_WIN) | 312 #elif defined(OS_WIN) |
308 *shm_handle = reinterpret_cast<int>(shared_memory_->handle()); | 313 *shm_handle = reinterpret_cast<int>( |
| 314 shared_memory_handle_for_create_callback_->handle()); |
309 #else | 315 #else |
310 #error "Platform not supported." | 316 #error "Platform not supported." |
311 #endif | 317 #endif |
312 *shm_size = shared_memory_size_; | 318 *shm_size = shared_memory_size_for_create_callback_; |
313 return PP_OK; | 319 return PP_OK; |
314 } | 320 } |
315 return PP_ERROR_FAILED; | 321 return PP_ERROR_FAILED; |
316 } | 322 } |
317 | 323 |
318 bool Audio::StartPlayback() { | |
319 if (playing_) | |
320 return true; | |
321 | |
322 CHECK(!audio_thread_.get()); | |
323 if (callback_ && socket_.get()) { | |
324 audio_thread_.reset(new base::DelegateSimpleThread(this, | |
325 "plugin_audio_thread")); | |
326 audio_thread_->Start(); | |
327 } | |
328 playing_ = true; | |
329 return audio_->StartPlayback(); | |
330 } | |
331 | |
332 bool Audio::StopPlayback() { | |
333 if (!playing_) | |
334 return true; | |
335 | |
336 if (!audio_->StopPlayback()) | |
337 return false; | |
338 | |
339 if (audio_thread_.get()) { | |
340 audio_thread_->Join(); | |
341 audio_thread_.reset(); | |
342 } | |
343 playing_ = false; | |
344 return true; | |
345 } | |
346 | |
347 void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle, | 324 void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle, |
348 size_t shared_memory_size, | 325 size_t shared_memory_size, |
349 base::SyncSocket::Handle socket_handle) { | 326 base::SyncSocket::Handle socket_handle) { |
350 socket_.reset(new base::SyncSocket(socket_handle)); | 327 if (create_callback_pending_) { |
351 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); | 328 // Trusted side of proxy can specify a callback to recieve handles. In |
352 shared_memory_size_ = shared_memory_size; | 329 // this case we don't need to map any data or start the thread since it |
| 330 // will be handled by the proxy. |
| 331 shared_memory_for_create_callback_.reset( |
| 332 new base::SharedMemory(shared_memory_handle, false)); |
| 333 shared_memory_size_for_create_callback_ = shared_memory_size; |
| 334 socket_for_create_callback_.reset(new base::SyncSocket(socket_handle)); |
353 | 335 |
354 // Trusted side of proxy can specify a callback to recieve handles. | |
355 if (create_callback_pending_) { | |
356 PP_RunCompletionCallback(&create_callback_, 0); | 336 PP_RunCompletionCallback(&create_callback_, 0); |
357 create_callback_pending_ = false; | 337 create_callback_pending_ = false; |
358 } | |
359 | 338 |
360 // Trusted, non-proxy audio will invoke buffer filling callback on a | 339 // Close the handles now that this process is done with them. |
361 // dedicated thread, see Audio::Run() below. | 340 shared_memory_for_create_callback_.reset(); |
362 if (callback_) { | 341 shared_memory_size_for_create_callback_ = 0; |
363 shared_memory_->Map(shared_memory_size_); | 342 socket_for_create_callback_.reset(); |
364 | 343 } else { |
365 // In common case StartPlayback() was called before StreamCreated(). | 344 SetStreamInfo(shared_memory_handle, shared_memory_size, socket_handle); |
366 if (playing_) { | |
367 audio_thread_.reset(new base::DelegateSimpleThread(this, | |
368 "plugin_audio_thread")); | |
369 audio_thread_->Start(); | |
370 } | |
371 } | |
372 } | |
373 | |
374 void Audio::Run() { | |
375 int pending_data; | |
376 void* buffer = shared_memory_->memory(); | |
377 size_t buffer_size_in_bytes = config_->BufferSize(); | |
378 | |
379 while (sizeof(pending_data) == | |
380 socket_->Receive(&pending_data, sizeof(pending_data)) && | |
381 pending_data >= 0) { | |
382 // Exit the thread on pause. | |
383 if (pending_data < 0) | |
384 return; | |
385 callback_(buffer, buffer_size_in_bytes, user_data_); | |
386 } | 345 } |
387 } | 346 } |
388 | 347 |
389 } // namespace pepper | 348 } // namespace pepper |
OLD | NEW |