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 |