| 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 stop_requested_(false) { | 63 num_buffers_left_(kNumBuffers) { |
| 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 | |
| 413 // Note to future hackers of this function: Do not add locks to this function | 382 // Note to future hackers of this function: Do not add locks to this function |
| 414 // that are held through any calls made back into AudioQueue APIs, or other | 383 // that are held through any calls made back into AudioQueue APIs, or other |
| 415 // OS audio functions. This is because the OS dispatch may grab external | 384 // OS audio functions. This is because the OS dispatch may grab external |
| 416 // locks, or possibly re-enter this function which can lead to a deadlock. | 385 // locks, or possibly re-enter this function which can lead to a deadlock. |
| 417 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, | 386 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, |
| 418 AudioQueueRef queue, | 387 AudioQueueRef queue, |
| 419 AudioQueueBufferRef buffer) { | 388 AudioQueueBufferRef buffer) { |
| 420 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); | 389 TRACE_EVENT0("audio", "PCMQueueOutAudioOutputStream::RenderCallback"); |
| 421 | 390 |
| 422 PCMQueueOutAudioOutputStream* audio_stream = | 391 PCMQueueOutAudioOutputStream* audio_stream = |
| 423 static_cast<PCMQueueOutAudioOutputStream*>(p_this); | 392 static_cast<PCMQueueOutAudioOutputStream*>(p_this); |
| 424 | 393 |
| 425 // Call the audio source to fill the free buffer with data. Not having a | 394 // Call the audio source to fill the free buffer with data. Not having a |
| 426 // source means that the queue has been stopped. | 395 // source means that the queue has been stopped. |
| 427 AudioSourceCallback* source = audio_stream->GetSource(); | 396 AudioSourceCallback* source = audio_stream->GetSource(); |
| 428 if (!source) { | 397 if (!source) { |
| 429 // PCMQueueOutAudioOutputStream::Stop() is waiting for callback to | 398 // PCMQueueOutAudioOutputStream::Stop() is waiting for callback to |
| 430 // stop the stream and signal when all activity ceased (we probably | 399 // stop the stream and signal when all callbacks are done. |
| 431 // can stop the stream there, but it is better to have all the | 400 // (we probably can stop the stream there, but it is better to have |
| 432 // complex logic in one place; stopping latency is not very important | 401 // all the complex logic in one place; stopping latency is not very |
| 433 // if you reuse audio stream in the mixer and not close it immediately). | 402 // important if you reuse audio stream in the mixer and not close it |
| 434 if (!audio_stream->stop_requested_) { | 403 // immediately). |
| 435 audio_stream->stop_requested_ = true; | 404 --audio_stream->num_buffers_left_; |
| 436 // Before actually stopping the stream, register callback that | 405 if (audio_stream->num_buffers_left_ == kNumBuffers - 1) { |
| 437 // OS would call when status of "is running" property changes. | 406 // First buffer after stop requested, stop the queue. |
| 438 // This way we (hopefully) would know when stream is actually | 407 OSStatus err = AudioQueueStop(audio_stream->audio_queue_, true); |
| 439 // stopped and it is safe to dispose it. | |
| 440 OSStatus err = AudioQueueAddPropertyListener( | |
| 441 queue, | |
| 442 kAudioQueueProperty_IsRunning, | |
| 443 PCMQueueOutAudioOutputStream::IsRunningCallback, | |
| 444 audio_stream); | |
| 445 if (err != noErr) | 408 if (err != noErr) |
| 446 audio_stream->HandleError(err); | 409 audio_stream->HandleError(err); |
| 447 // Now stop the queue. | 410 } |
| 448 err = AudioQueueStop(queue, true); | 411 if (audio_stream->num_buffers_left_ == 0) { |
| 449 if (err != noErr) | 412 // Now we finally saw all the buffers. |
| 450 audio_stream->HandleError(err); | 413 // Signal that stopping is complete. |
| 414 // Should never touch audio_stream after signaling as it |
| 415 // can be deleted at any moment. |
| 416 audio_stream->stopped_event_.Signal(); |
| 451 } | 417 } |
| 452 return; | 418 return; |
| 453 } | 419 } |
| 454 | 420 |
| 455 // Adjust the number of pending bytes by subtracting the amount played. | 421 // Adjust the number of pending bytes by subtracting the amount played. |
| 456 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) | 422 if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer) |
| 457 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; | 423 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; |
| 458 uint32 capacity = buffer->mAudioDataBytesCapacity; | 424 uint32 capacity = buffer->mAudioDataBytesCapacity; |
| 459 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. | 425 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. |
| 460 uint32 filled = source->OnMoreData( | 426 uint32 filled = source->OnMoreData( |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { | 502 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { |
| 537 DCHECK(callback); | 503 DCHECK(callback); |
| 538 DLOG_IF(ERROR, !audio_queue_) << "Open() has not been called successfully"; | 504 DLOG_IF(ERROR, !audio_queue_) << "Open() has not been called successfully"; |
| 539 if (!audio_queue_) | 505 if (!audio_queue_) |
| 540 return; | 506 return; |
| 541 | 507 |
| 542 OSStatus err = noErr; | 508 OSStatus err = noErr; |
| 543 SetSource(callback); | 509 SetSource(callback); |
| 544 pending_bytes_ = 0; | 510 pending_bytes_ = 0; |
| 545 stopped_event_.Reset(); | 511 stopped_event_.Reset(); |
| 546 stop_requested_ = false; | 512 num_buffers_left_ = kNumBuffers; |
| 547 // Ask the source to pre-fill all our buffers before playing. | 513 // Ask the source to pre-fill all our buffers before playing. |
| 548 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { | 514 for (uint32 ix = 0; ix != kNumBuffers; ++ix) { |
| 549 buffer_[ix]->mAudioDataByteSize = 0; | 515 buffer_[ix]->mAudioDataByteSize = 0; |
| 550 // Caller waits for 1st packet to become available, but not for others, | 516 // Caller waits for 1st packet to become available, but not for others, |
| 551 // so we wait for them here. | 517 // so we wait for them here. |
| 552 if (ix != 0) { | 518 if (ix != 0) { |
| 553 AudioSourceCallback* source = GetSource(); | 519 AudioSourceCallback* source = GetSource(); |
| 554 if (source) | 520 if (source) |
| 555 source->WaitTillDataReady(); | 521 source->WaitTillDataReady(); |
| 556 } | 522 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 577 source_ = source; | 543 source_ = source; |
| 578 } | 544 } |
| 579 | 545 |
| 580 AudioOutputStream::AudioSourceCallback* | 546 AudioOutputStream::AudioSourceCallback* |
| 581 PCMQueueOutAudioOutputStream::GetSource() { | 547 PCMQueueOutAudioOutputStream::GetSource() { |
| 582 base::AutoLock lock(source_lock_); | 548 base::AutoLock lock(source_lock_); |
| 583 return source_; | 549 return source_; |
| 584 } | 550 } |
| 585 | 551 |
| 586 } // namespace media | 552 } // namespace media |
| OLD | NEW |