| 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 |