Chromium Code Reviews| 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 "webkit/glue/plugins/pepper_common.h" | 11 #include "webkit/glue/plugins/pepper_common.h" |
| 11 | 12 |
| 12 namespace pepper { | 13 namespace pepper { |
| 13 | 14 |
| 14 namespace { | 15 namespace { |
| 15 | 16 |
| 16 // PPB_AudioConfig ------------------------------------------------------------- | 17 // PPB_AudioConfig ------------------------------------------------------------- |
| 17 | 18 |
| 18 uint32_t RecommendSampleFrameCount(uint32_t requested_sample_frame_count); | 19 uint32_t RecommendSampleFrameCount(uint32_t requested_sample_frame_count); |
| 19 | 20 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 &CreateStereo16bit, | 71 &CreateStereo16bit, |
| 71 &RecommendSampleFrameCount, | 72 &RecommendSampleFrameCount, |
| 72 &IsAudioConfig, | 73 &IsAudioConfig, |
| 73 &GetSampleRate, | 74 &GetSampleRate, |
| 74 &GetSampleFrameCount | 75 &GetSampleFrameCount |
| 75 }; | 76 }; |
| 76 | 77 |
| 77 // PPB_Audio ------------------------------------------------------------------- | 78 // PPB_Audio ------------------------------------------------------------------- |
| 78 | 79 |
| 79 PP_Resource Create(PP_Instance instance_id, PP_Resource config_id, | 80 PP_Resource Create(PP_Instance instance_id, PP_Resource config_id, |
| 80 PPB_Audio_Callback callback, void* user_data) { | 81 PPB_Audio_Callback user_callback, void* user_data) { |
| 81 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | 82 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); |
| 82 if (!instance) | 83 if (!instance) |
| 83 return 0; | 84 return 0; |
| 84 // TODO(neb): Require callback to be present for untrusted plugins. | 85 // TODO(neb): Require callback to be present for untrusted plugins. |
|
darin (slow to review)
2010/11/24 20:34:35
it seems like it'll be easy to enforce this TODO n
nfullagar
2010/11/24 23:01:05
Added check for NULL user_callback here, and check
| |
| 85 scoped_refptr<Audio> audio(new Audio(instance->module())); | 86 scoped_refptr<Audio> audio(new Audio(instance->module(), instance_id)); |
| 86 if (!audio->Init(instance->delegate(), config_id, callback, user_data)) | 87 if (!audio->Init(instance->delegate(), config_id, |
| 88 user_callback, user_data)) | |
| 87 return 0; | 89 return 0; |
| 88 return audio->GetReference(); | 90 return audio->GetReference(); |
| 89 } | 91 } |
| 90 | 92 |
| 91 PP_Bool IsAudio(PP_Resource resource) { | 93 PP_Bool IsAudio(PP_Resource resource) { |
| 92 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(resource); | 94 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(resource); |
| 93 return BoolToPPBool(!!audio); | 95 return BoolToPPBool(!!audio); |
| 94 } | 96 } |
| 95 | 97 |
| 96 PP_Resource GetCurrentConfiguration(PP_Resource audio_id) { | 98 PP_Resource GetCurrentConfiguration(PP_Resource audio_id) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 111 const PPB_Audio_Dev ppb_audio = { | 113 const PPB_Audio_Dev ppb_audio = { |
| 112 &Create, | 114 &Create, |
| 113 &IsAudio, | 115 &IsAudio, |
| 114 &GetCurrentConfiguration, | 116 &GetCurrentConfiguration, |
| 115 &StartPlayback, | 117 &StartPlayback, |
| 116 &StopPlayback, | 118 &StopPlayback, |
| 117 }; | 119 }; |
| 118 | 120 |
| 119 // PPB_AudioTrusted ------------------------------------------------------------ | 121 // PPB_AudioTrusted ------------------------------------------------------------ |
| 120 | 122 |
| 121 PP_Resource GetBuffer(PP_Resource audio_id) { | 123 PP_Resource CreateTrusted(PP_Instance instance_id) { |
| 122 // TODO(neb): Implement me! | 124 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); |
| 123 return 0; | 125 if (!instance) |
| 126 return 0; | |
| 127 scoped_refptr<Audio> audio(new Audio(instance->module(), instance_id)); | |
| 128 return audio->GetReference(); | |
| 124 } | 129 } |
| 125 | 130 |
| 126 int GetOSDescriptor(PP_Resource audio_id) { | 131 int32_t Open(PP_Resource audio_id, |
| 127 // TODO(neb): Implement me! | 132 PP_Resource config_id, |
| 128 return -1; | 133 PP_CompletionCallback created) { |
| 134 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); | |
| 135 if (!audio) | |
| 136 return PP_ERROR_BADARGUMENT; | |
| 137 PP_Instance instance_id = audio->pp_instance(); | |
| 138 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 139 if (!instance) | |
| 140 return PP_ERROR_FAILED; | |
| 141 return audio->OpenTrusted(instance->delegate(), config_id, created); | |
| 142 } | |
| 143 | |
| 144 int32_t GetSyncSocket(PP_Resource audio_id, int* sync_socket) { | |
| 145 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); | |
| 146 if (audio) | |
| 147 return audio->GetSyncSocket(sync_socket); | |
| 148 return PP_ERROR_BADARGUMENT; | |
| 149 } | |
| 150 | |
| 151 int32_t GetSharedMemory(PP_Resource audio_id, | |
| 152 int* shm_handle, | |
| 153 int32_t* shm_size) { | |
| 154 scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id); | |
| 155 if (audio) | |
| 156 return audio->GetSharedMemory(shm_handle, shm_size); | |
| 157 return PP_ERROR_BADARGUMENT; | |
| 129 } | 158 } |
| 130 | 159 |
| 131 const PPB_AudioTrusted_Dev ppb_audiotrusted = { | 160 const PPB_AudioTrusted_Dev ppb_audiotrusted = { |
| 132 &GetBuffer, | 161 &CreateTrusted, |
| 133 &GetOSDescriptor | 162 &Open, |
| 163 &GetSyncSocket, | |
| 164 &GetSharedMemory, | |
| 134 }; | 165 }; |
| 135 | 166 |
| 136 } // namespace | 167 } // namespace |
| 137 | 168 |
| 138 // AudioConfig ----------------------------------------------------------------- | 169 // AudioConfig ----------------------------------------------------------------- |
| 139 | 170 |
| 140 AudioConfig::AudioConfig(PluginModule* module, | 171 AudioConfig::AudioConfig(PluginModule* module, |
| 141 PP_AudioSampleRate_Dev sample_rate, | 172 PP_AudioSampleRate_Dev sample_rate, |
| 142 uint32_t sample_frame_count) | 173 uint32_t sample_frame_count) |
| 143 : Resource(module), | 174 : Resource(module), |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 158 const int kSizeOfSample = sizeof(int16_t); | 189 const int kSizeOfSample = sizeof(int16_t); |
| 159 return static_cast<size_t>(sample_frame_count_ * kSizeOfSample * kChannels); | 190 return static_cast<size_t>(sample_frame_count_ * kSizeOfSample * kChannels); |
| 160 } | 191 } |
| 161 | 192 |
| 162 AudioConfig* AudioConfig::AsAudioConfig() { | 193 AudioConfig* AudioConfig::AsAudioConfig() { |
| 163 return this; | 194 return this; |
| 164 } | 195 } |
| 165 | 196 |
| 166 // Audio ----------------------------------------------------------------------- | 197 // Audio ----------------------------------------------------------------------- |
| 167 | 198 |
| 168 Audio::Audio(PluginModule* module) | 199 Audio::Audio(PluginModule* module, PP_Instance instance_id) |
| 169 : Resource(module), | 200 : Resource(module), |
| 170 playing_(false), | 201 playing_(false), |
| 202 pp_instance_(instance_id), | |
| 203 audio_(NULL), | |
| 171 socket_(NULL), | 204 socket_(NULL), |
| 172 shared_memory_(NULL), | 205 shared_memory_(NULL), |
| 173 shared_memory_size_(0), | 206 shared_memory_size_(0), |
| 174 callback_(NULL), | 207 callback_(NULL), |
| 175 user_data_(NULL) { | 208 user_data_(NULL), |
| 209 create_callback_pending_(false) { | |
| 210 create_callback_ = PP_MakeCompletionCallback(NULL, NULL); | |
| 176 } | 211 } |
| 177 | 212 |
| 178 Audio::~Audio() { | 213 Audio::~Audio() { |
| 179 // Calling ShutDown() makes sure StreamCreated cannot be called anymore. | 214 // Calling ShutDown() makes sure StreamCreated cannot be called anymore. |
| 180 audio_->ShutDown(); | 215 audio_->ShutDown(); |
| 216 audio_ = NULL; | |
| 217 | |
| 181 // Closing the socket causes the thread to exit - wait for it. | 218 // Closing the socket causes the thread to exit - wait for it. |
| 182 socket_->Close(); | 219 socket_->Close(); |
| 183 if (audio_thread_.get()) { | 220 if (audio_thread_.get()) { |
| 184 audio_thread_->Join(); | 221 audio_thread_->Join(); |
| 185 audio_thread_.reset(); | 222 audio_thread_.reset(); |
| 186 } | 223 } |
| 224 | |
| 225 // If the completion callback hasn't fired yet, do so here | |
| 226 // with an error condition. | |
| 227 if (create_callback_pending_) { | |
| 228 PP_RunCompletionCallback(&create_callback_, PP_ERROR_ABORTED); | |
| 229 create_callback_pending_ = false; | |
| 230 } | |
| 187 // Shared memory destructor will unmap the memory automatically. | 231 // Shared memory destructor will unmap the memory automatically. |
| 188 } | 232 } |
| 189 | 233 |
| 190 const PPB_Audio_Dev* Audio::GetInterface() { | 234 const PPB_Audio_Dev* Audio::GetInterface() { |
| 191 return &ppb_audio; | 235 return &ppb_audio; |
| 192 } | 236 } |
| 193 | 237 |
| 194 const PPB_AudioTrusted_Dev* Audio::GetTrustedInterface() { | 238 const PPB_AudioTrusted_Dev* Audio::GetTrustedInterface() { |
| 195 return &ppb_audiotrusted; | 239 return &ppb_audiotrusted; |
| 196 } | 240 } |
| 197 | 241 |
| 198 Audio* Audio::AsAudio() { | 242 Audio* Audio::AsAudio() { |
| 199 return this; | 243 return this; |
| 200 } | 244 } |
| 201 | 245 |
| 202 bool Audio::Init(PluginDelegate* plugin_delegate, PP_Resource config_id, | 246 bool Audio::Init(PluginDelegate* plugin_delegate, |
| 247 PP_Resource config_id, | |
| 203 PPB_Audio_Callback callback, void* user_data) { | 248 PPB_Audio_Callback callback, void* user_data) { |
| 204 CHECK(!audio_.get()); | 249 CHECK(!audio_); |
| 205 config_ = Resource::GetAs<AudioConfig>(config_id); | 250 config_ = Resource::GetAs<AudioConfig>(config_id); |
| 206 if (!config_) | 251 if (!config_) |
| 207 return false; | 252 return false; |
| 208 callback_ = callback; | 253 callback_ = callback; |
| 209 user_data_ = user_data; | 254 user_data_ = user_data; |
| 210 // When the stream is created, we'll get called back in StreamCreated(). | 255 |
| 211 audio_.reset(plugin_delegate->CreateAudio(config_->sample_rate(), | 256 // When the stream is created, we'll get called back on StreamCreated(). |
| 212 config_->sample_frame_count(), | 257 audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), |
| 213 this)); | 258 config_->sample_frame_count(), |
| 214 return audio_.get() != NULL; | 259 this); |
| 260 return audio_ != NULL; | |
| 261 } | |
| 262 | |
| 263 int32_t Audio::OpenTrusted(PluginDelegate* plugin_delegate, | |
|
darin (slow to review)
2010/11/24 20:34:35
nit: might be nice to call this "Open" to match up
nfullagar
2010/11/24 23:01:05
Done.
| |
| 264 PP_Resource config_id, | |
| 265 PP_CompletionCallback create_callback) { | |
| 266 DCHECK(!audio_); | |
| 267 config_ = Resource::GetAs<AudioConfig>(config_id); | |
| 268 if (!config_) | |
| 269 return PP_ERROR_BADARGUMENT; | |
| 270 | |
| 271 // When the stream is created, we'll get called back on StreamCreated(). | |
| 272 audio_ = plugin_delegate->CreateAudio(config_->sample_rate(), | |
| 273 config_->sample_frame_count(), | |
| 274 this); | |
| 275 if (audio_ == NULL) | |
|
darin (slow to review)
2010/11/24 20:34:35
nit: in chromium code, we usually write "if (!audi
nfullagar
2010/11/24 23:01:05
Done.
| |
| 276 return PP_ERROR_FAILED; | |
| 277 | |
| 278 // At this point, we are guaranteeing ownership of the completion | |
| 279 // callback. Audio promises to fire the completion callback | |
| 280 // once and only once. | |
| 281 create_callback_ = create_callback; | |
| 282 create_callback_pending_ = true; | |
| 283 return PP_ERROR_WOULDBLOCK; | |
| 284 } | |
| 285 | |
| 286 int32_t Audio::GetSyncSocket(int* sync_socket) { | |
| 287 if (socket_ != NULL) { | |
| 288 #if defined(OS_POSIX) | |
| 289 *sync_socket = socket_->handle(); | |
| 290 #elif defined(OS_WIN) | |
| 291 *sync_socket = reinterpret_cast<int>(socket_->handle()); | |
| 292 #else | |
| 293 #error "Platform not supported." | |
| 294 #endif | |
| 295 return PP_OK; | |
| 296 } | |
| 297 return PP_ERROR_FAILED; | |
| 298 } | |
| 299 | |
| 300 int32_t Audio::GetSharedMemory(int* shm_handle, int32_t* shm_size) { | |
| 301 if (shared_memory_ != NULL) { | |
| 302 #if defined(OS_POSIX) | |
| 303 *shm_handle = shared_memory_->handle().fd; | |
| 304 #elif defined(OS_WIN) | |
| 305 *shm_handle = reinterpret_cast<int>(shared_memory_->handle()); | |
| 306 #else | |
| 307 #error "Platform not supported." | |
| 308 #endif | |
| 309 *shm_size = shared_memory_size_; | |
| 310 return PP_OK; | |
| 311 } | |
| 312 return PP_ERROR_FAILED; | |
| 215 } | 313 } |
| 216 | 314 |
| 217 bool Audio::StartPlayback() { | 315 bool Audio::StartPlayback() { |
| 218 if (playing_) | 316 if (playing_) |
| 219 return true; | 317 return true; |
| 220 | 318 |
| 221 CHECK(!audio_thread_.get()); | 319 CHECK(!audio_thread_.get()); |
| 222 if (callback_ && socket_.get()) { | 320 if (callback_ && socket_.get()) { |
| 223 audio_thread_.reset(new base::DelegateSimpleThread(this, | 321 audio_thread_.reset(new base::DelegateSimpleThread(this, |
| 224 "plugin_audio_thread")); | 322 "plugin_audio_thread")); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 243 return true; | 341 return true; |
| 244 } | 342 } |
| 245 | 343 |
| 246 void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle, | 344 void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle, |
| 247 size_t shared_memory_size, | 345 size_t shared_memory_size, |
| 248 base::SyncSocket::Handle socket_handle) { | 346 base::SyncSocket::Handle socket_handle) { |
| 249 socket_.reset(new base::SyncSocket(socket_handle)); | 347 socket_.reset(new base::SyncSocket(socket_handle)); |
| 250 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); | 348 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); |
| 251 shared_memory_size_ = shared_memory_size; | 349 shared_memory_size_ = shared_memory_size; |
| 252 | 350 |
| 351 // Trusted side of proxy can specify a callback to recieve handles. | |
| 352 if (create_callback_pending_) { | |
| 353 PP_RunCompletionCallback(&create_callback_, 0); | |
| 354 create_callback_pending_ = false; | |
| 355 } | |
| 356 | |
| 357 // Recurring callback to fill audio buffers. | |
|
darin (slow to review)
2010/11/24 20:34:35
nit: this comment is confusing... what is it tryin
nfullagar
2010/11/24 23:01:05
clarified
| |
| 253 if (callback_) { | 358 if (callback_) { |
| 254 shared_memory_->Map(shared_memory_size_); | 359 shared_memory_->Map(shared_memory_size_); |
| 360 | |
| 255 // In common case StartPlayback() was called before StreamCreated(). | 361 // In common case StartPlayback() was called before StreamCreated(). |
| 256 if (playing_) { | 362 if (playing_) { |
| 257 audio_thread_.reset(new base::DelegateSimpleThread(this, | 363 audio_thread_.reset(new base::DelegateSimpleThread(this, |
| 258 "plugin_audio_thread")); | 364 "plugin_audio_thread")); |
| 259 audio_thread_->Start(); | 365 audio_thread_->Start(); |
| 260 } | 366 } |
| 261 } | 367 } |
| 262 } | 368 } |
| 263 | 369 |
| 264 void Audio::Run() { | 370 void Audio::Run() { |
| 265 int pending_data; | 371 int pending_data; |
| 266 void* buffer = shared_memory_->memory(); | 372 void* buffer = shared_memory_->memory(); |
| 267 size_t buffer_size_in_bytes = config_->BufferSize(); | 373 size_t buffer_size_in_bytes = config_->BufferSize(); |
| 268 | 374 |
| 269 while (sizeof(pending_data) == | 375 while (sizeof(pending_data) == |
| 270 socket_->Receive(&pending_data, sizeof(pending_data)) && | 376 socket_->Receive(&pending_data, sizeof(pending_data)) && |
| 271 pending_data >= 0) { | 377 pending_data >= 0) { |
| 272 // Exit the thread on pause. | 378 // Exit the thread on pause. |
| 273 if (pending_data < 0) | 379 if (pending_data < 0) |
| 274 return; | 380 return; |
| 275 callback_(buffer, buffer_size_in_bytes, user_data_); | 381 callback_(buffer, buffer_size_in_bytes, user_data_); |
| 276 } | 382 } |
| 277 } | 383 } |
| 278 | 384 |
| 279 } // namespace pepper | 385 } // namespace pepper |
| 280 | |
| OLD | NEW |