| Index: webrtc/modules/audio_processing/audio_processing_impl.cc
|
| diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc
|
| index 12b4c949046f08ddcc3f974d26024bea7e516b54..0cdacbedba30c74054836b6bac092a43cfed1cee 100644
|
| --- a/webrtc/modules/audio_processing/audio_processing_impl.cc
|
| +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc
|
| @@ -35,6 +35,7 @@
|
| #include "webrtc/modules/audio_processing/level_controller/level_controller.h"
|
| #include "webrtc/modules/audio_processing/level_estimator_impl.h"
|
| #include "webrtc/modules/audio_processing/noise_suppression_impl.h"
|
| +#include "webrtc/modules/audio_processing/residual_echo_detector.h"
|
| #include "webrtc/modules/audio_processing/transient/transient_suppressor.h"
|
| #include "webrtc/modules/audio_processing/voice_detection_impl.h"
|
| #include "webrtc/modules/include/module_common_types.h"
|
| @@ -137,6 +138,7 @@ bool AudioProcessingImpl::ApmSubmoduleStates::Update(
|
| bool high_pass_filter_enabled,
|
| bool echo_canceller_enabled,
|
| bool mobile_echo_controller_enabled,
|
| + bool residual_echo_detector_enabled,
|
| bool noise_suppressor_enabled,
|
| bool intelligibility_enhancer_enabled,
|
| bool beamformer_enabled,
|
| @@ -150,6 +152,8 @@ bool AudioProcessingImpl::ApmSubmoduleStates::Update(
|
| changed |= (echo_canceller_enabled != echo_canceller_enabled_);
|
| changed |=
|
| (mobile_echo_controller_enabled != mobile_echo_controller_enabled_);
|
| + changed |=
|
| + (residual_echo_detector_enabled != residual_echo_detector_enabled_);
|
| changed |= (noise_suppressor_enabled != noise_suppressor_enabled_);
|
| changed |=
|
| (intelligibility_enhancer_enabled != intelligibility_enhancer_enabled_);
|
| @@ -165,6 +169,7 @@ bool AudioProcessingImpl::ApmSubmoduleStates::Update(
|
| high_pass_filter_enabled_ = high_pass_filter_enabled;
|
| echo_canceller_enabled_ = echo_canceller_enabled;
|
| mobile_echo_controller_enabled_ = mobile_echo_controller_enabled;
|
| + residual_echo_detector_enabled_ = residual_echo_detector_enabled;
|
| noise_suppressor_enabled_ = noise_suppressor_enabled;
|
| intelligibility_enhancer_enabled_ = intelligibility_enhancer_enabled;
|
| beamformer_enabled_ = beamformer_enabled;
|
| @@ -239,6 +244,7 @@ struct AudioProcessingImpl::ApmPrivateSubmodules {
|
| std::unique_ptr<NonlinearBeamformer> beamformer;
|
| std::unique_ptr<AgcManagerDirect> agc_manager;
|
| std::unique_ptr<LevelController> level_controller;
|
| + std::unique_ptr<ResidualEchoDetector> residual_echo_detector;
|
| };
|
|
|
| AudioProcessing* AudioProcessing::Create() {
|
| @@ -304,6 +310,8 @@ AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config,
|
| public_submodules_->gain_control_for_experimental_agc.reset(
|
| new GainControlForExperimentalAgc(
|
| public_submodules_->gain_control.get(), &crit_capture_));
|
| + private_submodules_->residual_echo_detector.reset(
|
| + new ResidualEchoDetector());
|
|
|
| // TODO(peah): Move this creation to happen only when the level controller
|
| // is enabled.
|
| @@ -469,6 +477,7 @@ int AudioProcessingImpl::InitializeLocked() {
|
| public_submodules_->voice_detection->Initialize(proc_split_sample_rate_hz());
|
| public_submodules_->level_estimator->Initialize();
|
| InitializeLevelController();
|
| + InitializeResidualEchoDetector();
|
|
|
| #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
|
| if (debug_dump_.debug_file->is_open()) {
|
| @@ -808,6 +817,18 @@ void AudioProcessingImpl::QueueRenderAudio(AudioBuffer* audio) {
|
| RTC_DCHECK(result);
|
| }
|
| }
|
| +
|
| + ResidualEchoDetector::PackRenderAudioBuffer(audio, &red_render_queue_buffer_);
|
| +
|
| + // Insert the samples into the queue.
|
| + if (!red_render_signal_queue_->Insert(&red_render_queue_buffer_)) {
|
| + // The data queue is full and needs to be emptied.
|
| + EmptyQueuedRenderAudio();
|
| +
|
| + // Retry the insert (should always work).
|
| + bool result = red_render_signal_queue_->Insert(&red_render_queue_buffer_);
|
| + RTC_DCHECK(result);
|
| + }
|
| }
|
|
|
| void AudioProcessingImpl::AllocateRenderQueue() {
|
| @@ -826,6 +847,9 @@ void AudioProcessingImpl::AllocateRenderQueue() {
|
| const size_t new_agc_render_queue_element_max_size =
|
| std::max(static_cast<size_t>(1), kMaxAllowedValuesOfSamplesPerFrame);
|
|
|
| + const size_t new_red_render_queue_element_max_size =
|
| + std::max(static_cast<size_t>(1), kMaxAllowedValuesOfSamplesPerFrame);
|
| +
|
| // Reallocate the queues if the queue item sizes are too small to fit the
|
| // data to put in the queues.
|
| if (aec_render_queue_element_max_size_ <
|
| @@ -885,6 +909,25 @@ void AudioProcessingImpl::AllocateRenderQueue() {
|
| } else {
|
| agc_render_signal_queue_->Clear();
|
| }
|
| +
|
| + if (red_render_queue_element_max_size_ <
|
| + new_red_render_queue_element_max_size) {
|
| + red_render_queue_element_max_size_ = new_red_render_queue_element_max_size;
|
| +
|
| + std::vector<float> template_queue_element(
|
| + red_render_queue_element_max_size_);
|
| +
|
| + red_render_signal_queue_.reset(
|
| + new SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>(
|
| + kMaxNumFramesToBuffer, template_queue_element,
|
| + RenderQueueItemVerifier<float>(
|
| + red_render_queue_element_max_size_)));
|
| +
|
| + red_render_queue_buffer_.resize(red_render_queue_element_max_size_);
|
| + red_capture_queue_buffer_.resize(red_render_queue_element_max_size_);
|
| + } else {
|
| + red_render_signal_queue_->Clear();
|
| + }
|
| }
|
|
|
| void AudioProcessingImpl::EmptyQueuedRenderAudio() {
|
| @@ -903,6 +946,11 @@ void AudioProcessingImpl::EmptyQueuedRenderAudio() {
|
| public_submodules_->gain_control->ProcessRenderAudio(
|
| agc_capture_queue_buffer_);
|
| }
|
| +
|
| + while (red_render_signal_queue_->Remove(&red_capture_queue_buffer_)) {
|
| + private_submodules_->residual_echo_detector->AnalyzeRenderAudio(
|
| + red_capture_queue_buffer_);
|
| + }
|
| }
|
|
|
| int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
|
| @@ -1078,6 +1126,13 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
|
| RETURN_ON_ERR(public_submodules_->echo_control_mobile->ProcessCaptureAudio(
|
| capture_buffer, stream_delay_ms()));
|
|
|
| + if (config_.residual_echo_detector.enabled) {
|
| + private_submodules_->residual_echo_detector->AnalyzeCaptureAudio(
|
| + rtc::ArrayView<const float>(
|
| + capture_buffer->split_bands_const_f(0)[kBand0To8kHz],
|
| + capture_buffer->num_frames_per_band()));
|
| + }
|
| +
|
| if (capture_nonlocked_.beamformer_enabled) {
|
| private_submodules_->beamformer->PostFilter(capture_buffer->split_data_f());
|
| }
|
| @@ -1453,6 +1508,7 @@ bool AudioProcessingImpl::UpdateActiveSubmoduleStates() {
|
| public_submodules_->high_pass_filter->is_enabled(),
|
| public_submodules_->echo_cancellation->is_enabled(),
|
| public_submodules_->echo_control_mobile->is_enabled(),
|
| + config_.residual_echo_detector.enabled,
|
| public_submodules_->noise_suppression->is_enabled(),
|
| capture_nonlocked_.intelligibility_enabled,
|
| capture_nonlocked_.beamformer_enabled,
|
| @@ -1502,6 +1558,10 @@ void AudioProcessingImpl::InitializeLevelController() {
|
| private_submodules_->level_controller->Initialize(proc_sample_rate_hz());
|
| }
|
|
|
| +void AudioProcessingImpl::InitializeResidualEchoDetector() {
|
| + private_submodules_->residual_echo_detector->Initialize();
|
| +}
|
| +
|
| void AudioProcessingImpl::MaybeUpdateHistograms() {
|
| static const int kMinDiffDelayMs = 60;
|
|
|
|
|