blob: 7518e3a3eaf79e882b3f45fb0c7c3e6aa876a2e2 [file] [log] [blame]
peah522d71b2017-02-23 05:16:26 -08001/*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/aec3/aec_state.h"
peah522d71b2017-02-23 05:16:26 -080012
13#include <math.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Yves Gerey988cc082018-10-23 12:03:01 +020015#include <algorithm>
peah522d71b2017-02-23 05:16:26 -080016#include <numeric>
17#include <vector>
18
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +020019#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "api/array_view.h"
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +020021#include "modules/audio_processing/aec3/aec3_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/audio_processing/logging/apm_data_dumper.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/checks.h"
peah522d71b2017-02-23 05:16:26 -080025
26namespace webrtc {
27namespace {
28
Per Åhgren5c532d32018-03-22 00:29:25 +010029constexpr size_t kBlocksSinceConvergencedFilterInit = 10000;
30constexpr size_t kBlocksSinceConsistentEstimateInit = 10000;
31
Per Åhgren1d3008b2019-10-09 12:54:43 +020032void UpdateAndComputeReverb(
33 const SpectrumBuffer& spectrum_buffer,
34 int delay_blocks,
35 float reverb_decay,
36 ReverbModel* reverb_model,
37 rtc::ArrayView<float, kFftLengthBy2Plus1> reverb_power_spectrum) {
38 RTC_DCHECK(reverb_model);
39 const size_t num_render_channels = spectrum_buffer.buffer[0].size();
40 int idx_at_delay =
41 spectrum_buffer.OffsetIndex(spectrum_buffer.read, delay_blocks);
42 int idx_past = spectrum_buffer.IncIndex(idx_at_delay);
43
44 std::array<float, kFftLengthBy2Plus1> X2_data;
45 rtc::ArrayView<const float> X2;
46 if (num_render_channels > 1) {
47 auto sum_channels =
48 [](size_t num_render_channels,
49 const std::vector<std::vector<float>>& spectrum_band_0,
50 rtc::ArrayView<float, kFftLengthBy2Plus1> render_power) {
51 std::fill(render_power.begin(), render_power.end(), 0.f);
52 for (size_t ch = 0; ch < num_render_channels; ++ch) {
53 RTC_DCHECK_EQ(spectrum_band_0[ch].size(), kFftLengthBy2Plus1);
54 for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
55 render_power[k] += spectrum_band_0[ch][k];
56 }
57 }
58 };
59 sum_channels(num_render_channels, spectrum_buffer.buffer[idx_past],
60 X2_data);
61 reverb_model->UpdateReverbNoFreqShaping(
62 X2_data, /*power_spectrum_scaling=*/1.0f, reverb_decay);
63
64 sum_channels(num_render_channels, spectrum_buffer.buffer[idx_at_delay],
65 X2_data);
66 X2 = X2_data;
67 } else {
68 reverb_model->UpdateReverbNoFreqShaping(
69 spectrum_buffer.buffer[idx_past][/*channel=*/0],
70 /*power_spectrum_scaling=*/1.0f, reverb_decay);
71
72 X2 = spectrum_buffer.buffer[idx_at_delay][/*channel=*/0];
73 }
74
75 rtc::ArrayView<const float, kFftLengthBy2Plus1> reverb_power =
76 reverb_model->reverb();
77 for (size_t k = 0; k < X2.size(); ++k) {
78 reverb_power_spectrum[k] = X2[k] + reverb_power[k];
79 }
80}
81
peah522d71b2017-02-23 05:16:26 -080082} // namespace
83
84int AecState::instance_count_ = 0;
85
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020086void AecState::GetResidualEchoScaling(
87 rtc::ArrayView<float> residual_scaling) const {
88 bool filter_has_had_time_to_converge;
89 if (config_.filter.conservative_initial_phase) {
90 filter_has_had_time_to_converge =
91 strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond;
92 } else {
93 filter_has_had_time_to_converge =
94 strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond;
95 }
96 echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge,
97 residual_scaling);
98}
99
100absl::optional<float> AecState::ErleUncertainty() const {
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100101 if (SaturatedEcho()) {
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200102 return 1.f;
103 }
104
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200105 return absl::nullopt;
106}
107
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200108AecState::AecState(const EchoCanceller3Config& config,
109 size_t num_capture_channels)
peah522d71b2017-02-23 05:16:26 -0800110 : data_dumper_(
111 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
peah8cee56f2017-08-24 22:36:53 -0700112 config_(config),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200113 initial_state_(config_),
Per Åhgren8be669f2019-10-11 23:02:26 +0200114 delay_state_(config_, num_capture_channels),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200115 transparent_state_(config_),
Per Åhgren8be669f2019-10-11 23:02:26 +0200116 filter_quality_state_(config_, num_capture_channels),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200117 erl_estimator_(2 * kNumBlocksPerSecond),
Per Åhgrenb4161d32019-10-08 12:35:47 +0200118 erle_estimator_(2 * kNumBlocksPerSecond, config_, num_capture_channels),
Per Åhgren8be669f2019-10-11 23:02:26 +0200119 filter_analyzer_(config_, num_capture_channels),
Jesús de Vicente Peña836a7a22018-08-31 15:03:04 +0200120 echo_audibility_(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200121 config_.echo_audibility.use_stationarity_properties_at_init),
Per Åhgren8be669f2019-10-11 23:02:26 +0200122 reverb_model_estimator_(config_, num_capture_channels),
123 subtractor_output_analyzers_(num_capture_channels) {}
peah522d71b2017-02-23 05:16:26 -0800124
125AecState::~AecState() = default;
126
peah86afe9d2017-04-06 15:45:32 -0700127void AecState::HandleEchoPathChange(
128 const EchoPathVariability& echo_path_variability) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100129 const auto full_reset = [&]() {
Per Åhgren8be669f2019-10-11 23:02:26 +0200130 filter_analyzer_.Reset();
peah86afe9d2017-04-06 15:45:32 -0700131 capture_signal_saturation_ = false;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200132 strong_not_saturated_render_blocks_ = 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100133 blocks_with_active_render_ = 0;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200134 initial_state_.Reset();
135 transparent_state_.Reset();
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200136 erle_estimator_.Reset(true);
137 erl_estimator_.Reset();
Jesús de Vicente Peña70a59632019-04-16 12:32:15 +0200138 filter_quality_state_.Reset();
Per Åhgren8ba58612017-12-01 23:01:44 +0100139 };
peah6d822ad2017-04-10 13:52:14 -0700140
Per Åhgren8ba58612017-12-01 23:01:44 +0100141 // TODO(peah): Refine the reset scheme according to the type of gain and
142 // delay adjustment.
Per Åhgren8ba58612017-12-01 23:01:44 +0100143
144 if (echo_path_variability.delay_change !=
Per Åhgren88cf0502018-07-16 17:08:41 +0200145 EchoPathVariability::DelayAdjustment::kNone) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100146 full_reset();
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100147 } else if (echo_path_variability.gain_change) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200148 erle_estimator_.Reset(false);
Per Åhgrend2650d12018-10-02 17:00:59 +0200149 }
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200150 for (auto& analyzer : subtractor_output_analyzers_) {
151 analyzer.HandleEchoPathChange();
152 }
peah86afe9d2017-04-06 15:45:32 -0700153}
154
Per Åhgren09a718a2017-12-11 22:28:45 +0100155void AecState::Update(
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +0200156 const absl::optional<DelayEstimate>& external_delay,
Sam Zackrisson46b01402019-10-08 16:17:48 +0200157 rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
Per Åhgren8be669f2019-10-11 23:02:26 +0200158 adaptive_filter_frequency_responses,
159 rtc::ArrayView<const std::vector<float>> adaptive_filter_impulse_responses,
Per Åhgren09a718a2017-12-11 22:28:45 +0100160 const RenderBuffer& render_buffer,
Per Åhgrenf9807252019-10-09 13:57:07 +0200161 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2_main,
162 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200163 rtc::ArrayView<const SubtractorOutput> subtractor_output) {
Per Åhgren8be669f2019-10-11 23:02:26 +0200164 const size_t num_capture_channels = subtractor_output_analyzers_.size();
Per Åhgrenf9807252019-10-09 13:57:07 +0200165 RTC_DCHECK_EQ(num_capture_channels, E2_main.size());
166 RTC_DCHECK_EQ(num_capture_channels, Y2.size());
Sam Zackrisson46b01402019-10-08 16:17:48 +0200167 RTC_DCHECK_EQ(num_capture_channels, subtractor_output.size());
168 RTC_DCHECK_EQ(num_capture_channels, subtractor_output_analyzers_.size());
169 RTC_DCHECK_EQ(num_capture_channels,
Per Åhgren8be669f2019-10-11 23:02:26 +0200170 adaptive_filter_frequency_responses.size());
171 RTC_DCHECK_EQ(num_capture_channels, adaptive_filter_impulse_responses.size());
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200172
Sam Zackrisson46b01402019-10-08 16:17:48 +0200173 // Analyze the filter outputs and filters.
174 bool any_filter_converged = false;
175 bool all_filters_diverged = true;
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200176 for (size_t ch = 0; ch < subtractor_output.size(); ++ch) {
177 subtractor_output_analyzers_[ch].Update(subtractor_output[ch]);
Sam Zackrisson46b01402019-10-08 16:17:48 +0200178 any_filter_converged = any_filter_converged ||
179 subtractor_output_analyzers_[ch].ConvergedFilter();
180 all_filters_diverged = all_filters_diverged &&
181 subtractor_output_analyzers_[ch].DivergedFilter();
Sam Zackrisson46b01402019-10-08 16:17:48 +0200182 }
Per Åhgren8be669f2019-10-11 23:02:26 +0200183 bool any_filter_consistent;
184 float max_echo_path_gain;
185 filter_analyzer_.Update(adaptive_filter_impulse_responses, render_buffer,
186 &any_filter_consistent, &max_echo_path_gain);
peah86afe9d2017-04-06 15:45:32 -0700187
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200188 // Estimate the direct path delay of the filter.
Gustaf Ullberg9466b662019-04-15 09:53:03 +0200189 if (config_.filter.use_linear_filter) {
Per Åhgren8be669f2019-10-11 23:02:26 +0200190 delay_state_.Update(filter_analyzer_.FilterDelaysBlocks(), external_delay,
Gustaf Ullberg9466b662019-04-15 09:53:03 +0200191 strong_not_saturated_render_blocks_);
192 }
Per Åhgren5c532d32018-03-22 00:29:25 +0100193
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200194 const std::vector<std::vector<float>>& aligned_render_block =
Per Åhgren8be669f2019-10-11 23:02:26 +0200195 render_buffer.Block(-delay_state_.DirectPathFilterDelays()[0])[0];
Per Åhgren5c532d32018-03-22 00:29:25 +0100196
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200197 // Update render counters.
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200198 bool active_render = false;
199 for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) {
200 const float render_energy = std::inner_product(
201 aligned_render_block[ch].begin(), aligned_render_block[ch].end(),
202 aligned_render_block[ch].begin(), 0.f);
203 if (render_energy > (config_.render_levels.active_render_limit *
204 config_.render_levels.active_render_limit) *
205 kFftLengthBy2) {
206 active_render = true;
207 break;
208 }
209 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200210 blocks_with_active_render_ += active_render ? 1 : 0;
211 strong_not_saturated_render_blocks_ +=
212 active_render && !SaturatedCapture() ? 1 : 0;
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100213
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200214 std::array<float, kFftLengthBy2Plus1> X2_reverb;
Per Åhgren1d3008b2019-10-09 12:54:43 +0200215
216 UpdateAndComputeReverb(render_buffer.GetSpectrumBuffer(),
Per Åhgren8be669f2019-10-11 23:02:26 +0200217 delay_state_.DirectPathFilterDelays()[0],
218 ReverbDecay(), &reverb_model_, X2_reverb);
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200219
Jesús de Vicente Peña70a59632019-04-16 12:32:15 +0200220 if (config_.echo_audibility.use_stationarity_properties) {
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200221 // Update the echo audibility evaluator.
Per Åhgren1d3008b2019-10-09 12:54:43 +0200222 echo_audibility_.Update(render_buffer, reverb_model_.reverb(),
Per Åhgren8be669f2019-10-11 23:02:26 +0200223 delay_state_.DirectPathFilterDelays()[0],
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200224 delay_state_.ExternalDelayReported());
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200225 }
226
peah86afe9d2017-04-06 15:45:32 -0700227 // Update the ERL and ERLE measures.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200228 if (initial_state_.TransitionTriggered()) {
229 erle_estimator_.Reset(false);
Jesús de Vicente Peña02e9e442018-08-29 13:34:07 +0200230 }
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200231
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200232 // TODO(bugs.webrtc.org/10913): Take all channels into account.
Per Åhgren8be669f2019-10-11 23:02:26 +0200233 const auto& X2 =
234 render_buffer.Spectrum(delay_state_.DirectPathFilterDelays()[0],
235 /*channel=*/0);
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100236 const auto& X2_input_erle = X2_reverb;
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200237
Per Åhgren8be669f2019-10-11 23:02:26 +0200238 erle_estimator_.Update(render_buffer, adaptive_filter_frequency_responses[0],
Per Åhgrenf9807252019-10-09 13:57:07 +0200239 X2_input_erle, Y2[0], E2_main[0],
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200240 subtractor_output_analyzers_[0].ConvergedFilter(),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200241 config_.erle.onset_detection);
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200242
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200243 erl_estimator_.Update(subtractor_output_analyzers_[0].ConvergedFilter(), X2,
Per Åhgrenf9807252019-10-09 13:57:07 +0200244 Y2[0]);
peah86afe9d2017-04-06 15:45:32 -0700245
Per Åhgren63b494d2017-12-06 11:32:38 +0100246 // Detect and flag echo saturation.
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100247 saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
248 UsableLinearEstimate(), subtractor_output,
Sam Zackrisson0169a3e2019-10-09 08:00:29 +0200249 max_echo_path_gain);
peah86afe9d2017-04-06 15:45:32 -0700250
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200251 // Update the decision on whether to use the initial state parameter set.
252 initial_state_.Update(active_render, SaturatedCapture());
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100253
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200254 // Detect whether the transparent mode should be activated.
Per Åhgren8be669f2019-10-11 23:02:26 +0200255 transparent_state_.Update(delay_state_.DirectPathFilterDelays()[0],
Sam Zackrisson46b01402019-10-08 16:17:48 +0200256 any_filter_consistent, any_filter_converged,
257 all_filters_diverged, active_render,
258 SaturatedCapture());
Per Åhgren5c532d32018-03-22 00:29:25 +0100259
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200260 // Analyze the quality of the filter.
Sam Zackrisson46b01402019-10-08 16:17:48 +0200261 filter_quality_state_.Update(active_render, TransparentMode(),
262 SaturatedCapture(), external_delay,
263 any_filter_converged);
Per Åhgrena98c8072018-01-15 19:17:16 +0100264
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200265 // Update the reverb estimate.
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200266 const bool stationary_block =
Jesús de Vicente Peña70a59632019-04-16 12:32:15 +0200267 config_.echo_audibility.use_stationarity_properties &&
Per Åhgrenf4801a12018-09-27 13:14:02 +0200268 echo_audibility_.IsBlockStationary();
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200269
Per Åhgren8be669f2019-10-11 23:02:26 +0200270 reverb_model_estimator_.Update(
271 filter_analyzer_.GetAdjustedFilters(),
272 adaptive_filter_frequency_responses,
273 erle_estimator_.GetInstLinearQualityEstimates(),
274 delay_state_.DirectPathFilterDelays(),
275 filter_quality_state_.UsableLinearFilterOutputs(), stationary_block);
Jesús de Vicente Peña075cb2b2018-06-13 15:13:55 +0200276
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200277 erle_estimator_.Dump(data_dumper_);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200278 reverb_model_estimator_.Dump(data_dumper_.get());
Per Åhgren5c532d32018-03-22 00:29:25 +0100279 data_dumper_->DumpRaw("aec3_erl", Erl());
Per Åhgren5c532d32018-03-22 00:29:25 +0100280 data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
Per Åhgrenb4161d32019-10-08 12:35:47 +0200281 data_dumper_->DumpRaw("aec3_erle", Erle()[0]);
Per Åhgren5c532d32018-03-22 00:29:25 +0100282 data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200283 data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode());
Sam Zackrisson46b01402019-10-08 16:17:48 +0200284 data_dumper_->DumpRaw("aec3_filter_delay",
Per Åhgren8be669f2019-10-11 23:02:26 +0200285 filter_analyzer_.MinFilterDelayBlocks());
Per Åhgren5c532d32018-03-22 00:29:25 +0100286
Sam Zackrisson46b01402019-10-08 16:17:48 +0200287 data_dumper_->DumpRaw("aec3_any_filter_consistent", any_filter_consistent);
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200288 data_dumper_->DumpRaw("aec3_initial_state",
289 initial_state_.InitialStateActive());
Per Åhgren5c532d32018-03-22 00:29:25 +0100290 data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200291 data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho());
Sam Zackrisson46b01402019-10-08 16:17:48 +0200292 data_dumper_->DumpRaw("aec3_any_filter_converged", any_filter_converged);
293 data_dumper_->DumpRaw("aec3_all_filters_diverged", all_filters_diverged);
Per Åhgren5c532d32018-03-22 00:29:25 +0100294
295 data_dumper_->DumpRaw("aec3_external_delay_avaliable",
296 external_delay ? 1 : 0);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200297 data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
298 GetReverbFrequencyResponse());
peah29103572017-07-11 02:54:02 -0700299}
300
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200301AecState::InitialState::InitialState(const EchoCanceller3Config& config)
302 : conservative_initial_phase_(config.filter.conservative_initial_phase),
303 initial_state_seconds_(config.filter.initial_state_seconds) {
304 Reset();
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100305}
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200306void AecState::InitialState::InitialState::Reset() {
307 initial_state_ = true;
308 strong_not_saturated_render_blocks_ = 0;
309}
310void AecState::InitialState::InitialState::Update(bool active_render,
311 bool saturated_capture) {
312 strong_not_saturated_render_blocks_ +=
313 active_render && !saturated_capture ? 1 : 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100314
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200315 // Flag whether the initial state is still active.
316 bool prev_initial_state = initial_state_;
317 if (conservative_initial_phase_) {
318 initial_state_ =
319 strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200320 } else {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200321 initial_state_ = strong_not_saturated_render_blocks_ <
322 initial_state_seconds_ * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200323 }
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100324
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200325 // Flag whether the transition from the initial state has started.
326 transition_triggered_ = !initial_state_ && prev_initial_state;
327}
328
Per Åhgren8be669f2019-10-11 23:02:26 +0200329AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config,
330 size_t num_capture_channels)
331 : delay_headroom_samples_(config.delay.delay_headroom_samples),
332 filter_delays_blocks_(num_capture_channels, 0) {}
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200333
334void AecState::FilterDelay::Update(
Per Åhgren8be669f2019-10-11 23:02:26 +0200335 rtc::ArrayView<const int> analyzer_filter_delay_estimates_blocks,
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200336 const absl::optional<DelayEstimate>& external_delay,
337 size_t blocks_with_proper_filter_adaptation) {
338 // Update the delay based on the external delay.
339 if (external_delay &&
340 (!external_delay_ || external_delay_->delay != external_delay->delay)) {
341 external_delay_ = external_delay;
342 external_delay_reported_ = true;
343 }
344
345 // Override the estimated delay if it is not certain that the filter has had
346 // time to converge.
347 const bool delay_estimator_may_not_have_converged =
348 blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
349 if (delay_estimator_may_not_have_converged && external_delay_) {
Per Åhgren8be669f2019-10-11 23:02:26 +0200350 int delay_guess = delay_headroom_samples_ / kBlockSize;
351 std::fill(filter_delays_blocks_.begin(), filter_delays_blocks_.end(),
352 delay_guess);
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200353 } else {
Per Åhgren8be669f2019-10-11 23:02:26 +0200354 RTC_DCHECK_EQ(filter_delays_blocks_.size(),
355 analyzer_filter_delay_estimates_blocks.size());
356 std::copy(analyzer_filter_delay_estimates_blocks.begin(),
357 analyzer_filter_delay_estimates_blocks.end(),
358 filter_delays_blocks_.begin());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200359 }
360}
361
362AecState::TransparentMode::TransparentMode(const EchoCanceller3Config& config)
363 : bounded_erl_(config.ep_strength.bounded_erl),
364 linear_and_stable_echo_path_(
365 config.echo_removal_control.linear_and_stable_echo_path),
366 active_blocks_since_sane_filter_(kBlocksSinceConsistentEstimateInit),
367 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
368
369void AecState::TransparentMode::Reset() {
370 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
371 diverged_sequence_size_ = 0;
372 strong_not_saturated_render_blocks_ = 0;
373 if (linear_and_stable_echo_path_) {
374 recent_convergence_during_activity_ = false;
375 }
376}
377
378void AecState::TransparentMode::Update(int filter_delay_blocks,
Sam Zackrisson46b01402019-10-08 16:17:48 +0200379 bool any_filter_consistent,
380 bool any_filter_converged,
381 bool all_filters_diverged,
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200382 bool active_render,
383 bool saturated_capture) {
384 ++capture_block_counter_;
385 strong_not_saturated_render_blocks_ +=
386 active_render && !saturated_capture ? 1 : 0;
387
Sam Zackrisson46b01402019-10-08 16:17:48 +0200388 if (any_filter_consistent && filter_delay_blocks < 5) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200389 sane_filter_observed_ = true;
390 active_blocks_since_sane_filter_ = 0;
391 } else if (active_render) {
392 ++active_blocks_since_sane_filter_;
393 }
394
395 bool sane_filter_recently_seen;
396 if (!sane_filter_observed_) {
397 sane_filter_recently_seen =
398 capture_block_counter_ <= 5 * kNumBlocksPerSecond;
399 } else {
400 sane_filter_recently_seen =
401 active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond;
402 }
403
Sam Zackrisson46b01402019-10-08 16:17:48 +0200404 if (any_filter_converged) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200405 recent_convergence_during_activity_ = true;
406 active_non_converged_sequence_size_ = 0;
407 non_converged_sequence_size_ = 0;
408 ++num_converged_blocks_;
409 } else {
410 if (++non_converged_sequence_size_ > 20 * kNumBlocksPerSecond) {
411 num_converged_blocks_ = 0;
412 }
413
414 if (active_render &&
415 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
416 recent_convergence_during_activity_ = false;
417 }
418 }
419
Sam Zackrisson46b01402019-10-08 16:17:48 +0200420 if (!all_filters_diverged) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200421 diverged_sequence_size_ = 0;
422 } else if (++diverged_sequence_size_ >= 60) {
423 // TODO(peah): Change these lines to ensure proper triggering of usable
424 // filter.
425 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
426 }
427
428 if (active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
429 finite_erl_recently_detected_ = false;
430 }
431 if (num_converged_blocks_ > 50) {
432 finite_erl_recently_detected_ = true;
433 }
434
435 if (bounded_erl_) {
436 transparency_activated_ = false;
437 } else if (finite_erl_recently_detected_) {
438 transparency_activated_ = false;
439 } else if (sane_filter_recently_seen && recent_convergence_during_activity_) {
440 transparency_activated_ = false;
441 } else {
442 const bool filter_should_have_converged =
443 strong_not_saturated_render_blocks_ > 6 * kNumBlocksPerSecond;
444 transparency_activated_ = filter_should_have_converged;
445 }
446}
447
448AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer(
Per Åhgren8be669f2019-10-11 23:02:26 +0200449 const EchoCanceller3Config& config,
450 size_t num_capture_channels)
451 : use_linear_filter_(config.filter.use_linear_filter),
452 usable_linear_filter_estimates_(num_capture_channels, false) {}
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200453
454void AecState::FilteringQualityAnalyzer::Reset() {
Per Åhgren8be669f2019-10-11 23:02:26 +0200455 std::fill(usable_linear_filter_estimates_.begin(),
456 usable_linear_filter_estimates_.end(), false);
457 overall_usable_linear_estimates_ = false;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200458 filter_update_blocks_since_reset_ = 0;
459}
460
461void AecState::FilteringQualityAnalyzer::Update(
462 bool active_render,
463 bool transparent_mode,
464 bool saturated_capture,
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200465 const absl::optional<DelayEstimate>& external_delay,
Sam Zackrisson46b01402019-10-08 16:17:48 +0200466 bool any_filter_converged) {
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200467 // Update blocks counter.
468 const bool filter_update = active_render && !saturated_capture;
469 filter_update_blocks_since_reset_ += filter_update ? 1 : 0;
470 filter_update_blocks_since_start_ += filter_update ? 1 : 0;
471
472 // Store convergence flag when observed.
Sam Zackrisson46b01402019-10-08 16:17:48 +0200473 convergence_seen_ = convergence_seen_ || any_filter_converged;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200474
475 // Verify requirements for achieving a decent filter. The requirements for
476 // filter adaptation at call startup are more restrictive than after an
477 // in-call reset.
478 const bool sufficient_data_to_converge_at_startup =
479 filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f;
480 const bool sufficient_data_to_converge_at_reset =
481 sufficient_data_to_converge_at_startup &&
482 filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f;
483
Per Åhgren8be669f2019-10-11 23:02:26 +0200484 // The linear filter can only be used if it has had time to converge.
485 overall_usable_linear_estimates_ = sufficient_data_to_converge_at_startup &&
486 sufficient_data_to_converge_at_reset;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200487
488 // The linear filter can only be used if an external delay or convergence have
489 // been identified
Per Åhgren8be669f2019-10-11 23:02:26 +0200490 overall_usable_linear_estimates_ =
491 overall_usable_linear_estimates_ && (external_delay || convergence_seen_);
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200492
493 // If transparent mode is on, deactivate usign the linear filter.
Per Åhgren8be669f2019-10-11 23:02:26 +0200494 overall_usable_linear_estimates_ =
495 overall_usable_linear_estimates_ && !transparent_mode;
496
497 if (use_linear_filter_) {
498 std::fill(usable_linear_filter_estimates_.begin(),
499 usable_linear_filter_estimates_.end(),
500 overall_usable_linear_estimates_);
501 }
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200502}
503
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200504void AecState::SaturationDetector::Update(
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200505 rtc::ArrayView<const std::vector<float>> x,
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200506 bool saturated_capture,
507 bool usable_linear_estimate,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200508 rtc::ArrayView<const SubtractorOutput> subtractor_output,
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200509 float echo_path_gain) {
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200510 saturated_echo_ = false;
511 if (!saturated_capture) {
512 return;
513 }
514
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200515 if (usable_linear_estimate) {
516 constexpr float kSaturationThreshold = 20000.f;
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200517 for (size_t ch = 0; ch < subtractor_output.size(); ++ch) {
518 saturated_echo_ =
519 saturated_echo_ ||
520 (subtractor_output[ch].s_main_max_abs > kSaturationThreshold ||
521 subtractor_output[ch].s_shadow_max_abs > kSaturationThreshold);
522 }
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200523 } else {
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200524 float max_sample = 0.f;
525 for (auto& channel : x) {
526 for (float sample : channel) {
527 max_sample = std::max(max_sample, fabsf(sample));
528 }
529 }
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200530
531 const float kMargin = 10.f;
532 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200533 saturated_echo_ = saturated_echo_ || peak_echo_amplitude > 32000;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200534 }
535}
536
peah522d71b2017-02-23 05:16:26 -0800537} // namespace webrtc