OLD | NEW |
---|---|
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 Loading... | |
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 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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, | |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
Guess thus guy is the key here. Nice.
| |
453 kAudioObjectPropertyScopeOutput, | |
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))); | |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
I always hesitate to use reinterpret; you don't ;-
tommi (sloooow) - chröme
2013/09/08 19:11:19
Not when it's the right thing to do ;)
| |
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], | |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
Nit, I did clang-format on my latest CL and I thin
tommi (sloooow) - chröme
2013/09/08 19:11:19
This is fine style-wize and consistent with all ot
| |
473 &pa, | |
474 0, | |
475 NULL, | |
476 &size); | |
477 if (result || !size) | |
478 continue; // Skip if there aren't any output channels. | |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
Don't we have methods to detect number of output d
tommi (sloooow) - chröme
2013/09/08 19:11:19
See line 453 where the "scope" is set to output.
W
| |
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)); | |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
What does these IDs look like?
tommi (sloooow) - chröme
2013/09/08 19:11:19
Here's an example of a USB device I tested with:
i
| |
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!"; | 511 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
500 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, input_device_id); | 558 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, input_device_id); |
501 if (audio_device_id == kAudioObjectUnknown) | 559 if (audio_device_id == kAudioObjectUnknown) |
502 return NULL; | 560 return NULL; |
503 | 561 |
504 return new AudioSynchronizedStream(this, | 562 return new AudioSynchronizedStream(this, |
505 params, | 563 params, |
506 audio_device_id, | 564 audio_device_id, |
507 kAudioDeviceUnknown); | 565 kAudioDeviceUnknown); |
508 } | 566 } |
509 | 567 |
568 std::string AudioManagerMac::GetDefaultOutputDeviceID() { | |
569 AudioDeviceID device_id = kAudioObjectUnknown; | |
570 if (!GetDefaultOutputDevice(&device_id)) | |
571 return std::string(); | |
572 | |
573 const AudioObjectPropertyAddress property_address = { | |
574 kAudioDevicePropertyDeviceUID, | |
575 kAudioObjectPropertyScopeGlobal, | |
576 kAudioObjectPropertyElementMaster | |
577 }; | |
578 CFStringRef device_uid = NULL; | |
579 UInt32 size = sizeof(device_uid); | |
580 OSStatus status = AudioObjectGetPropertyData(device_id, &property_address, 0, | |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
Different style than above ;-)
tommi (sloooow) - chröme
2013/09/08 19:11:19
Fixed.
| |
581 NULL, &size, &device_uid); | |
582 if (status != kAudioHardwareNoError || !device_uid) | |
583 return std::string(); | |
584 | |
585 std::string ret(base::SysCFStringRefToUTF8(device_uid)); | |
586 CFRelease(device_uid); | |
587 | |
588 return ret; | |
589 } | |
590 | |
510 AudioInputStream* AudioManagerMac::MakeLinearInputStream( | 591 AudioInputStream* AudioManagerMac::MakeLinearInputStream( |
511 const AudioParameters& params, const std::string& device_id) { | 592 const AudioParameters& params, const std::string& device_id) { |
512 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); | 593 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
513 return new PCMQueueInAudioInputStream(this, params); | 594 return new PCMQueueInAudioInputStream(this, params); |
514 } | 595 } |
515 | 596 |
516 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( | 597 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( |
517 const AudioParameters& params, const std::string& device_id) { | 598 const AudioParameters& params, const std::string& device_id) { |
518 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); | 599 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
519 // Gets the AudioDeviceID that refers to the AudioOutputDevice with the device | 600 // Gets the AudioDeviceID that refers to the AudioOutputDevice with the device |
520 // unique id. This AudioDeviceID is used to set the device for Audio Unit. | 601 // unique id. This AudioDeviceID is used to set the device for Audio Unit. |
521 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); | 602 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); |
522 AudioInputStream* stream = NULL; | 603 AudioInputStream* stream = NULL; |
523 if (audio_device_id != kAudioObjectUnknown) | 604 if (audio_device_id != kAudioObjectUnknown) |
524 stream = new AUAudioInputStream(this, params, audio_device_id); | 605 stream = new AUAudioInputStream(this, params, audio_device_id); |
525 | 606 |
526 return stream; | 607 return stream; |
527 } | 608 } |
528 | 609 |
529 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( | 610 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( |
530 const std::string& output_device_id, | 611 const std::string& output_device_id, |
531 const AudioParameters& input_params) { | 612 const AudioParameters& input_params) { |
532 // TODO(tommi): Support |output_device_id|. | 613 AudioDeviceID device = GetAudioDeviceIdByUId(true, output_device_id); |
533 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; | 614 if (device == kAudioObjectUnknown) { |
615 DLOG(ERROR) << "Invalid device " << output_device_id; | |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
I would say Invalid output device just in case
tommi (sloooow) - chröme
2013/09/08 19:11:19
Done.
| |
616 return AudioParameters(); | |
617 } | |
618 | |
534 int hardware_channels = 2; | 619 int hardware_channels = 2; |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
Don't understand this "fallback" scheme. Do you?
tommi (sloooow) - chröme
2013/09/08 19:11:19
Not really. I guess there must be a case where we
| |
535 if (!GetDefaultOutputChannels(&hardware_channels)) { | 620 if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput, |
621 &hardware_channels)) { | |
536 // Fallback to stereo. | 622 // Fallback to stereo. |
537 hardware_channels = 2; | 623 hardware_channels = 2; |
538 } | 624 } |
539 | 625 |
540 ChannelLayout channel_layout = GuessChannelLayout(hardware_channels); | 626 ChannelLayout channel_layout = GuessChannelLayout(hardware_channels); |
541 | 627 |
542 const int hardware_sample_rate = AUAudioOutputStream::HardwareSampleRate(); | 628 const int hardware_sample_rate = HardwareSampleRateForDevice(device); |
543 const int buffer_size = ChooseBufferSize(hardware_sample_rate); | 629 const int buffer_size = ChooseBufferSize(hardware_sample_rate); |
544 | 630 |
545 int input_channels = 0; | 631 int input_channels = 0; |
546 if (input_params.IsValid()) { | 632 if (input_params.IsValid()) { |
547 input_channels = input_params.input_channels(); | 633 input_channels = input_params.input_channels(); |
548 | 634 |
549 if (input_channels > 0) { | 635 if (input_channels > 0) { |
550 // TODO(crogers): given the limitations of the AudioOutputStream | 636 // TODO(crogers): given the limitations of the AudioOutputStream |
henrika (OOO until Aug 14)
2013/09/07 08:04:25
Change crogers to xians?
tommi (sloooow) - chröme
2013/09/08 19:11:19
Done.
| |
551 // back-ends used with synchronized I/O, we hard-code to stereo. | 637 // back-ends used with synchronized I/O, we hard-code to stereo. |
552 // Specifically, this is a limitation of AudioSynchronizedStream which | 638 // Specifically, this is a limitation of AudioSynchronizedStream which |
553 // can be removed as part of the work to consolidate these back-ends. | 639 // can be removed as part of the work to consolidate these back-ends. |
554 channel_layout = CHANNEL_LAYOUT_STEREO; | 640 channel_layout = CHANNEL_LAYOUT_STEREO; |
555 } | 641 } |
556 } | 642 } |
557 | 643 |
558 AudioParameters params( | 644 AudioParameters params( |
559 AudioParameters::AUDIO_PCM_LOW_LATENCY, | 645 AudioParameters::AUDIO_PCM_LOW_LATENCY, |
560 channel_layout, | 646 channel_layout, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
605 current_sample_rate_ = new_sample_rate; | 691 current_sample_rate_ = new_sample_rate; |
606 current_output_device_ = new_output_device; | 692 current_output_device_ = new_output_device; |
607 NotifyAllOutputDeviceChangeListeners(); | 693 NotifyAllOutputDeviceChangeListeners(); |
608 } | 694 } |
609 | 695 |
610 AudioManager* CreateAudioManager() { | 696 AudioManager* CreateAudioManager() { |
611 return new AudioManagerMac(); | 697 return new AudioManagerMac(); |
612 } | 698 } |
613 | 699 |
614 } // namespace media | 700 } // namespace media |
OLD | NEW |