Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / audio / mac / audio_manager_mac.cc
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
28 namespace media {
29
30 // Maximum number of output streams that can be open simultaneously.
31 static const int kMaxOutputStreams = 50;
32
33 // Default buffer size in samples for low-latency input and output streams.
34 static const int kDefaultLowLatencyBufferSize = 128;
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_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
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 class 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
262 AudioManagerMac::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
275 AudioManagerMac::~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
288 bool AudioManagerMac::HasAudioOutputDevices() {
289   return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice);
290 }
291
292 bool 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.
298 bool AudioManagerMac::GetDefaultInputDevice(
299     AudioDeviceID* device) {
300   return GetDefaultDevice(device, true);
301 }
302
303 bool AudioManagerMac::GetDefaultOutputDevice(
304     AudioDeviceID* device) {
305   return GetDefaultDevice(device, false);
306 }
307
308 bool 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
337 bool 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
348 bool 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
394 int 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
419 int 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
428 void AudioManagerMac::GetAudioInputDeviceNames(
429     media::AudioDeviceNames* device_names) {
430   DCHECK(device_names->empty());
431   GetAudioDeviceInfo(true, device_names);
432 }
433
434 void AudioManagerMac::GetAudioOutputDeviceNames(
435     media::AudioDeviceNames* device_names) {
436   DCHECK(device_names->empty());
437   GetAudioDeviceInfo(false, device_names);
438 }
439
440 AudioParameters 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
475 std::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
554 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
555     const AudioParameters& params) {
556   return MakeLowLatencyOutputStream(params, std::string());
557 }
558
559 AudioOutputStream* 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
583 std::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
610 AudioInputStream* 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
616 AudioInputStream* 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
641 AudioParameters 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
690 void AudioManagerMac::InitializeOnAudioThread() {
691   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
692   power_observer_.reset(new AudioPowerObserver());
693 }
694
695 void AudioManagerMac::ShutdownOnAudioThread() {
696   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
697   output_device_listener_.reset();
698   power_observer_.reset();
699 }
700
701 void 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
721 int 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
738 bool AudioManagerMac::ShouldDeferOutputStreamStart() {
739   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
740   return power_observer_->ShouldDeferOutputStreamStart();
741 }
742
743 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
744   return new AudioManagerMac(audio_log_factory);
745 }
746
747 }  // namespace media