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 1293674e14c2e0c2a4395694068430d71ab4d277..2928bc514ba806250c6a9427c7b0ea5ac1b8a97f 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) |
@@ -46,7 +47,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"; |
@@ -138,12 +140,12 @@ 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_); |
- |
+ DCHECK_LE(volume, 1.0); |
int output_delay_ms = 0; |
{ |
base::AutoLock auto_lock(lock_); |
@@ -171,15 +173,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, |
@@ -187,12 +191,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 |
scherkus (not reviewing)
2012/03/20 13:49:41
I'm confused -- isn't it the audio_transport_callb
henrika (OOO until Aug 14)
2012/03/21 10:16:04
The last two parameters in RecordedDataIsAvailable
|
+ // 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() { |
@@ -677,13 +693,19 @@ bool WebRtcAudioDeviceImpl::Recording() const { |
} |
int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) { |
- DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::SetAGC() " << "NOT IMPLEMENTED"; |
- return -1; |
+ // The most common usage is to set the AGC state before recording starts. |
+ // The AudioInputDevice also supports changing the AGC state on the fly, |
+ // i.e., it is possible to modify the AGC state while audio streaming is |
+ // active. |
scherkus (not reviewing)
2012/03/21 09:21:21
when you say "most common usage" do you actually m
henrika (OOO until Aug 14)
2012/03/21 10:16:04
I discussed it with Justin and it was OK to add su
|
+ audio_input_device_->SetAutomaticGainControl(enable); |
+ 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, |
@@ -756,8 +778,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; |
} |
@@ -774,32 +795,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); |
tommi (sloooow) - chröme
2012/03/16 13:31:05
is the cast needed?
henrika (OOO until Aug 14)
2012/03/21 10:16:04
Good question. I don't think is required for funda
|
+ 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(); |
tommi (sloooow) - chröme
2012/03/16 13:31:05
A comment on why we never expect this to be called
henrika (OOO until Aug 14)
2012/03/21 10:16:04
Good question. It is a method that have caused us
|
return -1; |
} |