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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
274 WASAPIAudioInputStream::HardwareChannelCount(device_id) == 1 ? | 274 WASAPIAudioInputStream::HardwareChannelCount(device_id) == 1 ? |
275 CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; | 275 CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; |
276 } | 276 } |
277 | 277 |
278 // TODO(Henrika): improve the default buffer size value for input stream. | 278 // TODO(Henrika): improve the default buffer size value for input stream. |
279 return AudioParameters( | 279 return AudioParameters( |
280 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 280 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
281 sample_rate, 16, kFallbackBufferSize); | 281 sample_rate, 16, kFallbackBufferSize); |
282 } | 282 } |
283 | 283 |
284 std::string AudioManagerWin::GetAssociatedOutputDeviceID( | |
285 const std::string& input_device_id) { | |
286 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); | |
287 } | |
288 | |
284 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR | 289 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR |
285 // mode. | 290 // mode. |
286 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. | 291 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. |
287 AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( | 292 AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( |
288 const AudioParameters& params) { | 293 const AudioParameters& params) { |
289 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); | 294 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
290 if (params.channels() > kWinMaxChannels) | 295 if (params.channels() > kWinMaxChannels) |
291 return NULL; | 296 return NULL; |
292 | 297 |
293 return new PCMWaveOutAudioOutputStream(this, | 298 return new PCMWaveOutAudioOutputStream(this, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
344 // Fall back to Windows Wave implementation on Windows XP or lower. | 349 // Fall back to Windows Wave implementation on Windows XP or lower. |
345 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; | 350 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; |
346 stream = CreatePCMWaveInAudioInputStream(params, device_id); | 351 stream = CreatePCMWaveInAudioInputStream(params, device_id); |
347 } else { | 352 } else { |
348 stream = new WASAPIAudioInputStream(this, params, device_id); | 353 stream = new WASAPIAudioInputStream(this, params, device_id); |
349 } | 354 } |
350 | 355 |
351 return stream; | 356 return stream; |
352 } | 357 } |
353 | 358 |
359 std::string AudioManagerWin::GetDefaultOutputDeviceID() { | |
360 if (!CoreAudioUtil::IsSupported()) | |
361 return std::string(); | |
362 return CoreAudioUtil::GetDefaultOutputDeviceID(); | |
363 } | |
364 | |
354 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( | 365 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( |
355 const std::string& output_device_id, | 366 const std::string& output_device_id, |
356 const AudioParameters& input_params) { | 367 const AudioParameters& input_params) { |
357 // TODO(tommi): Support |output_device_id|. | 368 // TODO(tommi): Support |output_device_id|. |
358 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; | 369 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; |
370 | |
371 const bool core_audio_supported = CoreAudioUtil::IsSupported(); | |
henrika (OOO until Aug 14)
2013/09/04 11:11:40
nice!
| |
372 DLOG_IF(ERROR, !core_audio_supported && !output_device_id.empty()) | |
373 << "CoreAudio is required to open non-default devices."; | |
374 | |
359 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 375 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
360 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; | 376 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
361 int sample_rate = 48000; | 377 int sample_rate = 48000; |
362 int buffer_size = kFallbackBufferSize; | 378 int buffer_size = kFallbackBufferSize; |
363 int bits_per_sample = 16; | 379 int bits_per_sample = 16; |
364 int input_channels = 0; | 380 int input_channels = 0; |
365 bool use_input_params = !CoreAudioUtil::IsSupported(); | 381 bool use_input_params = !core_audio_supported; |
366 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { | 382 if (core_audio_supported) { |
367 // TODO(crogers): tune these values for best possible WebAudio performance. | 383 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { |
368 // WebRTC works well at 48kHz and a buffer size of 480 samples will be used | 384 // TODO(crogers): tune these values for best possible WebAudio |
henrika (OOO until Aug 14)
2013/09/04 11:11:40
rtoy instead of crogers?
tommi (sloooow) - chröme
2013/09/04 13:06:55
Done.
| |
369 // for this case. Note that exclusive mode is experimental. | 385 // performance. WebRTC works well at 48kHz and a buffer size of 480 |
370 // This sample rate will be combined with a buffer size of 256 samples, | 386 // samples will be used for this case. Note that exclusive mode is |
371 // which corresponds to an output delay of ~5.33ms. | 387 // experimental. This sample rate will be combined with a buffer size of |
372 sample_rate = 48000; | 388 // 256 samples, which corresponds to an output delay of ~5.33ms. |
373 buffer_size = 256; | 389 sample_rate = 48000; |
374 if (input_params.IsValid()) | 390 buffer_size = 256; |
375 channel_layout = input_params.channel_layout(); | 391 if (input_params.IsValid()) |
376 } else if (!use_input_params) { | 392 channel_layout = input_params.channel_layout(); |
377 // Hardware sample-rate on Windows can be configured, so we must query. | |
378 // TODO(henrika): improve possibility to specify an audio endpoint. | |
379 // Use the default device (same as for Wave) for now to be compatible. | |
380 int hw_sample_rate = WASAPIAudioOutputStream::HardwareSampleRate(); | |
381 | |
382 AudioParameters params; | |
383 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole, | |
384 ¶ms); | |
385 int hw_buffer_size = | |
386 FAILED(hr) ? kFallbackBufferSize : params.frames_per_buffer(); | |
387 channel_layout = WASAPIAudioOutputStream::HardwareChannelLayout(); | |
388 | |
389 // TODO(henrika): Figure out the right thing to do here. | |
390 if (hw_sample_rate && hw_buffer_size) { | |
391 sample_rate = hw_sample_rate; | |
392 buffer_size = hw_buffer_size; | |
393 } else { | 393 } else { |
394 use_input_params = true; | 394 AudioParameters params; |
395 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(output_device_id, | |
396 ¶ms); | |
397 if (SUCCEEDED(hr)) { | |
398 bits_per_sample = params.bits_per_sample(); | |
399 buffer_size = params.frames_per_buffer(); | |
400 channel_layout = params.channel_layout(); | |
401 sample_rate = params.sample_rate(); | |
402 } else { | |
403 use_input_params = true; | |
404 } | |
395 } | 405 } |
396 } | 406 } |
397 | 407 |
398 if (input_params.IsValid()) { | 408 if (input_params.IsValid()) { |
399 if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) && | 409 if (core_audio_supported && |
400 CoreAudioUtil::IsSupported()) { | 410 cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts)) { |
401 // Check if it is possible to open up at the specified input channel | 411 // Check if it is possible to open up at the specified input channel |
402 // layout but avoid checking if the specified layout is the same as the | 412 // layout but avoid checking if the specified layout is the same as the |
403 // hardware (preferred) layout. We do this extra check to avoid the | 413 // hardware (preferred) layout. We do this extra check to avoid the |
404 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. | 414 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. |
405 if (input_params.channel_layout() != channel_layout) { | 415 if (input_params.channel_layout() != channel_layout) { |
416 // TODO(henrika): Use |output_device_id| here. | |
417 // Internally, IsChannelLayoutSupported does many of the operations | |
418 // that have already been done such as opening up a client and fetching | |
419 // the WAVEFORMATPCMEX format. Ideally we should only do that once and | |
420 // do it for the requested device. Then here, we can check the layout | |
421 // from the data we already hold. | |
406 if (CoreAudioUtil::IsChannelLayoutSupported( | 422 if (CoreAudioUtil::IsChannelLayoutSupported( |
407 eRender, eConsole, input_params.channel_layout())) { | 423 eRender, eConsole, input_params.channel_layout())) { |
408 // Open up using the same channel layout as the source if it is | 424 // Open up using the same channel layout as the source if it is |
409 // supported by the hardware. | 425 // supported by the hardware. |
410 channel_layout = input_params.channel_layout(); | 426 channel_layout = input_params.channel_layout(); |
411 VLOG(1) << "Hardware channel layout is not used; using same layout" | 427 VLOG(1) << "Hardware channel layout is not used; using same layout" |
412 << " as the source instead (" << channel_layout << ")"; | 428 << " as the source instead (" << channel_layout << ")"; |
413 } | 429 } |
414 } | 430 } |
415 } | 431 } |
416 input_channels = input_params.input_channels(); | 432 input_channels = input_params.input_channels(); |
417 if (use_input_params) { | 433 if (use_input_params) { |
418 // If WASAPI isn't supported we'll fallback to WaveOut, which will take | 434 // If WASAPI isn't supported we'll fallback to WaveOut, which will take |
419 // care of resampling and bits per sample changes. By setting these | 435 // care of resampling and bits per sample changes. By setting these |
420 // equal to the input values, AudioOutputResampler will skip resampling | 436 // equal to the input values, AudioOutputResampler will skip resampling |
421 // and bit per sample differences (since the input parameters will match | 437 // and bit per sample differences (since the input parameters will match |
422 // the output parameters). | 438 // the output parameters). |
439 bits_per_sample = input_params.bits_per_sample(); | |
440 buffer_size = input_params.frames_per_buffer(); | |
441 channel_layout = input_params.channel_layout(); | |
423 sample_rate = input_params.sample_rate(); | 442 sample_rate = input_params.sample_rate(); |
424 bits_per_sample = input_params.bits_per_sample(); | |
425 channel_layout = input_params.channel_layout(); | |
426 buffer_size = input_params.frames_per_buffer(); | |
427 } | 443 } |
428 } | 444 } |
429 | 445 |
430 int user_buffer_size = GetUserBufferSize(); | 446 int user_buffer_size = GetUserBufferSize(); |
431 if (user_buffer_size) | 447 if (user_buffer_size) |
432 buffer_size = user_buffer_size; | 448 buffer_size = user_buffer_size; |
433 | 449 |
434 return AudioParameters( | 450 return AudioParameters( |
435 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, | 451 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, |
436 sample_rate, bits_per_sample, buffer_size); | 452 sample_rate, bits_per_sample, buffer_size); |
(...skipping 16 matching lines...) Expand all Loading... | |
453 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, | 469 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, |
454 xp_device_id); | 470 xp_device_id); |
455 } | 471 } |
456 | 472 |
457 /// static | 473 /// static |
458 AudioManager* CreateAudioManager() { | 474 AudioManager* CreateAudioManager() { |
459 return new AudioManagerWin(); | 475 return new AudioManagerWin(); |
460 } | 476 } |
461 | 477 |
462 } // namespace media | 478 } // namespace media |
OLD | NEW |