Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(789)

Side by Side Diff: media/audio/win/audio_low_latency_input_win.cc

Issue 9702019: Adds Analog Gain Control (AGC) to the WebRTC client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improved volume updating on Mac Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698