| 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 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 DLOG(ERROR) << "Error getting default AudioDevice."; | 286 DLOG(ERROR) << "Error getting default AudioDevice."; |
| 287 return false; | 287 return false; |
| 288 } | 288 } |
| 289 return true; | 289 return true; |
| 290 } | 290 } |
| 291 | 291 |
| 292 static bool GetDefaultOutputDevice(AudioDeviceID* device) { | 292 static bool GetDefaultOutputDevice(AudioDeviceID* device) { |
| 293 return GetDefaultDevice(device, false); | 293 return GetDefaultDevice(device, false); |
| 294 } | 294 } |
| 295 | 295 |
| 296 // Returns the total number of channels on a device; regardless of what the |
| 297 // device's preferred rendering layout looks like. Should only be used for the |
| 298 // channel count when a device has more than kMaxConcurrentChannels. |
| 299 static bool GetDeviceTotalChannelCount(AudioDeviceID device, |
| 300 AudioObjectPropertyScope scope, |
| 301 int* channels) { |
| 302 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
| 303 CHECK(channels); |
| 304 |
| 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 |
| 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; |
| 315 |
| 316 std::unique_ptr<uint8_t[]> list_storage(new uint8_t[size]); |
| 317 AudioBufferList* buffer_list = |
| 318 reinterpret_cast<AudioBufferList*>(list_storage.get()); |
| 319 |
| 320 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, buffer_list); |
| 321 if (result != noErr) |
| 322 return false; |
| 323 |
| 324 // Determine number of channels based on the AudioBufferList. |
| 325 // |mNumberBuffers] is the number of interleaved channels in the buffer. |
| 326 // If the number is 1, the buffer is noninterleaved. |
| 327 *channels = 0; |
| 328 for (UInt32 i = 0; i < buffer_list->mNumberBuffers; ++i) |
| 329 *channels += buffer_list->mBuffers[i].mNumberChannels; |
| 330 |
| 331 DVLOG(1) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") |
| 332 << " total channels: " << *channels; |
| 333 return true; |
| 334 } |
| 335 |
| 296 class AudioManagerMac::AudioPowerObserver : public base::PowerObserver { | 336 class AudioManagerMac::AudioPowerObserver : public base::PowerObserver { |
| 297 public: | 337 public: |
| 298 AudioPowerObserver() | 338 AudioPowerObserver() |
| 299 : is_suspending_(false), | 339 : is_suspending_(false), |
| 300 is_monitoring_(base::PowerMonitor::Get()), | 340 is_monitoring_(base::PowerMonitor::Get()), |
| 301 num_resume_notifications_(0) { | 341 num_resume_notifications_(0) { |
| 302 // The PowerMonitor requires significant setup (a CFRunLoop and preallocated | 342 // The PowerMonitor requires significant setup (a CFRunLoop and preallocated |
| 303 // IO ports) so it's not available under unit tests. See the OSX impl of | 343 // IO ports) so it's not available under unit tests. See the OSX impl of |
| 304 // base::PowerMonitorDeviceSource for more details. | 344 // base::PowerMonitorDeviceSource for more details. |
| 305 if (!is_monitoring_) | 345 if (!is_monitoring_) |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 bool AudioManagerMac::HasAudioInputDevices() { | 434 bool AudioManagerMac::HasAudioInputDevices() { |
| 395 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 435 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); |
| 396 } | 436 } |
| 397 | 437 |
| 398 // static | 438 // static |
| 399 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, | 439 bool AudioManagerMac::GetDeviceChannels(AudioDeviceID device, |
| 400 AudioObjectPropertyScope scope, | 440 AudioObjectPropertyScope scope, |
| 401 int* channels) { | 441 int* channels) { |
| 402 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 442 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
| 403 CHECK(channels); | 443 CHECK(channels); |
| 404 const bool is_input = (scope == kAudioDevicePropertyScopeInput); | |
| 405 DVLOG(1) << "GetDeviceChannels(id=0x" << std::hex << device | |
| 406 << ", is_input=" << is_input << ")"; | |
| 407 | 444 |
| 408 // Get the stream configuration of the device in an AudioBufferList (with the | 445 // If the device has more channels than possible for layouts to express, use |
| 409 // buffer pointers set to NULL) which describes the list of streams and the | 446 // the total count of channels on the device; as of this writing, macOS will |
| 410 // number of channels in each stream. | 447 // only return up to 8 channels in any layout. To allow WebAudio to work with |
| 411 AudioObjectPropertyAddress pa; | 448 // > 8 channel devices, we must use the total channel count instead of the |
| 412 pa.mSelector = kAudioDevicePropertyStreamConfiguration; | 449 // channel count of the preferred layout. |
| 413 pa.mScope = scope; | 450 if (GetDeviceTotalChannelCount(device, scope, channels) && |
| 414 pa.mElement = kAudioObjectPropertyElementMaster; | 451 *channels > kMaxConcurrentChannels) { |
| 452 return true; |
| 453 } |
| 415 | 454 |
| 455 AudioObjectPropertyAddress pa = {kAudioDevicePropertyPreferredChannelLayout, |
| 456 scope, kAudioObjectPropertyElementMaster}; |
| 416 UInt32 size; | 457 UInt32 size; |
| 417 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); | 458 OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size); |
| 418 if (result != noErr || !size) | 459 if (result != noErr || !size) |
| 419 return false; | 460 return false; |
| 420 | 461 |
| 421 std::unique_ptr<uint8_t[]> list_storage(new uint8_t[size]); | 462 std::unique_ptr<uint8_t[]> layout_storage(new uint8_t[size]); |
| 422 AudioBufferList& buffer_list = | 463 AudioChannelLayout* layout = |
| 423 *reinterpret_cast<AudioBufferList*>(list_storage.get()); | 464 reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); |
| 424 | 465 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, layout); |
| 425 result = AudioObjectGetPropertyData(device, &pa, 0, 0, &size, &buffer_list); | |
| 426 if (result != noErr) | 466 if (result != noErr) |
| 427 return false; | 467 return false; |
| 428 | 468 |
| 429 // Determine number of channels based on the AudioBufferList. | 469 // We don't want to have to know about all channel layout tags, so force OSX |
| 430 // |mNumberBuffers] is the number of interleaved channels in the buffer. | 470 // to give us the channel descriptions from the bitmap or tag if necessary. |
| 431 // If the number is 1, the buffer is noninterleaved. | 471 const AudioChannelLayoutTag tag = layout->mChannelLayoutTag; |
| 432 // TODO(henrika): add UMA stats to track utilized hardware configurations. | 472 if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) { |
| 433 int num_channels = 0; | 473 const bool is_bitmap = tag == kAudioChannelLayoutTag_UseChannelBitmap; |
| 434 for (UInt32 i = 0; i < buffer_list.mNumberBuffers; ++i) { | 474 const AudioFormatPropertyID fa = |
| 435 num_channels += buffer_list.mBuffers[i].mNumberChannels; | 475 is_bitmap ? kAudioFormatProperty_ChannelLayoutForBitmap |
| 476 : kAudioFormatProperty_ChannelLayoutForTag; |
| 477 |
| 478 if (is_bitmap) { |
| 479 result = AudioFormatGetPropertyInfo(fa, sizeof(UInt32), |
| 480 &layout->mChannelBitmap, &size); |
| 481 } else { |
| 482 result = AudioFormatGetPropertyInfo(fa, sizeof(AudioChannelLayoutTag), |
| 483 &tag, &size); |
| 484 } |
| 485 if (result != noErr || !size) |
| 486 return false; |
| 487 |
| 488 layout_storage.reset(new uint8_t[size]); |
| 489 layout = reinterpret_cast<AudioChannelLayout*>(layout_storage.get()); |
| 490 if (is_bitmap) { |
| 491 result = AudioFormatGetProperty(fa, sizeof(UInt32), |
| 492 &layout->mChannelBitmap, &size, layout); |
| 493 } else { |
| 494 result = AudioFormatGetProperty(fa, sizeof(AudioChannelLayoutTag), &tag, |
| 495 &size, layout); |
| 496 } |
| 497 if (result != noErr) |
| 498 return false; |
| 436 } | 499 } |
| 437 *channels = num_channels; | 500 |
| 438 DVLOG(1) << "#channels: " << *channels; | 501 // There is no channel info for stereo, assume so for mono as well. |
| 502 if (layout->mNumberChannelDescriptions <= 2) { |
| 503 *channels = layout->mNumberChannelDescriptions; |
| 504 } else { |
| 505 *channels = 0; |
| 506 for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) { |
| 507 if (layout->mChannelDescriptions[i].mChannelLabel != |
| 508 kAudioChannelLabel_Unknown) |
| 509 (*channels)++; |
| 510 } |
| 511 } |
| 512 |
| 513 DVLOG(1) << (scope == kAudioDevicePropertyScopeInput ? "Input" : "Output") |
| 514 << " channels: " << *channels; |
| 439 return true; | 515 return true; |
| 440 } | 516 } |
| 441 | 517 |
| 442 // static | 518 // static |
| 443 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { | 519 int AudioManagerMac::HardwareSampleRateForDevice(AudioDeviceID device_id) { |
| 444 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); | 520 DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread()); |
| 445 Float64 nominal_sample_rate; | 521 Float64 nominal_sample_rate; |
| 446 UInt32 info_size = sizeof(nominal_sample_rate); | 522 UInt32 info_size = sizeof(nominal_sample_rate); |
| 447 | 523 |
| 448 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { | 524 static const AudioObjectPropertyAddress kNominalSampleRateAddress = { |
| (...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1084 ScopedAudioManagerPtr CreateAudioManager( | 1160 ScopedAudioManagerPtr CreateAudioManager( |
| 1085 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 1161 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 1086 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, | 1162 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, |
| 1087 AudioLogFactory* audio_log_factory) { | 1163 AudioLogFactory* audio_log_factory) { |
| 1088 return ScopedAudioManagerPtr( | 1164 return ScopedAudioManagerPtr( |
| 1089 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), | 1165 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), |
| 1090 audio_log_factory)); | 1166 audio_log_factory)); |
| 1091 } | 1167 } |
| 1092 | 1168 |
| 1093 } // namespace media | 1169 } // namespace media |
| OLD | NEW |