OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |