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

Unified Diff: content/renderer/media/webrtc_audio_device_impl.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 AGC comments 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 side-by-side diff with in-line comments
Download patch
Index: content/renderer/media/webrtc_audio_device_impl.cc
diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc
index fefb10efb8b7f8ea5cb63bdf68425b405b3c1773..12fcea72acda966b1b471f74ffd63c737b851a54 100644
--- a/content/renderer/media/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc_audio_device_impl.cc
@@ -12,6 +12,7 @@
#include "media/audio/audio_util.h"
static const int64 kMillisecondsBetweenProcessCalls = 5000;
+static const double kMaxVolumeLevel = 255.0;
// Supported hardware sample rates for input and output sides.
#if defined(OS_WIN) || defined(OS_MACOSX)
@@ -40,7 +41,8 @@ WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
bytes_per_sample_(0),
initialized_(false),
playing_(false),
- recording_(false) {
+ recording_(false),
+ agc_is_enabled_(false) {
DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
DCHECK(RenderThreadImpl::current()) <<
"WebRtcAudioDeviceImpl must be constructed on the render thread";
@@ -132,11 +134,21 @@ void WebRtcAudioDeviceImpl::OnRenderError() {
LOG(ERROR) << "OnRenderError()";
}
-void WebRtcAudioDeviceImpl::Capture(
- const std::vector<float*>& audio_data,
- size_t number_of_frames,
- size_t audio_delay_milliseconds) {
+void WebRtcAudioDeviceImpl::Capture(const std::vector<float*>& audio_data,
+ size_t number_of_frames,
+ size_t audio_delay_milliseconds,
+ double volume) {
DCHECK_LE(number_of_frames, input_buffer_size());
+ #if defined(OS_WIN) || defined(OS_MACOSX)
+ DCHECK_LE(volume, 1.0);
+ #elif defined(OS_LINUX) || defined(OS_OPENBSD)
+ // We have a special situation on Linux where the microphone volume can be
+ // "higher than maximum". The input volume slider in the sound preference
+ // allows the user to set a scaling that is higher than 100%. It means that
+ // even if the reported maximum levels is N, the actual microphone level can
+ // go up to 1.5*N and that corresponds to a normalized |volume| of 1.5.
+ DCHECK_LE(volume, 1.5);
+ #endif
int output_delay_ms = 0;
{
@@ -165,15 +177,17 @@ void WebRtcAudioDeviceImpl::Capture(
const int bytes_per_10_msec =
channels * samples_per_10_msec * bytes_per_sample_;
size_t accumulated_audio_samples = 0;
-
char* audio_byte_buffer = reinterpret_cast<char*>(input_buffer_.get());
+ // Map internal volume range of [0.0, 1.0] into [0, 255] used by the
+ // webrtc::VoiceEngine.
+ uint32_t current_mic_level = static_cast<uint32_t>(volume * kMaxVolumeLevel);
+
// Write audio samples in blocks of 10 milliseconds to the registered
// webrtc::AudioTransport sink. Keep writing until our internal byte
// buffer is empty.
while (accumulated_audio_samples < number_of_frames) {
- // Deliver 10ms of recorded PCM audio.
- // TODO(henrika): add support for analog AGC?
+ // Deliver 10ms of recorded 16-bit linear PCM audio.
audio_transport_callback_->RecordedDataIsAvailable(
audio_byte_buffer,
samples_per_10_msec,
@@ -181,12 +195,24 @@ void WebRtcAudioDeviceImpl::Capture(
channels,
samples_per_sec,
input_delay_ms_ + output_delay_ms,
- 0, // clock_drift
- 0, // current_mic_level
- new_mic_level); // not used
+ 0, // TODO(henrika): |clock_drift| parameter is not utilized today.
+ current_mic_level,
+ new_mic_level);
+
accumulated_audio_samples += samples_per_10_msec;
audio_byte_buffer += bytes_per_10_msec;
}
+
+ // The AGC returns a non-zero microphone level if it has been decided
+ // that a new level should be set.
+ if (new_mic_level != 0) {
+ // Use IPC and set the new level. Note that, it will take some time
+ // before the new level is effective due to the IPC scheme.
+ // During this time, |current_mic_level| will contain "non-valid" values
+ // and it might reduce the AGC performance. Measurements on Windows 7 have
+ // shown that we might receive old volume levels for one or two callbacks.
+ SetMicrophoneVolume(new_mic_level);
+ }
}
void WebRtcAudioDeviceImpl::OnCaptureError() {
@@ -675,13 +701,24 @@ bool WebRtcAudioDeviceImpl::Recording() const {
}
int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) {
- DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::SetAGC() " << "NOT IMPLEMENTED";
- return -1;
+ // The current implementation does not support changing the AGC state while
+ // recording. Using this approach simplifies the design and it is also
+ // inline with the latest WebRTC standard.
+ DCHECK(!recording_);
+ if (recording_) {
+ DLOG(ERROR) << "Failed to modify the AGC state since recording is active.";
+ return -1;
+ }
+
+ audio_input_device_->SetAutomaticGainControl(enable);
scherkus (not reviewing) 2012/03/26 22:41:04 nit: instead of a setter you may consider passing
henrika (OOO until Aug 14) 2012/03/27 09:20:38 Thanks for the proposal. I'd like to keep the curr
+ agc_is_enabled_ = enable;
+ return 0;
}
bool WebRtcAudioDeviceImpl::AGC() const {
- DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::AGC() " << "NOT IMPLEMENTED";
- return false;
+ // To reduce the usage of IPC messages, an internal AGC state is used.
+ // TODO(henrika): investigate if there is a need for a "deeper" getter.
+ return agc_is_enabled_;
}
int32_t WebRtcAudioDeviceImpl::SetWaveOutVolume(uint16_t volume_left,
@@ -754,8 +791,7 @@ int32_t WebRtcAudioDeviceImpl::MaxSpeakerVolume(uint32_t* max_volume) const {
return -1;
}
-int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume(
- uint32_t* min_volume) const {
+int32_t WebRtcAudioDeviceImpl::MinSpeakerVolume(uint32_t* min_volume) const {
NOTIMPLEMENTED();
return -1;
}
@@ -772,32 +808,39 @@ int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeIsAvailable(bool* available) {
}
int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
- NOTIMPLEMENTED();
- return -1;
+ DVLOG(1) << "SetMicrophoneVolume(" << volume << ")";
+ if (volume > kMaxVolumeLevel)
+ return -1;
+
+ // WebRTC uses a range of [0, 255] to represent the level of the microphone
+ // volume. The IPC channel between the renderer and browser process works
+ // with doubles in the [0.0, 1.0] range and we have to compensate for that.
+ double normalized_volume = static_cast<double>(volume / kMaxVolumeLevel);
+ audio_input_device_->SetVolume(normalized_volume);
+ return 0;
}
int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
- NOTIMPLEMENTED();
+ // The microphone level is fed to this class using the Capture() callback
+ // and this external API should not be used. Additional IPC messages are
+ // required if support for this API is ever needed.
+ NOTREACHED();
return -1;
}
-int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(
- uint32_t* max_volume) const {
- DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::MaxMicrophoneVolume() "
- << "NOT IMPLEMENTED";
- return -1;
+int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
+ *max_volume = kMaxVolumeLevel;
+ return 0;
}
-int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(
- uint32_t* min_volume) const {
- DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::MinMicrophoneVolume() "
- << "NOT IMPLEMENTED";
- return -1;
+int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
+ *min_volume = 0;
+ return 0;
}
int32_t WebRtcAudioDeviceImpl::MicrophoneVolumeStepSize(
uint16_t* step_size) const {
- NOTIMPLEMENTED();
+ NOTREACHED();
return -1;
}

Powered by Google App Engine
This is Rietveld 408576698