audio_manager_mac.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 3// found in the LICENSE file. 4 5#include "media/audio/mac/audio_manager_mac.h" 6 7#include <CoreAudio/AudioHardware.h> 8#include <string> 9 10#include "base/bind.h" 11#include "base/command_line.h" 12#include "base/mac/mac_logging.h" 13#include "base/mac/scoped_cftyperef.h" 14#include "base/power_monitor/power_monitor.h" 15#include "base/power_monitor/power_observer.h" 16#include "base/strings/sys_string_conversions.h" 17#include "base/threading/thread_checker.h" 18#include "media/audio/audio_parameters.h" 19#include "media/audio/mac/audio_auhal_mac.h" 20#include "media/audio/mac/audio_input_mac.h" 21#include "media/audio/mac/audio_low_latency_input_mac.h" 22#include "media/audio/mac/audio_low_latency_output_mac.h" 23#include "media/base/bind_to_current_loop.h" 24#include "media/base/channel_layout.h" 25#include "media/base/limits.h" 26#include "media/base/media_switches.h" 27 28namespace media { 29 30// Maximum number of output streams that can be open simultaneously. 31static const int kMaxOutputStreams = 50; 32 33// Default buffer size in samples for low-latency input and output streams. 34static const int kDefaultLowLatencyBufferSize = 128; 35 36// Default sample-rate on most Apple hardware. 37static const int kFallbackSampleRate = 44100; 38 39static bool HasAudioHardware(AudioObjectPropertySelector selector) { 40 AudioDeviceID output_device_id = kAudioObjectUnknown; 41 const AudioObjectPropertyAddress property_address = { 42 selector, 43 kAudioObjectPropertyScopeGlobal, // mScope 44 kAudioObjectPropertyElementMaster // mElement 45 }; 46 UInt32 output_device_id_size = static_cast<UInt32>(sizeof(output_device_id)); 47 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, 48 &property_address, 49 0, // inQualifierDataSize 50 NULL, // inQualifierData 51 &output_device_id_size, 52 &output_device_id); 53 return err == kAudioHardwareNoError && 54 output_device_id != kAudioObjectUnknown; 55} 56 57// Retrieves information on audio devices, and prepends the default 58// device to the list if the list is non-empty. 59static void GetAudioDeviceInfo(bool is_input, 60 media::AudioDeviceNames* device_names) { 61 // Query the number of total devices. 62 AudioObjectPropertyAddress property_address = { 63 kAudioHardwarePropertyDevices, 64 kAudioObjectPropertyScopeGlobal, 65 kAudioObjectPropertyElementMaster 66 }; 67 UInt32 size = 0; 68 OSStatus result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, 69 &property_address, 70 0, 71 NULL, 72 &size); 73 if (result || !size) 74 return; 75 76 int device_count = size / sizeof(AudioDeviceID); 77 78 // Get the array of device ids for all the devices, which includes both 79 // input devices and output devices. 80 scoped_ptr_malloc<AudioDeviceID> 81 devices(reinterpret_cast<AudioDeviceID*>(malloc(size))); 82 AudioDeviceID* device_ids = devices.get(); 83 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 84 &property_address, 85 0, 86 NULL, 87 &size, 88 device_ids); 89 if (result) 90 return; 91 92 // Iterate over all available devices to gather information. 93 for (int i = 0; i < device_count; ++i) { 94 // Get the number of input or output channels of the device. 95 property_address.mScope = is_input ? 96 kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; 97 property_address.mSelector = kAudioDevicePropertyStreams; 98 size = 0; 99 result = AudioObjectGetPropertyDataSize(device_ids[i], 100 &property_address, 101 0, 102 NULL, 103 &size); 104 if (result || !size) 105 continue; 106 107 // Get device UID. 108 CFStringRef uid = NULL; 109 size = sizeof(uid); 110 property_address.mSelector = kAudioDevicePropertyDeviceUID; 111 property_address.mScope = kAudioObjectPropertyScopeGlobal; 112 result = AudioObjectGetPropertyData(device_ids[i], 113 &property_address, 114 0, 115 NULL, 116 &size, 117 &uid); 118 if (result) 119 continue; 120 121 // Get device name. 122 CFStringRef name = NULL; 123 property_address.mSelector = kAudioObjectPropertyName; 124 property_address.mScope = kAudioObjectPropertyScopeGlobal; 125 result = AudioObjectGetPropertyData(device_ids[i], 126 &property_address, 127 0, 128 NULL, 129 &size, 130 &name); 131 if (result) { 132 if (uid) 133 CFRelease(uid); 134 continue; 135 } 136 137 // Store the device name and UID. 138 media::AudioDeviceName device_name; 139 device_name.device_name = base::SysCFStringRefToUTF8(name); 140 device_name.unique_id = base::SysCFStringRefToUTF8(uid); 141 device_names->push_back(device_name); 142 143 // We are responsible for releasing the returned CFObject. See the 144 // comment in the AudioHardware.h for constant 145 // kAudioDevicePropertyDeviceUID. 146 if (uid) 147 CFRelease(uid); 148 if (name) 149 CFRelease(name); 150 } 151 152 if (!device_names->empty()) { 153 // Prepend the default device to the list since we always want it to be 154 // on the top of the list for all platforms. There is no duplicate 155 // counting here since the default device has been abstracted out before. 156 media::AudioDeviceName name; 157 name.device_name = AudioManagerBase::kDefaultDeviceName; 158 name.unique_id = AudioManagerBase::kDefaultDeviceId; 159 device_names->push_front(name); 160 } 161} 162 163static AudioDeviceID GetAudioDeviceIdByUId(bool is_input, 164 const std::string& device_id) { 165 AudioObjectPropertyAddress property_address = { 166 kAudioHardwarePropertyDevices, 167 kAudioObjectPropertyScopeGlobal, 168 kAudioObjectPropertyElementMaster 169 }; 170 AudioDeviceID audio_device_id = kAudioObjectUnknown; 171 UInt32 device_size = sizeof(audio_device_id); 172 OSStatus result = -1; 173 174 if (device_id == AudioManagerBase::kDefaultDeviceId || device_id.empty()) { 175 // Default Device. 176 property_address.mSelector = is_input ? 177 kAudioHardwarePropertyDefaultInputDevice : 178 kAudioHardwarePropertyDefaultOutputDevice; 179 180 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 181 &property_address, 182 0, 183 0, 184 &device_size, 185 &audio_device_id); 186 } else { 187 // Non-default device. 188 base::ScopedCFTypeRef<CFStringRef> uid( 189 base::SysUTF8ToCFStringRef(device_id)); 190 AudioValueTranslation value; 191 value.mInputData = &uid; 192 value.mInputDataSize = sizeof(CFStringRef); 193 value.mOutputData = &audio_device_id; 194 value.mOutputDataSize = device_size; 195 UInt32 translation_size = sizeof(AudioValueTranslation); 196 197 property_address.mSelector = kAudioHardwarePropertyDeviceForUID; 198 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 199 &property_address, 200 0, 201 0, 202 &translation_size, 203 &value); 204 } 205 206 if (result) { 207 OSSTATUS_DLOG(WARNING, result) << "Unable to query device " << device_id 208 << " for AudioDeviceID"; 209 } 210 211 return audio_device_id; 212} 213 214class AudioManagerMac::AudioPowerObserver : public base::PowerObserver { 215 public: 216 AudioPowerObserver() 217 : is_suspending_(false), 218 is_monitoring_(base::PowerMonitor::Get()) { 219 // The PowerMonitor requires signifcant setup (a CFRunLoop and preallocated 220 // IO ports) so it's not available under unit tests. See the OSX impl of 221 // base::PowerMonitorDeviceSource for more details. 222 if (!is_monitoring_) 223 return; 224 base::PowerMonitor::Get()->AddObserver(this); 225 } 226 227 virtual ~AudioPowerObserver() { 228 DCHECK(thread_checker_.CalledOnValidThread()); 229 if (!is_monitoring_) 230 return; 231 base::PowerMonitor::Get()->RemoveObserver(this); 232 } 233 234 bool ShouldDeferOutputStreamStart() { 235 DCHECK(thread_checker_.CalledOnValidThread()); 236 // Start() should be deferred if the system is in the middle of a suspend or 237 // has recently started the process of resuming. 238 return is_suspending_ || base::TimeTicks::Now() < earliest_start_time_; 239 } 240 241 private: 242 virtual void OnSuspend() OVERRIDE { 243 DCHECK(thread_checker_.CalledOnValidThread()); 244 is_suspending_ = true; 245 } 246 247 virtual void OnResume() OVERRIDE { 248 DCHECK(thread_checker_.CalledOnValidThread()); 249 is_suspending_ = false; 250 earliest_start_time_ = base::TimeTicks::Now() + 251 base::TimeDelta::FromSeconds(kStartDelayInSecsForPowerEvents); 252 } 253 254 bool is_suspending_; 255 const bool is_monitoring_; 256 base::TimeTicks earliest_start_time_; 257 base::ThreadChecker thread_checker_; 258 259 DISALLOW_COPY_AND_ASSIGN(AudioPowerObserver); 260}; 261 262AudioManagerMac::AudioManagerMac(AudioLogFactory* audio_log_factory) 263 : AudioManagerBase(audio_log_factory), 264 current_sample_rate_(0), 265 current_output_device_(kAudioDeviceUnknown) { 266 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 267 268 // Task must be posted last to avoid races from handing out "this" to the 269 // audio thread. Always PostTask even if we're on the right thread since 270 // AudioManager creation is on the startup path and this may be slow. 271 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 272 &AudioManagerMac::InitializeOnAudioThread, base::Unretained(this))); 273} 274 275AudioManagerMac::~AudioManagerMac() { 276 if (GetTaskRunner()->BelongsToCurrentThread()) { 277 ShutdownOnAudioThread(); 278 } else { 279 // It's safe to post a task here since Shutdown() will wait for all tasks to 280 // complete before returning. 281 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 282 &AudioManagerMac::ShutdownOnAudioThread, base::Unretained(this))); 283 } 284 285 Shutdown(); 286} 287 288bool AudioManagerMac::HasAudioOutputDevices() { 289 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); 290} 291 292bool AudioManagerMac::HasAudioInputDevices() { 293 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); 294} 295 296// TODO(xians): There are several places on the OSX specific code which 297// could benefit from these helper functions. 298bool AudioManagerMac::GetDefaultInputDevice( 299 AudioDeviceID* device) { 300 return GetDefaultDevice(device, true); 301} 302 303bool AudioManagerMac::GetDefaultOutputDevice( 304 AudioDeviceID* device) { 305 return GetDefaultDevice(device, false); 306} 307 308bool AudioManagerMac::GetDefaultDevice( 309 AudioDeviceID* device, bool input) { 310 CHECK(device); 311 312 // Obtain the current output device selected by the user. 313 AudioObjectPropertyAddress pa; 314 pa.mSelector = input ? kAudioHardwarePropertyDefaultInputDevice : 315 kAudioHardwarePropertyDefaultOutputDevice; 316 pa.mScope = kAudioObjectPropertyScopeGlobal; 317 pa.mElement = kAudioObjectPropertyElementMaster; 318 319 UInt32 size = sizeof(*device); 320 321 OSStatus result = AudioObjectGetPropertyData( 322 kAudioObjectSystemObject, 323 &pa, 324 0, 325 0, 326 &size, 327 device); 328 329 if ((result != kAudioHardwareNoError) || (*device == kAudioDeviceUnknown)) { 330 DLOG(ERROR) << "Error getting default AudioDevice."; 331 return false; 332 } 333 334 return true; 335} 336 337bool AudioManagerMac::GetDefaultOutputChannels( 338 int* channels) { 339 AudioDeviceID device; 340 if (!GetDefaultOutputDevice(&device)) 341 return false; 342 343 return GetDeviceChannels(device, 344 kAudioDevicePropertyScopeOutput, 345 channels); 346} 347 348bool AudioManagerMac::GetDeviceChannels( 349 AudioDeviceID device, 350 AudioObjectPropertyScope scope, 351 int* channels) { 352 CHECK(channels); 353 354 // Get stream configuration. 355 AudioObjectPropertyAddress pa; 356 pa.mSelector = kAudioDevicePropertyStreamConfiguration; 357 pa.mScope = scope; 358 pa.mElement = kAudioObjectPropertyElementMaster; 359 360 UInt32 size; 361 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); 362 if (result != noErr || !size) 363 return false; 364 365 // Allocate storage. 366 scoped_ptr<uint8[]> list_storage(new uint8[size]); 367 AudioBufferList& buffer_list = 368 *reinterpret_cast<AudioBufferList*>(list_storage.get()); 369 370 result = AudioObjectGetPropertyData( 371 device, 372 &pa, 373 0, 374 0, 375 &size, 376 &buffer_list); 377 if (result != noErr) 378 return false; 379 380 // Determine number of input channels. 381 int channels_per_frame = buffer_list.mNumberBuffers > 0 ? 382 buffer_list.mBuffers[0].mNumberChannels : 0; 383 if (channels_per_frame == 1 && buffer_list.mNumberBuffers > 1) { 384 // Non-interleaved. 385 *channels = buffer_list.mNumberBuffers; 386 } else { 387 // Interleaved. 388 *channels = channels_per_frame; 389 } 390 391 return true; 392} 393 394int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { 395 Float64 nominal_sample_rate; 396 UInt32 info_size = sizeof(nominal_sample_rate); 397 398 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { 399 kAudioDevicePropertyNominalSampleRate, 400 kAudioObjectPropertyScopeGlobal, 401 kAudioObjectPropertyElementMaster 402 }; 403 OSStatus result = AudioObjectGetPropertyData( 404 device_id, 405 &kNominalSampleRateAddress, 406 0, 407 0, 408 &info_size, 409 &nominal_sample_rate); 410 if (result != noErr) { 411 OSSTATUS_DLOG(WARNING, result) 412 << "Could not get default sample rate for device: " << device_id; 413 return 0; 414 } 415 416 return static_cast<int>(nominal_sample_rate); 417} 418 419int AudioManagerMac::HardwareSampleRate() { 420 // Determine the default output device's sample-rate. 421 AudioDeviceID device_id = kAudioObjectUnknown; 422 if (!GetDefaultOutputDevice(&device_id)) 423 return kFallbackSampleRate; 424 425 return HardwareSampleRateForDevice(device_id); 426} 427 428void AudioManagerMac::GetAudioInputDeviceNames( 429 media::AudioDeviceNames* device_names) { 430 DCHECK(device_names->empty()); 431 GetAudioDeviceInfo(true, device_names); 432} 433 434void AudioManagerMac::GetAudioOutputDeviceNames( 435 media::AudioDeviceNames* device_names) { 436 DCHECK(device_names->empty()); 437 GetAudioDeviceInfo(false, device_names); 438} 439 440AudioParameters AudioManagerMac::GetInputStreamParameters( 441 const std::string& device_id) { 442 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id); 443 if (device == kAudioObjectUnknown) { 444 DLOG(ERROR) << "Invalid device " << device_id; 445 return AudioParameters( 446 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 447 kFallbackSampleRate, 16, ChooseBufferSize(kFallbackSampleRate)); 448 } 449 450 int channels = 0; 451 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 452 if (GetDeviceChannels(device, kAudioDevicePropertyScopeInput, &channels) && 453 channels <= 2) { 454 channel_layout = GuessChannelLayout(channels); 455 } else { 456 DLOG(ERROR) << "Failed to get the device channels, use stereo as default " 457 << "for device " << device_id; 458 } 459 460 int sample_rate = HardwareSampleRateForDevice(device); 461 if (!sample_rate) 462 sample_rate = kFallbackSampleRate; 463 464 // Due to the sharing of the input and output buffer sizes, we need to choose 465 // the input buffer size based on the output sample rate. See 466 // http://crbug.com/154352. 467 const int buffer_size = ChooseBufferSize(sample_rate); 468 469 // TODO(xians): query the native channel layout for the specific device. 470 return AudioParameters( 471 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 472 sample_rate, 16, buffer_size); 473} 474 475std::string AudioManagerMac::GetAssociatedOutputDeviceID( 476 const std::string& input_device_id) { 477 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); 478 if (device == kAudioObjectUnknown) 479 return std::string(); 480 481 UInt32 size = 0; 482 AudioObjectPropertyAddress pa = { 483 kAudioDevicePropertyRelatedDevices, 484 kAudioDevicePropertyScopeOutput, 485 kAudioObjectPropertyElementMaster 486 }; 487 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); 488 if (result || !size) 489 return std::string(); 490 491 int device_count = size / sizeof(AudioDeviceID); 492 scoped_ptr_malloc<AudioDeviceID> 493 devices(reinterpret_cast<AudioDeviceID*>(malloc(size))); 494 result = AudioObjectGetPropertyData( 495 device, &pa, 0, NULL, &size, devices.get()); 496 if (result) 497 return std::string(); 498 499 std::vector<std::string> associated_devices; 500 for (int i = 0; i < device_count; ++i) { 501 // Get the number of output channels of the device. 502 pa.mSelector = kAudioDevicePropertyStreams; 503 size = 0; 504 result = AudioObjectGetPropertyDataSize(devices.get()[i], 505 &pa, 506 0, 507 NULL, 508 &size); 509 if (result || !size) 510 continue; // Skip if there aren't any output channels. 511 512 // Get device UID. 513 CFStringRef uid = NULL; 514 size = sizeof(uid); 515 pa.mSelector = kAudioDevicePropertyDeviceUID; 516 result = AudioObjectGetPropertyData(devices.get()[i], 517 &pa, 518 0, 519 NULL, 520 &size, 521 &uid); 522 if (result || !uid) 523 continue; 524 525 std::string ret(base::SysCFStringRefToUTF8(uid)); 526 CFRelease(uid); 527 associated_devices.push_back(ret); 528 } 529 530 // No matching device found. 531 if (associated_devices.empty()) 532 return std::string(); 533 534 // Return the device if there is only one associated device. 535 if (associated_devices.size() == 1) 536 return associated_devices[0]; 537 538 // When there are multiple associated devices, we currently do not have a way 539 // to detect if a device (e.g. a digital output device) is actually connected 540 // to an endpoint, so we cannot randomly pick a device. 541 // We pick the device iff the associated device is the default output device. 542 const std::string default_device = GetDefaultOutputDeviceID(); 543 for (std::vector<std::string>::const_iterator iter = 544 associated_devices.begin(); 545 iter != associated_devices.end(); ++iter) { 546 if (default_device == *iter) 547 return *iter; 548 } 549 550 // Failed to figure out which is the matching device, return an emtpy string. 551 return std::string(); 552} 553 554AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( 555 const AudioParameters& params) { 556 return MakeLowLatencyOutputStream(params, std::string()); 557} 558 559AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( 560 const AudioParameters& params, 561 const std::string& device_id) { 562 AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id); 563 if (device == kAudioObjectUnknown) { 564 DLOG(ERROR) << "Failed to open output device: " << device_id; 565 return NULL; 566 } 567 568 // Lazily create the audio device listener on the first stream creation. 569 if (!output_device_listener_) { 570 output_device_listener_.reset(new AudioDeviceListenerMac(base::Bind( 571 &AudioManagerMac::HandleDeviceChanges, base::Unretained(this)))); 572 // Only set the current output device for the default device. 573 if (device_id == AudioManagerBase::kDefaultDeviceId || device_id.empty()) 574 current_output_device_ = device; 575 // Just use the current sample rate since we don't allow non-native sample 576 // rates on OSX. 577 current_sample_rate_ = params.sample_rate(); 578 } 579 580 return new AUHALStream(this, params, device); 581} 582 583std::string AudioManagerMac::GetDefaultOutputDeviceID() { 584 AudioDeviceID device_id = kAudioObjectUnknown; 585 if (!GetDefaultOutputDevice(&device_id)) 586 return std::string(); 587 588 const AudioObjectPropertyAddress property_address = { 589 kAudioDevicePropertyDeviceUID, 590 kAudioObjectPropertyScopeGlobal, 591 kAudioObjectPropertyElementMaster 592 }; 593 CFStringRef device_uid = NULL; 594 UInt32 size = sizeof(device_uid); 595 OSStatus status = AudioObjectGetPropertyData(device_id, 596 &property_address, 597 0, 598 NULL, 599 &size, 600 &device_uid); 601 if (status != kAudioHardwareNoError || !device_uid) 602 return std::string(); 603 604 std::string ret(base::SysCFStringRefToUTF8(device_uid)); 605 CFRelease(device_uid); 606 607 return ret; 608} 609 610AudioInputStream* AudioManagerMac::MakeLinearInputStream( 611 const AudioParameters& params, const std::string& device_id) { 612 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 613 return new PCMQueueInAudioInputStream(this, params); 614} 615 616AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( 617 const AudioParameters& params, const std::string& device_id) { 618 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 619 // Gets the AudioDeviceID that refers to the AudioInputDevice with the device 620 // unique id. This AudioDeviceID is used to set the device for Audio Unit. 621 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); 622 AudioInputStream* stream = NULL; 623 if (audio_device_id != kAudioObjectUnknown) { 624 // AUAudioInputStream needs to be fed the preferred audio output parameters 625 // of the matching device so that the buffer size of both input and output 626 // can be matched. See constructor of AUAudioInputStream for more. 627 const std::string associated_output_device( 628 GetAssociatedOutputDeviceID(device_id)); 629 const AudioParameters output_params = 630 GetPreferredOutputStreamParameters( 631 associated_output_device.empty() ? 632 AudioManagerBase::kDefaultDeviceId : associated_output_device, 633 params); 634 stream = new AUAudioInputStream(this, params, output_params, 635 audio_device_id); 636 } 637 638 return stream; 639} 640 641AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( 642 const std::string& output_device_id, 643 const AudioParameters& input_params) { 644 const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id); 645 if (device == kAudioObjectUnknown) { 646 DLOG(ERROR) << "Invalid output device " << output_device_id; 647 return input_params.IsValid() ? input_params : AudioParameters( 648 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 649 kFallbackSampleRate, 16, ChooseBufferSize(kFallbackSampleRate)); 650 } 651 652 const bool has_valid_input_params = input_params.IsValid(); 653 const int hardware_sample_rate = HardwareSampleRateForDevice(device); 654 const int buffer_size = ChooseBufferSize(hardware_sample_rate); 655 656 int hardware_channels; 657 if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput, 658 &hardware_channels)) { 659 hardware_channels = 2; 660 } 661 662 // Use the input channel count and channel layout if possible. Let OSX take 663 // care of remapping the channels; this lets user specified channel layouts 664 // work correctly. 665 int output_channels = input_params.channels(); 666 ChannelLayout channel_layout = input_params.channel_layout(); 667 if (!has_valid_input_params || output_channels > hardware_channels) { 668 output_channels = hardware_channels; 669 channel_layout = GuessChannelLayout(output_channels); 670 if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) 671 channel_layout = CHANNEL_LAYOUT_DISCRETE; 672 } 673 674 const int input_channels = 675 has_valid_input_params ? input_params.input_channels() : 0; 676 if (input_channels > 0) { 677 // TODO(xians): given the limitations of the AudioOutputStream 678 // back-ends used with synchronized I/O, we hard-code to stereo. 679 // Specifically, this is a limitation of AudioSynchronizedStream which 680 // can be removed as part of the work to consolidate these back-ends. 681 channel_layout = CHANNEL_LAYOUT_STEREO; 682 } 683 684 return AudioParameters( 685 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, output_channels, 686 input_channels, hardware_sample_rate, 16, buffer_size, 687 AudioParameters::NO_EFFECTS); 688} 689 690void AudioManagerMac::InitializeOnAudioThread() { 691 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 692 power_observer_.reset(new AudioPowerObserver()); 693} 694 695void AudioManagerMac::ShutdownOnAudioThread() { 696 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 697 output_device_listener_.reset(); 698 power_observer_.reset(); 699} 700 701void AudioManagerMac::HandleDeviceChanges() { 702 if (!GetTaskRunner()->BelongsToCurrentThread()) { 703 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 704 &AudioManagerMac::HandleDeviceChanges, base::Unretained(this))); 705 return; 706 } 707 708 int new_sample_rate = HardwareSampleRate(); 709 AudioDeviceID new_output_device; 710 GetDefaultOutputDevice(&new_output_device); 711 712 if (current_sample_rate_ == new_sample_rate && 713 current_output_device_ == new_output_device) 714 return; 715 716 current_sample_rate_ = new_sample_rate; 717 current_output_device_ = new_output_device; 718 NotifyAllOutputDeviceChangeListeners(); 719} 720 721int AudioManagerMac::ChooseBufferSize(int output_sample_rate) { 722 int buffer_size = kDefaultLowLatencyBufferSize; 723 const int user_buffer_size = GetUserBufferSize(); 724 if (user_buffer_size) { 725 buffer_size = user_buffer_size; 726 } else if (output_sample_rate > 48000) { 727 // The default buffer size is too small for higher sample rates and may lead 728 // to glitching. Adjust upwards by multiples of the default size. 729 if (output_sample_rate <= 96000) 730 buffer_size = 2 * kDefaultLowLatencyBufferSize; 731 else if (output_sample_rate <= 192000) 732 buffer_size = 4 * kDefaultLowLatencyBufferSize; 733 } 734 735 return buffer_size; 736} 737 738bool AudioManagerMac::ShouldDeferOutputStreamStart() { 739 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 740 return power_observer_->ShouldDeferOutputStreamStart(); 741} 742 743AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 744 return new AudioManagerMac(audio_log_factory); 745} 746 747} // namespace media 748