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