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

Side by Side Diff: media/audio/win/core_audio_util_win.cc

Issue 12918026: Adds support for CoreAudioUtil::IsChannelLayoutSupported() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 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 | Annotate | Revision Log
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/win/core_audio_util_win.h" 5 #include "media/audio/win/core_audio_util_win.h"
6 6
7 #include <Audioclient.h> 7 #include <Audioclient.h>
8 #include <Functiondiscoverykeys_devpkey.h> 8 #include <Functiondiscoverykeys_devpkey.h>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 return CHANNEL_LAYOUT_7_1_WIDE; 60 return CHANNEL_LAYOUT_7_1_WIDE;
61 case KSAUDIO_SPEAKER_7POINT1_SURROUND: 61 case KSAUDIO_SPEAKER_7POINT1_SURROUND:
62 DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1_SURROUND=>CHANNEL_LAYOUT_7_1"; 62 DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1_SURROUND=>CHANNEL_LAYOUT_7_1";
63 return CHANNEL_LAYOUT_7_1; 63 return CHANNEL_LAYOUT_7_1;
64 default: 64 default:
65 DVLOG(2) << "Unsupported channel layout: " << config; 65 DVLOG(2) << "Unsupported channel layout: " << config;
66 return CHANNEL_LAYOUT_UNSUPPORTED; 66 return CHANNEL_LAYOUT_UNSUPPORTED;
67 } 67 }
68 } 68 }
69 69
70 // TODO(henrika): add mapping for all types in the ChannelLayout enumerator.
71 static ChannelConfig ChannelLayoutToChannelConfig(ChannelLayout layout) {
72 switch (layout) {
73 case CHANNEL_LAYOUT_NONE:
DaleCurtis 2013/03/27 17:30:18 These top two should be UNSUPPORTED.
henrika (OOO until Aug 14) 2013/03/28 09:15:05 Defined KSAUDIO_SPEAKER_UNSUPPORTED locally.
74 DVLOG(2) << "CHANNEL_LAYOUT_NONE=>KSAUDIO_SPEAKER_DIRECTOUT";
75 return KSAUDIO_SPEAKER_DIRECTOUT;
76 case CHANNEL_LAYOUT_UNSUPPORTED:
77 DVLOG(2) << "CHANNEL_LAYOUT_UNSUPPORTED=>KSAUDIO_SPEAKER_DIRECTOUT";
78 return KSAUDIO_SPEAKER_DIRECTOUT;
79 case CHANNEL_LAYOUT_MONO:
80 DVLOG(2) << "CHANNEL_LAYOUT_MONO=>KSAUDIO_SPEAKER_MONO";
81 return KSAUDIO_SPEAKER_MONO;
82 case CHANNEL_LAYOUT_STEREO:
83 DVLOG(2) << "CHANNEL_LAYOUT_STEREO=>KSAUDIO_SPEAKER_STEREO";
84 return KSAUDIO_SPEAKER_STEREO;
85 case CHANNEL_LAYOUT_QUAD:
86 DVLOG(2) << "CHANNEL_LAYOUT_QUAD=>KSAUDIO_SPEAKER_QUAD";
87 return KSAUDIO_SPEAKER_QUAD;
88 case CHANNEL_LAYOUT_4_0:
89 DVLOG(2) << "CHANNEL_LAYOUT_4_0=>KSAUDIO_SPEAKER_SURROUND";
90 return KSAUDIO_SPEAKER_SURROUND;
91 case CHANNEL_LAYOUT_5_1_BACK:
92 DVLOG(2) << "CHANNEL_LAYOUT_5_1_BACK=>KSAUDIO_SPEAKER_5POINT1";
93 return KSAUDIO_SPEAKER_5POINT1;
94 case CHANNEL_LAYOUT_5_1:
95 DVLOG(2) << "CHANNEL_LAYOUT_5_1=>KSAUDIO_SPEAKER_5POINT1_SURROUND";
96 return KSAUDIO_SPEAKER_5POINT1_SURROUND;
97 case CHANNEL_LAYOUT_7_1_WIDE:
98 DVLOG(2) << "CHANNEL_LAYOUT_7_1_WIDE=>KSAUDIO_SPEAKER_7POINT1";
99 return KSAUDIO_SPEAKER_7POINT1;
100 case CHANNEL_LAYOUT_7_1:
101 DVLOG(2) << "CHANNEL_LAYOUT_7_1=>KSAUDIO_SPEAKER_7POINT1_SURROUND";
102 return KSAUDIO_SPEAKER_7POINT1_SURROUND;
103 default:
104 DVLOG(2) << "Unsupported channel layout: " << layout;
105 return CHANNEL_LAYOUT_UNSUPPORTED;
DaleCurtis 2013/03/27 17:30:18 I'm surprised this ChannelLayout returns correctly
henrika (OOO until Aug 14) 2013/03/28 09:15:05 fixed.
106 }
107 }
108
109 static std::ostream& operator<<(std::ostream& os,
110 const WAVEFORMATPCMEX& format) {
111 os << "wFormatTag: 0x" << std::hex << format.Format.wFormatTag
112 << ", nChannels: " << std::dec << format.Format.nChannels
113 << ", nSamplesPerSec: " << format.Format.nSamplesPerSec
114 << ", nAvgBytesPerSec: " << format.Format.nAvgBytesPerSec
115 << ", nBlockAlign: " << format.Format.nBlockAlign
116 << ", wBitsPerSample: " << format.Format.wBitsPerSample
117 << ", cbSize: " << format.Format.cbSize
118 << ", wValidBitsPerSample: " << format.Samples.wValidBitsPerSample
119 << ", dwChannelMask: 0x" << std::hex << format.dwChannelMask;
120 return os;
121 }
122
70 bool LoadAudiosesDll() { 123 bool LoadAudiosesDll() {
71 static const wchar_t* const kAudiosesDLL = 124 static const wchar_t* const kAudiosesDLL =
72 L"%WINDIR%\\system32\\audioses.dll"; 125 L"%WINDIR%\\system32\\audioses.dll";
73 126
74 wchar_t path[MAX_PATH] = {0}; 127 wchar_t path[MAX_PATH] = {0};
75 ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path)); 128 ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path));
76 return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL); 129 return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL);
77 } 130 }
78 131
79 bool CanCreateDeviceEnumerator() { 132 bool CanCreateDeviceEnumerator() {
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 ScopedCoMem<WAVEFORMATPCMEX> format_pcmex; 395 ScopedCoMem<WAVEFORMATPCMEX> format_pcmex;
343 HRESULT hr = client->GetMixFormat( 396 HRESULT hr = client->GetMixFormat(
344 reinterpret_cast<WAVEFORMATEX**>(&format_pcmex)); 397 reinterpret_cast<WAVEFORMATEX**>(&format_pcmex));
345 if (FAILED(hr)) 398 if (FAILED(hr))
346 return hr; 399 return hr;
347 400
348 size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize; 401 size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize;
349 DCHECK_EQ(bytes, sizeof(WAVEFORMATPCMEX)); 402 DCHECK_EQ(bytes, sizeof(WAVEFORMATPCMEX));
350 403
351 memcpy(format, format_pcmex, bytes); 404 memcpy(format, format_pcmex, bytes);
352 405 DVLOG(2) << *format;
353 DVLOG(2) << "wFormatTag: 0x" << std::hex << format->Format.wFormatTag
354 << ", nChannels: " << std::dec << format->Format.nChannels
355 << ", nSamplesPerSec: " << format->Format.nSamplesPerSec
356 << ", nAvgBytesPerSec: " << format->Format.nAvgBytesPerSec
357 << ", nBlockAlign: " << format->Format.nBlockAlign
358 << ", wBitsPerSample: " << format->Format.wBitsPerSample
359 << ", cbSize: " << format->Format.cbSize
360 << ", wValidBitsPerSample: " << format->Samples.wValidBitsPerSample
361 << ", dwChannelMask: 0x" << std::hex << format->dwChannelMask;
362 406
363 return hr; 407 return hr;
364 } 408 }
365 409
366 HRESULT CoreAudioUtil::GetDefaultSharedModeMixFormat( 410 HRESULT CoreAudioUtil::GetDefaultSharedModeMixFormat(
367 EDataFlow data_flow, ERole role, WAVEFORMATPCMEX* format) { 411 EDataFlow data_flow, ERole role, WAVEFORMATPCMEX* format) {
368 DCHECK(IsSupported()); 412 DCHECK(IsSupported());
369 ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role)); 413 ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role));
370 if (!client) { 414 if (!client) {
371 // Map NULL-pointer to new error code which can be different from the 415 // Map NULL-pointer to new error code which can be different from the
(...skipping 11 matching lines...) Expand all
383 HRESULT hr = client->IsFormatSupported( 427 HRESULT hr = client->IsFormatSupported(
384 share_mode, reinterpret_cast<const WAVEFORMATEX*>(format), 428 share_mode, reinterpret_cast<const WAVEFORMATEX*>(format),
385 reinterpret_cast<WAVEFORMATEX**>(&closest_match)); 429 reinterpret_cast<WAVEFORMATEX**>(&closest_match));
386 430
387 // This log can only be triggered for shared mode. 431 // This log can only be triggered for shared mode.
388 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " 432 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported "
389 << "but a closest match exists."; 433 << "but a closest match exists.";
390 // This log can be triggered both for shared and exclusive modes. 434 // This log can be triggered both for shared and exclusive modes.
391 DLOG_IF(ERROR, hr == AUDCLNT_E_UNSUPPORTED_FORMAT) << "Unsupported format."; 435 DLOG_IF(ERROR, hr == AUDCLNT_E_UNSUPPORTED_FORMAT) << "Unsupported format.";
392 if (hr == S_FALSE) { 436 if (hr == S_FALSE) {
393 DVLOG(2) << "wFormatTag: " << closest_match->Format.wFormatTag 437 DVLOG(2) << *closest_match;
394 << ", nChannels: " << closest_match->Format.nChannels
395 << ", nSamplesPerSec: " << closest_match->Format.nSamplesPerSec
396 << ", wBitsPerSample: " << closest_match->Format.wBitsPerSample;
397 } 438 }
398 439
399 return (hr == S_OK); 440 return (hr == S_OK);
400 } 441 }
401 442
443 bool CoreAudioUtil::IsChannelLayoutSupported(EDataFlow data_flow, ERole role,
444 ChannelLayout channel_layout) {
445 DCHECK(IsSupported());
446
447 // First, get the preferred mixing format for shared mode streams.
448
449 ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role));
450 if (!client)
451 return false;
452
453 WAVEFORMATPCMEX format;
454 HRESULT hr = CoreAudioUtil::GetSharedModeMixFormat(client, &format);
455 if (FAILED(hr))
456 return false;
457
458 // Next, check if it is possible to use an alternative format where the
459 // channel layout (and possibly number of channels) is modified.
460
461 const int channels = ChannelLayoutToChannelCount(channel_layout);
462 if (channels != format.Format.nChannels) {
463 format.Format.nChannels = channels;
464 format.Format.nBlockAlign = (format.Format.wBitsPerSample / 8) * channels;
465 format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec *
466 format.Format.nBlockAlign;
467 }
468
469 ChannelConfig new_config = ChannelLayoutToChannelConfig(channel_layout);
470 format.dwChannelMask = new_config;
DaleCurtis 2013/03/27 17:30:18 Bail early if new_config == unsupported? Should pr
henrika (OOO until Aug 14) 2013/03/28 09:15:05 Done.
471 DVLOG(2) << format;
472
473 // Some devices can initialize a shared-mode stream with a format that is
474 // not identical to the mix format obtained from the GetMixFormat() method.
475 // However, chances of succeeding increases if we use the same number of
476 // channels and the same sample rate as the mix format. I.e, this call will
477 // return true only in those cases where the audio engine is able to support
478 // an even wider range of shared-mode formats where the installation package
479 // for the audio device includes a local effects (LFX) audio processing
480 // object (APO) that can handle format conversions.
481 return CoreAudioUtil::IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED,
DaleCurtis 2013/03/27 17:30:18 align &format or wrap the whole line.
henrika (OOO until Aug 14) 2013/03/28 09:15:05 Done.
482 &format);
483 }
484
402 HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client, 485 HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client,
403 AUDCLNT_SHAREMODE share_mode, 486 AUDCLNT_SHAREMODE share_mode,
404 REFERENCE_TIME* device_period) { 487 REFERENCE_TIME* device_period) {
405 DCHECK(IsSupported()); 488 DCHECK(IsSupported());
406 489
407 // Get the period of the engine thread. 490 // Get the period of the engine thread.
408 REFERENCE_TIME default_period = 0; 491 REFERENCE_TIME default_period = 0;
409 REFERENCE_TIME minimum_period = 0; 492 REFERENCE_TIME minimum_period = 0;
410 HRESULT hr = client->GetDevicePeriod(&default_period, &minimum_period); 493 HRESULT hr = client->GetDevicePeriod(&default_period, &minimum_period);
411 if (FAILED(hr)) 494 if (FAILED(hr))
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 return false; 681 return false;
599 682
600 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to 683 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to
601 // explicitly write silence data to the rendering buffer. 684 // explicitly write silence data to the rendering buffer.
602 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence"; 685 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence";
603 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill, 686 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill,
604 AUDCLNT_BUFFERFLAGS_SILENT)); 687 AUDCLNT_BUFFERFLAGS_SILENT));
605 } 688 }
606 689
607 } // namespace media 690 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698