| 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 |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 CHECK(channels); | 303 CHECK(channels); |
| 304 | 304 |
| 305 // Get the stream configuration of the device in an AudioBufferList (with the | 305 // Get the stream configuration of the device in an AudioBufferList (with the |
| 306 // buffer pointers set to nullptr) which describes the list of streams and the | 306 // buffer pointers set to nullptr) which describes the list of streams and the |
| 307 // number of channels in each stream. | 307 // number of channels in each stream. |
| 308 AudioObjectPropertyAddress pa = {kAudioDevicePropertyStreamConfiguration, | 308 AudioObjectPropertyAddress pa = {kAudioDevicePropertyStreamConfiguration, |
| 309 scope, kAudioObjectPropertyElementMaster}; | 309 scope, kAudioObjectPropertyElementMaster}; |
| 310 | 310 |
| 311 UInt32 size; | 311 UInt32 size; |
| 312 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); | 312 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); |
| 313 if (result != noErr || !size) | 313 if (result != noErr || !size) { |
| 314 OSSTATUS_LOG(ERROR, result) << "Failed to get property size... " << size; |
| 314 return false; | 315 return false; |
| 316 } |
| 315 | 317 |
| 316 std::unique_ptr<uint8_t[]> list_storage(new uint8_t[size]); | 318 std::unique_ptr<uint8_t[]> list_storage(new uint8_t[size]); |
| 317 AudioBufferList* buffer_list = | 319 AudioBufferList* buffer_list = |
| 318 reinterpret_cast<AudioBufferList*>(list_storage.get()); | 320 reinterpret_cast<AudioBufferList*>(list_storage.get()); |
| 319 | 321 |
| 320 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, buffer_list); | 322 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, buffer_list); |
| 321 if (result != noErr) | 323 if (result != noErr) { |
| 324 OSSTATUS_LOG(ERROR, result) << "Failed to get property..."; |
| 322 return false; | 325 return false; |
| 326 } |
| 323 | 327 |
| 324 // Determine number of channels based on the AudioBufferList. | 328 // Determine number of channels based on the AudioBufferList. |
| 325 // |mNumberBuffers] is the number of interleaved channels in the buffer. | 329 // |mNumberBuffers] is the number of interleaved channels in the buffer. |
| 326 // If the number is 1, the buffer is noninterleaved. | 330 // If the number is 1, the buffer is noninterleaved. |
| 327 *channels = 0; | 331 *channels = 0; |
| 328 for (UInt32 i = 0; i < buffer_list->mNumberBuffers; ++i) | 332 for (UInt32 i = 0; i < buffer_list->mNumberBuffers; ++i) |
| 329 *channels += buffer_list->mBuffers[i].mNumberChannels; | 333 *channels += buffer_list->mBuffers[i].mNumberChannels; |
| 330 | 334 |
| 331 DVLOG(1) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") | 335 LOG(ERROR) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") |
| 332 << " total channels: " << *channels; | 336 << " total channels: " << *channels; |
| 333 return true; | 337 return true; |
| 334 } | 338 } |
| 335 | 339 |
| 336 class AudioManagerMac::AudioPowerObserver : public base::PowerObserver { | 340 class AudioManagerMac::AudioPowerObserver : public base::PowerObserver { |
| 337 public: | 341 public: |
| 338 AudioPowerObserver() | 342 AudioPowerObserver() |
| 339 : is_suspending_(false), | 343 : is_suspending_(false), |
| 340 is_monitoring_(base::PowerMonitor::Get()), | 344 is_monitoring_(base::PowerMonitor::Get()), |
| 341 num_resume_notifications_(0) { | 345 num_resume_notifications_(0) { |
| 342 // The PowerMonitor requires significant setup (a CFRunLoop and preallocated | 346 // The PowerMonitor requires significant setup (a CFRunLoop and preallocated |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 | 448 |
| 445 // If the device has more channels than possible for layouts to express, use | 449 // 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 | 450 // 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 | 451 // 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 | 452 // > 8 channel devices, we must use the total channel count instead of the |
| 449 // channel count of the preferred layout. | 453 // channel count of the preferred layout. |
| 450 int total_channel_count = 0; | 454 int total_channel_count = 0; |
| 451 if (GetDeviceTotalChannelCount(device, scope, &total_channel_count) && | 455 if (GetDeviceTotalChannelCount(device, scope, &total_channel_count) && |
| 452 total_channel_count > kMaxConcurrentChannels) { | 456 total_channel_count > kMaxConcurrentChannels) { |
| 453 *channels = total_channel_count; | 457 *channels = total_channel_count; |
| 458 LOG(ERROR) << "Total count exceeds 8 channels, preferring total count."; |
| 454 return true; | 459 return true; |
| 455 } | 460 } |
| 456 | 461 |
| 457 AudioObjectPropertyAddress pa = {kAudioDevicePropertyPreferredChannelLayout, | 462 AudioObjectPropertyAddress pa = {kAudioDevicePropertyPreferredChannelLayout, |
| 458 scope, kAudioObjectPropertyElementMaster}; | 463 scope, kAudioObjectPropertyElementMaster}; |
| 459 UInt32 size; | 464 UInt32 size; |
| 460 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); | 465 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); |
| 461 if (result != noErr || !size) | 466 if (result != noErr || !size) { |
| 467 OSSTATUS_LOG(ERROR, result) |
| 468 << "Failed to get property (2) size... " << size; |
| 462 return false; | 469 return false; |
| 470 } |
| 463 | 471 |
| 464 std::unique_ptr<uint8_t[]> layout_storage(new uint8_t[size]); | 472 std::unique_ptr<uint8_t[]> layout_storage(new uint8_t[size]); |
| 465 AudioChannelLayout* layout = | 473 AudioChannelLayout* layout = |
| 466 reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); | 474 reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); |
| 467 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, layout); | 475 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, layout); |
| 468 if (result != noErr) | 476 if (result != noErr) { |
| 477 OSSTATUS_LOG(ERROR, result) << "Failed to get property (2)... "; |
| 469 return false; | 478 return false; |
| 479 } |
| 470 | 480 |
| 471 // We don't want to have to know about all channel layout tags, so force OSX | 481 // 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. | 482 // to give us the channel descriptions from the bitmap or tag if necessary. |
| 473 const AudioChannelLayoutTag tag = layout->mChannelLayoutTag; | 483 const AudioChannelLayoutTag tag = layout->mChannelLayoutTag; |
| 474 if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) { | 484 if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) { |
| 475 const bool is_bitmap = tag == kAudioChannelLayoutTag_UseChannelBitmap; | 485 const bool is_bitmap = tag == kAudioChannelLayoutTag_UseChannelBitmap; |
| 476 const AudioFormatPropertyID fa = | 486 const AudioFormatPropertyID fa = |
| 477 is_bitmap ? kAudioFormatProperty_ChannelLayoutForBitmap | 487 is_bitmap ? kAudioFormatProperty_ChannelLayoutForBitmap |
| 478 : kAudioFormatProperty_ChannelLayoutForTag; | 488 : kAudioFormatProperty_ChannelLayoutForTag; |
| 479 | 489 |
| 480 if (is_bitmap) { | 490 if (is_bitmap) { |
| 481 result = AudioFormatGetPropertyInfo(fa, sizeof(UInt32), | 491 result = AudioFormatGetPropertyInfo(fa, sizeof(UInt32), |
| 482 &layout->mChannelBitmap, &size); | 492 &layout->mChannelBitmap, &size); |
| 483 } else { | 493 } else { |
| 484 result = AudioFormatGetPropertyInfo(fa, sizeof(AudioChannelLayoutTag), | 494 result = AudioFormatGetPropertyInfo(fa, sizeof(AudioChannelLayoutTag), |
| 485 &tag, &size); | 495 &tag, &size); |
| 486 } | 496 } |
| 487 if (result != noErr || !size) | 497 if (result != noErr || !size) { |
| 498 OSSTATUS_LOG(ERROR, result) << "Failed to get af info... " << size; |
| 488 return false; | 499 return false; |
| 500 } |
| 489 | 501 |
| 490 layout_storage.reset(new uint8_t[size]); | 502 layout_storage.reset(new uint8_t[size]); |
| 491 layout = reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); | 503 layout = reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); |
| 492 if (is_bitmap) { | 504 if (is_bitmap) { |
| 493 result = AudioFormatGetProperty(fa, sizeof(UInt32), | 505 result = AudioFormatGetProperty(fa, sizeof(UInt32), |
| 494 &layout->mChannelBitmap, &size, layout); | 506 &layout->mChannelBitmap, &size, layout); |
| 495 } else { | 507 } else { |
| 496 result = AudioFormatGetProperty(fa, sizeof(AudioChannelLayoutTag), &tag, | 508 result = AudioFormatGetProperty(fa, sizeof(AudioChannelLayoutTag), &tag, |
| 497 &size, layout); | 509 &size, layout); |
| 498 } | 510 } |
| 499 if (result != noErr) | 511 if (result != noErr) { |
| 512 OSSTATUS_LOG(ERROR, result) << "Failed to get af structure... "; |
| 500 return false; | 513 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 } | 514 } |
| 513 } | 515 } |
| 514 | 516 |
| 515 // If we still don't have a channel count, fall back to total channel count. | 517 bool is_au_based_retry = false; |
| 516 if (*channels == 0) { | 518 do { |
| 517 DLOG(WARNING) << "Unable to use channel layout for channel count."; | 519 // There is no channel info for stereo, assume so for mono as well. |
| 518 *channels = total_channel_count; | 520 if (layout->mNumberChannelDescriptions <= 2) { |
| 519 } | 521 *channels = layout->mNumberChannelDescriptions; |
| 522 } else { |
| 523 *channels = 0; |
| 524 for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) { |
| 525 if (layout->mChannelDescriptions[i].mChannelLabel != |
| 526 kAudioChannelLabel_Unknown) |
| 527 (*channels)++; |
| 528 } |
| 529 } |
| 520 | 530 |
| 521 DVLOG(1) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") | 531 // If we still don't have a channel count, fall back to total channel count. |
| 522 << " channels: " << *channels; | 532 if (*channels == 0 && !is_au_based_retry) { |
| 533 is_au_based_retry = true; |
| 534 |
| 535 const AudioUnitScope au_scope = |
| 536 scope == kAudioDevicePropertyScopeOutput ? 0 : 1; |
| 537 |
| 538 LOG(ERROR) |
| 539 << "Unable to use channel layout for channel count, trying AU."; |
| 540 |
| 541 AudioComponentDescription desc = {kAudioUnitType_Output, |
| 542 kAudioUnitSubType_HALOutput, |
| 543 kAudioUnitManufacturer_Apple, 0, 0}; |
| 544 AudioComponent comp = AudioComponentFindNext(0, &desc); |
| 545 if (!comp) { |
| 546 LOG(ERROR) << "Failed to find component."; |
| 547 return false; |
| 548 } |
| 549 |
| 550 AudioUnit audio_unit; |
| 551 result = AudioComponentInstanceNew(comp, &audio_unit); |
| 552 if (result != noErr) { |
| 553 OSSTATUS_LOG(ERROR, result) << "AudioComponentInstanceNew() failed."; |
| 554 return false; |
| 555 } |
| 556 |
| 557 Boolean writable; |
| 558 result = AudioUnitGetPropertyInfo( |
| 559 audio_unit, kAudioUnitProperty_AudioChannelLayout, |
| 560 kAudioUnitScope_Output, au_scope, &size, &writable); |
| 561 if (result != noErr) { |
| 562 OSSTATUS_LOG(ERROR, result) << "AudioUnitGetPropertyInfo() failed."; |
| 563 return false; |
| 564 } |
| 565 |
| 566 layout_storage.reset(new uint8_t[size]); |
| 567 layout = reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); |
| 568 |
| 569 result = AudioUnitGetProperty( |
| 570 audio_unit, kAudioUnitProperty_AudioChannelLayout, |
| 571 kAudioUnitScope_Output, au_scope, layout, &size); |
| 572 if (result != noErr) { |
| 573 OSSTATUS_LOG(ERROR, result) << "AudioUnitGetProperty() failed."; |
| 574 return false; |
| 575 } |
| 576 |
| 577 result = AudioUnitUninitialize(audio_unit); |
| 578 OSSTATUS_LOG_IF(ERROR, result != noErr, result) |
| 579 << "AudioUnitUninitialize() failed."; |
| 580 result = AudioComponentInstanceDispose(audio_unit); |
| 581 OSSTATUS_LOG_IF(ERROR, result != noErr, result) |
| 582 << "AudioComponentInstanceDispose() failed."; |
| 583 } |
| 584 } while (*channels == 0 && is_au_based_retry); |
| 585 |
| 586 LOG(ERROR) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") |
| 587 << " channels: " << *channels; |
| 523 return true; | 588 return true; |
| 524 } | 589 } |
| 525 | 590 |
| 526 // static | 591 // static |
| 527 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { | 592 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { |
| 528 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 593 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
| 529 Float64 nominal_sample_rate; | 594 Float64 nominal_sample_rate; |
| 530 UInt32 info_size = sizeof(nominal_sample_rate); | 595 UInt32 info_size = sizeof(nominal_sample_rate); |
| 531 | 596 |
| 532 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { | 597 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { |
| (...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1168 ScopedAudioManagerPtr CreateAudioManager( | 1233 ScopedAudioManagerPtr CreateAudioManager( |
| 1169 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 1234 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 1170 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, | 1235 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, |
| 1171 AudioLogFactory* audio_log_factory) { | 1236 AudioLogFactory* audio_log_factory) { |
| 1172 return ScopedAudioManagerPtr( | 1237 return ScopedAudioManagerPtr( |
| 1173 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), | 1238 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), |
| 1174 audio_log_factory)); | 1239 audio_log_factory)); |
| 1175 } | 1240 } |
| 1176 | 1241 |
| 1177 } // namespace media | 1242 } // namespace media |
| OLD | NEW |