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: 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
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 enumeration_type_(kUninitializedEnumeration),
133 // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing
134 // multiple initializations. This is however not thread safe.
135 // So, here we call it explicitly before we kick off the audio thread
136 // or do any other work.
137 core_audio_supported_(CoreAudioUtil::IsSupported()) {
DaleCurtis 2014/02/05 22:15:43 Heh, I just removed this from the startup path las
tommi (sloooow) - chröme 2014/02/06 11:50:34 Did you measure this impact? It's not clear to me
tommi (sloooow) - chröme 2014/02/06 12:55:34 Henrik - maybe you can weigh in here as well with
henrika (OOO until Aug 14) 2014/02/06 13:11:28 Link to original issue which triggered the change:
DaleCurtis 2014/02/06 19:09:21 Here's the CL I moved it off in: https://coderevie
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. 170 // Use the MMDevice API for device enumeration if Vista or higher.
166 enumeration_type_ = kMMDeviceEnumeration; 171 enumeration_type_ = kMMDeviceEnumeration;
167 172
168 // AudioDeviceListenerWin must be initialized on a COM thread and should 173 // AudioDeviceListenerWin must be initialized on a COM thread and should
169 // only be used if WASAPI / Core Audio is supported. 174 // only be used if WASAPI / Core Audio is supported.
170 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( 175 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop(
171 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners, 176 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners,
172 base::Unretained(this))))); 177 base::Unretained(this)))));
173 } else { 178 } else {
174 // Use the Wave API for device enumeration if XP or lower. 179 // Use the Wave API for device enumeration if XP or lower.
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 if (device_found) 246 if (device_found)
242 return GetDeviceAndDriverInfo(device_info, &device_data); 247 return GetDeviceAndDriverInfo(device_info, &device_data);
243 } 248 }
244 249
245 return base::string16(); 250 return base::string16();
246 } 251 }
247 252
248 void AudioManagerWin::ShowAudioInputSettings() { 253 void AudioManagerWin::ShowAudioInputSettings() {
249 std::wstring program; 254 std::wstring program;
250 std::string argument; 255 std::string argument;
251 if (!CoreAudioUtil::IsSupported()) { 256 if (!core_audio_supported_) {
252 program = L"sndvol32.exe"; 257 program = L"sndvol32.exe";
253 argument = "-R"; 258 argument = "-R";
254 } else { 259 } else {
255 program = L"control.exe"; 260 program = L"control.exe";
256 argument = "mmsys.cpl,,1"; 261 argument = "mmsys.cpl,,1";
257 } 262 }
258 263
259 base::FilePath path; 264 base::FilePath path;
260 PathService::Get(base::DIR_SYSTEM, &path); 265 PathService::Get(base::DIR_SYSTEM, &path);
261 path = path.Append(program); 266 path = path.Append(program);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 GetAudioDeviceNamesImpl(true, device_names); 302 GetAudioDeviceNamesImpl(true, device_names);
298 } 303 }
299 304
300 void AudioManagerWin::GetAudioOutputDeviceNames( 305 void AudioManagerWin::GetAudioOutputDeviceNames(
301 AudioDeviceNames* device_names) { 306 AudioDeviceNames* device_names) {
302 GetAudioDeviceNamesImpl(false, device_names); 307 GetAudioDeviceNamesImpl(false, device_names);
303 } 308 }
304 309
305 AudioParameters AudioManagerWin::GetInputStreamParameters( 310 AudioParameters AudioManagerWin::GetInputStreamParameters(
306 const std::string& device_id) { 311 const std::string& device_id) {
307 int sample_rate = 48000; 312 if (!core_audio_supported_) {
308 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 313 return AudioParameters(
309 if (CoreAudioUtil::IsSupported()) { 314 AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 0, 48000,
310 int hw_sample_rate = WASAPIAudioInputStream::HardwareSampleRate(device_id); 315 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 } 316 }
317 317
318 // TODO(Henrika): improve the default buffer size value for input stream. 318 return WASAPIAudioInputStream::GetInputStreamParameters(device_id);
319 return AudioParameters(
320 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
321 sample_rate, 16, kFallbackBufferSize);
322 } 319 }
323 320
324 std::string AudioManagerWin::GetAssociatedOutputDeviceID( 321 std::string AudioManagerWin::GetAssociatedOutputDeviceID(
325 const std::string& input_device_id) { 322 const std::string& input_device_id) {
326 if (!CoreAudioUtil::IsSupported()) { 323 if (!core_audio_supported_) {
327 NOTIMPLEMENTED() 324 NOTIMPLEMENTED()
328 << "GetAssociatedOutputDeviceID is not supported on this OS"; 325 << "GetAssociatedOutputDeviceID is not supported on this OS";
329 return std::string(); 326 return std::string();
330 } 327 }
331 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); 328 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id);
332 } 329 }
333 330
334 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR 331 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR
335 // mode. 332 // mode.
336 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 333 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
(...skipping 15 matching lines...) Expand all
352 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 349 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
353 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. 350 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API.
354 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( 351 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream(
355 const AudioParameters& params, 352 const AudioParameters& params,
356 const std::string& device_id, 353 const std::string& device_id,
357 const std::string& input_device_id) { 354 const std::string& input_device_id) {
358 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 355 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
359 if (params.channels() > kWinMaxChannels) 356 if (params.channels() > kWinMaxChannels)
360 return NULL; 357 return NULL;
361 358
362 if (!CoreAudioUtil::IsSupported()) { 359 if (!core_audio_supported_) {
363 // Fall back to Windows Wave implementation on Windows XP or lower. 360 // Fall back to Windows Wave implementation on Windows XP or lower.
364 DLOG_IF(ERROR, !device_id.empty() && 361 DLOG_IF(ERROR, !device_id.empty() &&
365 device_id != AudioManagerBase::kDefaultDeviceId) 362 device_id != AudioManagerBase::kDefaultDeviceId)
366 << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; 363 << "Opening by device id not supported by PCMWaveOutAudioOutputStream";
367 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; 364 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista.";
368 return new PCMWaveOutAudioOutputStream( 365 return new PCMWaveOutAudioOutputStream(
369 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); 366 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER);
370 } 367 }
371 368
372 // TODO(rtoy): support more than stereo input. 369 // TODO(rtoy): support more than stereo input.
(...skipping 21 matching lines...) Expand all
394 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 391 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
395 return CreatePCMWaveInAudioInputStream(params, device_id); 392 return CreatePCMWaveInAudioInputStream(params, device_id);
396 } 393 }
397 394
398 // Factory for the implementations of AudioInputStream for 395 // Factory for the implementations of AudioInputStream for
399 // AUDIO_PCM_LOW_LATENCY mode. 396 // AUDIO_PCM_LOW_LATENCY mode.
400 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( 397 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream(
401 const AudioParameters& params, const std::string& device_id) { 398 const AudioParameters& params, const std::string& device_id) {
402 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 399 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
403 AudioInputStream* stream = NULL; 400 AudioInputStream* stream = NULL;
404 if (!CoreAudioUtil::IsSupported()) { 401 if (!core_audio_supported_) {
405 // Fall back to Windows Wave implementation on Windows XP or lower. 402 // Fall back to Windows Wave implementation on Windows XP or lower.
406 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; 403 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista.";
407 stream = CreatePCMWaveInAudioInputStream(params, device_id); 404 stream = CreatePCMWaveInAudioInputStream(params, device_id);
408 } else { 405 } else {
409 stream = new WASAPIAudioInputStream(this, params, device_id); 406 stream = new WASAPIAudioInputStream(this, params, device_id);
410 } 407 }
411 408
412 return stream; 409 return stream;
413 } 410 }
414 411
415 std::string AudioManagerWin::GetDefaultOutputDeviceID() { 412 std::string AudioManagerWin::GetDefaultOutputDeviceID() {
416 if (!CoreAudioUtil::IsSupported()) 413 if (!core_audio_supported_)
417 return std::string(); 414 return std::string();
418 return CoreAudioUtil::GetDefaultOutputDeviceID(); 415 return CoreAudioUtil::GetDefaultOutputDeviceID();
419 } 416 }
420 417
421 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( 418 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
422 const std::string& output_device_id, 419 const std::string& output_device_id,
423 const AudioParameters& input_params) { 420 const AudioParameters& input_params) {
424 const bool core_audio_supported = CoreAudioUtil::IsSupported(); 421 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."; 422 << "CoreAudio is required to open non-default devices.";
427 423
428 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 424 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
429 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 425 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
430 int sample_rate = 48000; 426 int sample_rate = 48000;
431 int buffer_size = kFallbackBufferSize; 427 int buffer_size = kFallbackBufferSize;
432 int bits_per_sample = 16; 428 int bits_per_sample = 16;
433 int input_channels = 0; 429 int input_channels = 0;
434 bool use_input_params = !core_audio_supported; 430 bool use_input_params = !core_audio_supported_;
435 if (core_audio_supported) { 431 if (core_audio_supported_) {
436 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { 432 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
437 // TODO(rtoy): tune these values for best possible WebAudio 433 // TODO(rtoy): tune these values for best possible WebAudio
438 // performance. WebRTC works well at 48kHz and a buffer size of 480 434 // 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 435 // 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 436 // experimental. This sample rate will be combined with a buffer size of
441 // 256 samples, which corresponds to an output delay of ~5.33ms. 437 // 256 samples, which corresponds to an output delay of ~5.33ms.
442 sample_rate = 48000; 438 sample_rate = 48000;
443 buffer_size = 256; 439 buffer_size = 256;
444 if (input_params.IsValid()) 440 if (input_params.IsValid())
445 channel_layout = input_params.channel_layout(); 441 channel_layout = input_params.channel_layout();
(...skipping 11 matching lines...) Expand all
457 } else { 453 } else {
458 use_input_params = true; 454 use_input_params = true;
459 } 455 }
460 } 456 }
461 } 457 }
462 458
463 if (input_params.IsValid()) { 459 if (input_params.IsValid()) {
464 // If the user has enabled checking supported channel layouts or we don't 460 // 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 461 // 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. 462 // http://crbug.com/259165 and http://crbug.com/311906 for more details.
467 if (core_audio_supported && 463 if (core_audio_supported_ &&
468 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || 464 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) ||
469 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) { 465 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) {
470 // Check if it is possible to open up at the specified input channel 466 // 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 467 // 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 468 // hardware (preferred) layout. We do this extra check to avoid the
473 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. 469 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases.
474 if (input_params.channel_layout() != channel_layout) { 470 if (input_params.channel_layout() != channel_layout) {
475 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the 471 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the
476 // operations that have already been done such as opening up a client 472 // operations that have already been done such as opening up a client
477 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do 473 // 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, 524 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers,
529 xp_device_id); 525 xp_device_id);
530 } 526 }
531 527
532 /// static 528 /// static
533 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 529 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
534 return new AudioManagerWin(audio_log_factory); 530 return new AudioManagerWin(audio_log_factory);
535 } 531 }
536 532
537 } // namespace media 533 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698