| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/mac/mac_logging.h" | 13 #include "base/mac/mac_logging.h" |
| 14 #include "base/mac/scoped_cftyperef.h" | 14 #include "base/mac/scoped_cftyperef.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/free_deleter.h" | 16 #include "base/memory/free_deleter.h" |
| 17 #include "base/power_monitor/power_monitor.h" | 17 #include "base/power_monitor/power_monitor.h" |
| 18 #include "base/power_monitor/power_observer.h" | 18 #include "base/power_monitor/power_observer.h" |
| 19 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
| 20 #include "base/threading/thread_checker.h" | 20 #include "base/threading/thread_checker.h" |
| 21 #include "media/audio/audio_device_description.h" | 21 #include "media/audio/audio_device_description.h" |
| 22 #include "media/audio/mac/audio_auhal_mac.h" | 22 #include "media/audio/mac/audio_auhal_mac.h" |
| 23 #include "media/audio/mac/audio_input_mac.h" | 23 #include "media/audio/mac/audio_input_mac.h" |
| 24 #include "media/audio/mac/audio_low_latency_input_mac.h" | 24 #include "media/audio/mac/audio_low_latency_input_mac.h" |
| 25 #include "media/audio/mac/scoped_audio_unit.h" |
| 25 #include "media/base/audio_parameters.h" | 26 #include "media/base/audio_parameters.h" |
| 26 #include "media/base/bind_to_current_loop.h" | 27 #include "media/base/bind_to_current_loop.h" |
| 27 #include "media/base/channel_layout.h" | 28 #include "media/base/channel_layout.h" |
| 28 #include "media/base/limits.h" | 29 #include "media/base/limits.h" |
| 29 #include "media/base/media_switches.h" | 30 #include "media/base/media_switches.h" |
| 30 | 31 |
| 31 namespace media { | 32 namespace media { |
| 32 | 33 |
| 33 // Maximum number of output streams that can be open simultaneously. | 34 // Maximum number of output streams that can be open simultaneously. |
| 34 static const int kMaxOutputStreams = 50; | 35 static const int kMaxOutputStreams = 50; |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 DLOG(ERROR) << "Error getting default AudioDevice."; | 287 DLOG(ERROR) << "Error getting default AudioDevice."; |
| 287 return false; | 288 return false; |
| 288 } | 289 } |
| 289 return true; | 290 return true; |
| 290 } | 291 } |
| 291 | 292 |
| 292 static bool GetDefaultOutputDevice(AudioDeviceID* device) { | 293 static bool GetDefaultOutputDevice(AudioDeviceID* device) { |
| 293 return GetDefaultDevice(device, false); | 294 return GetDefaultDevice(device, false); |
| 294 } | 295 } |
| 295 | 296 |
| 296 // Returns the total number of channels on a device; regardless of what the | 297 static bool GetDeviceChannels(AudioDeviceID device, |
| 297 // device's preferred rendering layout looks like. Should only be used for the | 298 AUElement element, |
| 298 // channel count when a device has more than kMaxConcurrentChannels. | 299 int* channels) { |
| 299 static bool GetDeviceTotalChannelCount(AudioDeviceID device, | |
| 300 AudioObjectPropertyScope scope, | |
| 301 int* channels) { | |
| 302 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 300 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
| 303 CHECK(channels); | 301 CHECK(channels); |
| 304 | 302 |
| 305 // Get the stream configuration of the device in an AudioBufferList (with the | 303 ScopedAudioUnit au(device, element); |
| 306 // buffer pointers set to nullptr) which describes the list of streams and the | 304 if (!au.is_valid()) |
| 307 // number of channels in each stream. | |
| 308 AudioObjectPropertyAddress pa = {kAudioDevicePropertyStreamConfiguration, | |
| 309 scope, kAudioObjectPropertyElementMaster}; | |
| 310 | |
| 311 UInt32 size; | |
| 312 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); | |
| 313 if (result != noErr || !size) | |
| 314 return false; | 305 return false; |
| 315 | 306 |
| 316 std::unique_ptr<uint8_t[]> list_storage(new uint8_t[size]); | 307 // Attempt to retrieve the channel layout from the AudioUnit. |
| 317 AudioBufferList* buffer_list = | 308 // |
| 318 reinterpret_cast<AudioBufferList*>(list_storage.get()); | 309 // Note: We don't use kAudioDevicePropertyPreferredChannelLayout on the device |
| 310 // because it is not available on all devices. |
| 311 UInt32 size; |
| 312 Boolean writable; |
| 313 OSStatus result = AudioUnitGetPropertyInfo( |
| 314 au.audio_unit(), kAudioUnitProperty_AudioChannelLayout, |
| 315 kAudioUnitScope_Output, element, &size, &writable); |
| 316 if (result != noErr) { |
| 317 OSSTATUS_DLOG(ERROR, result) |
| 318 << "Failed to get property info for AudioUnit channel layout."; |
| 319 return false; |
| 320 } |
| 319 | 321 |
| 320 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, buffer_list); | 322 std::unique_ptr<uint8_t[]> layout_storage(new uint8_t[size]); |
| 321 if (result != noErr) | 323 AudioChannelLayout* layout = |
| 324 reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); |
| 325 |
| 326 result = AudioUnitGetProperty(au.audio_unit(), |
| 327 kAudioUnitProperty_AudioChannelLayout, |
| 328 kAudioUnitScope_Output, element, layout, &size); |
| 329 if (result != noErr) { |
| 330 OSSTATUS_LOG(ERROR, result) << "Failed to get AudioUnit channel layout."; |
| 322 return false; | 331 return false; |
| 332 } |
| 323 | 333 |
| 324 // Determine number of channels based on the AudioBufferList. | 334 // We don't want to have to know about all channel layout tags, so force OSX |
| 325 // |mNumberBuffers] is the number of interleaved channels in the buffer. | 335 // to give us the channel descriptions from the bitmap or tag if necessary. |
| 326 // If the number is 1, the buffer is noninterleaved. | 336 const AudioChannelLayoutTag tag = layout->mChannelLayoutTag; |
| 327 *channels = 0; | 337 if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) { |
| 328 for (UInt32 i = 0; i < buffer_list->mNumberBuffers; ++i) | 338 const bool is_bitmap = tag == kAudioChannelLayoutTag_UseChannelBitmap; |
| 329 *channels += buffer_list->mBuffers[i].mNumberChannels; | 339 const AudioFormatPropertyID fa = |
| 340 is_bitmap ? kAudioFormatProperty_ChannelLayoutForBitmap |
| 341 : kAudioFormatProperty_ChannelLayoutForTag; |
| 330 | 342 |
| 331 DVLOG(1) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") | 343 if (is_bitmap) { |
| 332 << " total channels: " << *channels; | 344 result = AudioFormatGetPropertyInfo(fa, sizeof(UInt32), |
| 345 &layout->mChannelBitmap, &size); |
| 346 } else { |
| 347 result = AudioFormatGetPropertyInfo(fa, sizeof(AudioChannelLayoutTag), |
| 348 &tag, &size); |
| 349 } |
| 350 if (result != noErr || !size) { |
| 351 OSSTATUS_DLOG(ERROR, result) |
| 352 << "Failed to get AudioFormat property info, size=" << size; |
| 353 return false; |
| 354 } |
| 355 |
| 356 layout_storage.reset(new uint8_t[size]); |
| 357 layout = reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); |
| 358 if (is_bitmap) { |
| 359 result = AudioFormatGetProperty(fa, sizeof(UInt32), |
| 360 &layout->mChannelBitmap, &size, layout); |
| 361 } else { |
| 362 result = AudioFormatGetProperty(fa, sizeof(AudioChannelLayoutTag), &tag, |
| 363 &size, layout); |
| 364 } |
| 365 if (result != noErr) { |
| 366 OSSTATUS_DLOG(ERROR, result) << "Failed to get AudioFormat property."; |
| 367 return false; |
| 368 } |
| 369 } |
| 370 |
| 371 // There is no channel info for stereo, assume so for mono as well. |
| 372 if (layout->mNumberChannelDescriptions <= 2) { |
| 373 *channels = layout->mNumberChannelDescriptions; |
| 374 } else { |
| 375 *channels = 0; |
| 376 for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) { |
| 377 if (layout->mChannelDescriptions[i].mChannelLabel != |
| 378 kAudioChannelLabel_Unknown) |
| 379 (*channels)++; |
| 380 } |
| 381 } |
| 382 |
| 383 DVLOG(1) << (element == AUElement::OUTPUT ? "Output" : "Input") |
| 384 << " channels: " << *channels; |
| 333 return true; | 385 return true; |
| 334 } | 386 } |
| 335 | 387 |
| 336 class AudioManagerMac::AudioPowerObserver : public base::PowerObserver { | 388 class AudioManagerMac::AudioPowerObserver : public base::PowerObserver { |
| 337 public: | 389 public: |
| 338 AudioPowerObserver() | 390 AudioPowerObserver() |
| 339 : is_suspending_(false), | 391 : is_suspending_(false), |
| 340 is_monitoring_(base::PowerMonitor::Get()), | 392 is_monitoring_(base::PowerMonitor::Get()), |
| 341 num_resume_notifications_(0) { | 393 num_resume_notifications_(0) { |
| 342 // The PowerMonitor requires significant setup (a CFRunLoop and preallocated | 394 // The PowerMonitor requires significant setup (a CFRunLoop and preallocated |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 | 481 |
| 430 bool AudioManagerMac::HasAudioOutputDevices() { | 482 bool AudioManagerMac::HasAudioOutputDevices() { |
| 431 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); | 483 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); |
| 432 } | 484 } |
| 433 | 485 |
| 434 bool AudioManagerMac::HasAudioInputDevices() { | 486 bool AudioManagerMac::HasAudioInputDevices() { |
| 435 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 487 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); |
| 436 } | 488 } |
| 437 | 489 |
| 438 // static | 490 // static |
| 439 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, | |
| 440 AudioObjectPropertyScope scope, | |
| 441 int* channels) { | |
| 442 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | |
| 443 CHECK(channels); | |
| 444 | |
| 445 // If the device has more channels than possible for layouts to express, use | |
| 446 // the total count of channels on the device; as of this writing, macOS will | |
| 447 // only return up to 8 channels in any layout. To allow WebAudio to work with | |
| 448 // > 8 channel devices, we must use the total channel count instead of the | |
| 449 // channel count of the preferred layout. | |
| 450 int total_channel_count = 0; | |
| 451 if (GetDeviceTotalChannelCount(device, scope, &total_channel_count) && | |
| 452 total_channel_count > kMaxConcurrentChannels) { | |
| 453 *channels = total_channel_count; | |
| 454 return true; | |
| 455 } | |
| 456 | |
| 457 AudioObjectPropertyAddress pa = {kAudioDevicePropertyPreferredChannelLayout, | |
| 458 scope, kAudioObjectPropertyElementMaster}; | |
| 459 UInt32 size; | |
| 460 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); | |
| 461 if (result != noErr || !size) | |
| 462 return false; | |
| 463 | |
| 464 std::unique_ptr<uint8_t[]> layout_storage(new uint8_t[size]); | |
| 465 AudioChannelLayout* layout = | |
| 466 reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); | |
| 467 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, layout); | |
| 468 if (result != noErr) | |
| 469 return false; | |
| 470 | |
| 471 // We don't want to have to know about all channel layout tags, so force OSX | |
| 472 // to give us the channel descriptions from the bitmap or tag if necessary. | |
| 473 const AudioChannelLayoutTag tag = layout->mChannelLayoutTag; | |
| 474 if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) { | |
| 475 const bool is_bitmap = tag == kAudioChannelLayoutTag_UseChannelBitmap; | |
| 476 const AudioFormatPropertyID fa = | |
| 477 is_bitmap ? kAudioFormatProperty_ChannelLayoutForBitmap | |
| 478 : kAudioFormatProperty_ChannelLayoutForTag; | |
| 479 | |
| 480 if (is_bitmap) { | |
| 481 result = AudioFormatGetPropertyInfo(fa, sizeof(UInt32), | |
| 482 &layout->mChannelBitmap, &size); | |
| 483 } else { | |
| 484 result = AudioFormatGetPropertyInfo(fa, sizeof(AudioChannelLayoutTag), | |
| 485 &tag, &size); | |
| 486 } | |
| 487 if (result != noErr || !size) | |
| 488 return false; | |
| 489 | |
| 490 layout_storage.reset(new uint8_t[size]); | |
| 491 layout = reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); | |
| 492 if (is_bitmap) { | |
| 493 result = AudioFormatGetProperty(fa, sizeof(UInt32), | |
| 494 &layout->mChannelBitmap, &size, layout); | |
| 495 } else { | |
| 496 result = AudioFormatGetProperty(fa, sizeof(AudioChannelLayoutTag), &tag, | |
| 497 &size, layout); | |
| 498 } | |
| 499 if (result != noErr) | |
| 500 return false; | |
| 501 } | |
| 502 | |
| 503 // There is no channel info for stereo, assume so for mono as well. | |
| 504 if (layout->mNumberChannelDescriptions <= 2) { | |
| 505 *channels = layout->mNumberChannelDescriptions; | |
| 506 } else { | |
| 507 *channels = 0; | |
| 508 for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) { | |
| 509 if (layout->mChannelDescriptions[i].mChannelLabel != | |
| 510 kAudioChannelLabel_Unknown) | |
| 511 (*channels)++; | |
| 512 } | |
| 513 } | |
| 514 | |
| 515 // If we still don't have a channel count, fall back to total channel count. | |
| 516 if (*channels == 0) { | |
| 517 DLOG(WARNING) << "Unable to use channel layout for channel count."; | |
| 518 *channels = total_channel_count; | |
| 519 } | |
| 520 | |
| 521 DVLOG(1) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") | |
| 522 << " channels: " << *channels; | |
| 523 return true; | |
| 524 } | |
| 525 | |
| 526 // static | |
| 527 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { | 491 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { |
| 528 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 492 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
| 529 Float64 nominal_sample_rate; | 493 Float64 nominal_sample_rate; |
| 530 UInt32 info_size = sizeof(nominal_sample_rate); | 494 UInt32 info_size = sizeof(nominal_sample_rate); |
| 531 | 495 |
| 532 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { | 496 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { |
| 533 kAudioDevicePropertyNominalSampleRate, | 497 kAudioDevicePropertyNominalSampleRate, |
| 534 kAudioObjectPropertyScopeGlobal, | 498 kAudioObjectPropertyScopeGlobal, |
| 535 kAudioObjectPropertyElementMaster | 499 kAudioObjectPropertyElementMaster |
| 536 }; | 500 }; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 DCHECK(device_names->empty()); | 534 DCHECK(device_names->empty()); |
| 571 GetAudioDeviceInfo(false, device_names); | 535 GetAudioDeviceInfo(false, device_names); |
| 572 } | 536 } |
| 573 | 537 |
| 574 AudioParameters AudioManagerMac::GetInputStreamParameters( | 538 AudioParameters AudioManagerMac::GetInputStreamParameters( |
| 575 const std::string& device_id) { | 539 const std::string& device_id) { |
| 576 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 540 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 577 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id); | 541 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id); |
| 578 if (device == kAudioObjectUnknown) { | 542 if (device == kAudioObjectUnknown) { |
| 579 DLOG(ERROR) << "Invalid device " << device_id; | 543 DLOG(ERROR) << "Invalid device " << device_id; |
| 580 return AudioParameters( | 544 return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 581 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, | 545 CHANNEL_LAYOUT_STEREO, kFallbackSampleRate, 16, |
| 582 kFallbackSampleRate, 16, ChooseBufferSize(true, kFallbackSampleRate)); | 546 ChooseBufferSize(true, kFallbackSampleRate)); |
| 583 } | 547 } |
| 584 | 548 |
| 585 int channels = 0; | 549 int channels = 0; |
| 586 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; | 550 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
| 587 if (GetDeviceChannels(device, kAudioDevicePropertyScopeInput, &channels) && | 551 if (GetDeviceChannels(device, AUElement::INPUT, &channels) && channels <= 2) { |
| 588 channels <= 2) { | |
| 589 channel_layout = GuessChannelLayout(channels); | 552 channel_layout = GuessChannelLayout(channels); |
| 590 } else { | 553 } else { |
| 591 DLOG(ERROR) << "Failed to get the device channels, use stereo as default " | 554 DLOG(ERROR) << "Failed to get the device channels, use stereo as default " |
| 592 << "for device " << device_id; | 555 << "for device " << device_id; |
| 593 } | 556 } |
| 594 | 557 |
| 595 int sample_rate = HardwareSampleRateForDevice(device); | 558 int sample_rate = HardwareSampleRateForDevice(device); |
| 596 if (!sample_rate) | 559 if (!sample_rate) |
| 597 sample_rate = kFallbackSampleRate; | 560 sample_rate = kFallbackSampleRate; |
| 598 | 561 |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 818 // exist, they will use the smallest buffer size amongst them. As such, each | 781 // exist, they will use the smallest buffer size amongst them. As such, each |
| 819 // stream must be able to FIFO requests appropriately when this happens. | 782 // stream must be able to FIFO requests appropriately when this happens. |
| 820 int buffer_size = ChooseBufferSize(false, hardware_sample_rate); | 783 int buffer_size = ChooseBufferSize(false, hardware_sample_rate); |
| 821 if (has_valid_input_params) { | 784 if (has_valid_input_params) { |
| 822 buffer_size = | 785 buffer_size = |
| 823 std::min(kMaximumInputOutputBufferSize, | 786 std::min(kMaximumInputOutputBufferSize, |
| 824 std::max(input_params.frames_per_buffer(), buffer_size)); | 787 std::max(input_params.frames_per_buffer(), buffer_size)); |
| 825 } | 788 } |
| 826 | 789 |
| 827 int hardware_channels; | 790 int hardware_channels; |
| 828 if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput, | 791 if (!GetDeviceChannels(device, AUElement::OUTPUT, &hardware_channels)) |
| 829 &hardware_channels)) { | |
| 830 hardware_channels = 2; | 792 hardware_channels = 2; |
| 831 } | |
| 832 | 793 |
| 833 // Use the input channel count and channel layout if possible. Let OSX take | 794 // Use the input channel count and channel layout if possible. Let OSX take |
| 834 // care of remapping the channels; this lets user specified channel layouts | 795 // care of remapping the channels; this lets user specified channel layouts |
| 835 // work correctly. | 796 // work correctly. |
| 836 int output_channels = input_params.channels(); | 797 int output_channels = input_params.channels(); |
| 837 ChannelLayout channel_layout = input_params.channel_layout(); | 798 ChannelLayout channel_layout = input_params.channel_layout(); |
| 838 if (!has_valid_input_params || output_channels > hardware_channels) { | 799 if (!has_valid_input_params || output_channels > hardware_channels) { |
| 839 output_channels = hardware_channels; | 800 output_channels = hardware_channels; |
| 840 channel_layout = GuessChannelLayout(output_channels); | 801 channel_layout = GuessChannelLayout(output_channels); |
| 841 if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) | 802 if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1168 ScopedAudioManagerPtr CreateAudioManager( | 1129 ScopedAudioManagerPtr CreateAudioManager( |
| 1169 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 1130 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 1170 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, | 1131 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, |
| 1171 AudioLogFactory* audio_log_factory) { | 1132 AudioLogFactory* audio_log_factory) { |
| 1172 return ScopedAudioManagerPtr( | 1133 return ScopedAudioManagerPtr( |
| 1173 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), | 1134 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), |
| 1174 audio_log_factory)); | 1135 audio_log_factory)); |
| 1175 } | 1136 } |
| 1176 | 1137 |
| 1177 } // namespace media | 1138 } // namespace media |
| OLD | NEW |