OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "media/audio/mac/audio_output_mac.h" | 5 #include "media/audio/mac/audio_output_mac.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 silence_bytes_ = format_.mBytesPerFrame * params.sample_rate * 6 / 1000; | 84 silence_bytes_ = format_.mBytesPerFrame * params.sample_rate * 6 / 1000; |
85 } | 85 } |
86 | 86 |
87 PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() { | 87 PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() { |
88 } | 88 } |
89 | 89 |
90 void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) { | 90 void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) { |
91 // source_ can be set to NULL from another thread. We need to cache its | 91 // source_ can be set to NULL from another thread. We need to cache its |
92 // pointer while we operate here. Note that does not mean that the source | 92 // pointer while we operate here. Note that does not mean that the source |
93 // has been destroyed. | 93 // has been destroyed. |
94 AudioSourceCallback* source = source_; | 94 AudioSourceCallback* source = GetSource(); |
95 if (source) | 95 if (source) |
96 source->OnError(this, static_cast<int>(err)); | 96 source->OnError(this, static_cast<int>(err)); |
97 NOTREACHED() << "error code " << err; | 97 NOTREACHED() << "error code " << err; |
98 } | 98 } |
99 | 99 |
100 bool PCMQueueOutAudioOutputStream::Open() { | 100 bool PCMQueueOutAudioOutputStream::Open() { |
101 // Get the default device id. | 101 // Get the default device id. |
102 AudioObjectID device_id = 0; | 102 AudioObjectID device_id = 0; |
103 AudioObjectPropertyAddress property_address = { | 103 AudioObjectPropertyAddress property_address = { |
104 kAudioHardwarePropertyDefaultOutputDevice, | 104 kAudioHardwarePropertyDefaultOutputDevice, |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 format_.mChannelsPerFrame = num_core_channels_; | 150 format_.mChannelsPerFrame = num_core_channels_; |
151 format_.mBytesPerFrame = (format_.mBitsPerChannel >> 3) * | 151 format_.mBytesPerFrame = (format_.mBitsPerChannel >> 3) * |
152 format_.mChannelsPerFrame; | 152 format_.mChannelsPerFrame; |
153 format_.mBytesPerPacket = format_.mBytesPerFrame * format_.mFramesPerPacket; | 153 format_.mBytesPerPacket = format_.mBytesPerFrame * format_.mFramesPerPacket; |
154 } else { | 154 } else { |
155 should_down_mix_ = false; | 155 should_down_mix_ = false; |
156 } | 156 } |
157 // Create the actual queue object and let the OS use its own thread to | 157 // Create the actual queue object and let the OS use its own thread to |
158 // run its CFRunLoop. | 158 // run its CFRunLoop. |
159 err = AudioQueueNewOutput(&format_, RenderCallback, this, NULL, | 159 err = AudioQueueNewOutput(&format_, RenderCallback, this, NULL, |
160 kCFRunLoopCommonModes, 0, &audio_queue_); | 160 kCFRunLoopCommonModes, 0, &audio_queue_); |
161 if (err != noErr) { | 161 if (err != noErr) { |
162 HandleError(err); | 162 HandleError(err); |
163 return false; | 163 return false; |
164 } | 164 } |
165 // Allocate the hardware-managed buffers. | 165 // Allocate the hardware-managed buffers. |
166 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { | 166 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { |
167 err = AudioQueueAllocateBuffer(audio_queue_, packet_size_, &buffer_[ix]); | 167 err = AudioQueueAllocateBuffer(audio_queue_, packet_size_, &buffer_[ix]); |
168 if (err != noErr) { | 168 if (err != noErr) { |
169 HandleError(err); | 169 HandleError(err); |
170 return false; | 170 return false; |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 HandleError(err); | 307 HandleError(err); |
308 } | 308 } |
309 // Inform the audio manager that we have been closed. This can cause our | 309 // Inform the audio manager that we have been closed. This can cause our |
310 // destruction. | 310 // destruction. |
311 manager_->ReleaseOutputStream(this); | 311 manager_->ReleaseOutputStream(this); |
312 } | 312 } |
313 | 313 |
314 void PCMQueueOutAudioOutputStream::Stop() { | 314 void PCMQueueOutAudioOutputStream::Stop() { |
315 // We request a synchronous stop, so the next call can take some time. In | 315 // We request a synchronous stop, so the next call can take some time. In |
316 // the windows implementation we block here as well. | 316 // the windows implementation we block here as well. |
317 source_ = NULL; | 317 SetSource(NULL); |
| 318 |
318 // We set the source to null to signal to the data queueing thread it can stop | 319 // We set the source to null to signal to the data queueing thread it can stop |
319 // queueing data, however at most one callback might still be in flight which | 320 // queueing data, however at most one callback might still be in flight which |
320 // could attempt to enqueue right after the next call. Rather that trying to | 321 // could attempt to enqueue right after the next call. Rather that trying to |
321 // use a lock we rely on the internal Mac queue lock so the enqueue might | 322 // use a lock we rely on the internal Mac queue lock so the enqueue might |
322 // succeed or might fail but it won't crash or leave the queue itself in an | 323 // succeed or might fail but it won't crash or leave the queue itself in an |
323 // inconsistent state. | 324 // inconsistent state. |
324 OSStatus err = AudioQueueStop(audio_queue_, true); | 325 OSStatus err = AudioQueueStop(audio_queue_, true); |
325 if (err != noErr) | 326 if (err != noErr) |
326 HandleError(err); | 327 HandleError(err); |
327 } | 328 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 core_channel_orderings_[input_channel] == kEmptyChannel && | 372 core_channel_orderings_[input_channel] == kEmptyChannel && |
372 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel && | 373 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel && |
373 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) { | 374 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) { |
374 channel_remap_[core_channel_orderings_[output_channel]] = | 375 channel_remap_[core_channel_orderings_[output_channel]] = |
375 kChannelOrderings[source_layout_][input_channel]; | 376 kChannelOrderings[source_layout_][input_channel]; |
376 return true; | 377 return true; |
377 } | 378 } |
378 return false; | 379 return false; |
379 } | 380 } |
380 | 381 |
381 // Note to future hackers of this function: Do not add locks here because we | 382 // Note to future hackers of this function: Do not add locks to this function |
382 // call out to third party source that might do crazy things including adquire | 383 // that are held through any calls made back into AudioQueue APIs, or other |
383 // external locks or somehow re-enter here because its legal for them to call | 384 // OS audio functions. This is because the OS dispatch may grab external |
384 // some audio functions. | 385 // locks, or possibly re-enter this function which can lead to a deadlock. |
385 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, | 386 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, |
386 AudioQueueRef queue, | 387 AudioQueueRef queue, |
387 AudioQueueBufferRef buffer) { | 388 AudioQueueBufferRef buffer) { |
388 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); | 389 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); |
389 | 390 |
390 PCMQueueOutAudioOutputStream* audio_stream = | 391 PCMQueueOutAudioOutputStream* audio_stream = |
391 static_cast<PCMQueueOutAudioOutputStream*>(p_this); | 392 static_cast<PCMQueueOutAudioOutputStream*>(p_this); |
392 // Call the audio source to fill the free buffer with data. Not having a | 393 // Call the audio source to fill the free buffer with data. Not having a |
393 // source means that the queue has been closed. This is not an error. | 394 // source means that the queue has been closed. This is not an error. |
394 AudioSourceCallback* source = audio_stream->source_; | 395 AudioSourceCallback* source = audio_stream->GetSource(); |
395 if (!source) | 396 if (!source) |
396 return; | 397 return; |
397 | 398 |
398 // Adjust the number of pending bytes by subtracting the amount played. | 399 // Adjust the number of pending bytes by subtracting the amount played. |
399 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) | 400 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) |
400 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; | 401 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; |
401 uint32 capacity = buffer->mAudioDataBytesCapacity; | 402 uint32 capacity = buffer->mAudioDataBytesCapacity; |
402 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. | 403 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. |
403 uint32 filled = source->OnMoreData( | 404 uint32 filled = source->OnMoreData( |
404 audio_stream, reinterpret_cast<uint8*>(buffer->mAudioData), capacity, | 405 audio_stream, reinterpret_cast<uint8*>(buffer->mAudioData), capacity, |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) | 461 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) |
461 audio_stream->pending_bytes_ += filled; | 462 audio_stream->pending_bytes_ += filled; |
462 if (NULL == queue) | 463 if (NULL == queue) |
463 return; | 464 return; |
464 // Queue the audio data to the audio driver. | 465 // Queue the audio data to the audio driver. |
465 OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); | 466 OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); |
466 if (err != noErr) { | 467 if (err != noErr) { |
467 if (err == kAudioQueueErr_EnqueueDuringReset) { | 468 if (err == kAudioQueueErr_EnqueueDuringReset) { |
468 // This is the error you get if you try to enqueue a buffer and the | 469 // This is the error you get if you try to enqueue a buffer and the |
469 // queue has been closed. Not really a problem if indeed the queue | 470 // queue has been closed. Not really a problem if indeed the queue |
470 // has been closed. | 471 // has been closed. We recheck the value of source now to see if it has |
471 if (!audio_stream->source_) | 472 // indeed been closed. |
| 473 if (!audio_stream->GetSource()) |
472 return; | 474 return; |
473 } | 475 } |
474 audio_stream->HandleError(err); | 476 audio_stream->HandleError(err); |
475 } | 477 } |
476 } | 478 } |
477 | 479 |
478 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { | 480 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { |
479 DCHECK(callback); | 481 DCHECK(callback); |
480 OSStatus err = noErr; | 482 OSStatus err = noErr; |
481 source_ = callback; | 483 SetSource(callback); |
482 pending_bytes_ = 0; | 484 pending_bytes_ = 0; |
483 // Ask the source to pre-fill all our buffers before playing. | 485 // Ask the source to pre-fill all our buffers before playing. |
484 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { | 486 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { |
485 buffer_[ix]->mAudioDataByteSize = 0; | 487 buffer_[ix]->mAudioDataByteSize = 0; |
486 RenderCallback(this, NULL, buffer_[ix]); | 488 RenderCallback(this, NULL, buffer_[ix]); |
487 } | 489 } |
488 | 490 |
489 // Queue the buffers to the audio driver, sounds starts now. | 491 // Queue the buffers to the audio driver, sounds starts now. |
490 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { | 492 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { |
491 err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL); | 493 err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL); |
492 if (err != noErr) { | 494 if (err != noErr) { |
493 HandleError(err); | 495 HandleError(err); |
494 return; | 496 return; |
495 } | 497 } |
496 } | 498 } |
497 err = AudioQueueStart(audio_queue_, NULL); | 499 err = AudioQueueStart(audio_queue_, NULL); |
498 if (err != noErr) { | 500 if (err != noErr) { |
499 HandleError(err); | 501 HandleError(err); |
500 return; | 502 return; |
501 } | 503 } |
502 } | 504 } |
| 505 |
| 506 void PCMQueueOutAudioOutputStream::SetSource(AudioSourceCallback* source) { |
| 507 base::AutoLock lock(source_lock_); |
| 508 source_ = source; |
| 509 } |
| 510 |
| 511 AudioOutputStream::AudioSourceCallback* |
| 512 PCMQueueOutAudioOutputStream::GetSource() { |
| 513 base::AutoLock lock(source_lock_); |
| 514 return source_; |
| 515 } |
OLD | NEW |