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/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/base/bind_to_current_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 // Define bounds for for low-latency input and output streams.
     33 static const int kMinimumInputOutputBufferSize = 128;
     34 static const int kMaximumInputOutputBufferSize = 4096;
     35 
     36 // Default sample-rate on most Apple hardware.
     37 static const int kFallbackSampleRate = 44100;
     38 
     39 static 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.
     59 static 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<AudioDeviceID, base::FreeDeleter>
     81       devices(static_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 
    163 static 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 
    214 template <class T>
    215 void StopStreams(std::list<T*>* streams) {
    216   for (typename std::list<T*>::iterator it = streams->begin();
    217        it != streams->end();
    218        ++it) {
    219     // Stop() is safe to call multiple times, so it doesn't matter if a stream
    220     // has already been stopped.
    221     (*it)->Stop();
    222   }
    223   streams->clear();
    224 }
    225 
    226 class AudioManagerMac::AudioPowerObserver : public base::PowerObserver {
    227  public:
    228   AudioPowerObserver()
    229       : is_suspending_(false),
    230         is_monitoring_(base::PowerMonitor::Get()) {
    231     // The PowerMonitor requires signifcant setup (a CFRunLoop and preallocated
    232     // IO ports) so it's not available under unit tests.  See the OSX impl of
    233     // base::PowerMonitorDeviceSource for more details.
    234     if (!is_monitoring_)
    235       return;
    236     base::PowerMonitor::Get()->AddObserver(this);
    237   }
    238 
    239   virtual ~AudioPowerObserver() {
    240     DCHECK(thread_checker_.CalledOnValidThread());
    241     if (!is_monitoring_)
    242       return;
    243     base::PowerMonitor::Get()->RemoveObserver(this);
    244   }
    245 
    246   bool ShouldDeferStreamStart() {
    247     DCHECK(thread_checker_.CalledOnValidThread());
    248     // Start() should be deferred if the system is in the middle of a suspend or
    249     // has recently started the process of resuming.
    250     return is_suspending_ || base::TimeTicks::Now() < earliest_start_time_;
    251   }
    252 
    253  private:
    254   virtual void OnSuspend() OVERRIDE {
    255     DCHECK(thread_checker_.CalledOnValidThread());
    256     is_suspending_ = true;
    257   }
    258 
    259   virtual void OnResume() OVERRIDE {
    260     DCHECK(thread_checker_.CalledOnValidThread());
    261     is_suspending_ = false;
    262     earliest_start_time_ = base::TimeTicks::Now() +
    263         base::TimeDelta::FromSeconds(kStartDelayInSecsForPowerEvents);
    264   }
    265 
    266   bool is_suspending_;
    267   const bool is_monitoring_;
    268   base::TimeTicks earliest_start_time_;
    269   base::ThreadChecker thread_checker_;
    270 
    271   DISALLOW_COPY_AND_ASSIGN(AudioPowerObserver);
    272 };
    273 
    274 AudioManagerMac::AudioManagerMac(AudioLogFactory* audio_log_factory)
    275     : AudioManagerBase(audio_log_factory),
    276       current_sample_rate_(0),
    277       current_output_device_(kAudioDeviceUnknown) {
    278   SetMaxOutputStreamsAllowed(kMaxOutputStreams);
    279 
    280   // Task must be posted last to avoid races from handing out "this" to the
    281   // audio thread.  Always PostTask even if we're on the right thread since
    282   // AudioManager creation is on the startup path and this may be slow.
    283   GetTaskRunner()->PostTask(FROM_HERE, base::Bind(
    284       &AudioManagerMac::InitializeOnAudioThread, base::Unretained(this)));
    285 }
    286 
    287 AudioManagerMac::~AudioManagerMac() {
    288   if (GetTaskRunner()->BelongsToCurrentThread()) {
    289     ShutdownOnAudioThread();
    290   } else {
    291     // It's safe to post a task here since Shutdown() will wait for all tasks to
    292     // complete before returning.
    293     GetTaskRunner()->PostTask(FROM_HERE, base::Bind(
    294         &AudioManagerMac::ShutdownOnAudioThread, base::Unretained(this)));
    295   }
    296 
    297   Shutdown();
    298 }
    299 
    300 bool AudioManagerMac::HasAudioOutputDevices() {
    301   return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice);
    302 }
    303 
    304 bool AudioManagerMac::HasAudioInputDevices() {
    305   return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
    306 }
    307 
    308 // TODO(xians): There are several places on the OSX specific code which
    309 // could benefit from these helper functions.
    310 bool AudioManagerMac::GetDefaultInputDevice(AudioDeviceID* device) {
    311   return GetDefaultDevice(device, true);
    312 }
    313 
    314 bool AudioManagerMac::GetDefaultOutputDevice(AudioDeviceID* device) {
    315   return GetDefaultDevice(device, false);
    316 }
    317 
    318 bool AudioManagerMac::GetDefaultDevice(AudioDeviceID* device, bool input) {
    319   CHECK(device);
    320 
    321   // Obtain the current output device selected by the user.
    322   AudioObjectPropertyAddress pa;
    323   pa.mSelector = input ? kAudioHardwarePropertyDefaultInputDevice :
    324       kAudioHardwarePropertyDefaultOutputDevice;
    325   pa.mScope = kAudioObjectPropertyScopeGlobal;
    326   pa.mElement = kAudioObjectPropertyElementMaster;
    327 
    328   UInt32 size = sizeof(*device);
    329   OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
    330                                                &pa,
    331                                                0,
    332                                                0,
    333                                                &size,
    334                                                device);
    335 
    336   if ((result != kAudioHardwareNoError) || (*device == kAudioDeviceUnknown)) {
    337     DLOG(ERROR) << "Error getting default AudioDevice.";
    338     return false;
    339   }
    340 
    341   return true;
    342 }
    343 
    344 bool AudioManagerMac::GetDefaultOutputChannels(int* channels) {
    345   AudioDeviceID device;
    346   if (!GetDefaultOutputDevice(&device))
    347     return false;
    348   return GetDeviceChannels(device, kAudioDevicePropertyScopeOutput, channels);
    349 }
    350 
    351 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device,
    352                                         AudioObjectPropertyScope scope,
    353                                         int* channels) {
    354   CHECK(channels);
    355 
    356   // Get stream configuration.
    357   AudioObjectPropertyAddress pa;
    358   pa.mSelector = kAudioDevicePropertyStreamConfiguration;
    359   pa.mScope = scope;
    360   pa.mElement = kAudioObjectPropertyElementMaster;
    361 
    362   UInt32 size;
    363   OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size);
    364   if (result != noErr || !size)
    365     return false;
    366 
    367   // Allocate storage.
    368   scoped_ptr<uint8[]> list_storage(new uint8[size]);
    369   AudioBufferList& buffer_list =
    370       *reinterpret_cast<AudioBufferList*>(list_storage.get());
    371 
    372   result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, &buffer_list);
    373   if (result != noErr)
    374     return false;
    375 
    376   // Determine number of input channels.
    377   int channels_per_frame = buffer_list.mNumberBuffers > 0 ?
    378       buffer_list.mBuffers[0].mNumberChannels : 0;
    379   if (channels_per_frame == 1 && buffer_list.mNumberBuffers > 1) {
    380     // Non-interleaved.
    381     *channels = buffer_list.mNumberBuffers;
    382   } else {
    383     // Interleaved.
    384     *channels = channels_per_frame;
    385   }
    386 
    387   return true;
    388 }
    389 
    390 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) {
    391   Float64 nominal_sample_rate;
    392   UInt32 info_size = sizeof(nominal_sample_rate);
    393 
    394   static const AudioObjectPropertyAddress kNominalSampleRateAddress = {
    395       kAudioDevicePropertyNominalSampleRate,
    396       kAudioObjectPropertyScopeGlobal,
    397       kAudioObjectPropertyElementMaster
    398   };
    399   OSStatus result = AudioObjectGetPropertyData(device_id,
    400                                                &kNominalSampleRateAddress,
    401                                                0,
    402                                                0,
    403                                                &info_size,
    404                                                &nominal_sample_rate);
    405   if (result != noErr) {
    406     OSSTATUS_DLOG(WARNING, result)
    407         << "Could not get default sample rate for device: " << device_id;
    408     return 0;
    409   }
    410 
    411   return static_cast<int>(nominal_sample_rate);
    412 }
    413 
    414 int AudioManagerMac::HardwareSampleRate() {
    415   // Determine the default output device's sample-rate.
    416   AudioDeviceID device_id = kAudioObjectUnknown;
    417   if (!GetDefaultOutputDevice(&device_id))
    418     return kFallbackSampleRate;
    419 
    420   return HardwareSampleRateForDevice(device_id);
    421 }
    422 
    423 void AudioManagerMac::GetAudioInputDeviceNames(
    424     media::AudioDeviceNames* device_names) {
    425   DCHECK(device_names->empty());
    426   GetAudioDeviceInfo(true, device_names);
    427 }
    428 
    429 void AudioManagerMac::GetAudioOutputDeviceNames(
    430     media::AudioDeviceNames* device_names) {
    431   DCHECK(device_names->empty());
    432   GetAudioDeviceInfo(false, device_names);
    433 }
    434 
    435 AudioParameters AudioManagerMac::GetInputStreamParameters(
    436     const std::string& device_id) {
    437   AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id);
    438   if (device == kAudioObjectUnknown) {
    439     DLOG(ERROR) << "Invalid device " << device_id;
    440     return AudioParameters(
    441         AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
    442         kFallbackSampleRate, 16, ChooseBufferSize(true, kFallbackSampleRate));
    443   }
    444 
    445   int channels = 0;
    446   ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
    447   if (GetDeviceChannels(device, kAudioDevicePropertyScopeInput, &channels) &&
    448       channels <= 2) {
    449     channel_layout = GuessChannelLayout(channels);
    450   } else {
    451     DLOG(ERROR) << "Failed to get the device channels, use stereo as default "
    452                 << "for device " << device_id;
    453   }
    454 
    455   int sample_rate = HardwareSampleRateForDevice(device);
    456   if (!sample_rate)
    457     sample_rate = kFallbackSampleRate;
    458 
    459   // Due to the sharing of the input and output buffer sizes, we need to choose
    460   // the input buffer size based on the output sample rate.  See
    461   // http://crbug.com/154352.
    462   const int buffer_size = ChooseBufferSize(true, sample_rate);
    463 
    464   // TODO(xians): query the native channel layout for the specific device.
    465   return AudioParameters(
    466       AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
    467       sample_rate, 16, buffer_size);
    468 }
    469 
    470 std::string AudioManagerMac::GetAssociatedOutputDeviceID(
    471     const std::string& input_device_id) {
    472   AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id);
    473   if (device == kAudioObjectUnknown)
    474     return std::string();
    475 
    476   UInt32 size = 0;
    477   AudioObjectPropertyAddress pa = {
    478     kAudioDevicePropertyRelatedDevices,
    479     kAudioDevicePropertyScopeOutput,
    480     kAudioObjectPropertyElementMaster
    481   };
    482   OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size);
    483   if (result || !size)
    484     return std::string();
    485 
    486   int device_count = size / sizeof(AudioDeviceID);
    487   scoped_ptr<AudioDeviceID, base::FreeDeleter>
    488       devices(static_cast<AudioDeviceID*>(malloc(size)));
    489   result = AudioObjectGetPropertyData(
    490       device, &pa, 0, NULL, &size, devices.get());
    491   if (result)
    492     return std::string();
    493 
    494   std::vector<std::string> associated_devices;
    495   for (int i = 0; i < device_count; ++i) {
    496     // Get the number of  output channels of the device.
    497     pa.mSelector = kAudioDevicePropertyStreams;
    498     size = 0;
    499     result = AudioObjectGetPropertyDataSize(devices.get()[i],
    500                                             &pa,
    501                                             0,
    502                                             NULL,
    503                                             &size);
    504     if (result || !size)
    505       continue;  // Skip if there aren't any output channels.
    506 
    507     // Get device UID.
    508     CFStringRef uid = NULL;
    509     size = sizeof(uid);
    510     pa.mSelector = kAudioDevicePropertyDeviceUID;
    511     result = AudioObjectGetPropertyData(devices.get()[i],
    512                                         &pa,
    513                                         0,
    514                                         NULL,
    515                                         &size,
    516                                         &uid);
    517     if (result || !uid)
    518       continue;
    519 
    520     std::string ret(base::SysCFStringRefToUTF8(uid));
    521     CFRelease(uid);
    522     associated_devices.push_back(ret);
    523   }
    524 
    525   // No matching device found.
    526   if (associated_devices.empty())
    527     return std::string();
    528 
    529   // Return the device if there is only one associated device.
    530   if (associated_devices.size() == 1)
    531     return associated_devices[0];
    532 
    533   // When there are multiple associated devices, we currently do not have a way
    534   // to detect if a device (e.g. a digital output device) is actually connected
    535   // to an endpoint, so we cannot randomly pick a device.
    536   // We pick the device iff the associated device is the default output device.
    537   const std::string default_device = GetDefaultOutputDeviceID();
    538   for (std::vector<std::string>::const_iterator iter =
    539            associated_devices.begin();
    540        iter != associated_devices.end(); ++iter) {
    541     if (default_device == *iter)
    542       return *iter;
    543   }
    544 
    545   // Failed to figure out which is the matching device, return an emtpy string.
    546   return std::string();
    547 }
    548 
    549 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
    550     const AudioParameters& params) {
    551   return MakeLowLatencyOutputStream(params, std::string());
    552 }
    553 
    554 AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
    555     const AudioParameters& params,
    556     const std::string& device_id) {
    557   AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id);
    558   if (device == kAudioObjectUnknown) {
    559     DLOG(ERROR) << "Failed to open output device: " << device_id;
    560     return NULL;
    561   }
    562 
    563   // Lazily create the audio device listener on the first stream creation.
    564   if (!output_device_listener_) {
    565     // NOTE: Use BindToCurrentLoop() to ensure the callback is always PostTask'd
    566     // even if OSX calls us on the right thread.  Some CoreAudio drivers will
    567     // fire the callbacks during stream creation, leading to re-entrancy issues
    568     // otherwise.  See http://crbug.com/349604
    569     output_device_listener_.reset(
    570         new AudioDeviceListenerMac(BindToCurrentLoop(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   AudioOutputStream* stream = new AUHALStream(this, params, device);
    581   output_streams_.push_back(stream);
    582   return stream;
    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   AudioInputStream* stream = new PCMQueueInAudioInputStream(this, params);
    616   input_streams_.push_back(stream);
    617   return stream;
    618 }
    619 
    620 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
    621     const AudioParameters& params, const std::string& device_id) {
    622   DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
    623   // Gets the AudioDeviceID that refers to the AudioInputDevice with the device
    624   // unique id. This AudioDeviceID is used to set the device for Audio Unit.
    625   AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id);
    626   AudioInputStream* stream = NULL;
    627   if (audio_device_id != kAudioObjectUnknown) {
    628     stream = new AUAudioInputStream(this, params, audio_device_id);
    629     input_streams_.push_back(stream);
    630   }
    631 
    632   return stream;
    633 }
    634 
    635 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
    636     const std::string& output_device_id,
    637     const AudioParameters& input_params) {
    638   const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id);
    639   if (device == kAudioObjectUnknown) {
    640     DLOG(ERROR) << "Invalid output device " << output_device_id;
    641     return input_params.IsValid() ? input_params : AudioParameters(
    642         AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
    643         kFallbackSampleRate, 16, ChooseBufferSize(false, kFallbackSampleRate));
    644   }
    645 
    646   const bool has_valid_input_params = input_params.IsValid();
    647   const int hardware_sample_rate = HardwareSampleRateForDevice(device);
    648 
    649   // Allow pass through buffer sizes.  If concurrent input and output streams
    650   // exist, they will use the smallest buffer size amongst them.  As such, each
    651   // stream must be able to FIFO requests appropriately when this happens.
    652   int buffer_size = ChooseBufferSize(false, hardware_sample_rate);
    653   if (has_valid_input_params) {
    654     buffer_size =
    655         std::min(kMaximumInputOutputBufferSize,
    656                  std::max(input_params.frames_per_buffer(), buffer_size));
    657   }
    658 
    659   int hardware_channels;
    660   if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput,
    661                          &hardware_channels)) {
    662     hardware_channels = 2;
    663   }
    664 
    665   // Use the input channel count and channel layout if possible.  Let OSX take
    666   // care of remapping the channels; this lets user specified channel layouts
    667   // work correctly.
    668   int output_channels = input_params.channels();
    669   ChannelLayout channel_layout = input_params.channel_layout();
    670   if (!has_valid_input_params || output_channels > hardware_channels) {
    671     output_channels = hardware_channels;
    672     channel_layout = GuessChannelLayout(output_channels);
    673     if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)
    674       channel_layout = CHANNEL_LAYOUT_DISCRETE;
    675   }
    676 
    677   return AudioParameters(
    678       AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, output_channels,
    679       hardware_sample_rate, 16, buffer_size, AudioParameters::NO_EFFECTS);
    680 }
    681 
    682 void AudioManagerMac::InitializeOnAudioThread() {
    683   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
    684   power_observer_.reset(new AudioPowerObserver());
    685 }
    686 
    687 void AudioManagerMac::ShutdownOnAudioThread() {
    688   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
    689   output_device_listener_.reset();
    690   power_observer_.reset();
    691 
    692   // Since CoreAudio calls have to run on the UI thread and browser shutdown
    693   // doesn't wait for outstanding tasks to complete, we may have input/output
    694   // streams still running at shutdown.
    695   //
    696   // To avoid calls into destructed classes, we need to stop the OS callbacks
    697   // by stopping the streams.  Note: The streams are leaked since process
    698   // destruction is imminent.
    699   //
    700   // See http://crbug.com/354139 for crash details.
    701   StopStreams(&input_streams_);
    702   StopStreams(&output_streams_);
    703 }
    704 
    705 void AudioManagerMac::HandleDeviceChanges() {
    706   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
    707   const int new_sample_rate = HardwareSampleRate();
    708   AudioDeviceID new_output_device;
    709   GetDefaultOutputDevice(&new_output_device);
    710 
    711   if (current_sample_rate_ == new_sample_rate &&
    712       current_output_device_ == new_output_device)
    713     return;
    714 
    715   current_sample_rate_ = new_sample_rate;
    716   current_output_device_ = new_output_device;
    717   NotifyAllOutputDeviceChangeListeners();
    718 }
    719 
    720 int AudioManagerMac::ChooseBufferSize(bool is_input, int sample_rate) {
    721   // kMinimumInputOutputBufferSize is too small for the output side because
    722   // CoreAudio can get into under-run if the renderer fails delivering data
    723   // to the browser within the allowed time by the OS. The workaround is to
    724   // use 256 samples as the default output buffer size for sample rates
    725   // smaller than 96KHz.
    726   // TODO(xians): Remove this workaround after WebAudio supports user defined
    727   // buffer size.  See https://github.com/WebAudio/web-audio-api/issues/348
    728   // for details.
    729   int buffer_size = is_input ?
    730       kMinimumInputOutputBufferSize : 2 * kMinimumInputOutputBufferSize;
    731   const int user_buffer_size = GetUserBufferSize();
    732   if (user_buffer_size) {
    733     buffer_size = user_buffer_size;
    734   } else if (sample_rate > 48000) {
    735     // The default buffer size is too small for higher sample rates and may lead
    736     // to glitching.  Adjust upwards by multiples of the default size.
    737     if (sample_rate <= 96000)
    738       buffer_size = 2 * kMinimumInputOutputBufferSize;
    739     else if (sample_rate <= 192000)
    740       buffer_size = 4 * kMinimumInputOutputBufferSize;
    741   }
    742 
    743   return buffer_size;
    744 }
    745 
    746 bool AudioManagerMac::ShouldDeferStreamStart() {
    747   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
    748   return power_observer_->ShouldDeferStreamStart();
    749 }
    750 
    751 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) {
    752   output_streams_.remove(stream);
    753   AudioManagerBase::ReleaseOutputStream(stream);
    754 }
    755 
    756 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) {
    757   input_streams_.remove(stream);
    758   AudioManagerBase::ReleaseInputStream(stream);
    759 }
    760 
    761 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
    762   return new AudioManagerMac(audio_log_factory);
    763 }
    764 
    765 }  // namespace media
    766