Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(548)

Side by Side Diff: media/audio/mac/audio_manager_mac.cc

Issue 1780333007: AudioManagerBase: Create and run the audio thread lazily. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: fixed media unittests on mac Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/audio/mac/audio_manager_mac.h ('k') | media/audio/mock_audio_manager.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 task_runner_ = base::MessageLoopForUI::IsCurrent()
378 ? base::ThreadTaskRunnerHandle::Get()
379 : AudioManagerBase::GetTaskRunner();
380
373 // Task must be posted last to avoid races from handing out "this" to the 381 // 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 382 // 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. 383 // AudioManager creation is on the startup path and this may be slow.
376 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 384 task_runner_->PostTask(FROM_HERE,
377 &AudioManagerMac::InitializeOnAudioThread, base::Unretained(this))); 385 base::Bind(&AudioManagerMac::InitializeOnAudioThread,
386 base::Unretained(this)));
378 } 387 }
379 388
380 AudioManagerMac::~AudioManagerMac() { 389 AudioManagerMac::~AudioManagerMac() {
381 if (GetTaskRunner()->BelongsToCurrentThread()) { 390 if (task_runner_->BelongsToCurrentThread()) {
382 ShutdownOnAudioThread(); 391 ShutdownOnAudioThread();
383 } else { 392 } else {
384 // It's safe to post a task here since Shutdown() will wait for all tasks to 393 // It's safe to post a task here since Shutdown() will wait for all tasks to
385 // complete before returning. 394 // complete before returning.
386 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 395 task_runner_->PostTask(FROM_HERE,
387 &AudioManagerMac::ShutdownOnAudioThread, base::Unretained(this))); 396 base::Bind(&AudioManagerMac::ShutdownOnAudioThread,
397 base::Unretained(this)));
388 } 398 }
389 399
390 Shutdown(); 400 Shutdown();
391 } 401 }
392 402
403 scoped_refptr<base::SingleThreadTaskRunner> AudioManagerMac::GetTaskRunner() {
404 return task_runner_;
405 }
406
407 scoped_refptr<base::SingleThreadTaskRunner>
408 AudioManagerMac::GetWorkerTaskRunner() {
409 if (!worker_thread_) {
410 worker_thread_.reset(new base::Thread("AudioWorkerThread"));
411 CHECK(worker_thread_->Start());
412 }
413 return worker_thread_->task_runner();
414 }
415
393 bool AudioManagerMac::HasAudioOutputDevices() { 416 bool AudioManagerMac::HasAudioOutputDevices() {
394 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); 417 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice);
395 } 418 }
396 419
397 bool AudioManagerMac::HasAudioInputDevices() { 420 bool AudioManagerMac::HasAudioInputDevices() {
398 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); 421 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
399 } 422 }
400 423
424 // static
401 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, 425 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device,
402 AudioObjectPropertyScope scope, 426 AudioObjectPropertyScope scope,
403 int* channels) { 427 int* channels) {
404 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 428 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
405 CHECK(channels); 429 CHECK(channels);
406 const bool is_input = (scope == kAudioDevicePropertyScopeInput); 430 const bool is_input = (scope == kAudioDevicePropertyScopeInput);
407 DVLOG(1) << "GetDeviceChannels(id=0x" << std::hex << device 431 DVLOG(1) << "GetDeviceChannels(id=0x" << std::hex << device
408 << ", is_input=" << is_input << ")"; 432 << ", is_input=" << is_input << ")";
409 433
410 // Get the stream configuration of the device in an AudioBufferList (with the 434 // Get the stream configuration of the device in an AudioBufferList (with the
(...skipping 23 matching lines...) Expand all
434 // TODO(henrika): add UMA stats to track utilized hardware configurations. 458 // TODO(henrika): add UMA stats to track utilized hardware configurations.
435 int num_channels = 0; 459 int num_channels = 0;
436 for (UInt32 i = 0; i < buffer_list.mNumberBuffers; ++i) { 460 for (UInt32 i = 0; i < buffer_list.mNumberBuffers; ++i) {
437 num_channels += buffer_list.mBuffers[i].mNumberChannels; 461 num_channels += buffer_list.mBuffers[i].mNumberChannels;
438 } 462 }
439 *channels = num_channels; 463 *channels = num_channels;
440 DVLOG(1) << "#channels: " << *channels; 464 DVLOG(1) << "#channels: " << *channels;
441 return true; 465 return true;
442 } 466 }
443 467
468 // static
444 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { 469 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) {
445 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); 470 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
446 Float64 nominal_sample_rate; 471 Float64 nominal_sample_rate;
447 UInt32 info_size = sizeof(nominal_sample_rate); 472 UInt32 info_size = sizeof(nominal_sample_rate);
448 473
449 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { 474 static const AudioObjectPropertyAddress kNominalSampleRateAddress = {
450 kAudioDevicePropertyNominalSampleRate, 475 kAudioDevicePropertyNominalSampleRate,
451 kAudioObjectPropertyScopeGlobal, 476 kAudioObjectPropertyScopeGlobal,
452 kAudioObjectPropertyElementMaster 477 kAudioObjectPropertyElementMaster
453 }; 478 };
454 OSStatus result = AudioObjectGetPropertyData(device_id, 479 OSStatus result = AudioObjectGetPropertyData(device_id,
455 &kNominalSampleRateAddress, 480 &kNominalSampleRateAddress,
456 0, 481 0,
457 0, 482 0,
458 &info_size, 483 &info_size,
459 &nominal_sample_rate); 484 &nominal_sample_rate);
460 if (result != noErr) { 485 if (result != noErr) {
461 OSSTATUS_DLOG(WARNING, result) 486 OSSTATUS_DLOG(WARNING, result)
462 << "Could not get default sample rate for device: " << device_id; 487 << "Could not get default sample rate for device: " << device_id;
463 return 0; 488 return 0;
464 } 489 }
465 490
466 return static_cast<int>(nominal_sample_rate); 491 return static_cast<int>(nominal_sample_rate);
467 } 492 }
468 493
494 // static
469 int AudioManagerMac::HardwareSampleRate() { 495 int AudioManagerMac::HardwareSampleRate() {
470 // Determine the default output device's sample-rate. 496 // Determine the default output device's sample-rate.
471 AudioDeviceID device_id = kAudioObjectUnknown; 497 AudioDeviceID device_id = kAudioObjectUnknown;
472 if (!GetDefaultOutputDevice(&device_id)) 498 if (!GetDefaultOutputDevice(&device_id))
473 return kFallbackSampleRate; 499 return kFallbackSampleRate;
474 500
475 return HardwareSampleRateForDevice(device_id); 501 return HardwareSampleRateForDevice(device_id);
476 } 502 }
477 503
478 void AudioManagerMac::GetAudioInputDeviceNames( 504 void AudioManagerMac::GetAudioInputDeviceNames(
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 const int buffer_size = ChooseBufferSize(true, sample_rate); 543 const int buffer_size = ChooseBufferSize(true, sample_rate);
518 544
519 // TODO(xians): query the native channel layout for the specific device. 545 // TODO(xians): query the native channel layout for the specific device.
520 return AudioParameters( 546 return AudioParameters(
521 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 547 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
522 sample_rate, 16, buffer_size); 548 sample_rate, 16, buffer_size);
523 } 549 }
524 550
525 std::string AudioManagerMac::GetAssociatedOutputDeviceID( 551 std::string AudioManagerMac::GetAssociatedOutputDeviceID(
526 const std::string& input_device_id) { 552 const std::string& input_device_id) {
527 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 553 DCHECK(task_runner_->BelongsToCurrentThread());
528 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); 554 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id);
529 if (device == kAudioObjectUnknown) 555 if (device == kAudioObjectUnknown)
530 return std::string(); 556 return std::string();
531 557
532 UInt32 size = 0; 558 UInt32 size = 0;
533 AudioObjectPropertyAddress pa = { 559 AudioObjectPropertyAddress pa = {
534 kAudioDevicePropertyRelatedDevices, 560 kAudioDevicePropertyRelatedDevices,
535 kAudioDevicePropertyScopeOutput, 561 kAudioDevicePropertyScopeOutput,
536 kAudioObjectPropertyElementMaster 562 kAudioObjectPropertyElementMaster
537 }; 563 };
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 // rates on OSX. 668 // rates on OSX.
643 current_sample_rate_ = params.sample_rate(); 669 current_sample_rate_ = params.sample_rate();
644 } 670 }
645 671
646 AUHALStream* stream = new AUHALStream(this, params, device); 672 AUHALStream* stream = new AUHALStream(this, params, device);
647 output_streams_.push_back(stream); 673 output_streams_.push_back(stream);
648 return stream; 674 return stream;
649 } 675 }
650 676
651 std::string AudioManagerMac::GetDefaultOutputDeviceID() { 677 std::string AudioManagerMac::GetDefaultOutputDeviceID() {
652 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 678 DCHECK(task_runner_->BelongsToCurrentThread());
653 AudioDeviceID device_id = kAudioObjectUnknown; 679 AudioDeviceID device_id = kAudioObjectUnknown;
654 if (!GetDefaultOutputDevice(&device_id)) 680 if (!GetDefaultOutputDevice(&device_id))
655 return std::string(); 681 return std::string();
656 682
657 const AudioObjectPropertyAddress property_address = { 683 const AudioObjectPropertyAddress property_address = {
658 kAudioDevicePropertyDeviceUID, 684 kAudioDevicePropertyDeviceUID,
659 kAudioObjectPropertyScopeGlobal, 685 kAudioObjectPropertyScopeGlobal,
660 kAudioObjectPropertyElementMaster 686 kAudioObjectPropertyElementMaster
661 }; 687 };
662 CFStringRef device_uid = NULL; 688 CFStringRef device_uid = NULL;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
741 channel_layout = CHANNEL_LAYOUT_DISCRETE; 767 channel_layout = CHANNEL_LAYOUT_DISCRETE;
742 } 768 }
743 769
744 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 770 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
745 hardware_sample_rate, 16, buffer_size); 771 hardware_sample_rate, 16, buffer_size);
746 params.set_channels_for_discrete(output_channels); 772 params.set_channels_for_discrete(output_channels);
747 return params; 773 return params;
748 } 774 }
749 775
750 void AudioManagerMac::InitializeOnAudioThread() { 776 void AudioManagerMac::InitializeOnAudioThread() {
751 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 777 DCHECK(task_runner_->BelongsToCurrentThread());
752 power_observer_.reset(new AudioPowerObserver()); 778 power_observer_.reset(new AudioPowerObserver());
753 } 779 }
754 780
755 void AudioManagerMac::ShutdownOnAudioThread() { 781 void AudioManagerMac::ShutdownOnAudioThread() {
756 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 782 DCHECK(task_runner_->BelongsToCurrentThread());
757 output_device_listener_.reset(); 783 output_device_listener_.reset();
758 power_observer_.reset(); 784 power_observer_.reset();
759 785
760 // Since CoreAudio calls have to run on the UI thread and browser shutdown 786 // Since CoreAudio calls have to run on the UI thread and browser shutdown
761 // doesn't wait for outstanding tasks to complete, we may have input/output 787 // doesn't wait for outstanding tasks to complete, we may have input/output
762 // streams still running at shutdown. 788 // streams still running at shutdown.
763 // 789 //
764 // To avoid calls into destructed classes, we need to stop the OS callbacks 790 // To avoid calls into destructed classes, we need to stop the OS callbacks
765 // by stopping the streams. Note: The streams are leaked since process 791 // by stopping the streams. Note: The streams are leaked since process
766 // destruction is imminent. 792 // destruction is imminent.
767 // 793 //
768 // See http://crbug.com/354139 for crash details. 794 // See http://crbug.com/354139 for crash details.
769 StopStreams(&basic_input_streams_); 795 StopStreams(&basic_input_streams_);
770 StopStreams(&low_latency_input_streams_); 796 StopStreams(&low_latency_input_streams_);
771 StopStreams(&output_streams_); 797 StopStreams(&output_streams_);
772 } 798 }
773 799
774 void AudioManagerMac::HandleDeviceChanges() { 800 void AudioManagerMac::HandleDeviceChanges() {
775 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 801 DCHECK(task_runner_->BelongsToCurrentThread());
776 const int new_sample_rate = HardwareSampleRate(); 802 const int new_sample_rate = HardwareSampleRate();
777 AudioDeviceID new_output_device; 803 AudioDeviceID new_output_device;
778 GetDefaultOutputDevice(&new_output_device); 804 GetDefaultOutputDevice(&new_output_device);
779 805
780 if (current_sample_rate_ == new_sample_rate && 806 if (current_sample_rate_ == new_sample_rate &&
781 current_output_device_ == new_output_device) { 807 current_output_device_ == new_output_device) {
782 return; 808 return;
783 } 809 }
784 810
785 current_sample_rate_ = new_sample_rate; 811 current_sample_rate_ = new_sample_rate;
(...skipping 21 matching lines...) Expand all
807 if (sample_rate <= 96000) 833 if (sample_rate <= 96000)
808 buffer_size = 2 * kMinimumInputOutputBufferSize; 834 buffer_size = 2 * kMinimumInputOutputBufferSize;
809 else if (sample_rate <= 192000) 835 else if (sample_rate <= 192000)
810 buffer_size = 4 * kMinimumInputOutputBufferSize; 836 buffer_size = 4 * kMinimumInputOutputBufferSize;
811 } 837 }
812 838
813 return buffer_size; 839 return buffer_size;
814 } 840 }
815 841
816 bool AudioManagerMac::ShouldDeferStreamStart() const { 842 bool AudioManagerMac::ShouldDeferStreamStart() const {
817 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 843 DCHECK(task_runner_->BelongsToCurrentThread());
818 return power_observer_->ShouldDeferStreamStart(); 844 return power_observer_->ShouldDeferStreamStart();
819 } 845 }
820 846
821 bool AudioManagerMac::IsOnBatteryPower() const { 847 bool AudioManagerMac::IsOnBatteryPower() const {
822 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 848 DCHECK(task_runner_->BelongsToCurrentThread());
823 return power_observer_->IsOnBatteryPower(); 849 return power_observer_->IsOnBatteryPower();
824 } 850 }
825 851
826 size_t AudioManagerMac::GetNumberOfResumeNotifications() const { 852 size_t AudioManagerMac::GetNumberOfResumeNotifications() const {
827 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 853 DCHECK(task_runner_->BelongsToCurrentThread());
828 return power_observer_->num_resume_notifications(); 854 return power_observer_->num_resume_notifications();
829 } 855 }
830 856
831 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id, 857 bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id,
832 AudioUnit audio_unit, 858 AudioUnit audio_unit,
833 AudioUnitElement element, 859 AudioUnitElement element,
834 size_t desired_buffer_size, 860 size_t desired_buffer_size,
835 bool* size_was_changed, 861 bool* size_was_changed,
836 size_t* io_buffer_frame_size) { 862 size_t* io_buffer_frame_size) {
837 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 863 DCHECK(task_runner_->BelongsToCurrentThread());
838 const bool is_input = (element == 1); 864 const bool is_input = (element == 1);
839 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id 865 DVLOG(1) << "MaybeChangeBufferSize(id=0x" << std::hex << device_id
840 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec 866 << ", is_input=" << is_input << ", desired_buffer_size=" << std::dec
841 << desired_buffer_size << ")"; 867 << desired_buffer_size << ")";
842 868
843 *size_was_changed = false; 869 *size_was_changed = false;
844 *io_buffer_frame_size = 0; 870 *io_buffer_frame_size = 0;
845 871
846 // Log the device name (and id) for debugging purposes. 872 // Log the device name (and id) for debugging purposes.
847 std::string device_name = GetAudioDeviceNameFromDeviceId(device_id, is_input); 873 std::string device_name = GetAudioDeviceNameFromDeviceId(device_id, is_input);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
952 basic_input_streams_.erase(stream_it); 978 basic_input_streams_.erase(stream_it);
953 979
954 AudioManagerBase::ReleaseInputStream(stream); 980 AudioManagerBase::ReleaseInputStream(stream);
955 } 981 }
956 982
957 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 983 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
958 return new AudioManagerMac(audio_log_factory); 984 return new AudioManagerMac(audio_log_factory);
959 } 985 }
960 986
961 } // namespace media 987 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/mac/audio_manager_mac.h ('k') | media/audio/mock_audio_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698