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_manager_mac.h" | 5 #include "media/audio/mac/audio_manager_mac.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 | 363 |
| 364 DISALLOW_COPY_AND_ASSIGN(AudioPowerObserver); | 364 DISALLOW_COPY_AND_ASSIGN(AudioPowerObserver); |
| 365 }; | 365 }; |
| 366 | 366 |
| 367 AudioManagerMac::AudioManagerMac(AudioLogFactory* audio_log_factory) | 367 AudioManagerMac::AudioManagerMac(AudioLogFactory* audio_log_factory) |
| 368 : AudioManagerBase(audio_log_factory), | 368 : AudioManagerBase(audio_log_factory), |
| 369 current_sample_rate_(0), | 369 current_sample_rate_(0), |
| 370 current_output_device_(kAudioDeviceUnknown) { | 370 current_output_device_(kAudioDeviceUnknown) { |
| 371 SetMaxOutputStreamsAllowed(kMaxOutputStreams); | 371 SetMaxOutputStreamsAllowed(kMaxOutputStreams); |
| 372 | 372 |
| 373 // CoreAudio calls must occur on the main thread of the process, which in our | |
| 374 // case is sadly the browser UI thread. Failure to execute calls on the right | |
| 375 // thread leads to crashes and odd behavior. See http://crbug.com/158170. | |
| 376 // TODO(dalecurtis): We should require the message loop to be passed in. | |
| 377 CHECK(base::MessageLoopForUI::IsCurrent()); | |
| 378 task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
| 379 | |
| 373 // Task must be posted last to avoid races from handing out "this" to the | 380 // Task must be posted last to avoid races from handing out "this" to the |
| 374 // audio thread. Always PostTask even if we're on the right thread since | 381 // audio thread. Always PostTask even if we're on the right thread since |
| 375 // AudioManager creation is on the startup path and this may be slow. | 382 // AudioManager creation is on the startup path and this may be slow. |
| 376 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( | 383 task_runner_->PostTask(FROM_HERE, |
| 377 &AudioManagerMac::InitializeOnAudioThread, base::Unretained(this))); | 384 base::Bind(&AudioManagerMac::InitializeOnAudioThread, |
| 385 base::Unretained(this))); | |
| 378 } | 386 } |
| 379 | 387 |
| 380 AudioManagerMac::~AudioManagerMac() { | 388 AudioManagerMac::~AudioManagerMac() { |
| 381 if (GetTaskRunner()->BelongsToCurrentThread()) { | 389 if (GetTaskRunner()->BelongsToCurrentThread()) { |
| 382 ShutdownOnAudioThread(); | 390 ShutdownOnAudioThread(); |
| 383 } else { | 391 } else { |
| 384 // It's safe to post a task here since Shutdown() will wait for all tasks to | 392 // It's safe to post a task here since Shutdown() will wait for all tasks to |
| 385 // complete before returning. | 393 // complete before returning. |
| 386 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( | 394 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( |
| 387 &AudioManagerMac::ShutdownOnAudioThread, base::Unretained(this))); | 395 &AudioManagerMac::ShutdownOnAudioThread, base::Unretained(this))); |
| 388 } | 396 } |
| 389 | 397 |
| 390 Shutdown(); | 398 Shutdown(); |
| 391 } | 399 } |
| 392 | 400 |
| 401 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerMac::GetTaskRunner() { | |
| 402 return task_runner_; | |
| 403 } | |
| 404 | |
| 405 scoped_refptr<base::SingleThreadTaskRunner> | |
| 406 AudioManagerMac::GetWorkerTaskRunner() { | |
| 407 if (!worker_thread_) { | |
| 408 worker_thread_.reset(new base::Thread("AudioWorkerThread")); | |
| 409 CHECK(worker_thread_->Start()); | |
| 410 } | |
| 411 return worker_thread_->task_runner(); | |
| 412 } | |
| 413 | |
| 393 bool AudioManagerMac::HasAudioOutputDevices() { | 414 bool AudioManagerMac::HasAudioOutputDevices() { |
| 394 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); | 415 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); |
| 395 } | 416 } |
| 396 | 417 |
| 397 bool AudioManagerMac::HasAudioInputDevices() { | 418 bool AudioManagerMac::HasAudioInputDevices() { |
| 398 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 419 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); |
| 399 } | 420 } |
| 400 | 421 |
| 401 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, | 422 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, |
| 402 AudioObjectPropertyScope scope, | 423 AudioObjectPropertyScope scope, |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 const int buffer_size = ChooseBufferSize(true, sample_rate); | 538 const int buffer_size = ChooseBufferSize(true, sample_rate); |
| 518 | 539 |
| 519 // TODO(xians): query the native channel layout for the specific device. | 540 // TODO(xians): query the native channel layout for the specific device. |
| 520 return AudioParameters( | 541 return AudioParameters( |
| 521 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 542 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
| 522 sample_rate, 16, buffer_size); | 543 sample_rate, 16, buffer_size); |
| 523 } | 544 } |
| 524 | 545 |
| 525 std::string AudioManagerMac::GetAssociatedOutputDeviceID( | 546 std::string AudioManagerMac::GetAssociatedOutputDeviceID( |
| 526 const std::string& input_device_id) { | 547 const std::string& input_device_id) { |
| 527 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 548 DCHECK(task_runner_->BelongsToCurrentThread()); |
|
DaleCurtis
2016/03/14 21:46:09
Why this change? Seems better to use the GetTaskRu
alokp
2016/03/14 22:07:17
reverted in the new patch.
| |
| 528 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); | 549 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); |
| 529 if (device == kAudioObjectUnknown) | 550 if (device == kAudioObjectUnknown) |
| 530 return std::string(); | 551 return std::string(); |
| 531 | 552 |
| 532 UInt32 size = 0; | 553 UInt32 size = 0; |
| 533 AudioObjectPropertyAddress pa = { | 554 AudioObjectPropertyAddress pa = { |
| 534 kAudioDevicePropertyRelatedDevices, | 555 kAudioDevicePropertyRelatedDevices, |
| 535 kAudioDevicePropertyScopeOutput, | 556 kAudioDevicePropertyScopeOutput, |
| 536 kAudioObjectPropertyElementMaster | 557 kAudioObjectPropertyElementMaster |
| 537 }; | 558 }; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 632 // rates on OSX. | 653 // rates on OSX. |
| 633 current_sample_rate_ = params.sample_rate(); | 654 current_sample_rate_ = params.sample_rate(); |
| 634 } | 655 } |
| 635 | 656 |
| 636 AUHALStream* stream = new AUHALStream(this, params, device); | 657 AUHALStream* stream = new AUHALStream(this, params, device); |
| 637 output_streams_.push_back(stream); | 658 output_streams_.push_back(stream); |
| 638 return stream; | 659 return stream; |
| 639 } | 660 } |
| 640 | 661 |
| 641 std::string AudioManagerMac::GetDefaultOutputDeviceID() { | 662 std::string AudioManagerMac::GetDefaultOutputDeviceID() { |
| 642 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 663 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 643 AudioDeviceID device_id = kAudioObjectUnknown; | 664 AudioDeviceID device_id = kAudioObjectUnknown; |
| 644 if (!GetDefaultOutputDevice(&device_id)) | 665 if (!GetDefaultOutputDevice(&device_id)) |
| 645 return std::string(); | 666 return std::string(); |
| 646 | 667 |
| 647 const AudioObjectPropertyAddress property_address = { | 668 const AudioObjectPropertyAddress property_address = { |
| 648 kAudioDevicePropertyDeviceUID, | 669 kAudioDevicePropertyDeviceUID, |
| 649 kAudioObjectPropertyScopeGlobal, | 670 kAudioObjectPropertyScopeGlobal, |
| 650 kAudioObjectPropertyElementMaster | 671 kAudioObjectPropertyElementMaster |
| 651 }; | 672 }; |
| 652 CFStringRef device_uid = NULL; | 673 CFStringRef device_uid = NULL; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 731 channel_layout = CHANNEL_LAYOUT_DISCRETE; | 752 channel_layout = CHANNEL_LAYOUT_DISCRETE; |
| 732 } | 753 } |
| 733 | 754 |
| 734 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 755 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
| 735 hardware_sample_rate, 16, buffer_size); | 756 hardware_sample_rate, 16, buffer_size); |
| 736 params.set_channels_for_discrete(output_channels); | 757 params.set_channels_for_discrete(output_channels); |
| 737 return params; | 758 return params; |
| 738 } | 759 } |
| 739 | 760 |
| 740 void AudioManagerMac::InitializeOnAudioThread() { | 761 void AudioManagerMac::InitializeOnAudioThread() { |
| 741 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 762 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 742 power_observer_.reset(new AudioPowerObserver()); | 763 power_observer_.reset(new AudioPowerObserver()); |
| 743 } | 764 } |
| 744 | 765 |
| 745 void AudioManagerMac::ShutdownOnAudioThread() { | 766 void AudioManagerMac::ShutdownOnAudioThread() { |
| 746 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 767 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 747 output_device_listener_.reset(); | 768 output_device_listener_.reset(); |
| 748 power_observer_.reset(); | 769 power_observer_.reset(); |
| 749 | 770 |
| 750 // Since CoreAudio calls have to run on the UI thread and browser shutdown | 771 // Since CoreAudio calls have to run on the UI thread and browser shutdown |
| 751 // doesn't wait for outstanding tasks to complete, we may have input/output | 772 // doesn't wait for outstanding tasks to complete, we may have input/output |
| 752 // streams still running at shutdown. | 773 // streams still running at shutdown. |
| 753 // | 774 // |
| 754 // To avoid calls into destructed classes, we need to stop the OS callbacks | 775 // To avoid calls into destructed classes, we need to stop the OS callbacks |
| 755 // by stopping the streams. Note: The streams are leaked since process | 776 // by stopping the streams. Note: The streams are leaked since process |
| 756 // destruction is imminent. | 777 // destruction is imminent. |
| 757 // | 778 // |
| 758 // See http://crbug.com/354139 for crash details. | 779 // See http://crbug.com/354139 for crash details. |
| 759 StopStreams(&basic_input_streams_); | 780 StopStreams(&basic_input_streams_); |
| 760 StopStreams(&low_latency_input_streams_); | 781 StopStreams(&low_latency_input_streams_); |
| 761 StopStreams(&output_streams_); | 782 StopStreams(&output_streams_); |
| 762 } | 783 } |
| 763 | 784 |
| 764 void AudioManagerMac::HandleDeviceChanges() { | 785 void AudioManagerMac::HandleDeviceChanges() { |
| 765 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 786 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 766 const int new_sample_rate = HardwareSampleRate(); | 787 const int new_sample_rate = HardwareSampleRate(); |
| 767 AudioDeviceID new_output_device; | 788 AudioDeviceID new_output_device; |
| 768 GetDefaultOutputDevice(&new_output_device); | 789 GetDefaultOutputDevice(&new_output_device); |
| 769 | 790 |
| 770 if (current_sample_rate_ == new_sample_rate && | 791 if (current_sample_rate_ == new_sample_rate && |
| 771 current_output_device_ == new_output_device) { | 792 current_output_device_ == new_output_device) { |
| 772 return; | 793 return; |
| 773 } | 794 } |
| 774 | 795 |
| 775 current_sample_rate_ = new_sample_rate; | 796 current_sample_rate_ = new_sample_rate; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 797 if (sample_rate <= 96000) | 818 if (sample_rate <= 96000) |
| 798 buffer_size = 2 * kMinimumInputOutputBufferSize; | 819 buffer_size = 2 * kMinimumInputOutputBufferSize; |
| 799 else if (sample_rate <= 192000) | 820 else if (sample_rate <= 192000) |
| 800 buffer_size = 4 * kMinimumInputOutputBufferSize; | 821 buffer_size = 4 * kMinimumInputOutputBufferSize; |
| 801 } | 822 } |
| 802 | 823 |
| 803 return buffer_size; | 824 return buffer_size; |
| 804 } | 825 } |
| 805 | 826 |
| 806 bool AudioManagerMac::ShouldDeferStreamStart() const { | 827 bool AudioManagerMac::ShouldDeferStreamStart() const { |
| 807 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 828 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 808 return power_observer_->ShouldDeferStreamStart(); | 829 return power_observer_->ShouldDeferStreamStart(); |
| 809 } | 830 } |
| 810 | 831 |
| 811 bool AudioManagerMac::IsOnBatteryPower() const { | 832 bool AudioManagerMac::IsOnBatteryPower() const { |
| 812 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 833 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 813 return power_observer_->IsOnBatteryPower(); | 834 return power_observer_->IsOnBatteryPower(); |
| 814 } | 835 } |
| 815 | 836 |
| 816 size_t AudioManagerMac::GetNumberOfResumeNotifications() const { | 837 size_t AudioManagerMac::GetNumberOfResumeNotifications() const { |
| 817 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 838 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 818 return power_observer_->num_resume_notifications(); | 839 return power_observer_->num_resume_notifications(); |
| 819 } | 840 } |
| 820 | 841 |
| 821 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, | 842 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, |
| 822 AudioUnit audio_unit, | 843 AudioUnit audio_unit, |
| 823 AudioUnitElement element, | 844 AudioUnitElement element, |
| 824 size_t desired_buffer_size, | 845 size_t desired_buffer_size, |
| 825 bool* size_was_changed, | 846 bool* size_was_changed, |
| 826 size_t* io_buffer_frame_size) { | 847 size_t* io_buffer_frame_size) { |
| 827 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 848 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 828 const bool is_input = (element == 1); | 849 const bool is_input = (element == 1); |
| 829 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id | 850 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id |
| 830 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec | 851 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec |
| 831 << desired_buffer_size << ")"; | 852 << desired_buffer_size << ")"; |
| 832 | 853 |
| 833 *size_was_changed = false; | 854 *size_was_changed = false; |
| 834 *io_buffer_frame_size = 0; | 855 *io_buffer_frame_size = 0; |
| 835 | 856 |
| 836 // Log the device name (and id) for debugging purposes. | 857 // Log the device name (and id) for debugging purposes. |
| 837 std::string device_name = GetAudioDeviceNameFromDeviceId(device_id, is_input); | 858 std::string device_name = GetAudioDeviceNameFromDeviceId(device_id, is_input); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 942 basic_input_streams_.erase(stream_it); | 963 basic_input_streams_.erase(stream_it); |
| 943 | 964 |
| 944 AudioManagerBase::ReleaseInputStream(stream); | 965 AudioManagerBase::ReleaseInputStream(stream); |
| 945 } | 966 } |
| 946 | 967 |
| 947 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { | 968 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { |
| 948 return new AudioManagerMac(audio_log_factory); | 969 return new AudioManagerMac(audio_log_factory); |
| 949 } | 970 } |
| 950 | 971 |
| 951 } // namespace media | 972 } // namespace media |
| OLD | NEW |