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

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: nit 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
« no previous file with comments | « media/audio/win/core_audio_util_win.h ('k') | media/audio/win/core_audio_util_win_unittest.cc » ('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/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"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
13 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
14 #include "base/win/scoped_co_mem.h" 14 #include "base/win/scoped_co_mem.h"
15 #include "base/win/scoped_handle.h" 15 #include "base/win/scoped_handle.h"
16 #include "base/win/scoped_propvariant.h" 16 #include "base/win/scoped_propvariant.h"
17 #include "base/win/windows_version.h" 17 #include "base/win/windows_version.h"
18 #include "media/base/media_switches.h" 18 #include "media/base/media_switches.h"
19 19
20 using base::win::ScopedCoMem; 20 using base::win::ScopedCoMem;
21 using base::win::ScopedHandle; 21 using base::win::ScopedHandle;
22 22
23 namespace media { 23 namespace media {
24 24
25 enum { KSAUDIO_SPEAKER_UNSUPPORTED = 0 };
26
25 typedef uint32 ChannelConfig; 27 typedef uint32 ChannelConfig;
26 28
27 // Converts Microsoft's channel configuration to ChannelLayout. 29 // Converts Microsoft's channel configuration to ChannelLayout.
28 // This mapping is not perfect but the best we can do given the current 30 // This mapping is not perfect but the best we can do given the current
29 // ChannelLayout enumerator and the Windows-specific speaker configurations 31 // ChannelLayout enumerator and the Windows-specific speaker configurations
30 // defined in ksmedia.h. Don't assume that the channel ordering in 32 // defined in ksmedia.h. Don't assume that the channel ordering in
31 // ChannelLayout is exactly the same as the Windows specific configuration. 33 // ChannelLayout is exactly the same as the Windows specific configuration.
32 // As an example: KSAUDIO_SPEAKER_7POINT1_SURROUND is mapped to 34 // As an example: KSAUDIO_SPEAKER_7POINT1_SURROUND is mapped to
33 // CHANNEL_LAYOUT_7_1 but the positions of Back L, Back R and Side L, Side R 35 // CHANNEL_LAYOUT_7_1 but the positions of Back L, Back R and Side L, Side R
34 // speakers are different in these two definitions. 36 // speakers are different in these two definitions.
(...skipping 20 matching lines...) Expand all
55 case KSAUDIO_SPEAKER_5POINT1_SURROUND: 57 case KSAUDIO_SPEAKER_5POINT1_SURROUND:
56 DVLOG(2) << "KSAUDIO_SPEAKER_5POINT1_SURROUND=>CHANNEL_LAYOUT_5_1"; 58 DVLOG(2) << "KSAUDIO_SPEAKER_5POINT1_SURROUND=>CHANNEL_LAYOUT_5_1";
57 return CHANNEL_LAYOUT_5_1; 59 return CHANNEL_LAYOUT_5_1;
58 case KSAUDIO_SPEAKER_7POINT1: 60 case KSAUDIO_SPEAKER_7POINT1:
59 DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1=>CHANNEL_LAYOUT_7_1_WIDE"; 61 DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1=>CHANNEL_LAYOUT_7_1_WIDE";
60 return CHANNEL_LAYOUT_7_1_WIDE; 62 return CHANNEL_LAYOUT_7_1_WIDE;
61 case KSAUDIO_SPEAKER_7POINT1_SURROUND: 63 case KSAUDIO_SPEAKER_7POINT1_SURROUND:
62 DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1_SURROUND=>CHANNEL_LAYOUT_7_1"; 64 DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1_SURROUND=>CHANNEL_LAYOUT_7_1";
63 return CHANNEL_LAYOUT_7_1; 65 return CHANNEL_LAYOUT_7_1;
64 default: 66 default:
65 DVLOG(2) << "Unsupported channel layout: " << config; 67 DVLOG(2) << "Unsupported channel configuration: " << config;
66 return CHANNEL_LAYOUT_UNSUPPORTED; 68 return CHANNEL_LAYOUT_UNSUPPORTED;
67 } 69 }
68 } 70 }
69 71
72 // TODO(henrika): add mapping for all types in the ChannelLayout enumerator.
73 static ChannelConfig ChannelLayoutToChannelConfig(ChannelLayout layout) {
74 switch (layout) {
75 case CHANNEL_LAYOUT_NONE:
76 DVLOG(2) << "CHANNEL_LAYOUT_NONE=>KSAUDIO_SPEAKER_UNSUPPORTED";
77 return KSAUDIO_SPEAKER_UNSUPPORTED;
78 case CHANNEL_LAYOUT_UNSUPPORTED:
79 DVLOG(2) << "CHANNEL_LAYOUT_UNSUPPORTED=>KSAUDIO_SPEAKER_UNSUPPORTED";
80 return KSAUDIO_SPEAKER_UNSUPPORTED;
81 case CHANNEL_LAYOUT_MONO:
82 DVLOG(2) << "CHANNEL_LAYOUT_MONO=>KSAUDIO_SPEAKER_MONO";
83 return KSAUDIO_SPEAKER_MONO;
84 case CHANNEL_LAYOUT_STEREO:
85 DVLOG(2) << "CHANNEL_LAYOUT_STEREO=>KSAUDIO_SPEAKER_STEREO";
86 return KSAUDIO_SPEAKER_STEREO;
87 case CHANNEL_LAYOUT_QUAD:
88 DVLOG(2) << "CHANNEL_LAYOUT_QUAD=>KSAUDIO_SPEAKER_QUAD";
89 return KSAUDIO_SPEAKER_QUAD;
90 case CHANNEL_LAYOUT_4_0:
91 DVLOG(2) << "CHANNEL_LAYOUT_4_0=>KSAUDIO_SPEAKER_SURROUND";
92 return KSAUDIO_SPEAKER_SURROUND;
93 case CHANNEL_LAYOUT_5_1_BACK:
94 DVLOG(2) << "CHANNEL_LAYOUT_5_1_BACK=>KSAUDIO_SPEAKER_5POINT1";
95 return KSAUDIO_SPEAKER_5POINT1;
96 case CHANNEL_LAYOUT_5_1:
97 DVLOG(2) << "CHANNEL_LAYOUT_5_1=>KSAUDIO_SPEAKER_5POINT1_SURROUND";
98 return KSAUDIO_SPEAKER_5POINT1_SURROUND;
99 case CHANNEL_LAYOUT_7_1_WIDE:
100 DVLOG(2) << "CHANNEL_LAYOUT_7_1_WIDE=>KSAUDIO_SPEAKER_7POINT1";
101 return KSAUDIO_SPEAKER_7POINT1;
102 case CHANNEL_LAYOUT_7_1:
103 DVLOG(2) << "CHANNEL_LAYOUT_7_1=>KSAUDIO_SPEAKER_7POINT1_SURROUND";
104 return KSAUDIO_SPEAKER_7POINT1_SURROUND;
105 default:
106 DVLOG(2) << "Unsupported channel layout: " << layout;
107 return KSAUDIO_SPEAKER_UNSUPPORTED;
108 }
109 }
110
111 static std::ostream& operator<<(std::ostream& os,
112 const WAVEFORMATPCMEX& format) {
113 os << "wFormatTag: 0x" << std::hex << format.Format.wFormatTag
114 << ", nChannels: " << std::dec << format.Format.nChannels
115 << ", nSamplesPerSec: " << format.Format.nSamplesPerSec
116 << ", nAvgBytesPerSec: " << format.Format.nAvgBytesPerSec
117 << ", nBlockAlign: " << format.Format.nBlockAlign
118 << ", wBitsPerSample: " << format.Format.wBitsPerSample
119 << ", cbSize: " << format.Format.cbSize
120 << ", wValidBitsPerSample: " << format.Samples.wValidBitsPerSample
121 << ", dwChannelMask: 0x" << std::hex << format.dwChannelMask;
122 return os;
123 }
124
70 bool LoadAudiosesDll() { 125 bool LoadAudiosesDll() {
71 static const wchar_t* const kAudiosesDLL = 126 static const wchar_t* const kAudiosesDLL =
72 L"%WINDIR%\\system32\\audioses.dll"; 127 L"%WINDIR%\\system32\\audioses.dll";
73 128
74 wchar_t path[MAX_PATH] = {0}; 129 wchar_t path[MAX_PATH] = {0};
75 ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path)); 130 ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path));
76 return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL); 131 return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL);
77 } 132 }
78 133
79 bool CanCreateDeviceEnumerator() { 134 bool CanCreateDeviceEnumerator() {
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 ScopedCoMem<WAVEFORMATPCMEX> format_pcmex; 397 ScopedCoMem<WAVEFORMATPCMEX> format_pcmex;
343 HRESULT hr = client->GetMixFormat( 398 HRESULT hr = client->GetMixFormat(
344 reinterpret_cast<WAVEFORMATEX**>(&format_pcmex)); 399 reinterpret_cast<WAVEFORMATEX**>(&format_pcmex));
345 if (FAILED(hr)) 400 if (FAILED(hr))
346 return hr; 401 return hr;
347 402
348 size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize; 403 size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize;
349 DCHECK_EQ(bytes, sizeof(WAVEFORMATPCMEX)); 404 DCHECK_EQ(bytes, sizeof(WAVEFORMATPCMEX));
350 405
351 memcpy(format, format_pcmex, bytes); 406 memcpy(format, format_pcmex, bytes);
352 407 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 408
363 return hr; 409 return hr;
364 } 410 }
365 411
366 HRESULT CoreAudioUtil::GetDefaultSharedModeMixFormat( 412 HRESULT CoreAudioUtil::GetDefaultSharedModeMixFormat(
367 EDataFlow data_flow, ERole role, WAVEFORMATPCMEX* format) { 413 EDataFlow data_flow, ERole role, WAVEFORMATPCMEX* format) {
368 DCHECK(IsSupported()); 414 DCHECK(IsSupported());
369 ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role)); 415 ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role));
370 if (!client) { 416 if (!client) {
371 // Map NULL-pointer to new error code which can be different from the 417 // Map NULL-pointer to new error code which can be different from the
(...skipping 11 matching lines...) Expand all
383 HRESULT hr = client->IsFormatSupported( 429 HRESULT hr = client->IsFormatSupported(
384 share_mode, reinterpret_cast<const WAVEFORMATEX*>(format), 430 share_mode, reinterpret_cast<const WAVEFORMATEX*>(format),
385 reinterpret_cast<WAVEFORMATEX**>(&closest_match)); 431 reinterpret_cast<WAVEFORMATEX**>(&closest_match));
386 432
387 // This log can only be triggered for shared mode. 433 // This log can only be triggered for shared mode.
388 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " 434 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported "
389 << "but a closest match exists."; 435 << "but a closest match exists.";
390 // This log can be triggered both for shared and exclusive modes. 436 // This log can be triggered both for shared and exclusive modes.
391 DLOG_IF(ERROR, hr == AUDCLNT_E_UNSUPPORTED_FORMAT) << "Unsupported format."; 437 DLOG_IF(ERROR, hr == AUDCLNT_E_UNSUPPORTED_FORMAT) << "Unsupported format.";
392 if (hr == S_FALSE) { 438 if (hr == S_FALSE) {
393 DVLOG(2) << "wFormatTag: " << closest_match->Format.wFormatTag 439 DVLOG(2) << *closest_match;
394 << ", nChannels: " << closest_match->Format.nChannels
395 << ", nSamplesPerSec: " << closest_match->Format.nSamplesPerSec
396 << ", wBitsPerSample: " << closest_match->Format.wBitsPerSample;
397 } 440 }
398 441
399 return (hr == S_OK); 442 return (hr == S_OK);
400 } 443 }
401 444
445 bool CoreAudioUtil::IsChannelLayoutSupported(EDataFlow data_flow, ERole role,
446 ChannelLayout channel_layout) {
447 DCHECK(IsSupported());
448
449 // First, get the preferred mixing format for shared mode streams.
450
451 ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role));
452 if (!client)
453 return false;
454
455 WAVEFORMATPCMEX format;
456 HRESULT hr = CoreAudioUtil::GetSharedModeMixFormat(client, &format);
457 if (FAILED(hr))
458 return false;
459
460 // Next, check if it is possible to use an alternative format where the
461 // channel layout (and possibly number of channels) is modified.
462
463 // Convert generic channel layout into Windows-specific channel configuration.
464 ChannelConfig new_config = ChannelLayoutToChannelConfig(channel_layout);
465 if (new_config == KSAUDIO_SPEAKER_UNSUPPORTED) {
466 return false;
467 }
468 format.dwChannelMask = new_config;
469
470 // Modify the format if the new channel layout has changed the number of
471 // utilized channels.
472 const int channels = ChannelLayoutToChannelCount(channel_layout);
473 if (channels != format.Format.nChannels) {
474 format.Format.nChannels = channels;
475 format.Format.nBlockAlign = (format.Format.wBitsPerSample / 8) * channels;
476 format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec *
477 format.Format.nBlockAlign;
478 }
479 DVLOG(2) << format;
480
481 // Some devices can initialize a shared-mode stream with a format that is
482 // not identical to the mix format obtained from the GetMixFormat() method.
483 // However, chances of succeeding increases if we use the same number of
484 // channels and the same sample rate as the mix format. I.e, this call will
485 // return true only in those cases where the audio engine is able to support
486 // an even wider range of shared-mode formats where the installation package
487 // for the audio device includes a local effects (LFX) audio processing
488 // object (APO) that can handle format conversions.
489 return CoreAudioUtil::IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED,
490 &format);
491 }
492
402 HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client, 493 HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client,
403 AUDCLNT_SHAREMODE share_mode, 494 AUDCLNT_SHAREMODE share_mode,
404 REFERENCE_TIME* device_period) { 495 REFERENCE_TIME* device_period) {
405 DCHECK(IsSupported()); 496 DCHECK(IsSupported());
406 497
407 // Get the period of the engine thread. 498 // Get the period of the engine thread.
408 REFERENCE_TIME default_period = 0; 499 REFERENCE_TIME default_period = 0;
409 REFERENCE_TIME minimum_period = 0; 500 REFERENCE_TIME minimum_period = 0;
410 HRESULT hr = client->GetDevicePeriod(&default_period, &minimum_period); 501 HRESULT hr = client->GetDevicePeriod(&default_period, &minimum_period);
411 if (FAILED(hr)) 502 if (FAILED(hr))
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 return false; 689 return false;
599 690
600 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to 691 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to
601 // explicitly write silence data to the rendering buffer. 692 // explicitly write silence data to the rendering buffer.
602 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence"; 693 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence";
603 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill, 694 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill,
604 AUDCLNT_BUFFERFLAGS_SILENT)); 695 AUDCLNT_BUFFERFLAGS_SILENT));
605 } 696 }
606 697
607 } // namespace media 698 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/win/core_audio_util_win.h ('k') | media/audio/win/core_audio_util_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698