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 16 matching lines...) Expand all Loading... |
310 if (params.channels() > kWinMaxChannels) | 315 if (params.channels() > kWinMaxChannels) |
311 return NULL; | 316 return NULL; |
312 | 317 |
313 if (!CoreAudioUtil::IsSupported()) { | 318 if (!CoreAudioUtil::IsSupported()) { |
314 // Fall back to Windows Wave implementation on Windows XP or lower. | 319 // Fall back to Windows Wave implementation on Windows XP or lower. |
315 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; | 320 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; |
316 return new PCMWaveOutAudioOutputStream( | 321 return new PCMWaveOutAudioOutputStream( |
317 this, params, media::NumberOfWaveOutBuffers(), WAVE_MAPPER); | 322 this, params, media::NumberOfWaveOutBuffers(), WAVE_MAPPER); |
318 } | 323 } |
319 | 324 |
320 // TODO(crogers): support more than stereo input. | 325 // TODO(rtoy): support more than stereo input. |
321 if (params.input_channels() > 0) { | 326 if (params.input_channels() > 0) { |
322 DVLOG(1) << "WASAPIUnifiedStream is created."; | 327 DVLOG(1) << "WASAPIUnifiedStream is created."; |
323 return new WASAPIUnifiedStream(this, params, input_device_id); | 328 return new WASAPIUnifiedStream(this, params, input_device_id); |
324 } | 329 } |
325 | 330 |
326 return new WASAPIAudioOutputStream(this, params, eConsole); | 331 return new WASAPIAudioOutputStream(this, params, eConsole); |
327 } | 332 } |
328 | 333 |
329 // Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR | 334 // Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR |
330 // mode. | 335 // mode. |
(...skipping 13 matching lines...) Expand all 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(); |
| 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(rtoy): tune these values for best possible WebAudio |
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 |