Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Side by Side Diff: media/audio/mac/audio_manager_mac.cc

Issue 12387006: Pass more detailed audio hardware configuration information to the renderer (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/mac/audio_manager_mac.h" 5 #include "media/audio/mac/audio_manager_mac.h"
6 6
7 #include <CoreAudio/AudioHardware.h> 7 #include <CoreAudio/AudioHardware.h>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/mac/mac_logging.h" 12 #include "base/mac/mac_logging.h"
13 #include "base/mac/scoped_cftyperef.h" 13 #include "base/mac/scoped_cftyperef.h"
14 #include "base/sys_string_conversions.h" 14 #include "base/sys_string_conversions.h"
15 #include "media/audio/audio_parameters.h" 15 #include "media/audio/audio_parameters.h"
16 #include "media/audio/mac/audio_input_mac.h" 16 #include "media/audio/mac/audio_input_mac.h"
17 #include "media/audio/mac/audio_low_latency_input_mac.h" 17 #include "media/audio/mac/audio_low_latency_input_mac.h"
18 #include "media/audio/mac/audio_low_latency_output_mac.h" 18 #include "media/audio/mac/audio_low_latency_output_mac.h"
19 #include "media/audio/mac/audio_output_mac.h" 19 #include "media/audio/mac/audio_output_mac.h"
20 #include "media/audio/mac/audio_synchronized_mac.h" 20 #include "media/audio/mac/audio_synchronized_mac.h"
21 #include "media/audio/mac/audio_unified_mac.h" 21 #include "media/audio/mac/audio_unified_mac.h"
22 #include "media/base/bind_to_loop.h" 22 #include "media/base/bind_to_loop.h"
23 #include "media/base/channel_layout.h" 23 #include "media/base/channel_layout.h"
24 #include "media/base/limits.h" 24 #include "media/base/limits.h"
25 #include "media/base/media_switches.h" 25 #include "media/base/media_switches.h"
26 #include "media/ffmpeg/ffmpeg_common.h"
DaleCurtis 2013/03/07 02:41:39 You can't include this here which is why I said th
Chris Rogers 2013/03/09 01:37:50 Ah I didn't understand what you had meant before -
26 27
27 namespace media { 28 namespace media {
28 29
29 // Maximum number of output streams that can be open simultaneously. 30 // Maximum number of output streams that can be open simultaneously.
30 static const int kMaxOutputStreams = 50; 31 static const int kMaxOutputStreams = 50;
31 32
32 // Default buffer size in samples for low-latency input and output streams. 33 // Default buffer size in samples for low-latency input and output streams.
33 static const int kDefaultLowLatencyBufferSize = 128; 34 static const int kDefaultLowLatencyBufferSize = 128;
34 35
35 static bool HasAudioHardware(AudioObjectPropertySelector selector) { 36 static bool HasAudioHardware(AudioObjectPropertySelector selector) {
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 } 257 }
257 258
258 bool AudioManagerMac::HasAudioOutputDevices() { 259 bool AudioManagerMac::HasAudioOutputDevices() {
259 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); 260 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice);
260 } 261 }
261 262
262 bool AudioManagerMac::HasAudioInputDevices() { 263 bool AudioManagerMac::HasAudioInputDevices() {
263 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); 264 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
264 } 265 }
265 266
267 // TODO(crogers): There are several places on the OSX specific code which
268 // could benefit from this helper function.
269 bool AudioManagerMac::GetDefaultOutputDevice(
270 AudioDeviceID* device) {
271 if (!device)
DaleCurtis 2013/03/07 02:41:39 CHECK().
Chris Rogers 2013/03/09 01:37:50 Done.
272 return false;
273
274 // Obtain the current output device selected by the user.
275 AudioObjectPropertyAddress pa;
DaleCurtis 2013/03/07 02:41:39 static const this like: static const AudioObject
Chris Rogers 2013/03/09 01:37:50 Done.
276 pa.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
277 pa.mScope = kAudioObjectPropertyScopeGlobal;
278 pa.mElement = kAudioObjectPropertyElementMaster;
279
280 UInt32 size = sizeof(*device);
281
282 OSStatus result = AudioObjectGetPropertyData(
283 kAudioObjectSystemObject,
284 &pa,
285 0,
286 0,
287 &size,
288 device);
289
290 if ((result != kAudioHardwareNoError) || (*device == kAudioDeviceUnknown)) {
291 LOG(ERROR) << "Error getting default output AudioDevice.";
DaleCurtis 2013/03/07 02:41:39 DLOG?
Chris Rogers 2013/03/09 01:37:50 Done.
292 return false;
293 }
294
295 return true;
296 }
297
298 bool AudioManagerMac::GetDefaultOutputChannels(
299 int* channels, int* channels_per_frame) {
300 AudioDeviceID device;
301 if (!GetDefaultOutputDevice(&device))
302 return false;
303
304 return GetDeviceChannels(device,
305 kAudioDevicePropertyScopeOutput,
306 channels,
307 channels_per_frame);
308 }
309
310 bool AudioManagerMac::GetDeviceChannels(
311 AudioDeviceID device,
312 AudioObjectPropertyScope scope,
313 int* channels,
314 int* channels_per_frame) {
DaleCurtis 2013/03/07 02:41:39 Nothing seems to be using this? Drop for now?
Chris Rogers 2013/03/09 01:37:50 It will soon be using it (AudioHardwareUnifiedStre
315 if (!channels || !channels_per_frame)
DaleCurtis 2013/03/07 02:41:39 these should be CHECK().
Chris Rogers 2013/03/09 01:37:50 Done.
316 return false;
317
318 // Get stream configuration.
319 AudioObjectPropertyAddress pa;
DaleCurtis 2013/03/07 02:41:39 Same static const comment.
Chris Rogers 2013/03/09 01:37:50 It can't be static const because the scope is set
320 pa.mSelector = kAudioDevicePropertyStreamConfiguration;
321 pa.mScope = scope;
322 pa.mElement = kAudioObjectPropertyElementMaster;
323
324 UInt32 size;
325 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size);
326 OSSTATUS_DCHECK(result == noErr, result);
DaleCurtis 2013/03/07 02:41:39 Don't DCHECK, this should just return false.
Chris Rogers 2013/03/09 01:37:50 Done.
327
328 if (result == noErr && size > 0) {
DaleCurtis 2013/03/07 02:41:39 early return instead of indenting the entire next
Chris Rogers 2013/03/09 01:37:50 Done.
329 // Allocate storage.
330 scoped_array<uint8> list_storage(new uint8[size]);
331 AudioBufferList& buffer_list =
332 *reinterpret_cast<AudioBufferList*>(list_storage.get());
333
334 result = AudioObjectGetPropertyData(
335 device,
336 &pa,
337 0,
338 0,
339 &size,
340 &buffer_list);
341 OSSTATUS_DCHECK(result == noErr, result);
DaleCurtis 2013/03/07 02:41:39 Ditto.
Chris Rogers 2013/03/09 01:37:50 Done.
342
343 if (result == noErr) {
344 // Determine number of input channels.
345 *channels_per_frame = buffer_list.mNumberBuffers > 0 ?
346 buffer_list.mBuffers[0].mNumberChannels : 0;
347 if (*channels_per_frame == 1 && buffer_list.mNumberBuffers > 1) {
348 // Non-interleaved.
349 *channels = buffer_list.mNumberBuffers;
350 } else {
351 // Interleaved.
352 *channels = *channels_per_frame;
353 }
354 }
355 }
356
357 return result == noErr;
358 }
359
266 void AudioManagerMac::GetAudioInputDeviceNames( 360 void AudioManagerMac::GetAudioInputDeviceNames(
267 media::AudioDeviceNames* device_names) { 361 media::AudioDeviceNames* device_names) {
268 GetAudioDeviceInfo(true, device_names); 362 GetAudioDeviceInfo(true, device_names);
269 if (!device_names->empty()) { 363 if (!device_names->empty()) {
270 // Prepend the default device to the list since we always want it to be 364 // Prepend the default device to the list since we always want it to be
271 // on the top of the list for all platforms. There is no duplicate 365 // on the top of the list for all platforms. There is no duplicate
272 // counting here since the default device has been abstracted out before. 366 // counting here since the default device has been abstracted out before.
273 media::AudioDeviceName name; 367 media::AudioDeviceName name;
274 name.device_name = AudioManagerBase::kDefaultDeviceName; 368 name.device_name = AudioManagerBase::kDefaultDeviceName;
275 name.unique_id = AudioManagerBase::kDefaultDeviceId; 369 name.unique_id = AudioManagerBase::kDefaultDeviceId;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); 423 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id);
330 AudioInputStream* stream = NULL; 424 AudioInputStream* stream = NULL;
331 if (audio_device_id != kAudioObjectUnknown) 425 if (audio_device_id != kAudioObjectUnknown)
332 stream = new AUAudioInputStream(this, params, audio_device_id); 426 stream = new AUAudioInputStream(this, params, audio_device_id);
333 427
334 return stream; 428 return stream;
335 } 429 }
336 430
337 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( 431 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
338 const AudioParameters& input_params) { 432 const AudioParameters& input_params) {
339 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 433 int hardware_channels = 2;
434 int hardware_channels_per_frame;
435 GetDefaultOutputChannels(&hardware_channels, &hardware_channels_per_frame);
436
437 ChannelLayout channel_layout = GuessChannelLayout(hardware_channels);
DaleCurtis 2013/03/07 02:41:39 Hmm, this isn't what I thought you wanted. This wi
Chris Rogers 2013/03/09 01:37:50 Actually, I'm just being consistent with the Audio
438
340 int input_channels = 0; 439 int input_channels = 0;
341 if (input_params.IsValid()) { 440 if (input_params.IsValid()) {
342 channel_layout = input_params.channel_layout();
343 input_channels = input_params.input_channels(); 441 input_channels = input_params.input_channels();
344 442
345 if (CommandLine::ForCurrentProcess()->HasSwitch( 443 if (CommandLine::ForCurrentProcess()->HasSwitch(
346 switches::kEnableWebAudioInput)) { 444 switches::kEnableWebAudioInput)) {
347 // TODO(crogers): given the limitations of the AudioOutputStream 445 // TODO(crogers): given the limitations of the AudioOutputStream
348 // back-ends used with kEnableWebAudioInput, we hard-code to stereo. 446 // back-ends used with kEnableWebAudioInput, we hard-code to stereo.
349 // Specifically, this is a limitation of AudioSynchronizedStream which 447 // Specifically, this is a limitation of AudioSynchronizedStream which
350 // can be removed as part of the work to consolidate these back-ends. 448 // can be removed as part of the work to consolidate these back-ends.
351 channel_layout = CHANNEL_LAYOUT_STEREO; 449 channel_layout = CHANNEL_LAYOUT_STEREO;
352 } 450 }
353 } 451 }
354 452
355 return AudioParameters( 453 AudioParameters params(
356 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, 454 AudioParameters::AUDIO_PCM_LOW_LATENCY,
357 AUAudioOutputStream::HardwareSampleRate(), 16, 455 channel_layout,
456 input_channels,
457 AUAudioOutputStream::HardwareSampleRate(),
458 16,
358 kDefaultLowLatencyBufferSize); 459 kDefaultLowLatencyBufferSize);
460
461 if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)
DaleCurtis 2013/03/07 02:41:39 DISCRETE?
Chris Rogers 2013/03/09 01:37:50 Actually, I think that's right because GuessChanne
462 params.SetDiscreteChannels(hardware_channels);
463
464 return params;
359 } 465 }
360 466
361 void AudioManagerMac::CreateDeviceListener() { 467 void AudioManagerMac::CreateDeviceListener() {
362 DCHECK(GetMessageLoop()->BelongsToCurrentThread()); 468 DCHECK(GetMessageLoop()->BelongsToCurrentThread());
363 output_device_listener_.reset(new AudioDeviceListenerMac(base::Bind( 469 output_device_listener_.reset(new AudioDeviceListenerMac(base::Bind(
364 &AudioManagerMac::DelayedDeviceChange, base::Unretained(this)))); 470 &AudioManagerMac::DelayedDeviceChange, base::Unretained(this))));
365 } 471 }
366 472
367 void AudioManagerMac::DestroyDeviceListener() { 473 void AudioManagerMac::DestroyDeviceListener() {
368 DCHECK(GetMessageLoop()->BelongsToCurrentThread()); 474 DCHECK(GetMessageLoop()->BelongsToCurrentThread());
369 output_device_listener_.reset(); 475 output_device_listener_.reset();
370 } 476 }
371 477
372 void AudioManagerMac::DelayedDeviceChange() { 478 void AudioManagerMac::DelayedDeviceChange() {
373 // TODO(dalecurtis): This is ridiculous, but we need to delay device changes 479 // TODO(dalecurtis): This is ridiculous, but we need to delay device changes
374 // to workaround threading issues with OSX property listener callbacks. See 480 // to workaround threading issues with OSX property listener callbacks. See
375 // http://crbug.com/158170 481 // http://crbug.com/158170
376 GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind( 482 GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind(
377 &AudioManagerMac::NotifyAllOutputDeviceChangeListeners, 483 &AudioManagerMac::NotifyAllOutputDeviceChangeListeners,
378 base::Unretained(this)), base::TimeDelta::FromSeconds(2)); 484 base::Unretained(this)), base::TimeDelta::FromSeconds(2));
379 } 485 }
380 486
381 AudioManager* CreateAudioManager() { 487 AudioManager* CreateAudioManager() {
382 return new AudioManagerMac(); 488 return new AudioManagerMac();
383 } 489 }
384 490
385 } // namespace media 491 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698