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

Unified Diff: webrtc/modules/audio_processing/aec3/echo_remover.cc

Issue 2678423005: Finalization of the first version of EchoCanceller 3 (Closed)
Patch Set: Fixed compilation error Created 3 years, 10 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: webrtc/modules/audio_processing/aec3/echo_remover.cc
diff --git a/webrtc/modules/audio_processing/aec3/echo_remover.cc b/webrtc/modules/audio_processing/aec3/echo_remover.cc
index ab0b68bb168f5b60b14cd02dd89d510c908721f0..f7003894758e7ef8d972e28656d28031f4c0a346 100644
--- a/webrtc/modules/audio_processing/aec3/echo_remover.cc
+++ b/webrtc/modules/audio_processing/aec3/echo_remover.cc
@@ -10,59 +10,237 @@
#include "webrtc/modules/audio_processing/aec3/echo_remover.h"
#include <algorithm>
-#include <vector>
+#include <memory>
+#include <numeric>
+#include <string>
+#include "webrtc/base/array_view.h"
+#include "webrtc/base/atomicops.h"
#include "webrtc/base/constructormagic.h"
-#include "webrtc/base/checks.h"
-#include "webrtc/base/optional.h"
-#include "webrtc/modules/audio_processing/aec3/aec3_constants.h"
+#include "webrtc/modules/audio_processing/aec3/aec3_common.h"
+#include "webrtc/modules/audio_processing/aec3/aec_state.h"
+#include "webrtc/modules/audio_processing/aec3/comfort_noise_generator.h"
+#include "webrtc/modules/audio_processing/aec3/echo_path_variability.h"
+#include "webrtc/modules/audio_processing/aec3/fft_buffer.h"
+#include "webrtc/modules/audio_processing/aec3/fft_data.h"
+#include "webrtc/modules/audio_processing/aec3/output_selector.h"
+#include "webrtc/modules/audio_processing/aec3/power_echo_model.h"
+#include "webrtc/modules/audio_processing/aec3/render_delay_buffer.h"
+#include "webrtc/modules/audio_processing/aec3/residual_echo_estimator.h"
+#include "webrtc/modules/audio_processing/aec3/subtractor.h"
+#include "webrtc/modules/audio_processing/aec3/suppression_filter.h"
+#include "webrtc/modules/audio_processing/aec3/suppression_gain.h"
+#include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
namespace webrtc {
namespace {
+
+void LinearEchoPower(const FftData& E,
+ const FftData& Y,
+ std::array<float, kFftLengthBy2Plus1>* S2) {
+ for (size_t k = 0; k < E.re.size(); ++k) {
+ (*S2)[k] = (Y.re[k] - E.re[k]) * (Y.re[k] - E.re[k]) +
+ (Y.im[k] - E.im[k]) * (Y.im[k] - E.im[k]);
+ }
+}
+
+float BlockPower(const std::array<float, kBlockSize> x) {
+ return std::accumulate(x.begin(), x.end(), 0.f,
+ [](float a, float b) -> float { return a + b * b; });
+}
+
+// Class for removing the echo from the capture signal.
class EchoRemoverImpl final : public EchoRemover {
public:
explicit EchoRemoverImpl(int sample_rate_hz);
~EchoRemoverImpl() override;
- void ProcessBlock(const rtc::Optional<size_t>& echo_path_delay_samples,
- const EchoPathVariability& echo_path_variability,
- bool capture_signal_saturation,
- const std::vector<std::vector<float>>& render,
- std::vector<std::vector<float>>* capture) override;
+ // Removes the echo from a block of samples from the capture signal. The
+ // supplied render signal is assumed to be pre-aligned with the capture
+ // signal.
+ void ProcessBlock(
+ const rtc::Optional<size_t>& external_echo_path_delay_estimate,
+ const EchoPathVariability& echo_path_variability,
+ bool capture_signal_saturation,
+ const std::vector<std::vector<float>>& render,
+ std::vector<std::vector<float>>* capture) override;
- void UpdateEchoLeakageStatus(bool leakage_detected) override;
+ // Updates the status on whether echo leakage is detected in the output of the
+ // echo remover.
+ void UpdateEchoLeakageStatus(bool leakage_detected) override {
+ echo_leakage_detected_ = leakage_detected;
+ }
private:
+ static int instance_count_;
+ const Aec3Fft fft_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const Aec3Optimization optimization_;
const int sample_rate_hz_;
+ Subtractor subtractor_;
+ SuppressionGain suppression_gain_;
+ ComfortNoiseGenerator cng_;
+ SuppressionFilter suppression_filter_;
+ PowerEchoModel power_echo_model_;
+ FftBuffer X_buffer_;
+ RenderSignalAnalyzer render_signal_analyzer_;
+ OutputSelector output_selector_;
+ ResidualEchoEstimator residual_echo_estimator_;
+ bool echo_leakage_detected_ = false;
+ std::array<float, kBlockSize> x_old_;
+ AecState aec_state_;
RTC_DISALLOW_COPY_AND_ASSIGN(EchoRemoverImpl);
};
-// TODO(peah): Add functionality.
+int EchoRemoverImpl::instance_count_ = 0;
+
EchoRemoverImpl::EchoRemoverImpl(int sample_rate_hz)
- : sample_rate_hz_(sample_rate_hz) {
- RTC_DCHECK(ValidFullBandRate(sample_rate_hz_));
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ optimization_(DetectOptimization()),
+ sample_rate_hz_(sample_rate_hz),
+ subtractor_(data_dumper_.get(), optimization_),
+ suppression_gain_(optimization_),
+ cng_(optimization_),
+ suppression_filter_(sample_rate_hz_),
+ X_buffer_(optimization_,
+ std::max(subtractor_.MinFarendBufferLength(),
+ power_echo_model_.MinFarendBufferLength()),
+ subtractor_.NumBlocksInRenderSums()) {
+ RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
+ x_old_.fill(0.f);
}
EchoRemoverImpl::~EchoRemoverImpl() = default;
-// TODO(peah): Add functionality.
void EchoRemoverImpl::ProcessBlock(
const rtc::Optional<size_t>& echo_path_delay_samples,
const EchoPathVariability& echo_path_variability,
bool capture_signal_saturation,
const std::vector<std::vector<float>>& render,
std::vector<std::vector<float>>* capture) {
- RTC_DCHECK(capture);
- RTC_DCHECK_EQ(render.size(), NumBandsForRate(sample_rate_hz_));
- RTC_DCHECK_EQ(capture->size(), NumBandsForRate(sample_rate_hz_));
- RTC_DCHECK_EQ(render[0].size(), kBlockSize);
- RTC_DCHECK_EQ((*capture)[0].size(), kBlockSize);
-}
+ const std::vector<std::vector<float>>& x = render;
+ std::vector<std::vector<float>>* y = capture;
+
+ RTC_DCHECK(y);
+ RTC_DCHECK_EQ(x.size(), NumBandsForRate(sample_rate_hz_));
+ RTC_DCHECK_EQ(y->size(), NumBandsForRate(sample_rate_hz_));
+ RTC_DCHECK_EQ(x[0].size(), kBlockSize);
+ RTC_DCHECK_EQ((*y)[0].size(), kBlockSize);
+ const std::vector<float>& x0 = x[0];
+ std::vector<float>& y0 = (*y)[0];
+
+ data_dumper_->DumpWav("aec3_processblock_capture_input", kBlockSize, &y0[0],
+ LowestBandRate(sample_rate_hz_), 1);
+ data_dumper_->DumpWav("aec3_processblock_render_input", kBlockSize, &x0[0],
+ LowestBandRate(sample_rate_hz_), 1);
+
+ aec_state_.UpdateCaptureSaturation(capture_signal_saturation);
+
+ if (echo_path_variability.AudioPathChanged()) {
+ subtractor_.HandleEchoPathChange(echo_path_variability);
+ power_echo_model_.HandleEchoPathChange(echo_path_variability);
+ }
+
+ std::array<float, kFftLengthBy2Plus1> Y2;
+ std::array<float, kFftLengthBy2Plus1> S2_power;
+ std::array<float, kFftLengthBy2Plus1> R2;
+ std::array<float, kFftLengthBy2Plus1> S2_linear;
+ std::array<float, kFftLengthBy2Plus1> G;
+ FftData X;
+ FftData Y;
+ FftData comfort_noise;
+ FftData high_band_comfort_noise;
+ SubtractorOutput subtractor_output;
+ FftData& E_main = subtractor_output.E_main;
+ auto& E2_main = subtractor_output.E2_main;
+ auto& E2_shadow = subtractor_output.E2_shadow;
+ auto& e_main = subtractor_output.e_main;
+ auto& e_shadow = subtractor_output.e_shadow;
-// TODO(peah): Add functionality.
-void EchoRemoverImpl::UpdateEchoLeakageStatus(bool leakage_detected) {}
+ // Update the render signal buffer.
+ fft_.PaddedFft(x0, x_old_, &X);
+ X_buffer_.Insert(X);
+
+ // Analyze the render signal.
+ render_signal_analyzer_.Update(X_buffer_, aec_state_.FilterDelay());
+
+ // Perform linear echo cancellation.
+ subtractor_.Process(X_buffer_, y0, render_signal_analyzer_,
+ aec_state_.SaturatedCapture(), &subtractor_output);
+
+ // Compute spectra.
+ fft_.ZeroPaddedFft(y0, &Y);
+ LinearEchoPower(E_main, Y, &S2_linear);
+ Y.Spectrum(optimization_, &Y2);
+
+ // Update the AEC state information.
+ aec_state_.Update(subtractor_.FilterFrequencyResponse(),
+ echo_path_delay_samples, X_buffer_, E2_main, E2_shadow, Y2,
+ x0, echo_path_variability, echo_leakage_detected_);
+
+ // Use the power model to estimate the echo.
+ power_echo_model_.EstimateEcho(X_buffer_, Y2, aec_state_, &S2_power);
+
+ // Choose the linear output.
+ output_selector_.FormLinearOutput(e_main, y0);
+ data_dumper_->DumpWav("aec3_output_linear", kBlockSize, &y0[0],
+ LowestBandRate(sample_rate_hz_), 1);
+ const auto& E2 = output_selector_.UseSubtractorOutput() ? E2_main : Y2;
+
+ // Estimate the residual echo power.
+ residual_echo_estimator_.Estimate(
+ output_selector_.UseSubtractorOutput(), aec_state_, X_buffer_,
+ subtractor_.FilterFrequencyResponse(), E2_main, E2_shadow, S2_linear,
+ S2_power, Y2, &R2);
+
+ // Estimate the comfort noise.
+ cng_.Compute(aec_state_, Y2, &comfort_noise, &high_band_comfort_noise);
+
+ // Detect basic doubletalk.
+ const bool doubletalk = BlockPower(e_shadow) < BlockPower(e_main);
+
+ // A choose and apply echo suppression gain.
+ suppression_gain_.GetGain(E2, R2, cng_.NoiseSpectrum(),
+ doubletalk ? 0.001f : 0.0001f, &G);
+ suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G, y);
+
+ // Debug outputs for the purpose of development and analysis.
+ data_dumper_->DumpRaw("aec3_N2", cng_.NoiseSpectrum());
+ data_dumper_->DumpRaw("aec3_suppressor_gain", G);
+ data_dumper_->DumpWav("aec3_output",
+ rtc::ArrayView<const float>(&y0[0], kBlockSize),
+ LowestBandRate(sample_rate_hz_), 1);
+ data_dumper_->DumpRaw("aec3_using_subtractor_output",
+ output_selector_.UseSubtractorOutput() ? 1 : 0);
+ data_dumper_->DumpRaw("aec3_doubletalk", doubletalk ? 1 : 0);
+ data_dumper_->DumpRaw("aec3_E2", E2);
+ data_dumper_->DumpRaw("aec3_E2_main", E2_main);
+ data_dumper_->DumpRaw("aec3_E2_shadow", E2_shadow);
+ data_dumper_->DumpRaw("aec3_S2_linear", S2_linear);
+ data_dumper_->DumpRaw("aec3_S2_power", S2_power);
+ data_dumper_->DumpRaw("aec3_Y2", Y2);
+ data_dumper_->DumpRaw("aec3_R2", R2);
+ data_dumper_->DumpRaw("aec3_erle", aec_state_.Erle());
+ data_dumper_->DumpRaw("aec3_erl", aec_state_.Erl());
+ data_dumper_->DumpRaw("aec3_reliable_filter_bands",
+ aec_state_.BandsWithReliableFilter());
+ data_dumper_->DumpRaw("aec3_active_render", aec_state_.ActiveRender());
+ data_dumper_->DumpRaw("aec3_model_based_aec_feasible",
+ aec_state_.ModelBasedAecFeasible());
+ data_dumper_->DumpRaw("aec3_usable_linear_estimate",
+ aec_state_.UsableLinearEstimate());
+ data_dumper_->DumpRaw(
+ "aec3_filter_delay",
+ aec_state_.FilterDelay() ? *aec_state_.FilterDelay() : -1);
+ data_dumper_->DumpRaw(
+ "aec3_external_delay",
+ aec_state_.ExternalDelay() ? *aec_state_.ExternalDelay() : -1);
+ data_dumper_->DumpRaw("aec3_capture_saturation",
+ aec_state_.SaturatedCapture() ? 1 : 0);
+}
} // namespace

Powered by Google App Engine
This is Rietveld 408576698