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 ? |
DaleCurtis
2014/02/05 22:15:43
Won't this blow up on multichannel input systems?
tommi (sloooow) - chröme
2014/02/06 11:50:34
Henrik - I guess this is rather a question for you
henrika (OOO until Aug 14)
2014/02/06 12:07:56
Well, as Tommi states, nothing is changed here. I
tommi (sloooow) - chröme
2014/02/06 12:55:34
Multichannel devices that I've tried, all support
henrika (OOO until Aug 14)
2014/02/06 13:11:28
Hope I am not repeating anything here but we are t
tommi (sloooow) - chröme
2014/02/06 13:28:33
Ah, sorry, brainfart :) Yes we are. I haven't te
| |
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; | |
henrika (OOO until Aug 14)
2014/02/05 16:19:01
Have you been able to verify this change somehow?
no longer working on chromium
2014/02/05 16:43:25
I did a quick check on the code, speech is using t
tommi (sloooow) - chröme
2014/02/06 11:50:34
In practice it's actually not a big change for two
| |
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 |