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