summaryrefslogtreecommitdiffstats
path: root/media/audio
diff options
context:
space:
mode:
authorhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-28 11:51:42 +0000
committerhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-28 11:51:42 +0000
commitaffb228b3addc94ecb7a049fbd93412d7390f4b4 (patch)
treeed1468cd2525a9cfec0dd5befb8e6922bdc3b1e6 /media/audio
parenta26740dd0887ed17898c965ad42e789a9525a9df (diff)
downloadchromium_src-affb228b3addc94ecb7a049fbd93412d7390f4b4.zip
chromium_src-affb228b3addc94ecb7a049fbd93412d7390f4b4.tar.gz
chromium_src-affb228b3addc94ecb7a049fbd93412d7390f4b4.tar.bz2
Improved AGC update scheme for the audio backend in Chrome.
This CL serves two purposes: 1) Improve the existing "mic-volume-checking"-scheme by ensuring that we no longer calls native audio functions from the core capture thread. 2) Prepare for adding AGC to the live-audio backend. TBR=tommi@chromium.org BUG=none TEST=WebRTC loopback tests in Chrome where I monitor the microphone volume while speaking into the mic. Review URL: https://codereview.chromium.org/15563004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202538 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio')
-rw-r--r--media/audio/agc_audio_stream.h205
-rw-r--r--media/audio/audio_input_stream_impl.cc71
-rw-r--r--media/audio/audio_input_stream_impl.h71
-rw-r--r--media/audio/cras/cras_input.cc6
-rw-r--r--media/audio/cras/cras_input.h4
-rw-r--r--media/audio/linux/alsa_input.cc5
-rw-r--r--media/audio/linux/alsa_input.h4
-rw-r--r--media/audio/mac/audio_low_latency_input_mac.cc10
-rw-r--r--media/audio/mac/audio_low_latency_input_mac.h4
-rw-r--r--media/audio/pulse/pulse_input.cc9
-rw-r--r--media/audio/pulse/pulse_input.h4
-rw-r--r--media/audio/win/audio_low_latency_input_win.cc15
-rw-r--r--media/audio/win/audio_low_latency_input_win.h4
13 files changed, 247 insertions, 165 deletions
diff --git a/media/audio/agc_audio_stream.h b/media/audio/agc_audio_stream.h
new file mode 100644
index 0000000..ebf0da6
--- /dev/null
+++ b/media/audio/agc_audio_stream.h
@@ -0,0 +1,205 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_AUDIO_AGC_AUDIO_STREAM_H_
+#define MEDIA_AUDIO_AGC_AUDIO_STREAM_H_
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer.h"
+#include "media/audio/audio_io.h"
+
+// The template based AgcAudioStream implements platform-independent parts
+// of the AudioInterface interface. Supported interfaces to pass as
+// AudioInterface are AudioIntputStream and AudioOutputStream. Each platform-
+// dependent implementation should derive from this class.
+//
+// Usage example (on Windows):
+//
+// class WASAPIAudioInputStream : public AgcAudioStream<AudioInputStream> {
+// public:
+// WASAPIAudioInputStream();
+// ...
+// };
+//
+// Call flow example:
+//
+// 1) User creates AgcAudioStream<AudioInputStream>
+// 2) User calls AudioInputStream::SetAutomaticGainControl(true) =>
+// AGC usage is now initialized but not yet started.
+// 3) User calls AudioInputStream::Start() => implementation calls
+// AgcAudioStream<AudioInputStream>::StartAgc() which detects that AGC
+// is enabled and then starts the periodic AGC timer.
+// 4) Microphone volume samples are now taken and included in all
+// AudioInputCallback::OnData() callbacks.
+// 5) User calls AudioInputStream::Stop() => implementation calls
+// AgcAudioStream<AudioInputStream>::StopAgc() which stops the timer.
+//
+// Note that, calling AudioInputStream::SetAutomaticGainControl(false) while
+// AGC measurements are active will not have an effect until StopAgc(),
+// StartAgc() are called again since SetAutomaticGainControl() only sets a
+// a state.
+//
+// Calling SetAutomaticGainControl(true) enables the AGC and StartAgc() starts
+// a periodic timer which calls OnTimer() approximately once every second.
+// OnTimer() calls the QueryAndStoreNewMicrophoneVolume() method which asks
+// the actual microphone about its current volume level. This value is
+// normalized and stored so it can be read by GetAgcVolume() when the real-time
+// audio thread needs the value. The main idea behind this scheme is to avoid
+// accessing the audio hardware from the real-time audio thread and to ensure
+// that we don't take new microphone-level samples too often (~1 Hz is a
+// suitable compromise). The timer will be active until StopAgc() is called.
+//
+// This class should be created and destroyed on the audio manager thread and
+// a thread checker is added to ensure that this is the case (uses DCHECK).
+// All methods except GetAgcVolume() should be called on the creating thread
+// as well to ensure that thread safety is maintained. It will also guarantee
+// that the periodic timer runs on the audio manager thread.
+// |normalized_volume_|, which is updated by QueryAndStoreNewMicrophoneVolume()
+// and read in GetAgcVolume(), is protected by a lock to ensure that it can
+// be accessed from any real-time audio thread that needs it to update the its
+// AGC volume.
+
+namespace media {
+
+template <typename AudioInterface>
+class MEDIA_EXPORT AgcAudioStream : public AudioInterface {
+ public:
+ // Time between two successive timer events.
+ static const int kIntervalBetweenVolumeUpdatesMs = 1000;
+
+ AgcAudioStream()
+ : agc_is_enabled_(false), max_volume_(0.0), normalized_volume_(0.0) {
+ DVLOG(1) << __FUNCTION__;
+ }
+
+ virtual ~AgcAudioStream() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(1) << __FUNCTION__;
+ }
+
+ protected:
+ // Starts the periodic timer which periodically checks and updates the
+ // current microphone volume level.
+ // The timer is only started if AGC mode is first enabled using the
+ // SetAutomaticGainControl() method.
+ void StartAgc() {
+ DVLOG(1) << "StartAgc()";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!agc_is_enabled_ || timer_.IsRunning())
+ return;
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kIntervalBetweenVolumeUpdatesMs),
+ this, &AgcAudioStream::OnTimer);
+ }
+
+ // Stops the periodic timer which periodically checks and updates the
+ // current microphone volume level.
+ void StopAgc() {
+ DVLOG(1) << "StopAgc()";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (timer_.IsRunning())
+ timer_.Stop();
+ }
+
+ // Stores a new microphone volume level by checking the audio input device.
+ // Called on the audio manager thread.
+ void UpdateAgcVolume() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // We take new volume samples once every second when the AGC is enabled.
+ // To ensure that a new setting has an immediate effect, the new volume
+ // setting is cached here. It will ensure that the next OnData() callback
+ // will contain a new valid volume level. If this approach was not taken,
+ // we could report invalid volume levels to the client for a time period
+ // of up to one second.
+ QueryAndStoreNewMicrophoneVolume();
+ }
+
+ // Gets the latest stored volume level if AGC is enabled.
+ // Called at each capture callback on a real-time capture thread (platform
+ // dependent).
+ void GetAgcVolume(double* normalized_volume) {
+ base::AutoLock lock(lock_);
+ *normalized_volume = normalized_volume_;
+ }
+
+ private:
+ // Sets the automatic gain control (AGC) to on or off. When AGC is enabled,
+ // the microphone volume is queried periodically and the volume level can
+ // be read in each AudioInputCallback::OnData() callback and fed to the
+ // render-side AGC. User must call StartAgc() as well to start measuring
+ // the microphone level.
+ virtual void SetAutomaticGainControl(bool enabled) OVERRIDE {
+ DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ agc_is_enabled_ = enabled;
+ }
+
+ // Gets the current automatic gain control state.
+ virtual bool GetAutomaticGainControl() OVERRIDE {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return agc_is_enabled_;
+ }
+
+ // Takes a new microphone volume sample and stores it in |normalized_volume_|.
+ // Range is normalized to [0.0,1.0] or [0.0, 1.5] on Linux.
+ void QueryAndStoreNewMicrophoneVolume() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(timer_.IsRunning());
+
+ // Cach the maximum volume if this is the first time we ask for it.
+ if (max_volume_ == 0.0)
+ max_volume_ = static_cast<AudioInterface*>(this)->GetMaxVolume();
+
+ // Retrieve the current volume level by asking the audio hardware.
+ // Range is normalized to [0.0,1.0] or [0.0, 1.5] on Linux.
+ if (max_volume_ != 0.0) {
+ double normalized_volume =
+ static_cast<AudioInterface*>(this)->GetVolume() / max_volume_;
+ base::AutoLock auto_lock(lock_);
+ normalized_volume_ = normalized_volume;
+ }
+ }
+
+ // This method is called periodically when AGC is enabled and always on the
+ // audio manager thread. We use it to read the current microphone level and
+ // to store it so it can be read by the main capture thread. By using this
+ // approach, we can avoid accessing audio hardware from a real-time audio
+ // thread and it leads to a more stable capture performance.
+ void OnTimer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ QueryAndStoreNewMicrophoneVolume();
+ }
+
+ // Ensures that this class is created and destroyed on the same thread.
+ base::ThreadChecker thread_checker_;
+
+ // Repeating timer which cancels itself when it goes out of scope.
+ // Used to check the microphone volume periodically.
+ base::RepeatingTimer<AgcAudioStream<AudioInterface> > timer_;
+
+ // True when automatic gain control is enabled, false otherwise.
+ bool agc_is_enabled_;
+
+ // Stores the maximum volume which is used for normalization to a volume
+ // range of [0.0, 1.0].
+ double max_volume_;
+
+ // Contains last result of internal call to GetVolume(). We save resources
+ // by not querying the capture volume for each callback. Guarded by |lock_|.
+ // The range is normalized to [0.0, 1.0].
+ double normalized_volume_;
+
+ // Protects |normalized_volume_| .
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(AgcAudioStream<AudioInterface>);
+};
+
+} // namespace media
+
+#endif // MEDIA_AUDIO_AGC_AUDIO_STREAM_H_
diff --git a/media/audio/audio_input_stream_impl.cc b/media/audio/audio_input_stream_impl.cc
deleted file mode 100644
index f68317c..0000000
--- a/media/audio/audio_input_stream_impl.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "media/audio/audio_input_stream_impl.h"
-
-namespace media {
-
-static const int kMinIntervalBetweenVolumeUpdatesMs = 1000;
-
-AudioInputStreamImpl::AudioInputStreamImpl()
- : agc_is_enabled_(false),
- max_volume_(0.0),
- normalized_volume_(0.0) {
-}
-
-AudioInputStreamImpl::~AudioInputStreamImpl() {}
-
-void AudioInputStreamImpl::SetAutomaticGainControl(bool enabled) {
- agc_is_enabled_ = enabled;
-}
-
-bool AudioInputStreamImpl::GetAutomaticGainControl() {
- return agc_is_enabled_;
-}
-
-void AudioInputStreamImpl::UpdateAgcVolume() {
- base::AutoLock lock(lock_);
-
- // We take new volume samples once every second when the AGC is enabled.
- // To ensure that a new setting has an immediate effect, the new volume
- // setting is cached here. It will ensure that the next OnData() callback
- // will contain a new valid volume level. If this approach was not taken,
- // we could report invalid volume levels to the client for a time period
- // of up to one second.
- if (agc_is_enabled_) {
- GetNormalizedVolume();
- }
-}
-
-void AudioInputStreamImpl::QueryAgcVolume(double* normalized_volume) {
- base::AutoLock lock(lock_);
-
- // Only modify the |volume| output reference if AGC is enabled and if
- // more than one second has passed since the volume was updated the last time.
- if (agc_is_enabled_) {
- base::Time now = base::Time::Now();
- if ((now - last_volume_update_time_).InMilliseconds() >
- kMinIntervalBetweenVolumeUpdatesMs) {
- GetNormalizedVolume();
- last_volume_update_time_ = now;
- }
- *normalized_volume = normalized_volume_;
- }
-}
-
-void AudioInputStreamImpl::GetNormalizedVolume() {
- if (max_volume_ == 0.0) {
- // Cach the maximum volume if this is the first time we ask for it.
- max_volume_ = GetMaxVolume();
- }
-
- if (max_volume_ != 0.0) {
- // Retrieve the current volume level by asking the audio hardware.
- // Range is normalized to [0.0,1.0] or [0.0, 1.5] on Linux.
- normalized_volume_ = GetVolume() / max_volume_;
- }
-}
-
-} // namespace media
diff --git a/media/audio/audio_input_stream_impl.h b/media/audio/audio_input_stream_impl.h
deleted file mode 100644
index 64980a9..0000000
--- a/media/audio/audio_input_stream_impl.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_AUDIO_AUDIO_INPUT_STREAM_IMPL_H_
-#define MEDIA_AUDIO_AUDIO_INPUT_STREAM_IMPL_H_
-
-#include "base/compiler_specific.h"
-#include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "media/audio/audio_io.h"
-
-namespace media {
-
-// AudioInputStreamImpl implements platform-independent parts of the
-// AudioInputStream interface. Each platform dependent implementation
-// should derive from this class.
-// TODO(henrika): we can probably break out more parts from our current
-// AudioInputStream implementation and move out to this class.
-class MEDIA_EXPORT AudioInputStreamImpl : public AudioInputStream {
- public:
- AudioInputStreamImpl();
- virtual ~AudioInputStreamImpl();
-
- // Sets the automatic gain control (AGC) to on or off. When AGC is enabled,
- // the microphone volume is queried periodically and the volume level is
- // provided in each AudioInputCallback::OnData() callback and fed to the
- // render-side AGC.
- virtual void SetAutomaticGainControl(bool enabled) OVERRIDE;
-
- // Gets the current automatic gain control state.
- virtual bool GetAutomaticGainControl() OVERRIDE;
-
- protected:
- // Stores a new volume level by asking the audio hardware.
- // This method only has an effect if AGC is enabled.
- void UpdateAgcVolume();
-
- // Gets the latest stored volume level if AGC is enabled and if
- // more than one second has passed since the volume was updated the last time.
- void QueryAgcVolume(double* normalized_volume);
-
- private:
- // Takes a volume sample and stores it in |normalized_volume_|.
- void GetNormalizedVolume();
-
- // True when automatic gain control is enabled, false otherwise.
- // Guarded by |lock_|.
- bool agc_is_enabled_;
-
- // Stores the maximum volume which is used for normalization to a volume
- // range of [0.0, 1.0].
- double max_volume_;
-
- // Contains last result of internal call to GetVolume(). We save resources
- // but not querying the capture volume for each callback. Guarded by |lock_|.
- // The range is normalized to [0.0, 1.0].
- double normalized_volume_;
-
- // Protects |agc_is_enabled_| and |volume_| .
- base::Lock lock_;
-
- // Keeps track of the last time the microphone volume level was queried.
- base::Time last_volume_update_time_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioInputStreamImpl);
-};
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_AUDIO_INPUT_STREAM_IMPL_H_
diff --git a/media/audio/cras/cras_input.cc b/media/audio/cras/cras_input.cc
index aa398b6..c080ac6 100644
--- a/media/audio/cras/cras_input.cc
+++ b/media/audio/cras/cras_input.cc
@@ -107,6 +107,8 @@ void CrasInputStream::Start(AudioInputCallback* callback) {
if (started_)
return;
+ StartAgc();
+
callback_ = callback;
LOG(ERROR) << "Input Start";
@@ -169,6 +171,8 @@ void CrasInputStream::Stop() {
if (!callback_ || !started_)
return;
+ StopAgc();
+
// Removing the stream from the client stops audio.
cras_client_rm_stream(client_, stream_id_);
@@ -222,7 +226,7 @@ void CrasInputStream::ReadAudio(size_t frames,
// also updated each time SetVolume() is called through IPC by the
// render-side AGC.
double normalized_volume = 0.0;
- QueryAgcVolume(&normalized_volume);
+ GetAgcVolume(&normalized_volume);
callback_->OnData(this,
buffer,
diff --git a/media/audio/cras/cras_input.h b/media/audio/cras/cras_input.h
index 37772bf..1b2a611 100644
--- a/media/audio/cras/cras_input.h
+++ b/media/audio/cras/cras_input.h
@@ -12,7 +12,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "media/audio/audio_input_stream_impl.h"
+#include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
@@ -23,7 +23,7 @@ class AudioManagerCras;
// Provides an input stream for audio capture based on CRAS, the ChromeOS Audio
// Server. This object is not thread safe and all methods should be invoked in
// the thread that created the object.
-class CrasInputStream : public AudioInputStreamImpl {
+class CrasInputStream : public AgcAudioStream<AudioInputStream> {
public:
// The ctor takes all the usual parameters, plus |manager| which is the
// audio manager who is creating this object.
diff --git a/media/audio/linux/alsa_input.cc b/media/audio/linux/alsa_input.cc
index 8f78530..ce337d3 100644
--- a/media/audio/linux/alsa_input.cc
+++ b/media/audio/linux/alsa_input.cc
@@ -102,6 +102,7 @@ bool AlsaPcmInputStream::Open() {
void AlsaPcmInputStream::Start(AudioInputCallback* callback) {
DCHECK(!callback_ && callback);
callback_ = callback;
+ StartAgc();
int error = wrapper_->PcmPrepare(device_handle_);
if (error < 0) {
HandleError("PcmPrepare", error);
@@ -203,7 +204,7 @@ void AlsaPcmInputStream::ReadAudio() {
// Update the AGC volume level once every second. Note that, |volume| is
// also updated each time SetVolume() is called through IPC by the
// render-side AGC.
- QueryAgcVolume(&normalized_volume);
+ GetAgcVolume(&normalized_volume);
while (num_buffers--) {
int frames_read = wrapper_->PcmReadi(device_handle_, audio_buffer_.get(),
@@ -240,6 +241,8 @@ void AlsaPcmInputStream::Stop() {
if (!device_handle_ || !callback_)
return;
+ StopAgc();
+
// Stop is always called before Close. In case of error, this will be
// also called when closing the input controller.
audio_manager_->DecreaseActiveInputStreamCount();
diff --git a/media/audio/linux/alsa_input.h b/media/audio/linux/alsa_input.h
index df2b471..57092eb 100644
--- a/media/audio/linux/alsa_input.h
+++ b/media/audio/linux/alsa_input.h
@@ -13,7 +13,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time.h"
-#include "media/audio/audio_input_stream_impl.h"
+#include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
@@ -25,7 +25,7 @@ class AudioManagerLinux;
// Provides an input stream for audio capture based on the ALSA PCM interface.
// This object is not thread safe and all methods should be invoked in the
// thread that created the object.
-class AlsaPcmInputStream : public AudioInputStreamImpl {
+class AlsaPcmInputStream : public AgcAudioStream<AudioInputStream> {
public:
// Pass this to the constructor if you want to attempt auto-selection
// of the audio recording device.
diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc
index cf9d180..ff2f83f 100644
--- a/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/media/audio/mac/audio_low_latency_input_mac.cc
@@ -268,6 +268,7 @@ void AUAudioInputStream::Start(AudioInputCallback* callback) {
if (started_ || !audio_unit_)
return;
sink_ = callback;
+ StartAgc();
OSStatus result = AudioOutputUnitStart(audio_unit_);
if (result == noErr) {
started_ = true;
@@ -279,6 +280,7 @@ void AUAudioInputStream::Start(AudioInputCallback* callback) {
void AUAudioInputStream::Stop() {
if (!started_)
return;
+ StopAgc();
OSStatus result = AudioOutputUnitStop(audio_unit_);
if (result == noErr) {
started_ = false;
@@ -483,11 +485,11 @@ OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
// Update the capture latency.
double capture_latency_frames = GetCaptureLatency(time_stamp);
- // Update the AGC volume level once every second. Note that, |volume| is
- // also updated each time SetVolume() is called through IPC by the
- // render-side AGC.
+ // The AGC volume level is updated once every second on a separate thread.
+ // Note that, |volume| is also updated each time SetVolume() is called
+ // through IPC by the render-side AGC.
double normalized_volume = 0.0;
- QueryAgcVolume(&normalized_volume);
+ GetAgcVolume(&normalized_volume);
AudioBuffer& buffer = io_data->mBuffers[0];
uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
diff --git a/media/audio/mac/audio_low_latency_input_mac.h b/media/audio/mac/audio_low_latency_input_mac.h
index 04a4ff8..07a727b 100644
--- a/media/audio/mac/audio_low_latency_input_mac.h
+++ b/media/audio/mac/audio_low_latency_input_mac.h
@@ -42,8 +42,8 @@
#include "base/atomicops.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
+#include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_io.h"
-#include "media/audio/audio_input_stream_impl.h"
#include "media/audio/audio_parameters.h"
#include "media/base/seekable_buffer.h"
@@ -52,7 +52,7 @@ namespace media {
class AudioManagerMac;
class DataBuffer;
-class AUAudioInputStream : public AudioInputStreamImpl {
+class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
public:
// The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object.
diff --git a/media/audio/pulse/pulse_input.cc b/media/audio/pulse/pulse_input.cc
index 4e48e10..c365c47 100644
--- a/media/audio/pulse/pulse_input.cc
+++ b/media/audio/pulse/pulse_input.cc
@@ -66,6 +66,8 @@ void PulseAudioInputStream::Start(AudioInputCallback* callback) {
if (stream_started_)
return;
+ StartAgc();
+
// Clean up the old buffer.
pa_stream_drop(handle_);
buffer_->Clear();
@@ -86,6 +88,8 @@ void PulseAudioInputStream::Stop() {
if (!stream_started_)
return;
+ StopAgc();
+
// Set the flag to false to stop filling new data to soundcard.
stream_started_ = false;
@@ -246,11 +250,10 @@ void PulseAudioInputStream::ReadData() {
// Update the AGC volume level once every second. Note that,
// |volume| is also updated each time SetVolume() is called
// through IPC by the render-side AGC.
- // QueryAgcVolume() will trigger a callback to asynchronously update the
- // |volume_|, we disregard the |normalized_volume| from QueryAgcVolume()
+ // We disregard the |normalized_volume| from GetAgcVolume()
// and use the value calculated by |volume_|.
double normalized_volume = 0.0;
- QueryAgcVolume(&normalized_volume);
+ GetAgcVolume(&normalized_volume);
normalized_volume = volume_ / GetMaxVolume();
do {
diff --git a/media/audio/pulse/pulse_input.h b/media/audio/pulse/pulse_input.h
index 00bc03f..7566eac 100644
--- a/media/audio/pulse/pulse_input.h
+++ b/media/audio/pulse/pulse_input.h
@@ -8,8 +8,8 @@
#include <string>
#include "base/threading/thread_checker.h"
+#include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_device_name.h"
-#include "media/audio/audio_input_stream_impl.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
@@ -23,7 +23,7 @@ namespace media {
class AudioManagerPulse;
class SeekableBuffer;
-class PulseAudioInputStream : public AudioInputStreamImpl {
+class PulseAudioInputStream : public AgcAudioStream<AudioInputStream> {
public:
PulseAudioInputStream(AudioManagerPulse* audio_manager,
const std::string& device_name,
diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc
index ae4c630..a57a1cb 100644
--- a/media/audio/win/audio_low_latency_input_win.cc
+++ b/media/audio/win/audio_low_latency_input_win.cc
@@ -127,6 +127,10 @@ void WASAPIAudioInputStream::Start(AudioInputCallback* callback) {
sink_ = callback;
+ // Starts periodic AGC microphone measurements if the AGC has been enabled
+ // using SetAutomaticGainControl().
+ StartAgc();
+
// Create and start the thread that will drive the capturing by waiting for
// capture events.
capture_thread_ =
@@ -146,6 +150,9 @@ void WASAPIAudioInputStream::Stop() {
if (!started_)
return;
+ // Stops periodic AGC microphone measurements.
+ StopAgc();
+
// Shut down the capture thread.
if (stop_capture_event_.IsValid()) {
SetEvent(stop_capture_event_.Get());
@@ -387,10 +394,10 @@ void WASAPIAudioInputStream::Run() {
first_audio_frame_timestamp) / 10000.0) * ms_to_frame_count_ +
buffer_frame_index - num_frames_to_read;
- // Update the AGC volume level once every second. Note that,
- // |volume| is also updated each time SetVolume() is called
- // through IPC by the render-side AGC.
- QueryAgcVolume(&volume);
+ // Get a cached AGC volume level which is updated once every second
+ // on the audio manager thread. Note that, |volume| is also updated
+ // each time SetVolume() is called through IPC by the render-side AGC.
+ GetAgcVolume(&volume);
// Deliver captured data to the registered consumer using a packet
// size which was specified at construction.
diff --git a/media/audio/win/audio_low_latency_input_win.h b/media/audio/win/audio_low_latency_input_win.h
index 68b0c61..4f9c7fb 100644
--- a/media/audio/win/audio_low_latency_input_win.h
+++ b/media/audio/win/audio_low_latency_input_win.h
@@ -69,7 +69,7 @@
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_handle.h"
-#include "media/audio/audio_input_stream_impl.h"
+#include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_parameters.h"
#include "media/base/media_export.h"
@@ -79,7 +79,7 @@ class AudioManagerWin;
// AudioInputStream implementation using Windows Core Audio APIs.
class MEDIA_EXPORT WASAPIAudioInputStream
- : public AudioInputStreamImpl,
+ : public AgcAudioStream<AudioInputStream>,
public base::DelegateSimpleThread::Delegate,
NON_EXPORTED_BASE(public base::NonThreadSafe) {
public: