| 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..973227805d9d97189554053238f5b116030f99d9 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
|
| + // 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,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);
|
| + 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 +783,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 +800,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;
|
| }
|
|
|
|
|