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 |
DaleCurtis
2016/04/06 22:07:49
These should be removable if you change the scoped
alokp
2016/04/07 00:38:10
Done.
| |
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 |