Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <CoreServices/CoreServices.h> | 7 #include <CoreServices/CoreServices.h> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 53 packet_size_(params.GetBytesPerBuffer()), | 53 packet_size_(params.GetBytesPerBuffer()), |
| 54 silence_bytes_(0), | 54 silence_bytes_(0), |
| 55 volume_(1), | 55 volume_(1), |
| 56 pending_bytes_(0), | 56 pending_bytes_(0), |
| 57 num_source_channels_(params.channels()), | 57 num_source_channels_(params.channels()), |
| 58 source_layout_(params.channel_layout()), | 58 source_layout_(params.channel_layout()), |
| 59 num_core_channels_(0), | 59 num_core_channels_(0), |
| 60 should_swizzle_(false), | 60 should_swizzle_(false), |
| 61 should_down_mix_(false), | 61 should_down_mix_(false), |
| 62 stopped_event_(true /* manual reset */, false /* initial state */), | 62 stopped_event_(true /* manual reset */, false /* initial state */), |
| 63 num_buffers_left_(kNumBuffers) { | 63 stop_requested_(false) { |
| 64 // We must have a manager. | 64 // We must have a manager. |
| 65 DCHECK(manager_); | 65 DCHECK(manager_); |
| 66 // A frame is one sample across all channels. In interleaved audio the per | 66 // A frame is one sample across all channels. In interleaved audio the per |
| 67 // frame fields identify the set of n |channels|. In uncompressed audio, a | 67 // frame fields identify the set of n |channels|. In uncompressed audio, a |
| 68 // packet is always one frame. | 68 // packet is always one frame. |
| 69 format_.mSampleRate = params.sample_rate(); | 69 format_.mSampleRate = params.sample_rate(); |
| 70 format_.mFormatID = kAudioFormatLinearPCM; | 70 format_.mFormatID = kAudioFormatLinearPCM; |
| 71 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked; | 71 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked; |
| 72 format_.mBitsPerChannel = params.bits_per_sample(); | 72 format_.mBitsPerChannel = params.bits_per_sample(); |
| 73 format_.mChannelsPerFrame = params.channels(); | 73 format_.mChannelsPerFrame = params.channels(); |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 core_channel_orderings_[input_channel] == kEmptyChannel && | 372 core_channel_orderings_[input_channel] == kEmptyChannel && |
| 373 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel && | 373 kChannelOrderings[source_layout_][input_channel] > kEmptyChannel && |
| 374 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) { | 374 kChannelOrderings[source_layout_][output_channel] == kEmptyChannel) { |
| 375 channel_remap_[core_channel_orderings_[output_channel]] = | 375 channel_remap_[core_channel_orderings_[output_channel]] = |
| 376 kChannelOrderings[source_layout_][input_channel]; | 376 kChannelOrderings[source_layout_][input_channel]; |
| 377 return true; | 377 return true; |
| 378 } | 378 } |
| 379 return false; | 379 return false; |
| 380 } | 380 } |
| 381 | 381 |
| 382 void PCMQueueOutAudioOutputStream::IsRunningCallback( | |
| 383 void* p_this, | |
| 384 AudioQueueRef queue, | |
| 385 AudioQueuePropertyID inID) { | |
| 386 PCMQueueOutAudioOutputStream* audio_stream = | |
| 387 static_cast<PCMQueueOutAudioOutputStream*>(p_this); | |
| 388 UInt32 running = 0; | |
| 389 UInt32 size = sizeof(running); | |
| 390 OSStatus err = AudioQueueGetProperty(queue, | |
| 391 kAudioQueueProperty_IsRunning, | |
| 392 &running, | |
| 393 &size); | |
| 394 if (err) { | |
| 395 audio_stream->HandleError(err); | |
| 396 return; | |
| 397 } | |
| 398 if (!running) { | |
| 399 // Remove property listener, we don't need it anymore. | |
| 400 OSStatus err = AudioQueueRemovePropertyListener( | |
| 401 queue, | |
| 402 kAudioQueueProperty_IsRunning, | |
| 403 PCMQueueOutAudioOutputStream::IsRunningCallback, | |
| 404 audio_stream); | |
| 405 if (err != noErr) | |
| 406 audio_stream->HandleError(err); | |
| 407 | |
| 408 // Ok, finally signal that stream is not running. | |
| 409 audio_stream->stopped_event_.Signal(); | |
| 410 } | |
| 411 } | |
| 412 | |
| 382 // Note to future hackers of this function: Do not add locks to this function | 413 // Note to future hackers of this function: Do not add locks to this function |
| 383 // that are held through any calls made back into AudioQueue APIs, or other | 414 // that are held through any calls made back into AudioQueue APIs, or other |
| 384 // OS audio functions. This is because the OS dispatch may grab external | 415 // OS audio functions. This is because the OS dispatch may grab external |
| 385 // locks, or possibly re-enter this function which can lead to a deadlock. | 416 // locks, or possibly re-enter this function which can lead to a deadlock. |
| 386 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, | 417 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, |
| 387 AudioQueueRef queue, | 418 AudioQueueRef queue, |
| 388 AudioQueueBufferRef buffer) { | 419 AudioQueueBufferRef buffer) { |
| 389 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); | 420 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); |
| 390 | 421 |
| 391 PCMQueueOutAudioOutputStream* audio_stream = | 422 PCMQueueOutAudioOutputStream* audio_stream = |
| 392 static_cast<PCMQueueOutAudioOutputStream*>(p_this); | 423 static_cast<PCMQueueOutAudioOutputStream*>(p_this); |
| 393 | 424 |
| 394 // Call the audio source to fill the free buffer with data. Not having a | 425 // Call the audio source to fill the free buffer with data. Not having a |
| 395 // source means that the queue has been stopped. | 426 // source means that the queue has been stopped. |
| 396 AudioSourceCallback* source = audio_stream->GetSource(); | 427 AudioSourceCallback* source = audio_stream->GetSource(); |
| 397 if (!source) { | 428 if (!source) { |
| 398 // PCMQueueOutAudioOutputStream::Stop() is waiting for callback to | 429 // PCMQueueOutAudioOutputStream::Stop() is waiting for callback to |
| 399 // stop the stream and signal when all callbacks are done. | 430 // stop the stream and signal when all activity ceased (we probably |
| 400 // (we probably can stop the stream there, but it is better to have | 431 // can stop the stream there, but it is better to have all the |
| 401 // all the complex logic in one place; stopping latency is not very | 432 // complex logic in one place; stopping latency is not very important |
| 402 // important if you reuse audio stream in the mixer and not close it | 433 // if you reuse audio stream in the mixer and not close it immediately). |
| 403 // immediately). | 434 if (!audio_stream->stop_requested_) { |
| 404 --audio_stream->num_buffers_left_; | 435 audio_stream->stop_requested_ = true; |
|
scherkus (not reviewing)
2012/06/18 19:40:53
do we need to reset this to false at some point in
enal1
2012/06/18 19:58:47
When starting the stream. in PCMQueueOutAudioOutpu
| |
| 405 if (audio_stream->num_buffers_left_ == kNumBuffers - 1) { | 436 // Before actually stopping the stream, register callback that |
| 406 // First buffer after stop requested, stop the queue. | 437 // OS would call when status of "is running" property changes. |
| 407 OSStatus err = AudioQueueStop(audio_stream->audio_queue_, true); | 438 // This way we (hopefully) would know when stream is actually |
| 439 // stopped and it is safe to dispose it. | |
| 440 OSStatus err = AudioQueueAddPropertyListener( | |
| 441 queue, | |
|
scherkus (not reviewing)
2012/06/18 19:40:53
minor nit: in line 448 you use audio_stream->audio
enal1
2012/06/18 19:58:47
Done.
| |
| 442 kAudioQueueProperty_IsRunning, | |
| 443 PCMQueueOutAudioOutputStream::IsRunningCallback, | |
| 444 audio_stream); | |
| 408 if (err != noErr) | 445 if (err != noErr) |
| 409 audio_stream->HandleError(err); | 446 audio_stream->HandleError(err); |
| 410 } | 447 // Now stop the queue. |
| 411 if (audio_stream->num_buffers_left_ == 0) { | 448 err = AudioQueueStop(audio_stream->audio_queue_, true); |
| 412 // Now we finally saw all the buffers. | 449 if (err != noErr) |
| 413 // Signal that stopping is complete. | 450 audio_stream->HandleError(err); |
| 414 // Should never touch audio_stream after signaling as it | |
| 415 // can be deleted at any moment. | |
| 416 audio_stream->stopped_event_.Signal(); | |
| 417 } | 451 } |
| 418 return; | 452 return; |
| 419 } | 453 } |
| 420 | 454 |
| 421 // Adjust the number of pending bytes by subtracting the amount played. | 455 // Adjust the number of pending bytes by subtracting the amount played. |
| 422 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) | 456 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) |
| 423 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; | 457 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; |
| 424 uint32 capacity = buffer->mAudioDataBytesCapacity; | 458 uint32 capacity = buffer->mAudioDataBytesCapacity; |
| 425 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. | 459 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. |
| 426 uint32 filled = source->OnMoreData( | 460 uint32 filled = source->OnMoreData( |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 502 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { | 536 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { |
| 503 DCHECK(callback); | 537 DCHECK(callback); |
| 504 DLOG_IF(ERROR, !audio_queue_) << "Open() has not been called successfully"; | 538 DLOG_IF(ERROR, !audio_queue_) << "Open() has not been called successfully"; |
| 505 if (!audio_queue_) | 539 if (!audio_queue_) |
| 506 return; | 540 return; |
| 507 | 541 |
| 508 OSStatus err = noErr; | 542 OSStatus err = noErr; |
| 509 SetSource(callback); | 543 SetSource(callback); |
| 510 pending_bytes_ = 0; | 544 pending_bytes_ = 0; |
| 511 stopped_event_.Reset(); | 545 stopped_event_.Reset(); |
| 512 num_buffers_left_ = kNumBuffers; | 546 stop_requested_ = false; |
| 513 // Ask the source to pre-fill all our buffers before playing. | 547 // Ask the source to pre-fill all our buffers before playing. |
| 514 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { | 548 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { |
| 515 buffer_[ix]->mAudioDataByteSize = 0; | 549 buffer_[ix]->mAudioDataByteSize = 0; |
| 516 // Caller waits for 1st packet to become available, but not for others, | 550 // Caller waits for 1st packet to become available, but not for others, |
| 517 // so we wait for them here. | 551 // so we wait for them here. |
| 518 if (ix != 0) { | 552 if (ix != 0) { |
| 519 AudioSourceCallback* source = GetSource(); | 553 AudioSourceCallback* source = GetSource(); |
| 520 if (source) | 554 if (source) |
| 521 source->WaitTillDataReady(); | 555 source->WaitTillDataReady(); |
| 522 } | 556 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 543 source_ = source; | 577 source_ = source; |
| 544 } | 578 } |
| 545 | 579 |
| 546 AudioOutputStream::AudioSourceCallback* | 580 AudioOutputStream::AudioSourceCallback* |
| 547 PCMQueueOutAudioOutputStream::GetSource() { | 581 PCMQueueOutAudioOutputStream::GetSource() { |
| 548 base::AutoLock lock(source_lock_); | 582 base::AutoLock lock(source_lock_); |
| 549 return source_; | 583 return source_; |
| 550 } | 584 } |
| 551 | 585 |
| 552 } // namespace media | 586 } // namespace media |
| OLD | NEW |