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