Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: media/audio/mac/audio_manager_mac.cc

Issue 2695633006: Use preferred channel layout on macOS instead of total channel count. (Closed)
Patch Set: Fix compilation issues. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | media/base/channel_layout.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | media/base/channel_layout.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698