Chromium Code Reviews| 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 |