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/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
10 #include "media/audio/audio_util.h" | 10 #include "media/audio/audio_util.h" |
11 #include "media/audio/win/audio_manager_win.h" | 11 #include "media/audio/win/audio_manager_win.h" |
12 #include "media/audio/win/avrt_wrapper_win.h" | 12 #include "media/audio/win/avrt_wrapper_win.h" |
13 | 13 |
14 static const int kMinIntervalBetweenVolumeUpdatesMs = 1000; | |
15 | |
14 using base::win::ScopedComPtr; | 16 using base::win::ScopedComPtr; |
15 using base::win::ScopedCOMInitializer; | 17 using base::win::ScopedCOMInitializer; |
16 | 18 |
17 WASAPIAudioInputStream::WASAPIAudioInputStream( | 19 WASAPIAudioInputStream::WASAPIAudioInputStream( |
18 AudioManagerWin* manager, const AudioParameters& params, | 20 AudioManagerWin* manager, const AudioParameters& params, |
19 const std::string& device_id) | 21 const std::string& device_id) |
20 : com_init_(ScopedCOMInitializer::kMTA), | 22 : com_init_(ScopedCOMInitializer::kMTA), |
21 manager_(manager), | 23 manager_(manager), |
22 capture_thread_(NULL), | 24 capture_thread_(NULL), |
23 opened_(false), | 25 opened_(false), |
24 started_(false), | 26 started_(false), |
25 endpoint_buffer_size_frames_(0), | 27 endpoint_buffer_size_frames_(0), |
26 device_id_(device_id), | 28 device_id_(device_id), |
27 sink_(NULL) { | 29 sink_(NULL), |
30 volume_(0.0), | |
31 agc_is_enabled_(0) { | |
28 DCHECK(manager_); | 32 DCHECK(manager_); |
29 | 33 |
30 // Load the Avrt DLL if not already loaded. Required to support MMCSS. | 34 // Load the Avrt DLL if not already loaded. Required to support MMCSS. |
31 bool avrt_init = avrt::Initialize(); | 35 bool avrt_init = avrt::Initialize(); |
32 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; | 36 DCHECK(avrt_init) << "Failed to load the Avrt.dll"; |
33 | 37 |
34 // Set up the desired capture format specified by the client. | 38 // Set up the desired capture format specified by the client. |
35 format_.nSamplesPerSec = params.sample_rate; | 39 format_.nSamplesPerSec = params.sample_rate; |
36 format_.wFormatTag = WAVE_FORMAT_PCM; | 40 format_.wFormatTag = WAVE_FORMAT_PCM; |
37 format_.wBitsPerSample = params.bits_per_sample; | 41 format_.wBitsPerSample = params.bits_per_sample; |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
185 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; | 189 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; |
186 if (!opened_) | 190 if (!opened_) |
187 return 0.0; | 191 return 0.0; |
188 | 192 |
189 // The effective volume value is always in the range 0.0 to 1.0, hence | 193 // The effective volume value is always in the range 0.0 to 1.0, hence |
190 // we can return a fixed value (=1.0) here. | 194 // we can return a fixed value (=1.0) here. |
191 return 1.0; | 195 return 1.0; |
192 } | 196 } |
193 | 197 |
194 void WASAPIAudioInputStream::SetVolume(double volume) { | 198 void WASAPIAudioInputStream::SetVolume(double volume) { |
199 DVLOG(1) << "SetVolume(volume=" << volume << ")"; | |
195 DCHECK(CalledOnValidThread()); | 200 DCHECK(CalledOnValidThread()); |
196 DCHECK(volume <= 1.0 && volume >= 0.0); | 201 DCHECK(volume <= 1.0 && volume >= 0.0); |
197 | 202 |
198 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; | 203 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; |
199 if (!opened_) | 204 if (!opened_) |
200 return; | 205 return; |
201 | 206 |
202 // Set a new master volume level. Valid volume levels are in the range | 207 // Set a new master volume level. Valid volume levels are in the range |
203 // 0.0 to 1.0. Ignore volume-change events. | 208 // 0.0 to 1.0. Ignore volume-change events. |
204 HRESULT hr = simple_audio_volume_->SetMasterVolume(static_cast<float>(volume), | 209 HRESULT hr = simple_audio_volume_->SetMasterVolume(static_cast<float>(volume), |
205 NULL); | 210 NULL); |
tommi (sloooow) - chröme
2012/03/16 13:31:05
indent
henrika (OOO until Aug 14)
2012/03/21 10:16:04
Done.
| |
206 DLOG_IF(WARNING, FAILED(hr)) << "Failed to set new input master volume."; | 211 DLOG_IF(WARNING, FAILED(hr)) << "Failed to set new input master volume."; |
212 | |
213 // We take new volume samples once every second when the AGC is enabled. | |
214 // To ensure that a new setting has an immediate effect, the new volume | |
215 // setting is cached here. It will ensure that the next OnData() callback | |
216 // will contain a new valid volume level. If this approach was not taken, | |
217 // we could report invalid volume levels to the client for a time period | |
218 // of up to one second. | |
219 if (GetAutomaticGainControl()) { | |
220 volume_ = GetVolume(); | |
221 } | |
207 } | 222 } |
208 | 223 |
209 double WASAPIAudioInputStream::GetVolume() { | 224 double WASAPIAudioInputStream::GetVolume() { |
210 DCHECK(CalledOnValidThread()); | 225 DCHECK(CalledOnValidThread()); |
211 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; | 226 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; |
212 if (!opened_) | 227 if (!opened_) |
213 return 0.0; | 228 return 0.0; |
214 | 229 |
215 // Retrieve the current volume level. The value is in the range 0.0 to 1.0. | 230 // Retrieve the current volume level. The value is in the range 0.0 to 1.0. |
216 float level = 0.0f; | 231 float level = 0.0f; |
217 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); | 232 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); |
218 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume."; | 233 DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume."; |
219 | 234 |
220 return static_cast<double>(level); | 235 return static_cast<double>(level); |
221 } | 236 } |
222 | 237 |
238 void WASAPIAudioInputStream::SetAutomaticGainControl(bool enabled) { | |
tommi (sloooow) - chröme
2012/03/16 13:31:05
seems like we have a lot of similar or exactly the
henrika (OOO until Aug 14)
2012/03/21 10:16:04
I feel the same way. Let me try to come up with so
| |
239 base::subtle::Release_Store(&agc_is_enabled_, enabled); | |
240 } | |
241 | |
242 bool WASAPIAudioInputStream::GetAutomaticGainControl() { | |
243 return (base::subtle::Acquire_Load(&agc_is_enabled_) == 1); | |
244 } | |
245 | |
223 // static | 246 // static |
224 double WASAPIAudioInputStream::HardwareSampleRate( | 247 double WASAPIAudioInputStream::HardwareSampleRate( |
225 const std::string& device_id) { | 248 const std::string& device_id) { |
226 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; | 249 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format; |
227 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format); | 250 HRESULT hr = GetMixFormat(device_id, &audio_engine_mix_format); |
228 if (FAILED(hr)) | 251 if (FAILED(hr)) |
229 return 0.0; | 252 return 0.0; |
230 | 253 |
231 return static_cast<double>(audio_engine_mix_format->nSamplesPerSec); | 254 return static_cast<double>(audio_engine_mix_format->nSamplesPerSec); |
232 } | 255 } |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
382 // Derive a delay estimate for the captured audio packet. | 405 // Derive a delay estimate for the captured audio packet. |
383 // The value contains two parts (A+B), where A is the delay of the | 406 // The value contains two parts (A+B), where A is the delay of the |
384 // first audio frame in the packet and B is the extra delay | 407 // first audio frame in the packet and B is the extra delay |
385 // contained in any stored data. Unit is in audio frames. | 408 // contained in any stored data. Unit is in audio frames. |
386 QueryPerformanceCounter(&now_count); | 409 QueryPerformanceCounter(&now_count); |
387 double audio_delay_frames = | 410 double audio_delay_frames = |
388 ((perf_count_to_100ns_units_ * now_count.QuadPart - | 411 ((perf_count_to_100ns_units_ * now_count.QuadPart - |
389 first_audio_frame_timestamp) / 10000.0) * ms_to_frame_count_ + | 412 first_audio_frame_timestamp) / 10000.0) * ms_to_frame_count_ + |
390 buffer_frame_index - num_frames_to_read; | 413 buffer_frame_index - num_frames_to_read; |
391 | 414 |
415 // Query a new volume level if AGC is enabled and if it is time to | |
416 // update the old value. | |
417 if (GetAutomaticGainControl()) { | |
tommi (sloooow) - chröme
2012/03/16 13:31:05
this code looks the same too
| |
418 base::Time now = base::Time::Now(); | |
419 if ((now - last_volume_update_time_).InMilliseconds() > | |
420 kMinIntervalBetweenVolumeUpdatesMs) { | |
421 // Retrieve the current volume level. Range is [0.0,1.0]. | |
422 float level = 0.0f; | |
423 HRESULT hr = simple_audio_volume_->GetMasterVolume(&level); | |
424 if (SUCCEEDED(hr)) | |
425 volume_ = static_cast<double>(level); | |
426 last_volume_update_time_ = now; | |
427 } | |
428 } | |
429 | |
392 // Deliver captured data to the registered consumer using a packet | 430 // Deliver captured data to the registered consumer using a packet |
393 // size which was specified at construction. | 431 // size which was specified at construction. |
394 uint32 delay_frames = static_cast<uint32>(audio_delay_frames + 0.5); | 432 uint32 delay_frames = static_cast<uint32>(audio_delay_frames + 0.5); |
395 while (buffer_frame_index >= packet_size_frames_) { | 433 while (buffer_frame_index >= packet_size_frames_) { |
396 uint8* audio_data = | 434 uint8* audio_data = |
397 reinterpret_cast<uint8*>(capture_buffer.get()); | 435 reinterpret_cast<uint8*>(capture_buffer.get()); |
398 | 436 |
399 // Deliver data packet and delay estimation to the user. | 437 // Deliver data packet, delay estimation and volume level to |
438 // the user. | |
400 sink_->OnData(this, | 439 sink_->OnData(this, |
401 audio_data, | 440 audio_data, |
402 packet_size_bytes_, | 441 packet_size_bytes_, |
403 delay_frames * frame_size_); | 442 delay_frames * frame_size_, |
443 volume_); | |
404 | 444 |
405 // Store parts of the recorded data which can't be delivered | 445 // Store parts of the recorded data which can't be delivered |
406 // using the current packet size. The stored section will be used | 446 // using the current packet size. The stored section will be used |
407 // either in the next while-loop iteration or in the next | 447 // either in the next while-loop iteration or in the next |
408 // capture event. | 448 // capture event. |
409 memmove(&capture_buffer[0], | 449 memmove(&capture_buffer[0], |
410 &capture_buffer[packet_size_bytes_], | 450 &capture_buffer[packet_size_bytes_], |
411 (buffer_frame_index - packet_size_frames_) * frame_size_); | 451 (buffer_frame_index - packet_size_frames_) * frame_size_); |
412 | 452 |
413 buffer_frame_index -= packet_size_frames_; | 453 buffer_frame_index -= packet_size_frames_; |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
618 audio_capture_client_.ReceiveVoid()); | 658 audio_capture_client_.ReceiveVoid()); |
619 if (FAILED(hr)) | 659 if (FAILED(hr)) |
620 return hr; | 660 return hr; |
621 | 661 |
622 // Obtain a reference to the ISimpleAudioVolume interface which enables | 662 // Obtain a reference to the ISimpleAudioVolume interface which enables |
623 // us to control the master volume level of an audio session. | 663 // us to control the master volume level of an audio session. |
624 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), | 664 hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume), |
625 simple_audio_volume_.ReceiveVoid()); | 665 simple_audio_volume_.ReceiveVoid()); |
626 return hr; | 666 return hr; |
627 } | 667 } |
OLD | NEW |