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 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 | 358 |
| 359 bool is_suspending_; | 359 bool is_suspending_; |
| 360 const bool is_monitoring_; | 360 const bool is_monitoring_; |
| 361 base::TimeTicks earliest_start_time_; | 361 base::TimeTicks earliest_start_time_; |
| 362 base::ThreadChecker thread_checker_; | 362 base::ThreadChecker thread_checker_; |
| 363 size_t num_resume_notifications_; | 363 size_t num_resume_notifications_; |
| 364 | 364 |
| 365 DISALLOW_COPY_AND_ASSIGN(AudioPowerObserver); | 365 DISALLOW_COPY_AND_ASSIGN(AudioPowerObserver); |
| 366 }; | 366 }; |
| 367 | 367 |
| 368 AudioManagerMac::AudioManagerMac(AudioLogFactory* audio_log_factory) | 368 AudioManagerMac::AudioManagerMac( |
| 369 : AudioManagerBase(audio_log_factory), | 369 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 370 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, | |
| 371 AudioLogFactory* audio_log_factory) | |
| 372 : AudioManagerBase(std::move(task_runner), | |
| 373 std::move(worker_task_runner), | |
| 374 audio_log_factory), | |
| 370 current_sample_rate_(0), | 375 current_sample_rate_(0), |
| 371 current_output_device_(kAudioDeviceUnknown) { | 376 current_output_device_(kAudioDeviceUnknown) { |
| 372 SetMaxOutputStreamsAllowed(kMaxOutputStreams); | 377 SetMaxOutputStreamsAllowed(kMaxOutputStreams); |
| 373 | 378 |
| 374 // CoreAudio calls must occur on the main thread of the process, which in our | |
| 375 // case is sadly the browser UI thread. Failure to execute calls on the right | |
| 376 // thread leads to crashes and odd behavior. See http://crbug.com/158170. | |
| 377 // TODO(dalecurtis): We should require the message loop to be passed in. | |
| 378 task_runner_ = base::MessageLoopForUI::IsCurrent() | |
| 379 ? base::ThreadTaskRunnerHandle::Get() | |
| 380 : AudioManagerBase::GetTaskRunner(); | |
| 381 | |
| 382 // Task must be posted last to avoid races from handing out "this" to the | 379 // Task must be posted last to avoid races from handing out "this" to the |
| 383 // audio thread. Always PostTask even if we're on the right thread since | 380 // audio thread. Always PostTask even if we're on the right thread since |
| 384 // AudioManager creation is on the startup path and this may be slow. | 381 // AudioManager creation is on the startup path and this may be slow. |
| 385 task_runner_->PostTask(FROM_HERE, | 382 GetTaskRunner()->PostTask( |
| 386 base::Bind(&AudioManagerMac::InitializeOnAudioThread, | 383 FROM_HERE, base::Bind(&AudioManagerMac::InitializeOnAudioThread, |
| 387 base::Unretained(this))); | 384 base::Unretained(this))); |
| 388 } | 385 } |
| 389 | 386 |
| 390 AudioManagerMac::~AudioManagerMac() { | 387 AudioManagerMac::~AudioManagerMac() { |
| 391 if (task_runner_->BelongsToCurrentThread()) { | 388 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 392 ShutdownOnAudioThread(); | |
| 393 } else { | |
| 394 // It's safe to post a task here since Shutdown() will wait for all tasks to | |
| 395 // complete before returning. | |
| 396 task_runner_->PostTask(FROM_HERE, | |
| 397 base::Bind(&AudioManagerMac::ShutdownOnAudioThread, | |
| 398 base::Unretained(this))); | |
| 399 } | |
| 400 | 389 |
| 401 Shutdown(); | 390 Shutdown(); |
| 402 } | 391 ShutdownOnAudioThread(); |
|
DaleCurtis
2016/04/05 21:55:36
Ditto. Also these methods are confusing now. Maybe
| |
| 403 | |
| 404 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerMac::GetTaskRunner() { | |
| 405 return task_runner_; | |
| 406 } | |
| 407 | |
| 408 scoped_refptr<base::SingleThreadTaskRunner> | |
| 409 AudioManagerMac::GetWorkerTaskRunner() { | |
| 410 if (!worker_thread_) { | |
| 411 worker_thread_.reset(new base::Thread("AudioWorkerThread")); | |
| 412 CHECK(worker_thread_->Start()); | |
| 413 } | |
| 414 return worker_thread_->task_runner(); | |
| 415 } | 392 } |
| 416 | 393 |
| 417 bool AudioManagerMac::HasAudioOutputDevices() { | 394 bool AudioManagerMac::HasAudioOutputDevices() { |
| 418 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); | 395 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); |
| 419 } | 396 } |
| 420 | 397 |
| 421 bool AudioManagerMac::HasAudioInputDevices() { | 398 bool AudioManagerMac::HasAudioInputDevices() { |
| 422 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 399 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); |
| 423 } | 400 } |
| 424 | 401 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 const int buffer_size = ChooseBufferSize(true, sample_rate); | 521 const int buffer_size = ChooseBufferSize(true, sample_rate); |
| 545 | 522 |
| 546 // TODO(xians): query the native channel layout for the specific device. | 523 // TODO(xians): query the native channel layout for the specific device. |
| 547 return AudioParameters( | 524 return AudioParameters( |
| 548 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 525 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
| 549 sample_rate, 16, buffer_size); | 526 sample_rate, 16, buffer_size); |
| 550 } | 527 } |
| 551 | 528 |
| 552 std::string AudioManagerMac::GetAssociatedOutputDeviceID( | 529 std::string AudioManagerMac::GetAssociatedOutputDeviceID( |
| 553 const std::string& input_device_id) { | 530 const std::string& input_device_id) { |
| 554 DCHECK(task_runner_->BelongsToCurrentThread()); | 531 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 555 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); | 532 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); |
| 556 if (device == kAudioObjectUnknown) | 533 if (device == kAudioObjectUnknown) |
| 557 return std::string(); | 534 return std::string(); |
| 558 | 535 |
| 559 UInt32 size = 0; | 536 UInt32 size = 0; |
| 560 AudioObjectPropertyAddress pa = { | 537 AudioObjectPropertyAddress pa = { |
| 561 kAudioDevicePropertyRelatedDevices, | 538 kAudioDevicePropertyRelatedDevices, |
| 562 kAudioDevicePropertyScopeOutput, | 539 kAudioDevicePropertyScopeOutput, |
| 563 kAudioObjectPropertyElementMaster | 540 kAudioObjectPropertyElementMaster |
| 564 }; | 541 }; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 669 // rates on OSX. | 646 // rates on OSX. |
| 670 current_sample_rate_ = params.sample_rate(); | 647 current_sample_rate_ = params.sample_rate(); |
| 671 } | 648 } |
| 672 | 649 |
| 673 AUHALStream* stream = new AUHALStream(this, params, device); | 650 AUHALStream* stream = new AUHALStream(this, params, device); |
| 674 output_streams_.push_back(stream); | 651 output_streams_.push_back(stream); |
| 675 return stream; | 652 return stream; |
| 676 } | 653 } |
| 677 | 654 |
| 678 std::string AudioManagerMac::GetDefaultOutputDeviceID() { | 655 std::string AudioManagerMac::GetDefaultOutputDeviceID() { |
| 679 DCHECK(task_runner_->BelongsToCurrentThread()); | 656 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 680 AudioDeviceID device_id = kAudioObjectUnknown; | 657 AudioDeviceID device_id = kAudioObjectUnknown; |
| 681 if (!GetDefaultOutputDevice(&device_id)) | 658 if (!GetDefaultOutputDevice(&device_id)) |
| 682 return std::string(); | 659 return std::string(); |
| 683 | 660 |
| 684 const AudioObjectPropertyAddress property_address = { | 661 const AudioObjectPropertyAddress property_address = { |
| 685 kAudioDevicePropertyDeviceUID, | 662 kAudioDevicePropertyDeviceUID, |
| 686 kAudioObjectPropertyScopeGlobal, | 663 kAudioObjectPropertyScopeGlobal, |
| 687 kAudioObjectPropertyElementMaster | 664 kAudioObjectPropertyElementMaster |
| 688 }; | 665 }; |
| 689 CFStringRef device_uid = NULL; | 666 CFStringRef device_uid = NULL; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 768 channel_layout = CHANNEL_LAYOUT_DISCRETE; | 745 channel_layout = CHANNEL_LAYOUT_DISCRETE; |
| 769 } | 746 } |
| 770 | 747 |
| 771 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 748 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
| 772 hardware_sample_rate, 16, buffer_size); | 749 hardware_sample_rate, 16, buffer_size); |
| 773 params.set_channels_for_discrete(output_channels); | 750 params.set_channels_for_discrete(output_channels); |
| 774 return params; | 751 return params; |
| 775 } | 752 } |
| 776 | 753 |
| 777 void AudioManagerMac::InitializeOnAudioThread() { | 754 void AudioManagerMac::InitializeOnAudioThread() { |
| 778 DCHECK(task_runner_->BelongsToCurrentThread()); | 755 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 779 power_observer_.reset(new AudioPowerObserver()); | 756 power_observer_.reset(new AudioPowerObserver()); |
| 780 } | 757 } |
| 781 | 758 |
| 782 void AudioManagerMac::ShutdownOnAudioThread() { | 759 void AudioManagerMac::ShutdownOnAudioThread() { |
| 783 DCHECK(task_runner_->BelongsToCurrentThread()); | 760 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 784 output_device_listener_.reset(); | 761 output_device_listener_.reset(); |
| 785 power_observer_.reset(); | 762 power_observer_.reset(); |
| 786 | 763 |
| 787 // Since CoreAudio calls have to run on the UI thread and browser shutdown | 764 // Since CoreAudio calls have to run on the UI thread and browser shutdown |
| 788 // doesn't wait for outstanding tasks to complete, we may have input/output | 765 // doesn't wait for outstanding tasks to complete, we may have input/output |
| 789 // streams still running at shutdown. | 766 // streams still running at shutdown. |
| 790 // | 767 // |
| 791 // To avoid calls into destructed classes, we need to stop the OS callbacks | 768 // To avoid calls into destructed classes, we need to stop the OS callbacks |
| 792 // by stopping the streams. Note: The streams are leaked since process | 769 // by stopping the streams. Note: The streams are leaked since process |
| 793 // destruction is imminent. | 770 // destruction is imminent. |
| 794 // | 771 // |
| 795 // See http://crbug.com/354139 for crash details. | 772 // See http://crbug.com/354139 for crash details. |
| 796 StopStreams(&basic_input_streams_); | 773 StopStreams(&basic_input_streams_); |
| 797 StopStreams(&low_latency_input_streams_); | 774 StopStreams(&low_latency_input_streams_); |
| 798 StopStreams(&output_streams_); | 775 StopStreams(&output_streams_); |
| 799 } | 776 } |
| 800 | 777 |
| 801 void AudioManagerMac::HandleDeviceChanges() { | 778 void AudioManagerMac::HandleDeviceChanges() { |
| 802 DCHECK(task_runner_->BelongsToCurrentThread()); | 779 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 803 const int new_sample_rate = HardwareSampleRate(); | 780 const int new_sample_rate = HardwareSampleRate(); |
| 804 AudioDeviceID new_output_device; | 781 AudioDeviceID new_output_device; |
| 805 GetDefaultOutputDevice(&new_output_device); | 782 GetDefaultOutputDevice(&new_output_device); |
| 806 | 783 |
| 807 if (current_sample_rate_ == new_sample_rate && | 784 if (current_sample_rate_ == new_sample_rate && |
| 808 current_output_device_ == new_output_device) { | 785 current_output_device_ == new_output_device) { |
| 809 return; | 786 return; |
| 810 } | 787 } |
| 811 | 788 |
| 812 current_sample_rate_ = new_sample_rate; | 789 current_sample_rate_ = new_sample_rate; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 834 if (sample_rate <= 96000) | 811 if (sample_rate <= 96000) |
| 835 buffer_size = 2 * kMinimumInputOutputBufferSize; | 812 buffer_size = 2 * kMinimumInputOutputBufferSize; |
| 836 else if (sample_rate <= 192000) | 813 else if (sample_rate <= 192000) |
| 837 buffer_size = 4 * kMinimumInputOutputBufferSize; | 814 buffer_size = 4 * kMinimumInputOutputBufferSize; |
| 838 } | 815 } |
| 839 | 816 |
| 840 return buffer_size; | 817 return buffer_size; |
| 841 } | 818 } |
| 842 | 819 |
| 843 bool AudioManagerMac::ShouldDeferStreamStart() const { | 820 bool AudioManagerMac::ShouldDeferStreamStart() const { |
| 844 DCHECK(task_runner_->BelongsToCurrentThread()); | 821 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 845 return power_observer_->ShouldDeferStreamStart(); | 822 return power_observer_->ShouldDeferStreamStart(); |
| 846 } | 823 } |
| 847 | 824 |
| 848 bool AudioManagerMac::IsOnBatteryPower() const { | 825 bool AudioManagerMac::IsOnBatteryPower() const { |
| 849 DCHECK(task_runner_->BelongsToCurrentThread()); | 826 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 850 return power_observer_->IsOnBatteryPower(); | 827 return power_observer_->IsOnBatteryPower(); |
| 851 } | 828 } |
| 852 | 829 |
| 853 size_t AudioManagerMac::GetNumberOfResumeNotifications() const { | 830 size_t AudioManagerMac::GetNumberOfResumeNotifications() const { |
| 854 DCHECK(task_runner_->BelongsToCurrentThread()); | 831 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 855 return power_observer_->num_resume_notifications(); | 832 return power_observer_->num_resume_notifications(); |
| 856 } | 833 } |
| 857 | 834 |
| 858 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, | 835 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, |
| 859 AudioUnit audio_unit, | 836 AudioUnit audio_unit, |
| 860 AudioUnitElement element, | 837 AudioUnitElement element, |
| 861 size_t desired_buffer_size, | 838 size_t desired_buffer_size, |
| 862 bool* size_was_changed, | 839 bool* size_was_changed, |
| 863 size_t* io_buffer_frame_size) { | 840 size_t* io_buffer_frame_size) { |
| 864 DCHECK(task_runner_->BelongsToCurrentThread()); | 841 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 865 const bool is_input = (element == 1); | 842 const bool is_input = (element == 1); |
| 866 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id | 843 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id |
| 867 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec | 844 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec |
| 868 << desired_buffer_size << ")"; | 845 << desired_buffer_size << ")"; |
| 869 | 846 |
| 870 *size_was_changed = false; | 847 *size_was_changed = false; |
| 871 *io_buffer_frame_size = 0; | 848 *io_buffer_frame_size = 0; |
| 872 | 849 |
| 873 // Log the device name (and id) for debugging purposes. | 850 // Log the device name (and id) for debugging purposes. |
| 874 std::string device_name = GetAudioDeviceNameFromDeviceId(device_id, is_input); | 851 std::string device_name = GetAudioDeviceNameFromDeviceId(device_id, is_input); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 974 basic_input_streams_.end(), | 951 basic_input_streams_.end(), |
| 975 stream); | 952 stream); |
| 976 if (stream_it == basic_input_streams_.end()) | 953 if (stream_it == basic_input_streams_.end()) |
| 977 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); | 954 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); |
| 978 else | 955 else |
| 979 basic_input_streams_.erase(stream_it); | 956 basic_input_streams_.erase(stream_it); |
| 980 | 957 |
| 981 AudioManagerBase::ReleaseInputStream(stream); | 958 AudioManagerBase::ReleaseInputStream(stream); |
| 982 } | 959 } |
| 983 | 960 |
| 984 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { | 961 ScopedAudioManagerPtr CreateAudioManager( |
| 985 return new AudioManagerMac(audio_log_factory); | 962 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 963 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, | |
| 964 AudioLogFactory* audio_log_factory) { | |
| 965 return ScopedAudioManagerPtr( | |
| 966 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), | |
| 967 audio_log_factory)); | |
| 986 } | 968 } |
| 987 | 969 |
| 988 } // namespace media | 970 } // namespace media |
| OLD | NEW |