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

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

Issue 23533045: Implement GetDefaultOutputDeviceID, GetAssociatedOutputDeviceID and ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix apparent sdk build problem Created 7 years, 3 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
« no previous file with comments | « media/audio/mac/audio_manager_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 const std::string& device_id) { 179 const std::string& device_id) {
180 AudioObjectPropertyAddress property_address = { 180 AudioObjectPropertyAddress property_address = {
181 kAudioHardwarePropertyDevices, 181 kAudioHardwarePropertyDevices,
182 kAudioObjectPropertyScopeGlobal, 182 kAudioObjectPropertyScopeGlobal,
183 kAudioObjectPropertyElementMaster 183 kAudioObjectPropertyElementMaster
184 }; 184 };
185 AudioDeviceID audio_device_id = kAudioObjectUnknown; 185 AudioDeviceID audio_device_id = kAudioObjectUnknown;
186 UInt32 device_size = sizeof(audio_device_id); 186 UInt32 device_size = sizeof(audio_device_id);
187 OSStatus result = -1; 187 OSStatus result = -1;
188 188
189 if (device_id == AudioManagerBase::kDefaultDeviceId) { 189 if (device_id == AudioManagerBase::kDefaultDeviceId || device_id.empty()) {
190 // Default Device. 190 // Default Device.
191 property_address.mSelector = is_input ? 191 property_address.mSelector = is_input ?
192 kAudioHardwarePropertyDefaultInputDevice : 192 kAudioHardwarePropertyDefaultInputDevice :
193 kAudioHardwarePropertyDefaultOutputDevice; 193 kAudioHardwarePropertyDefaultOutputDevice;
194 194
195 result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 195 result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
196 &property_address, 196 &property_address,
197 0, 197 0,
198 0, 198 0,
199 &device_size, 199 &device_size,
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 } 253 }
254 254
255 bool AudioManagerMac::HasAudioOutputDevices() { 255 bool AudioManagerMac::HasAudioOutputDevices() {
256 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); 256 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice);
257 } 257 }
258 258
259 bool AudioManagerMac::HasAudioInputDevices() { 259 bool AudioManagerMac::HasAudioInputDevices() {
260 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); 260 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
261 } 261 }
262 262
263 // TODO(crogers): There are several places on the OSX specific code which 263 // TODO(xians): There are several places on the OSX specific code which
264 // could benefit from these helper functions. 264 // could benefit from these helper functions.
265 bool AudioManagerMac::GetDefaultInputDevice( 265 bool AudioManagerMac::GetDefaultInputDevice(
266 AudioDeviceID* device) { 266 AudioDeviceID* device) {
267 return GetDefaultDevice(device, true); 267 return GetDefaultDevice(device, true);
268 } 268 }
269 269
270 bool AudioManagerMac::GetDefaultOutputDevice( 270 bool AudioManagerMac::GetDefaultOutputDevice(
271 AudioDeviceID* device) { 271 AudioDeviceID* device) {
272 return GetDefaultDevice(device, false); 272 return GetDefaultDevice(device, false);
273 } 273 }
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 int sample_rate = HardwareSampleRateForDevice(device); 434 int sample_rate = HardwareSampleRateForDevice(device);
435 if (!sample_rate) 435 if (!sample_rate)
436 sample_rate = kFallbackSampleRate; 436 sample_rate = kFallbackSampleRate;
437 437
438 // TODO(xians): query the native channel layout for the specific device. 438 // TODO(xians): query the native channel layout for the specific device.
439 return AudioParameters( 439 return AudioParameters(
440 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 440 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
441 sample_rate, 16, buffer_size); 441 sample_rate, 16, buffer_size);
442 } 442 }
443 443
444 std::string AudioManagerMac::GetAssociatedOutputDeviceID(
445 const std::string& input_device_id) {
446 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id);
447 if (device == kAudioObjectUnknown)
448 return std::string();
449
450 UInt32 size = 0;
451 AudioObjectPropertyAddress pa = {
452 kAudioDevicePropertyRelatedDevices,
453 kAudioDevicePropertyScopeOutput,
454 kAudioObjectPropertyElementMaster
455 };
456 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size);
457 if (result || !size)
458 return std::string();
459
460 int device_count = size / sizeof(AudioDeviceID);
461 scoped_ptr_malloc<AudioDeviceID>
462 devices(reinterpret_cast<AudioDeviceID*>(malloc(size)));
463 result = AudioObjectGetPropertyData(
464 device, &pa, 0, NULL, &size, devices.get());
465 if (result)
466 return std::string();
467
468 for (int i = 0; i < device_count; ++i) {
469 // Get the number of output channels of the device.
470 pa.mSelector = kAudioDevicePropertyStreams;
471 size = 0;
472 result = AudioObjectGetPropertyDataSize(devices.get()[i],
473 &pa,
474 0,
475 NULL,
476 &size);
477 if (result || !size)
478 continue; // Skip if there aren't any output channels.
479
480 // Get device UID.
481 CFStringRef uid = NULL;
482 size = sizeof(uid);
483 pa.mSelector = kAudioDevicePropertyDeviceUID;
484 result = AudioObjectGetPropertyData(devices.get()[i],
485 &pa,
486 0,
487 NULL,
488 &size,
489 &uid);
490 if (result || !uid)
491 continue;
492
493 std::string ret(base::SysCFStringRefToUTF8(uid));
494 CFRelease(uid);
495 return ret;
496 }
497
498 // No matching device found.
499 return std::string();
500 }
501
444 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( 502 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
445 const AudioParameters& params) { 503 const AudioParameters& params) {
446 return MakeLowLatencyOutputStream(params, std::string(), std::string()); 504 return MakeLowLatencyOutputStream(params, std::string(), std::string());
447 } 505 }
448 506
449 AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( 507 AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
450 const AudioParameters& params, 508 const AudioParameters& params,
451 const std::string& device_id, 509 const std::string& device_id,
452 const std::string& input_device_id) { 510 const std::string& input_device_id) {
453 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
454 // Handle basic output with no input channels. 511 // Handle basic output with no input channels.
455 if (params.input_channels() == 0) { 512 if (params.input_channels() == 0) {
456 AudioDeviceID device = kAudioObjectUnknown; 513 AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id);
457 GetDefaultOutputDevice(&device); 514 if (device == kAudioObjectUnknown) {
515 DLOG(ERROR) << "Failed to open output device: " << device_id;
516 return NULL;
517 }
458 return new AUHALStream(this, params, device); 518 return new AUHALStream(this, params, device);
459 } 519 }
460 520
461 // TODO(crogers): support more than stereo input. 521 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
522
523 // TODO(xians): support more than stereo input.
462 if (params.input_channels() != 2) { 524 if (params.input_channels() != 2) {
463 // WebAudio is currently hard-coded to 2 channels so we should not 525 // WebAudio is currently hard-coded to 2 channels so we should not
464 // see this case. 526 // see this case.
465 NOTREACHED() << "Only stereo input is currently supported!"; 527 NOTREACHED() << "Only stereo input is currently supported!";
466 return NULL; 528 return NULL;
467 } 529 }
468 530
469 AudioDeviceID device = kAudioObjectUnknown; 531 AudioDeviceID device = kAudioObjectUnknown;
470 if (HasUnifiedDefaultIO()) { 532 if (HasUnifiedDefaultIO()) {
471 // For I/O, the simplest case is when the default input and output 533 // For I/O, the simplest case is when the default input and output
(...skipping 16 matching lines...) Expand all
488 } 550 }
489 551
490 if (device != kAudioObjectUnknown && 552 if (device != kAudioObjectUnknown &&
491 input_device_id == AudioManagerBase::kDefaultDeviceId) 553 input_device_id == AudioManagerBase::kDefaultDeviceId)
492 return new AUHALStream(this, params, device); 554 return new AUHALStream(this, params, device);
493 555
494 // Fallback to AudioSynchronizedStream which will handle completely 556 // Fallback to AudioSynchronizedStream which will handle completely
495 // different and arbitrary combinations of input and output devices 557 // different and arbitrary combinations of input and output devices
496 // even running at different sample-rates. 558 // even running at different sample-rates.
497 // kAudioDeviceUnknown translates to "use default" here. 559 // kAudioDeviceUnknown translates to "use default" here.
498 // TODO(crogers): consider tracking UMA stats on AUHALStream 560 // TODO(xians): consider tracking UMA stats on AUHALStream
499 // versus AudioSynchronizedStream. 561 // versus AudioSynchronizedStream.
500 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, input_device_id); 562 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, input_device_id);
501 if (audio_device_id == kAudioObjectUnknown) 563 if (audio_device_id == kAudioObjectUnknown)
502 return NULL; 564 return NULL;
503 565
504 return new AudioSynchronizedStream(this, 566 return new AudioSynchronizedStream(this,
505 params, 567 params,
506 audio_device_id, 568 audio_device_id,
507 kAudioDeviceUnknown); 569 kAudioDeviceUnknown);
508 } 570 }
509 571
572 std::string AudioManagerMac::GetDefaultOutputDeviceID() {
573 AudioDeviceID device_id = kAudioObjectUnknown;
574 if (!GetDefaultOutputDevice(&device_id))
575 return std::string();
576
577 const AudioObjectPropertyAddress property_address = {
578 kAudioDevicePropertyDeviceUID,
579 kAudioObjectPropertyScopeGlobal,
580 kAudioObjectPropertyElementMaster
581 };
582 CFStringRef device_uid = NULL;
583 UInt32 size = sizeof(device_uid);
584 OSStatus status = AudioObjectGetPropertyData(device_id,
585 &property_address,
586 0,
587 NULL,
588 &size,
589 &device_uid);
590 if (status != kAudioHardwareNoError || !device_uid)
591 return std::string();
592
593 std::string ret(base::SysCFStringRefToUTF8(device_uid));
594 CFRelease(device_uid);
595
596 return ret;
597 }
598
510 AudioInputStream* AudioManagerMac::MakeLinearInputStream( 599 AudioInputStream* AudioManagerMac::MakeLinearInputStream(
511 const AudioParameters& params, const std::string& device_id) { 600 const AudioParameters& params, const std::string& device_id) {
512 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 601 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
513 return new PCMQueueInAudioInputStream(this, params); 602 return new PCMQueueInAudioInputStream(this, params);
514 } 603 }
515 604
516 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( 605 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
517 const AudioParameters& params, const std::string& device_id) { 606 const AudioParameters& params, const std::string& device_id) {
518 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 607 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
519 // Gets the AudioDeviceID that refers to the AudioOutputDevice with the device 608 // Gets the AudioDeviceID that refers to the AudioInputDevice with the device
520 // unique id. This AudioDeviceID is used to set the device for Audio Unit. 609 // unique id. This AudioDeviceID is used to set the device for Audio Unit.
521 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); 610 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id);
522 AudioInputStream* stream = NULL; 611 AudioInputStream* stream = NULL;
523 if (audio_device_id != kAudioObjectUnknown) 612 if (audio_device_id != kAudioObjectUnknown) {
524 stream = new AUAudioInputStream(this, params, audio_device_id); 613 // AUAudioInputStream needs to be fed the preferred audio output parameters
614 // of the matching device so that the buffer size of both input and output
615 // can be matched. See constructor of AUAudioInputStream for more.
616 const std::string associated_output_device(
617 GetAssociatedOutputDeviceID(device_id));
618 const AudioParameters output_params =
619 GetPreferredOutputStreamParameters(
620 associated_output_device.empty() ?
621 AudioManagerBase::kDefaultDeviceId : associated_output_device,
622 params);
623 stream = new AUAudioInputStream(this, params, output_params,
624 audio_device_id);
625 }
525 626
526 return stream; 627 return stream;
527 } 628 }
528 629
529 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( 630 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
530 const std::string& output_device_id, 631 const std::string& output_device_id,
531 const AudioParameters& input_params) { 632 const AudioParameters& input_params) {
532 // TODO(tommi): Support |output_device_id|. 633 AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id);
533 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; 634 if (device == kAudioObjectUnknown) {
635 DLOG(ERROR) << "Invalid output device " << output_device_id;
636 return AudioParameters();
637 }
638
534 int hardware_channels = 2; 639 int hardware_channels = 2;
535 if (!GetDefaultOutputChannels(&hardware_channels)) { 640 if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput,
641 &hardware_channels)) {
536 // Fallback to stereo. 642 // Fallback to stereo.
537 hardware_channels = 2; 643 hardware_channels = 2;
538 } 644 }
539 645
540 ChannelLayout channel_layout = GuessChannelLayout(hardware_channels); 646 ChannelLayout channel_layout = GuessChannelLayout(hardware_channels);
541 647
542 const int hardware_sample_rate = AUAudioOutputStream::HardwareSampleRate(); 648 const int hardware_sample_rate = HardwareSampleRateForDevice(device);
543 const int buffer_size = ChooseBufferSize(hardware_sample_rate); 649 const int buffer_size = ChooseBufferSize(hardware_sample_rate);
544 650
545 int input_channels = 0; 651 int input_channels = 0;
546 if (input_params.IsValid()) { 652 if (input_params.IsValid()) {
547 input_channels = input_params.input_channels(); 653 input_channels = input_params.input_channels();
548 654
549 if (input_channels > 0) { 655 if (input_channels > 0) {
550 // TODO(crogers): given the limitations of the AudioOutputStream 656 // TODO(xians): given the limitations of the AudioOutputStream
551 // back-ends used with synchronized I/O, we hard-code to stereo. 657 // back-ends used with synchronized I/O, we hard-code to stereo.
552 // Specifically, this is a limitation of AudioSynchronizedStream which 658 // Specifically, this is a limitation of AudioSynchronizedStream which
553 // can be removed as part of the work to consolidate these back-ends. 659 // can be removed as part of the work to consolidate these back-ends.
554 channel_layout = CHANNEL_LAYOUT_STEREO; 660 channel_layout = CHANNEL_LAYOUT_STEREO;
555 } 661 }
556 } 662 }
557 663
558 AudioParameters params( 664 AudioParameters params(
559 AudioParameters::AUDIO_PCM_LOW_LATENCY, 665 AudioParameters::AUDIO_PCM_LOW_LATENCY,
560 channel_layout, 666 channel_layout,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 current_sample_rate_ = new_sample_rate; 711 current_sample_rate_ = new_sample_rate;
606 current_output_device_ = new_output_device; 712 current_output_device_ = new_output_device;
607 NotifyAllOutputDeviceChangeListeners(); 713 NotifyAllOutputDeviceChangeListeners();
608 } 714 }
609 715
610 AudioManager* CreateAudioManager() { 716 AudioManager* CreateAudioManager() {
611 return new AudioManagerMac(); 717 return new AudioManagerMac();
612 } 718 }
613 719
614 } // namespace media 720 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/mac/audio_manager_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698