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

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

Issue 155863003: Add basic support for "googDucking" to getUserMedia on Windows. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Initialize enumeration flag in constructor Created 6 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 | « media/audio/win/audio_manager_win.h ('k') | media/audio/win/core_audio_util_win.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/audio_io.h" 5 #include "media/audio/audio_io.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <objbase.h> // This has to be before initguid.h 8 #include <objbase.h> // This has to be before initguid.h
9 #include <initguid.h> 9 #include <initguid.h>
10 #include <mmsystem.h> 10 #include <mmsystem.h>
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 // - The entire Windows audio stack was rewritten for Windows Vista and wave 122 // - The entire Windows audio stack was rewritten for Windows Vista and wave
123 // out performance was degraded compared to XP. 123 // out performance was degraded compared to XP.
124 // - The regression was fixed in Windows 7 and most configurations will work 124 // - The regression was fixed in Windows 7 and most configurations will work
125 // with 2, but some (e.g., some Sound Blasters) still need 3. 125 // with 2, but some (e.g., some Sound Blasters) still need 3.
126 // - Some XP configurations (even multi-processor ones) also need 3. 126 // - Some XP configurations (even multi-processor ones) also need 3.
127 return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3; 127 return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3;
128 } 128 }
129 129
130 AudioManagerWin::AudioManagerWin(AudioLogFactory* audio_log_factory) 130 AudioManagerWin::AudioManagerWin(AudioLogFactory* audio_log_factory)
131 : AudioManagerBase(audio_log_factory), 131 : AudioManagerBase(audio_log_factory),
132 enumeration_type_(kUninitializedEnumeration) { 132 // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing
133 // multiple initializations. This is however not thread safe.
134 // So, here we call it explicitly before we kick off the audio thread
135 // or do any other work.
136 enumeration_type_(CoreAudioUtil::IsSupported() ?
137 kMMDeviceEnumeration : kWaveEnumeration) {
133 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 138 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
134 139
135 // WARNING: This is executed on the UI loop, do not add any code here which 140 // WARNING: This is executed on the UI loop, do not add any code here which
136 // loads libraries or attempts to call out into the OS. Instead add such code 141 // loads libraries or attempts to call out into the OS. Instead add such code
137 // to the InitializeOnAudioThread() method below. 142 // to the InitializeOnAudioThread() method below.
138 143
139 // Task must be posted last to avoid races from handing out "this" to the 144 // Task must be posted last to avoid races from handing out "this" to the
140 // audio thread. 145 // audio thread.
141 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 146 GetTaskRunner()->PostTask(FROM_HERE, base::Bind(
142 &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this))); 147 &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this)));
(...skipping 11 matching lines...) Expand all
154 return (::waveOutGetNumDevs() != 0); 159 return (::waveOutGetNumDevs() != 0);
155 } 160 }
156 161
157 bool AudioManagerWin::HasAudioInputDevices() { 162 bool AudioManagerWin::HasAudioInputDevices() {
158 return (::waveInGetNumDevs() != 0); 163 return (::waveInGetNumDevs() != 0);
159 } 164 }
160 165
161 void AudioManagerWin::InitializeOnAudioThread() { 166 void AudioManagerWin::InitializeOnAudioThread() {
162 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 167 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
163 168
164 if (CoreAudioUtil::IsSupported()) { 169 if (core_audio_supported()) {
165 // Use the MMDevice API for device enumeration if Vista or higher.
166 enumeration_type_ = kMMDeviceEnumeration;
167
168 // AudioDeviceListenerWin must be initialized on a COM thread and should 170 // AudioDeviceListenerWin must be initialized on a COM thread and should
169 // only be used if WASAPI / Core Audio is supported. 171 // only be used if WASAPI / Core Audio is supported.
170 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( 172 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop(
171 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners, 173 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners,
172 base::Unretained(this))))); 174 base::Unretained(this)))));
173 } else {
174 // Use the Wave API for device enumeration if XP or lower.
175 enumeration_type_ = kWaveEnumeration;
176 } 175 }
177 } 176 }
178 177
179 void AudioManagerWin::ShutdownOnAudioThread() { 178 void AudioManagerWin::ShutdownOnAudioThread() {
180 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 179 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
181 output_device_listener_.reset(); 180 output_device_listener_.reset();
182 } 181 }
183 182
184 base::string16 AudioManagerWin::GetAudioInputDeviceModel() { 183 base::string16 AudioManagerWin::GetAudioInputDeviceModel() {
185 // Get the default audio capture device and its device interface name. 184 // Get the default audio capture device and its device interface name.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 if (device_found) 240 if (device_found)
242 return GetDeviceAndDriverInfo(device_info, &device_data); 241 return GetDeviceAndDriverInfo(device_info, &device_data);
243 } 242 }
244 243
245 return base::string16(); 244 return base::string16();
246 } 245 }
247 246
248 void AudioManagerWin::ShowAudioInputSettings() { 247 void AudioManagerWin::ShowAudioInputSettings() {
249 std::wstring program; 248 std::wstring program;
250 std::string argument; 249 std::string argument;
251 if (!CoreAudioUtil::IsSupported()) { 250 if (!core_audio_supported()) {
252 program = L"sndvol32.exe"; 251 program = L"sndvol32.exe";
253 argument = "-R"; 252 argument = "-R";
254 } else { 253 } else {
255 program = L"control.exe"; 254 program = L"control.exe";
256 argument = "mmsys.cpl,,1"; 255 argument = "mmsys.cpl,,1";
257 } 256 }
258 257
259 base::FilePath path; 258 base::FilePath path;
260 PathService::Get(base::DIR_SYSTEM, &path); 259 PathService::Get(base::DIR_SYSTEM, &path);
261 path = path.Append(program); 260 path = path.Append(program);
262 CommandLine command_line(path); 261 CommandLine command_line(path);
263 command_line.AppendArg(argument); 262 command_line.AppendArg(argument);
264 base::LaunchProcess(command_line, base::LaunchOptions(), NULL); 263 base::LaunchProcess(command_line, base::LaunchOptions(), NULL);
265 } 264 }
266 265
267 void AudioManagerWin::GetAudioDeviceNamesImpl( 266 void AudioManagerWin::GetAudioDeviceNamesImpl(
268 bool input, 267 bool input,
269 AudioDeviceNames* device_names) { 268 AudioDeviceNames* device_names) {
270 DCHECK(device_names->empty()); 269 DCHECK(device_names->empty());
271 DCHECK(enumeration_type() != kUninitializedEnumeration);
272 // Enumerate all active audio-endpoint capture devices. 270 // Enumerate all active audio-endpoint capture devices.
273 if (enumeration_type() == kWaveEnumeration) { 271 if (enumeration_type() == kWaveEnumeration) {
274 // Utilize the Wave API for Windows XP. 272 // Utilize the Wave API for Windows XP.
275 if (input) 273 if (input)
276 GetInputDeviceNamesWinXP(device_names); 274 GetInputDeviceNamesWinXP(device_names);
277 else 275 else
278 GetOutputDeviceNamesWinXP(device_names); 276 GetOutputDeviceNamesWinXP(device_names);
279 } else { 277 } else {
280 // Utilize the MMDevice API (part of Core Audio) for Vista and higher. 278 // Utilize the MMDevice API (part of Core Audio) for Vista and higher.
281 if (input) 279 if (input)
(...skipping 15 matching lines...) Expand all
297 GetAudioDeviceNamesImpl(true, device_names); 295 GetAudioDeviceNamesImpl(true, device_names);
298 } 296 }
299 297
300 void AudioManagerWin::GetAudioOutputDeviceNames( 298 void AudioManagerWin::GetAudioOutputDeviceNames(
301 AudioDeviceNames* device_names) { 299 AudioDeviceNames* device_names) {
302 GetAudioDeviceNamesImpl(false, device_names); 300 GetAudioDeviceNamesImpl(false, device_names);
303 } 301 }
304 302
305 AudioParameters AudioManagerWin::GetInputStreamParameters( 303 AudioParameters AudioManagerWin::GetInputStreamParameters(
306 const std::string& device_id) { 304 const std::string& device_id) {
307 int sample_rate = 48000; 305 if (!core_audio_supported()) {
308 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 306 return AudioParameters(
309 if (CoreAudioUtil::IsSupported()) { 307 AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 0, 48000,
310 int hw_sample_rate = WASAPIAudioInputStream::HardwareSampleRate(device_id); 308 16, kFallbackBufferSize, AudioParameters::NO_EFFECTS);
311 if (hw_sample_rate)
312 sample_rate = hw_sample_rate;
313 channel_layout =
314 WASAPIAudioInputStream::HardwareChannelCount(device_id) == 1 ?
315 CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO;
316 } 309 }
317 310
318 // TODO(Henrika): improve the default buffer size value for input stream. 311 return WASAPIAudioInputStream::GetInputStreamParameters(device_id);
319 return AudioParameters(
320 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
321 sample_rate, 16, kFallbackBufferSize);
322 } 312 }
323 313
324 std::string AudioManagerWin::GetAssociatedOutputDeviceID( 314 std::string AudioManagerWin::GetAssociatedOutputDeviceID(
325 const std::string& input_device_id) { 315 const std::string& input_device_id) {
326 if (!CoreAudioUtil::IsSupported()) { 316 if (!core_audio_supported()) {
327 NOTIMPLEMENTED() 317 NOTIMPLEMENTED()
328 << "GetAssociatedOutputDeviceID is not supported on this OS"; 318 << "GetAssociatedOutputDeviceID is not supported on this OS";
329 return std::string(); 319 return std::string();
330 } 320 }
331 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); 321 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id);
332 } 322 }
333 323
334 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR 324 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR
335 // mode. 325 // mode.
336 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 326 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
(...skipping 15 matching lines...) Expand all
352 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 342 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
353 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. 343 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API.
354 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( 344 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream(
355 const AudioParameters& params, 345 const AudioParameters& params,
356 const std::string& device_id, 346 const std::string& device_id,
357 const std::string& input_device_id) { 347 const std::string& input_device_id) {
358 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 348 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
359 if (params.channels() > kWinMaxChannels) 349 if (params.channels() > kWinMaxChannels)
360 return NULL; 350 return NULL;
361 351
362 if (!CoreAudioUtil::IsSupported()) { 352 if (!core_audio_supported()) {
363 // Fall back to Windows Wave implementation on Windows XP or lower. 353 // Fall back to Windows Wave implementation on Windows XP or lower.
364 DLOG_IF(ERROR, !device_id.empty() && 354 DLOG_IF(ERROR, !device_id.empty() &&
365 device_id != AudioManagerBase::kDefaultDeviceId) 355 device_id != AudioManagerBase::kDefaultDeviceId)
366 << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; 356 << "Opening by device id not supported by PCMWaveOutAudioOutputStream";
367 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; 357 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista.";
368 return new PCMWaveOutAudioOutputStream( 358 return new PCMWaveOutAudioOutputStream(
369 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); 359 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER);
370 } 360 }
371 361
372 // TODO(rtoy): support more than stereo input. 362 // TODO(rtoy): support more than stereo input.
(...skipping 20 matching lines...) Expand all
393 const AudioParameters& params, const std::string& device_id) { 383 const AudioParameters& params, const std::string& device_id) {
394 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 384 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
395 return CreatePCMWaveInAudioInputStream(params, device_id); 385 return CreatePCMWaveInAudioInputStream(params, device_id);
396 } 386 }
397 387
398 // Factory for the implementations of AudioInputStream for 388 // Factory for the implementations of AudioInputStream for
399 // AUDIO_PCM_LOW_LATENCY mode. 389 // AUDIO_PCM_LOW_LATENCY mode.
400 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( 390 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream(
401 const AudioParameters& params, const std::string& device_id) { 391 const AudioParameters& params, const std::string& device_id) {
402 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 392 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
393 DVLOG(1) << "MakeLowLatencyInputStream: " << device_id;
403 AudioInputStream* stream = NULL; 394 AudioInputStream* stream = NULL;
404 if (!CoreAudioUtil::IsSupported()) { 395 if (!core_audio_supported()) {
405 // Fall back to Windows Wave implementation on Windows XP or lower. 396 // Fall back to Windows Wave implementation on Windows XP or lower.
406 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; 397 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista.";
407 stream = CreatePCMWaveInAudioInputStream(params, device_id); 398 stream = CreatePCMWaveInAudioInputStream(params, device_id);
408 } else { 399 } else {
409 stream = new WASAPIAudioInputStream(this, params, device_id); 400 stream = new WASAPIAudioInputStream(this, params, device_id);
410 } 401 }
411 402
412 return stream; 403 return stream;
413 } 404 }
414 405
415 std::string AudioManagerWin::GetDefaultOutputDeviceID() { 406 std::string AudioManagerWin::GetDefaultOutputDeviceID() {
416 if (!CoreAudioUtil::IsSupported()) 407 if (!core_audio_supported())
417 return std::string(); 408 return std::string();
418 return CoreAudioUtil::GetDefaultOutputDeviceID(); 409 return CoreAudioUtil::GetDefaultOutputDeviceID();
419 } 410 }
420 411
421 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( 412 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
422 const std::string& output_device_id, 413 const std::string& output_device_id,
423 const AudioParameters& input_params) { 414 const AudioParameters& input_params) {
424 const bool core_audio_supported = CoreAudioUtil::IsSupported(); 415 DLOG_IF(ERROR, !core_audio_supported() && !output_device_id.empty())
425 DLOG_IF(ERROR, !core_audio_supported && !output_device_id.empty())
426 << "CoreAudio is required to open non-default devices."; 416 << "CoreAudio is required to open non-default devices.";
427 417
428 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 418 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
429 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 419 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
430 int sample_rate = 48000; 420 int sample_rate = 48000;
431 int buffer_size = kFallbackBufferSize; 421 int buffer_size = kFallbackBufferSize;
432 int bits_per_sample = 16; 422 int bits_per_sample = 16;
433 int input_channels = 0; 423 int input_channels = 0;
434 bool use_input_params = !core_audio_supported; 424 bool use_input_params = !core_audio_supported();
435 if (core_audio_supported) { 425 if (core_audio_supported()) {
436 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { 426 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
437 // TODO(rtoy): tune these values for best possible WebAudio 427 // TODO(rtoy): tune these values for best possible WebAudio
438 // performance. WebRTC works well at 48kHz and a buffer size of 480 428 // performance. WebRTC works well at 48kHz and a buffer size of 480
439 // samples will be used for this case. Note that exclusive mode is 429 // samples will be used for this case. Note that exclusive mode is
440 // experimental. This sample rate will be combined with a buffer size of 430 // experimental. This sample rate will be combined with a buffer size of
441 // 256 samples, which corresponds to an output delay of ~5.33ms. 431 // 256 samples, which corresponds to an output delay of ~5.33ms.
442 sample_rate = 48000; 432 sample_rate = 48000;
443 buffer_size = 256; 433 buffer_size = 256;
444 if (input_params.IsValid()) 434 if (input_params.IsValid())
445 channel_layout = input_params.channel_layout(); 435 channel_layout = input_params.channel_layout();
(...skipping 11 matching lines...) Expand all
457 } else { 447 } else {
458 use_input_params = true; 448 use_input_params = true;
459 } 449 }
460 } 450 }
461 } 451 }
462 452
463 if (input_params.IsValid()) { 453 if (input_params.IsValid()) {
464 // If the user has enabled checking supported channel layouts or we don't 454 // If the user has enabled checking supported channel layouts or we don't
465 // have a valid channel layout yet, try to use the input layout. See bugs 455 // have a valid channel layout yet, try to use the input layout. See bugs
466 // http://crbug.com/259165 and http://crbug.com/311906 for more details. 456 // http://crbug.com/259165 and http://crbug.com/311906 for more details.
467 if (core_audio_supported && 457 if (core_audio_supported() &&
468 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || 458 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) ||
469 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) { 459 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) {
470 // Check if it is possible to open up at the specified input channel 460 // Check if it is possible to open up at the specified input channel
471 // layout but avoid checking if the specified layout is the same as the 461 // layout but avoid checking if the specified layout is the same as the
472 // hardware (preferred) layout. We do this extra check to avoid the 462 // hardware (preferred) layout. We do this extra check to avoid the
473 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. 463 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases.
474 if (input_params.channel_layout() != channel_layout) { 464 if (input_params.channel_layout() != channel_layout) {
475 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the 465 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the
476 // operations that have already been done such as opening up a client 466 // operations that have already been done such as opening up a client
477 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do 467 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, 518 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers,
529 xp_device_id); 519 xp_device_id);
530 } 520 }
531 521
532 /// static 522 /// static
533 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 523 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
534 return new AudioManagerWin(audio_log_factory); 524 return new AudioManagerWin(audio_log_factory);
535 } 525 }
536 526
537 } // namespace media 527 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/win/audio_manager_win.h ('k') | media/audio/win/core_audio_util_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698