diff options
Diffstat (limited to 'content/renderer/media/webrtc_audio_device_impl.cc')
-rw-r--r-- | content/renderer/media/webrtc_audio_device_impl.cc | 117 |
1 files changed, 82 insertions, 35 deletions
diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc index fefb10e..a25bdca 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() { @@ -331,8 +357,8 @@ int32_t WebRtcAudioDeviceImpl::Init() { ChannelLayout out_channel_layout = CHANNEL_LAYOUT_MONO; AudioParameters::Format in_format = AudioParameters::AUDIO_PCM_LINEAR; - size_t in_buffer_size = 0; - size_t out_buffer_size = 0; + int in_buffer_size = 0; + int out_buffer_size = 0; // TODO(henrika): factor out all platform specific parts in separate // functions. Code is a bit messy right now. @@ -357,6 +383,8 @@ int32_t WebRtcAudioDeviceImpl::Init() { in_buffer_size = 440; } else { in_buffer_size = (in_sample_rate / 100); + DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << + "Sample rate not supported. Should have been caught in Init()."; } // Render side: AUDIO_PCM_LOW_LATENCY is based on the Core Audio (WASAPI) @@ -401,6 +429,8 @@ int32_t WebRtcAudioDeviceImpl::Init() { in_buffer_size = 440; } else { in_buffer_size = (in_sample_rate / 100); + DCHECK_EQ(in_buffer_size * 100, in_sample_rate) << + "Sample rate not supported. Should have been caught in Init()."; } // Render side: AUDIO_PCM_LOW_LATENCY on Mac OS X is based on a callback- @@ -594,8 +624,8 @@ bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const { int32_t WebRtcAudioDeviceImpl::StartPlayout() { DVLOG(1) << "StartPlayout()"; + LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing"; if (!audio_transport_callback_) { - LOG(ERROR) << "Audio transport is missing"; return -1; } if (playing_) { @@ -627,7 +657,6 @@ int32_t WebRtcAudioDeviceImpl::StartRecording() { DVLOG(1) << "StartRecording()"; LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing"; if (!audio_transport_callback_) { - LOG(ERROR) << "Audio transport is missing"; return -1; } @@ -675,13 +704,25 @@ bool WebRtcAudioDeviceImpl::Recording() const { } int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) { - DVLOG(2) << "WARNING: WebRtcAudioDeviceImpl::SetAGC() " << "NOT IMPLEMENTED"; - return -1; + DVLOG(1) << "SetAGC(enable=" << enable << ")"; + // 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(initialized_); + DCHECK(!recording_) << "Unable to set AGC state while recording is active."; + if (recording_) { + 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, @@ -754,8 +795,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 +812,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; } |