| 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(); | 389 output_device_listener_.reset(); |
| 393 } else { | 390 power_observer_.reset(); |
| 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 | 391 |
| 401 Shutdown(); | 392 // Since CoreAudio calls have to run on the UI thread and browser shutdown |
| 402 } | 393 // doesn't wait for outstanding tasks to complete, we may have input/output |
| 403 | 394 // streams still running at shutdown. |
| 404 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerMac::GetTaskRunner() { | 395 // |
| 405 return task_runner_; | 396 // To avoid calls into destructed classes, we need to stop the OS callbacks |
| 406 } | 397 // by stopping the streams. Note: The streams are leaked since process |
| 407 | 398 // destruction is imminent. |
| 408 scoped_refptr<base::SingleThreadTaskRunner> | 399 // |
| 409 AudioManagerMac::GetWorkerTaskRunner() { | 400 // See http://crbug.com/354139 for crash details. |
| 410 if (!worker_thread_) { | 401 StopStreams(&basic_input_streams_); |
| 411 worker_thread_.reset(new base::Thread("AudioWorkerThread")); | 402 StopStreams(&low_latency_input_streams_); |
| 412 CHECK(worker_thread_->Start()); | 403 StopStreams(&output_streams_); |
| 413 } | |
| 414 return worker_thread_->task_runner(); | |
| 415 } | 404 } |
| 416 | 405 |
| 417 bool AudioManagerMac::HasAudioOutputDevices() { | 406 bool AudioManagerMac::HasAudioOutputDevices() { |
| 418 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); | 407 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); |
| 419 } | 408 } |
| 420 | 409 |
| 421 bool AudioManagerMac::HasAudioInputDevices() { | 410 bool AudioManagerMac::HasAudioInputDevices() { |
| 422 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 411 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); |
| 423 } | 412 } |
| 424 | 413 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 const int buffer_size = ChooseBufferSize(true, sample_rate); | 533 const int buffer_size = ChooseBufferSize(true, sample_rate); |
| 545 | 534 |
| 546 // TODO(xians): query the native channel layout for the specific device. | 535 // TODO(xians): query the native channel layout for the specific device. |
| 547 return AudioParameters( | 536 return AudioParameters( |
| 548 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 537 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
| 549 sample_rate, 16, buffer_size); | 538 sample_rate, 16, buffer_size); |
| 550 } | 539 } |
| 551 | 540 |
| 552 std::string AudioManagerMac::GetAssociatedOutputDeviceID( | 541 std::string AudioManagerMac::GetAssociatedOutputDeviceID( |
| 553 const std::string& input_device_id) { | 542 const std::string& input_device_id) { |
| 554 DCHECK(task_runner_->BelongsToCurrentThread()); | 543 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 555 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); | 544 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); |
| 556 if (device == kAudioObjectUnknown) | 545 if (device == kAudioObjectUnknown) |
| 557 return std::string(); | 546 return std::string(); |
| 558 | 547 |
| 559 UInt32 size = 0; | 548 UInt32 size = 0; |
| 560 AudioObjectPropertyAddress pa = { | 549 AudioObjectPropertyAddress pa = { |
| 561 kAudioDevicePropertyRelatedDevices, | 550 kAudioDevicePropertyRelatedDevices, |
| 562 kAudioDevicePropertyScopeOutput, | 551 kAudioDevicePropertyScopeOutput, |
| 563 kAudioObjectPropertyElementMaster | 552 kAudioObjectPropertyElementMaster |
| 564 }; | 553 }; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 // rates on OSX. | 658 // rates on OSX. |
| 670 current_sample_rate_ = params.sample_rate(); | 659 current_sample_rate_ = params.sample_rate(); |
| 671 } | 660 } |
| 672 | 661 |
| 673 AUHALStream* stream = new AUHALStream(this, params, device); | 662 AUHALStream* stream = new AUHALStream(this, params, device); |
| 674 output_streams_.push_back(stream); | 663 output_streams_.push_back(stream); |
| 675 return stream; | 664 return stream; |
| 676 } | 665 } |
| 677 | 666 |
| 678 std::string AudioManagerMac::GetDefaultOutputDeviceID() { | 667 std::string AudioManagerMac::GetDefaultOutputDeviceID() { |
| 679 DCHECK(task_runner_->BelongsToCurrentThread()); | 668 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 680 AudioDeviceID device_id = kAudioObjectUnknown; | 669 AudioDeviceID device_id = kAudioObjectUnknown; |
| 681 if (!GetDefaultOutputDevice(&device_id)) | 670 if (!GetDefaultOutputDevice(&device_id)) |
| 682 return std::string(); | 671 return std::string(); |
| 683 | 672 |
| 684 const AudioObjectPropertyAddress property_address = { | 673 const AudioObjectPropertyAddress property_address = { |
| 685 kAudioDevicePropertyDeviceUID, | 674 kAudioDevicePropertyDeviceUID, |
| 686 kAudioObjectPropertyScopeGlobal, | 675 kAudioObjectPropertyScopeGlobal, |
| 687 kAudioObjectPropertyElementMaster | 676 kAudioObjectPropertyElementMaster |
| 688 }; | 677 }; |
| 689 CFStringRef device_uid = NULL; | 678 CFStringRef device_uid = NULL; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 channel_layout = CHANNEL_LAYOUT_DISCRETE; | 757 channel_layout = CHANNEL_LAYOUT_DISCRETE; |
| 769 } | 758 } |
| 770 | 759 |
| 771 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 760 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
| 772 hardware_sample_rate, 16, buffer_size); | 761 hardware_sample_rate, 16, buffer_size); |
| 773 params.set_channels_for_discrete(output_channels); | 762 params.set_channels_for_discrete(output_channels); |
| 774 return params; | 763 return params; |
| 775 } | 764 } |
| 776 | 765 |
| 777 void AudioManagerMac::InitializeOnAudioThread() { | 766 void AudioManagerMac::InitializeOnAudioThread() { |
| 778 DCHECK(task_runner_->BelongsToCurrentThread()); | 767 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 779 power_observer_.reset(new AudioPowerObserver()); | 768 power_observer_.reset(new AudioPowerObserver()); |
| 780 } | 769 } |
| 781 | 770 |
| 782 void AudioManagerMac::ShutdownOnAudioThread() { | |
| 783 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 784 output_device_listener_.reset(); | |
| 785 power_observer_.reset(); | |
| 786 | |
| 787 // 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 | |
| 789 // streams still running at shutdown. | |
| 790 // | |
| 791 // 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 | |
| 793 // destruction is imminent. | |
| 794 // | |
| 795 // See http://crbug.com/354139 for crash details. | |
| 796 StopStreams(&basic_input_streams_); | |
| 797 StopStreams(&low_latency_input_streams_); | |
| 798 StopStreams(&output_streams_); | |
| 799 } | |
| 800 | |
| 801 void AudioManagerMac::HandleDeviceChanges() { | 771 void AudioManagerMac::HandleDeviceChanges() { |
| 802 DCHECK(task_runner_->BelongsToCurrentThread()); | 772 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 803 const int new_sample_rate = HardwareSampleRate(); | 773 const int new_sample_rate = HardwareSampleRate(); |
| 804 AudioDeviceID new_output_device; | 774 AudioDeviceID new_output_device; |
| 805 GetDefaultOutputDevice(&new_output_device); | 775 GetDefaultOutputDevice(&new_output_device); |
| 806 | 776 |
| 807 if (current_sample_rate_ == new_sample_rate && | 777 if (current_sample_rate_ == new_sample_rate && |
| 808 current_output_device_ == new_output_device) { | 778 current_output_device_ == new_output_device) { |
| 809 return; | 779 return; |
| 810 } | 780 } |
| 811 | 781 |
| 812 current_sample_rate_ = new_sample_rate; | 782 current_sample_rate_ = new_sample_rate; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 834 if (sample_rate <= 96000) | 804 if (sample_rate <= 96000) |
| 835 buffer_size = 2 * kMinimumInputOutputBufferSize; | 805 buffer_size = 2 * kMinimumInputOutputBufferSize; |
| 836 else if (sample_rate <= 192000) | 806 else if (sample_rate <= 192000) |
| 837 buffer_size = 4 * kMinimumInputOutputBufferSize; | 807 buffer_size = 4 * kMinimumInputOutputBufferSize; |
| 838 } | 808 } |
| 839 | 809 |
| 840 return buffer_size; | 810 return buffer_size; |
| 841 } | 811 } |
| 842 | 812 |
| 843 bool AudioManagerMac::ShouldDeferStreamStart() const { | 813 bool AudioManagerMac::ShouldDeferStreamStart() const { |
| 844 DCHECK(task_runner_->BelongsToCurrentThread()); | 814 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 845 return power_observer_->ShouldDeferStreamStart(); | 815 return power_observer_->ShouldDeferStreamStart(); |
| 846 } | 816 } |
| 847 | 817 |
| 848 bool AudioManagerMac::IsOnBatteryPower() const { | 818 bool AudioManagerMac::IsOnBatteryPower() const { |
| 849 DCHECK(task_runner_->BelongsToCurrentThread()); | 819 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 850 return power_observer_->IsOnBatteryPower(); | 820 return power_observer_->IsOnBatteryPower(); |
| 851 } | 821 } |
| 852 | 822 |
| 853 size_t AudioManagerMac::GetNumberOfResumeNotifications() const { | 823 size_t AudioManagerMac::GetNumberOfResumeNotifications() const { |
| 854 DCHECK(task_runner_->BelongsToCurrentThread()); | 824 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 855 return power_observer_->num_resume_notifications(); | 825 return power_observer_->num_resume_notifications(); |
| 856 } | 826 } |
| 857 | 827 |
| 858 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, | 828 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, |
| 859 AudioUnit audio_unit, | 829 AudioUnit audio_unit, |
| 860 AudioUnitElement element, | 830 AudioUnitElement element, |
| 861 size_t desired_buffer_size, | 831 size_t desired_buffer_size, |
| 862 bool* size_was_changed, | 832 bool* size_was_changed, |
| 863 size_t* io_buffer_frame_size) { | 833 size_t* io_buffer_frame_size) { |
| 864 DCHECK(task_runner_->BelongsToCurrentThread()); | 834 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 865 const bool is_input = (element == 1); | 835 const bool is_input = (element == 1); |
| 866 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id | 836 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id |
| 867 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec | 837 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec |
| 868 << desired_buffer_size << ")"; | 838 << desired_buffer_size << ")"; |
| 869 | 839 |
| 870 *size_was_changed = false; | 840 *size_was_changed = false; |
| 871 *io_buffer_frame_size = 0; | 841 *io_buffer_frame_size = 0; |
| 872 | 842 |
| 873 // Log the device name (and id) for debugging purposes. | 843 // Log the device name (and id) for debugging purposes. |
| 874 std::string device_name = GetAudioDeviceNameFromDeviceId(device_id, is_input); | 844 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(), | 944 basic_input_streams_.end(), |
| 975 stream); | 945 stream); |
| 976 if (stream_it == basic_input_streams_.end()) | 946 if (stream_it == basic_input_streams_.end()) |
| 977 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); | 947 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); |
| 978 else | 948 else |
| 979 basic_input_streams_.erase(stream_it); | 949 basic_input_streams_.erase(stream_it); |
| 980 | 950 |
| 981 AudioManagerBase::ReleaseInputStream(stream); | 951 AudioManagerBase::ReleaseInputStream(stream); |
| 982 } | 952 } |
| 983 | 953 |
| 984 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { | 954 ScopedAudioManagerPtr CreateAudioManager( |
| 985 return new AudioManagerMac(audio_log_factory); | 955 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 956 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, |
| 957 AudioLogFactory* audio_log_factory) { |
| 958 return ScopedAudioManagerPtr( |
| 959 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), |
| 960 audio_log_factory)); |
| 986 } | 961 } |
| 987 | 962 |
| 988 } // namespace media | 963 } // namespace media |
| OLD | NEW |