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