Upstream version 9.38.198.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/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(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(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(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(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   const int input_channels =
678       has_valid_input_params ? input_params.input_channels() : 0;
679   if (input_channels > 0) {
680     // TODO(xians): given the limitations of the AudioOutputStream
681     // back-ends used with synchronized I/O, we hard-code to stereo.
682     // Specifically, this is a limitation of AudioSynchronizedStream which
683     // can be removed as part of the work to consolidate these back-ends.
684     channel_layout = CHANNEL_LAYOUT_STEREO;
685   }
686
687   return AudioParameters(
688       AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, output_channels,
689       input_channels, hardware_sample_rate, 16, buffer_size,
690       AudioParameters::NO_EFFECTS);
691 }
692
693 void AudioManagerMac::InitializeOnAudioThread() {
694   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
695   power_observer_.reset(new AudioPowerObserver());
696 }
697
698 void AudioManagerMac::ShutdownOnAudioThread() {
699   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
700   output_device_listener_.reset();
701   power_observer_.reset();
702
703   // Since CoreAudio calls have to run on the UI thread and browser shutdown
704   // doesn't wait for outstanding tasks to complete, we may have input/output
705   // streams still running at shutdown.
706   //
707   // To avoid calls into destructed classes, we need to stop the OS callbacks
708   // by stopping the streams.  Note: The streams are leaked since process
709   // destruction is imminent.
710   //
711   // See http://crbug.com/354139 for crash details.
712   StopStreams(&input_streams_);
713   StopStreams(&output_streams_);
714 }
715
716 void AudioManagerMac::HandleDeviceChanges() {
717   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
718   const int new_sample_rate = HardwareSampleRate();
719   AudioDeviceID new_output_device;
720   GetDefaultOutputDevice(&new_output_device);
721
722   if (current_sample_rate_ == new_sample_rate &&
723       current_output_device_ == new_output_device)
724     return;
725
726   current_sample_rate_ = new_sample_rate;
727   current_output_device_ = new_output_device;
728   NotifyAllOutputDeviceChangeListeners();
729 }
730
731 int AudioManagerMac::ChooseBufferSize(int output_sample_rate) {
732   int buffer_size = kMinimumInputOutputBufferSize;
733   const int user_buffer_size = GetUserBufferSize();
734   if (user_buffer_size) {
735     buffer_size = user_buffer_size;
736   } else if (output_sample_rate > 48000) {
737     // The default buffer size is too small for higher sample rates and may lead
738     // to glitching.  Adjust upwards by multiples of the default size.
739     if (output_sample_rate <= 96000)
740       buffer_size = 2 * kMinimumInputOutputBufferSize;
741     else if (output_sample_rate <= 192000)
742       buffer_size = 4 * kMinimumInputOutputBufferSize;
743   }
744
745   return buffer_size;
746 }
747
748 bool AudioManagerMac::ShouldDeferStreamStart() {
749   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
750   return power_observer_->ShouldDeferStreamStart();
751 }
752
753 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) {
754   output_streams_.remove(stream);
755   AudioManagerBase::ReleaseOutputStream(stream);
756 }
757
758 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) {
759   input_streams_.remove(stream);
760   AudioManagerBase::ReleaseInputStream(stream);
761 }
762
763 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
764   return new AudioManagerMac(audio_log_factory);
765 }
766
767 }  // namespace media