| 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/win/audio_low_latency_input_win.h" | 5 #include "media/audio/win/audio_low_latency_input_win.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "media/audio/win/audio_manager_win.h" | 10 #include "media/audio/win/audio_manager_win.h" |
| 11 #include "media/audio/win/avrt_wrapper_win.h" | 11 #include "media/audio/win/avrt_wrapper_win.h" |
| 12 | 12 |
| 13 using base::win::ScopedComPtr; | 13 using base::win::ScopedComPtr; |
| 14 using base::win::ScopedCOMInitializer; | 14 using base::win::ScopedCOMInitializer; |
| 15 | 15 |
| 16 namespace media { | 16 namespace media { |
| 17 | 17 |
| 18 WASAPIAudioInputStream::WASAPIAudioInputStream( | 18 WASAPIAudioInputStream::WASAPIAudioInputStream( |
| 19 AudioManagerWin* manager, const AudioParameters& params, | 19 AudioManagerWin* manager, |
| 20 const AudioParameters& params, |
| 20 const std::string& device_id) | 21 const std::string& device_id) |
| 21 : manager_(manager), | 22 : manager_(manager), |
| 22 capture_thread_(NULL), | 23 capture_thread_(NULL), |
| 23 opened_(false), | 24 opened_(false), |
| 24 started_(false), | 25 started_(false), |
| 26 frame_size_(0), |
| 27 packet_size_frames_(0), |
| 28 packet_size_bytes_(0), |
| 25 endpoint_buffer_size_frames_(0), | 29 endpoint_buffer_size_frames_(0), |
| 30 effects_(params.effects()), |
| 26 device_id_(device_id), | 31 device_id_(device_id), |
| 32 perf_count_to_100ns_units_(0.0), |
| 33 ms_to_frame_count_(0.0), |
| 27 sink_(NULL) { | 34 sink_(NULL) { |
| 28 DCHECK(manager_); | 35 DCHECK(manager_); |
| 29 | 36 |
| 30 // Load the Avrt DLL if not already loaded. Required to support MMCSS. | 37 // Load the Avrt DLL if not already loaded. Required to support MMCSS. |
| 31 bool avrt_init = avrt::Initialize(); | 38 bool avrt_init = avrt::Initialize(); |
| 32 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; | 39 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; |
| 33 | 40 |
| 34 // Set up the desired capture format specified by the client. | 41 // Set up the desired capture format specified by the client. |
| 35 format_.nSamplesPerSec = params.sample_rate(); | 42 format_.nSamplesPerSec = params.sample_rate(); |
| 36 format_.wFormatTag = WAVE_FORMAT_PCM; | 43 format_.wFormatTag = WAVE_FORMAT_PCM; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 60 stop_capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); | 67 stop_capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); |
| 61 DCHECK(stop_capture_event_.IsValid()); | 68 DCHECK(stop_capture_event_.IsValid()); |
| 62 | 69 |
| 63 ms_to_frame_count_ = static_cast<double>(params.sample_rate()) / 1000.0; | 70 ms_to_frame_count_ = static_cast<double>(params.sample_rate()) / 1000.0; |
| 64 | 71 |
| 65 LARGE_INTEGER performance_frequency; | 72 LARGE_INTEGER performance_frequency; |
| 66 if (QueryPerformanceFrequency(&performance_frequency)) { | 73 if (QueryPerformanceFrequency(&performance_frequency)) { |
| 67 perf_count_to_100ns_units_ = | 74 perf_count_to_100ns_units_ = |
| 68 (10000000.0 / static_cast<double>(performance_frequency.QuadPart)); | 75 (10000000.0 / static_cast<double>(performance_frequency.QuadPart)); |
| 69 } else { | 76 } else { |
| 70 LOG(ERROR) << "High-resolution performance counters are not supported."; | 77 DLOG(ERROR) << "High-resolution performance counters are not supported."; |
| 71 perf_count_to_100ns_units_ = 0.0; | |
| 72 } | 78 } |
| 73 } | 79 } |
| 74 | 80 |
| 75 WASAPIAudioInputStream::~WASAPIAudioInputStream() {} | 81 WASAPIAudioInputStream::~WASAPIAudioInputStream() {} |
| 76 | 82 |
| 77 bool WASAPIAudioInputStream::Open() { | 83 bool WASAPIAudioInputStream::Open() { |
| 78 DCHECK(CalledOnValidThread()); | 84 DCHECK(CalledOnValidThread()); |
| 79 // Verify that we are not already opened. | 85 // Verify that we are not already opened. |
| 80 if (opened_) | 86 if (opened_) |
| 81 return false; | 87 return false; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 | 237 |
| 232 // Retrieve the current volume level. The value is in the range 0.0 to 1.0. | 238 // Retrieve the current volume level. The value is in the range 0.0 to 1.0. |
| 233 float level = 0.0f; | 239 float level = 0.0f; |
| 234 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); | 240 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); |
| 235 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume."; | 241 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume."; |
| 236 | 242 |
| 237 return static_cast<double>(level); | 243 return static_cast<double>(level); |
| 238 } | 244 } |
| 239 | 245 |
| 240 // static | 246 // static |
| 241 int WASAPIAudioInputStream::HardwareSampleRate( | 247 AudioParameters WASAPIAudioInputStream::GetInputStreamParameters( |
| 242 const std::string& device_id) { | 248 const std::string& device_id) { |
| 249 int sample_rate = 48000; |
| 250 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
| 251 |
| 243 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; | 252 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; |
| 244 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format); | 253 if (SUCCEEDED(GetMixFormat(device_id, &audio_engine_mix_format))) { |
| 245 if (FAILED(hr)) | 254 sample_rate = static_cast<int>(audio_engine_mix_format->nSamplesPerSec); |
| 246 return 0; | 255 channel_layout = audio_engine_mix_format->nChannels == 1 ? |
| 256 CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; |
| 257 } |
| 247 | 258 |
| 248 return static_cast<int>(audio_engine_mix_format->nSamplesPerSec); | 259 int effects = AudioParameters::NO_EFFECTS; |
| 260 // For non-loopback devices, advertise that ducking is supported. |
| 261 if (device_id != AudioManagerBase::kLoopbackInputDeviceId) |
| 262 effects |= AudioParameters::DUCKING; |
| 263 |
| 264 // Use 10ms frame size as default. |
| 265 int frames_per_buffer = sample_rate / 100; |
| 266 return AudioParameters( |
| 267 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, sample_rate, |
| 268 16, frames_per_buffer, effects); |
| 249 } | 269 } |
| 250 | 270 |
| 251 // static | 271 // static |
| 252 uint32 WASAPIAudioInputStream::HardwareChannelCount( | |
| 253 const std::string& device_id) { | |
| 254 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; | |
| 255 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format); | |
| 256 if (FAILED(hr)) | |
| 257 return 0; | |
| 258 | |
| 259 return static_cast<uint32>(audio_engine_mix_format->nChannels); | |
| 260 } | |
| 261 | |
| 262 // static | |
| 263 HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id, | 272 HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id, |
| 264 WAVEFORMATEX** device_format) { | 273 WAVEFORMATEX** device_format) { |
| 265 // It is assumed that this static method is called from a COM thread, i.e., | 274 // It is assumed that this static method is called from a COM thread, i.e., |
| 266 // CoInitializeEx() is not called here to avoid STA/MTA conflicts. | 275 // CoInitializeEx() is not called here to avoid STA/MTA conflicts. |
| 267 ScopedComPtr<IMMDeviceEnumerator> enumerator; | 276 ScopedComPtr<IMMDeviceEnumerator> enumerator; |
| 268 HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), NULL, | 277 HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), NULL, |
| 269 CLSCTX_INPROC_SERVER); | 278 CLSCTX_INPROC_SERVER); |
| 270 if (FAILED(hr)) | 279 if (FAILED(hr)) |
| 271 return hr; | 280 return hr; |
| 272 | 281 |
| 273 ScopedComPtr<IMMDevice> endpoint_device; | 282 ScopedComPtr<IMMDevice> endpoint_device; |
| 274 if (device_id == AudioManagerBase::kDefaultDeviceId) { | 283 if (device_id == AudioManagerBase::kDefaultDeviceId) { |
| 275 // Retrieve the default capture audio endpoint. | 284 // Retrieve the default capture audio endpoint. |
| 276 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, | 285 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, |
| 277 endpoint_device.Receive()); | 286 endpoint_device.Receive()); |
| 278 } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) { | 287 } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) { |
| 279 // Capture the default playback stream. | 288 // Get the mix format of the default playback stream. |
| 280 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, | 289 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, |
| 281 endpoint_device.Receive()); | 290 endpoint_device.Receive()); |
| 282 } else { | 291 } else { |
| 283 // Retrieve a capture endpoint device that is specified by an endpoint | 292 // Retrieve a capture endpoint device that is specified by an endpoint |
| 284 // device-identification string. | 293 // device-identification string. |
| 285 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id).c_str(), | 294 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id).c_str(), |
| 286 endpoint_device.Receive()); | 295 endpoint_device.Receive()); |
| 287 } | 296 } |
| 288 if (FAILED(hr)) | 297 if (FAILED(hr)) |
| 289 return hr; | 298 return hr; |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 if (FAILED(hr)) | 471 if (FAILED(hr)) |
| 463 return hr; | 472 return hr; |
| 464 | 473 |
| 465 // Retrieve the IMMDevice by using the specified role or the specified | 474 // Retrieve the IMMDevice by using the specified role or the specified |
| 466 // unique endpoint device-identification string. | 475 // unique endpoint device-identification string. |
| 467 // TODO(henrika): possibly add support for the eCommunications as well. | 476 // TODO(henrika): possibly add support for the eCommunications as well. |
| 468 if (device_id_ == AudioManagerBase::kDefaultDeviceId) { | 477 if (device_id_ == AudioManagerBase::kDefaultDeviceId) { |
| 469 // Retrieve the default capture audio endpoint for the specified role. | 478 // Retrieve the default capture audio endpoint for the specified role. |
| 470 // Note that, in Windows Vista, the MMDevice API supports device roles | 479 // Note that, in Windows Vista, the MMDevice API supports device roles |
| 471 // but the system-supplied user interface programs do not. | 480 // but the system-supplied user interface programs do not. |
| 472 hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole, | 481 |
| 482 // If the caller has requested to turn on ducking, we select the default |
| 483 // communications device instead of the default capture device. |
| 484 // This implicitly turns on ducking and allows the user to control the |
| 485 // attenuation level. |
| 486 ERole role = (effects_ & AudioParameters::DUCKING) ? |
| 487 eCommunications : eConsole; |
| 488 |
| 489 hr = enumerator->GetDefaultAudioEndpoint(eCapture, role, |
| 473 endpoint_device_.Receive()); | 490 endpoint_device_.Receive()); |
| 474 } else if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) { | 491 } else if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) { |
| 475 // Capture the default playback stream. | 492 // Capture the default playback stream. |
| 476 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, | 493 hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, |
| 477 endpoint_device_.Receive()); | 494 endpoint_device_.Receive()); |
| 478 } else { | 495 } else { |
| 479 // Retrieve a capture endpoint device that is specified by an endpoint | 496 // Retrieve a capture endpoint device that is specified by an endpoint |
| 480 // device-identification string. | 497 // device-identification string. |
| 498 // TODO(tommi): Opt into ducking for non-default audio devices. |
| 499 DLOG_IF(WARNING, effects_ & AudioParameters::DUCKING) |
| 500 << "Ducking has been requested for a non-default device." |
| 501 "Not implemented."; |
| 481 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(), | 502 hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(), |
| 482 endpoint_device_.Receive()); | 503 endpoint_device_.Receive()); |
| 483 } | 504 } |
| 484 | 505 |
| 485 if (FAILED(hr)) | 506 if (FAILED(hr)) |
| 486 return hr; | 507 return hr; |
| 487 | 508 |
| 488 // Verify that the audio endpoint device is active, i.e., the audio | 509 // Verify that the audio endpoint device is active, i.e., the audio |
| 489 // adapter that connects to the endpoint device is present and enabled. | 510 // adapter that connects to the endpoint device is present and enabled. |
| 490 DWORD state = DEVICE_STATE_DISABLED; | 511 DWORD state = DEVICE_STATE_DISABLED; |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 return hr; | 700 return hr; |
| 680 | 701 |
| 681 // Obtain a reference to the ISimpleAudioVolume interface which enables | 702 // Obtain a reference to the ISimpleAudioVolume interface which enables |
| 682 // us to control the master volume level of an audio session. | 703 // us to control the master volume level of an audio session. |
| 683 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), | 704 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), |
| 684 simple_audio_volume_.ReceiveVoid()); | 705 simple_audio_volume_.ReceiveVoid()); |
| 685 return hr; | 706 return hr; |
| 686 } | 707 } |
| 687 | 708 |
| 688 } // namespace media | 709 } // namespace media |
| OLD | NEW |