| Index: webrtc/modules/audio_processing/aec3/aec_state.cc
|
| diff --git a/webrtc/modules/audio_processing/aec3/aec_state.cc b/webrtc/modules/audio_processing/aec3/aec_state.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c18fd6d8709e9c8075ebade9ad8d67f26350210c
|
| --- /dev/null
|
| +++ b/webrtc/modules/audio_processing/aec3/aec_state.cc
|
| @@ -0,0 +1,162 @@
|
| +/*
|
| + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license
|
| + * that can be found in the LICENSE file in the root of the source
|
| + * tree. An additional intellectual property rights grant can be found
|
| + * in the file PATENTS. All contributing project authors may
|
| + * be found in the AUTHORS file in the root of the source tree.
|
| + */
|
| +
|
| +#include "webrtc/modules/audio_processing/aec3/aec_state.h"
|
| +
|
| +#include <math.h>
|
| +#include <numeric>
|
| +#include <vector>
|
| +
|
| +#include "webrtc/base/atomicops.h"
|
| +#include "webrtc/base/checks.h"
|
| +#include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
|
| +
|
| +namespace webrtc {
|
| +namespace {
|
| +
|
| +constexpr float kMaxFilterEstimateStrength = 1000.f;
|
| +
|
| +// Compute the delay of the adaptive filter as the partition with a distinct
|
| +// peak.
|
| +void AnalyzeFilter(
|
| + const std::vector<std::array<float, kFftLengthBy2Plus1>>&
|
| + filter_frequency_response,
|
| + std::array<bool, kFftLengthBy2Plus1>* bands_with_reliable_filter,
|
| + std::array<float, kFftLengthBy2Plus1>* filter_estimate_strength,
|
| + rtc::Optional<size_t>* filter_delay) {
|
| + const auto& H2 = filter_frequency_response;
|
| +
|
| + size_t reliable_delays_sum = 0;
|
| + size_t num_reliable_delays = 0;
|
| +
|
| + constexpr size_t kUpperBin = kFftLengthBy2 - 5;
|
| + for (size_t k = 1; k < kUpperBin; ++k) {
|
| + int peak = 0;
|
| + for (size_t j = 0; j < H2.size(); ++j) {
|
| + if (H2[j][k] > H2[peak][k]) {
|
| + peak = j;
|
| + }
|
| + }
|
| +
|
| + if (H2[peak][k] == 0.f) {
|
| + (*filter_estimate_strength)[k] = 0.f;
|
| + } else if (H2[H2.size() - 1][k] == 0.f) {
|
| + (*filter_estimate_strength)[k] = kMaxFilterEstimateStrength;
|
| + } else {
|
| + (*filter_estimate_strength)[k] = std::min(
|
| + kMaxFilterEstimateStrength, H2[peak][k] / H2[H2.size() - 1][k]);
|
| + }
|
| +
|
| + constexpr float kMargin = 10.f;
|
| + if (kMargin * H2[H2.size() - 1][k] < H2[peak][k]) {
|
| + (*bands_with_reliable_filter)[k] = true;
|
| + reliable_delays_sum += peak;
|
| + ++num_reliable_delays;
|
| + } else {
|
| + (*bands_with_reliable_filter)[k] = false;
|
| + }
|
| + }
|
| + (*bands_with_reliable_filter)[0] = (*bands_with_reliable_filter)[1];
|
| + std::fill(bands_with_reliable_filter->begin() + kUpperBin,
|
| + bands_with_reliable_filter->end(),
|
| + (*bands_with_reliable_filter)[kUpperBin - 1]);
|
| + (*filter_estimate_strength)[0] = (*filter_estimate_strength)[1];
|
| + std::fill(filter_estimate_strength->begin() + kUpperBin,
|
| + filter_estimate_strength->end(),
|
| + (*filter_estimate_strength)[kUpperBin - 1]);
|
| +
|
| + *filter_delay =
|
| + num_reliable_delays > 20
|
| + ? rtc::Optional<size_t>(reliable_delays_sum / num_reliable_delays)
|
| + : rtc::Optional<size_t>();
|
| +}
|
| +
|
| +constexpr int kActiveRenderCounterInitial = 50;
|
| +constexpr int kActiveRenderCounterMax = 200;
|
| +constexpr int kEchoPathChangeCounterInitial = 50;
|
| +constexpr int kEchoPathChangeCounterMax = 200;
|
| +
|
| +} // namespace
|
| +
|
| +int AecState::instance_count_ = 0;
|
| +
|
| +AecState::AecState()
|
| + : data_dumper_(
|
| + new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
| + echo_path_change_counter_(kEchoPathChangeCounterInitial),
|
| + active_render_counter_(kActiveRenderCounterInitial) {
|
| + bands_with_reliable_filter_.fill(false);
|
| + filter_estimate_strength_.fill(0.f);
|
| +}
|
| +
|
| +AecState::~AecState() = default;
|
| +
|
| +void AecState::Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
|
| + filter_frequency_response,
|
| + const rtc::Optional<size_t>& external_delay_samples,
|
| + const FftBuffer& X_buffer,
|
| + const std::array<float, kFftLengthBy2Plus1>& E2_main,
|
| + const std::array<float, kFftLengthBy2Plus1>& E2_shadow,
|
| + const std::array<float, kFftLengthBy2Plus1>& Y2,
|
| + rtc::ArrayView<const float> x,
|
| + const EchoPathVariability& echo_path_variability,
|
| + bool echo_leakage_detected) {
|
| + filter_length_ = filter_frequency_response.size();
|
| + AnalyzeFilter(filter_frequency_response, &bands_with_reliable_filter_,
|
| + &filter_estimate_strength_, &filter_delay_);
|
| + // Compute the externally provided delay in partitions. The truncation is
|
| + // intended here.
|
| + external_delay_ =
|
| + external_delay_samples
|
| + ? rtc::Optional<size_t>(*external_delay_samples / kBlockSize)
|
| + : rtc::Optional<size_t>();
|
| +
|
| + const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f);
|
| +
|
| + echo_path_change_counter_ = echo_path_variability.AudioPathChanged()
|
| + ? kEchoPathChangeCounterMax
|
| + : echo_path_change_counter_ - 1;
|
| + active_render_counter_ = x_energy > 10000.f * kFftLengthBy2
|
| + ? kActiveRenderCounterMax
|
| + : active_render_counter_ - 1;
|
| +
|
| + usable_linear_estimate_ = filter_delay_ && echo_path_change_counter_ <= 0;
|
| +
|
| + echo_leakage_detected_ = echo_leakage_detected;
|
| +
|
| + model_based_aec_feasible_ = usable_linear_estimate_ || external_delay_;
|
| +
|
| + if (usable_linear_estimate_) {
|
| + const auto& X2 = X_buffer.Spectrum(*filter_delay_);
|
| +
|
| + // TODO(peah): Expose these as stats.
|
| + erle_estimator_.Update(X2, Y2, E2_main);
|
| + erl_estimator_.Update(X2, Y2);
|
| +
|
| +// TODO(peah): Add working functionality for headset detection. Until the
|
| +// functionality for that is working the headset detector is hardcoded to detect
|
| +// no headset.
|
| +#if 0
|
| + const auto& erl = erl_estimator_.Erl();
|
| + const int low_erl_band_count = std::count_if(
|
| + erl.begin(), erl.end(), [](float a) { return a <= 0.1f; });
|
| +
|
| + const int noisy_band_count = std::count_if(
|
| + filter_estimate_strength_.begin(), filter_estimate_strength_.end(),
|
| + [](float a) { return a <= 10.f; });
|
| + headset_detected_ = low_erl_band_count > 20 && noisy_band_count > 20;
|
| +#endif
|
| + headset_detected_ = false;
|
| + } else {
|
| + headset_detected_ = false;
|
| + }
|
| +}
|
| +
|
| +} // namespace webrtc
|
|
|