blob: 4b30d3017f78a9c5dd388220cca6672f3bcc36f4 [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
peah522d71b2017-02-23 05:16:26 -080032} // namespace
33
34int AecState::instance_count_ = 0;
35
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020036void AecState::GetResidualEchoScaling(
37 rtc::ArrayView<float> residual_scaling) const {
38 bool filter_has_had_time_to_converge;
39 if (config_.filter.conservative_initial_phase) {
40 filter_has_had_time_to_converge =
41 strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond;
42 } else {
43 filter_has_had_time_to_converge =
44 strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond;
45 }
46 echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge,
47 residual_scaling);
48}
49
50absl::optional<float> AecState::ErleUncertainty() const {
Gustaf Ullberg68d6d442019-01-29 10:08:15 +010051 if (SaturatedEcho()) {
Per Åhgren3e7b7b12018-10-16 14:38:10 +020052 return 1.f;
53 }
54
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020055 return absl::nullopt;
56}
57
Sam Zackrisson8f736c02019-10-01 12:47:53 +020058AecState::AecState(const EchoCanceller3Config& config,
59 size_t num_capture_channels)
peah522d71b2017-02-23 05:16:26 -080060 : data_dumper_(
61 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
peah8cee56f2017-08-24 22:36:53 -070062 config_(config),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020063 initial_state_(config_),
64 delay_state_(config_),
65 transparent_state_(config_),
66 filter_quality_state_(config_),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020067 erl_estimator_(2 * kNumBlocksPerSecond),
Per Åhgrenb4161d32019-10-08 12:35:47 +020068 erle_estimator_(2 * kNumBlocksPerSecond, config_, num_capture_channels),
Per Åhgren5c532d32018-03-22 00:29:25 +010069 filter_analyzer_(config_),
Jesús de Vicente Peña836a7a22018-08-31 15:03:04 +020070 echo_audibility_(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020071 config_.echo_audibility.use_stationarity_properties_at_init),
Sam Zackrisson8f736c02019-10-01 12:47:53 +020072 reverb_model_estimator_(config_),
73 subtractor_output_analyzers_(num_capture_channels) {}
peah522d71b2017-02-23 05:16:26 -080074
75AecState::~AecState() = default;
76
peah86afe9d2017-04-06 15:45:32 -070077void AecState::HandleEchoPathChange(
78 const EchoPathVariability& echo_path_variability) {
Per Åhgren8ba58612017-12-01 23:01:44 +010079 const auto full_reset = [&]() {
Per Åhgren5c532d32018-03-22 00:29:25 +010080 filter_analyzer_.Reset();
peah86afe9d2017-04-06 15:45:32 -070081 capture_signal_saturation_ = false;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020082 strong_not_saturated_render_blocks_ = 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +010083 blocks_with_active_render_ = 0;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020084 initial_state_.Reset();
85 transparent_state_.Reset();
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020086 erle_estimator_.Reset(true);
87 erl_estimator_.Reset();
Jesús de Vicente Peña70a59632019-04-16 12:32:15 +020088 filter_quality_state_.Reset();
Per Åhgren8ba58612017-12-01 23:01:44 +010089 };
peah6d822ad2017-04-10 13:52:14 -070090
Per Åhgren8ba58612017-12-01 23:01:44 +010091 // TODO(peah): Refine the reset scheme according to the type of gain and
92 // delay adjustment.
Per Åhgren8ba58612017-12-01 23:01:44 +010093
94 if (echo_path_variability.delay_change !=
Per Åhgren88cf0502018-07-16 17:08:41 +020095 EchoPathVariability::DelayAdjustment::kNone) {
Per Åhgren8ba58612017-12-01 23:01:44 +010096 full_reset();
Gustaf Ullberg68d6d442019-01-29 10:08:15 +010097 } else if (echo_path_variability.gain_change) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020098 erle_estimator_.Reset(false);
Per Åhgrend2650d12018-10-02 17:00:59 +020099 }
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200100 for (auto& analyzer : subtractor_output_analyzers_) {
101 analyzer.HandleEchoPathChange();
102 }
peah86afe9d2017-04-06 15:45:32 -0700103}
104
Per Åhgren09a718a2017-12-11 22:28:45 +0100105void AecState::Update(
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +0200106 const absl::optional<DelayEstimate>& external_delay,
Per Åhgren09a718a2017-12-11 22:28:45 +0100107 const std::vector<std::array<float, kFftLengthBy2Plus1>>&
108 adaptive_filter_frequency_response,
109 const std::vector<float>& adaptive_filter_impulse_response,
Per Åhgren09a718a2017-12-11 22:28:45 +0100110 const RenderBuffer& render_buffer,
111 const std::array<float, kFftLengthBy2Plus1>& E2_main,
112 const std::array<float, kFftLengthBy2Plus1>& Y2,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200113 rtc::ArrayView<const SubtractorOutput> subtractor_output) {
114 RTC_DCHECK_EQ(subtractor_output.size(), subtractor_output_analyzers_.size());
115
Per Åhgrenb20b9372018-07-13 00:22:54 +0200116 // Analyze the filter output.
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200117 for (size_t ch = 0; ch < subtractor_output.size(); ++ch) {
118 subtractor_output_analyzers_[ch].Update(subtractor_output[ch]);
119 }
Per Åhgrenb20b9372018-07-13 00:22:54 +0200120
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200121 // Analyze the properties of the filter.
Jesús de Vicente Peñacf69d222018-11-27 09:24:29 +0100122 filter_analyzer_.Update(adaptive_filter_impulse_response, render_buffer);
peah86afe9d2017-04-06 15:45:32 -0700123
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200124 // Estimate the direct path delay of the filter.
Gustaf Ullberg9466b662019-04-15 09:53:03 +0200125 if (config_.filter.use_linear_filter) {
126 delay_state_.Update(filter_analyzer_, external_delay,
127 strong_not_saturated_render_blocks_);
128 }
Per Åhgren5c532d32018-03-22 00:29:25 +0100129
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200130 const std::vector<std::vector<float>>& aligned_render_block =
131 render_buffer.Block(-delay_state_.DirectPathFilterDelay())[0];
Per Åhgren5c532d32018-03-22 00:29:25 +0100132
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200133 // Update render counters.
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200134 bool active_render = false;
135 for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) {
136 const float render_energy = std::inner_product(
137 aligned_render_block[ch].begin(), aligned_render_block[ch].end(),
138 aligned_render_block[ch].begin(), 0.f);
139 if (render_energy > (config_.render_levels.active_render_limit *
140 config_.render_levels.active_render_limit) *
141 kFftLengthBy2) {
142 active_render = true;
143 break;
144 }
145 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200146 blocks_with_active_render_ += active_render ? 1 : 0;
147 strong_not_saturated_render_blocks_ +=
148 active_render && !SaturatedCapture() ? 1 : 0;
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100149
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200150 std::array<float, kFftLengthBy2Plus1> X2_reverb;
Per Åhgreneac47f72019-08-08 09:08:52 +0200151 render_reverb_.Apply(render_buffer.GetSpectrumBuffer(),
152 delay_state_.DirectPathFilterDelay(), ReverbDecay(),
153 X2_reverb);
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200154
Jesús de Vicente Peña70a59632019-04-16 12:32:15 +0200155 if (config_.echo_audibility.use_stationarity_properties) {
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200156 // Update the echo audibility evaluator.
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200157 echo_audibility_.Update(render_buffer,
158 render_reverb_.GetReverbContributionPowerSpectrum(),
159 delay_state_.DirectPathFilterDelay(),
160 delay_state_.ExternalDelayReported());
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200161 }
162
peah86afe9d2017-04-06 15:45:32 -0700163 // Update the ERL and ERLE measures.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200164 if (initial_state_.TransitionTriggered()) {
165 erle_estimator_.Reset(false);
Jesús de Vicente Peña02e9e442018-08-29 13:34:07 +0200166 }
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200167
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200168 // TODO(bugs.webrtc.org/10913): Take all channels into account.
Sam Zackrissona81c09d2019-09-05 09:35:10 +0200169 const auto& X2 = render_buffer.Spectrum(delay_state_.DirectPathFilterDelay(),
170 /*channel=*/0);
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100171 const auto& X2_input_erle = X2_reverb;
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200172
Jesús de Vicente Peña44974e12018-11-20 12:54:23 +0100173 erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response,
174 X2_input_erle, Y2, E2_main,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200175 subtractor_output_analyzers_[0].ConvergedFilter(),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200176 config_.erle.onset_detection);
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200177
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200178 erl_estimator_.Update(subtractor_output_analyzers_[0].ConvergedFilter(), X2,
179 Y2);
peah86afe9d2017-04-06 15:45:32 -0700180
Per Åhgren63b494d2017-12-06 11:32:38 +0100181 // Detect and flag echo saturation.
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100182 saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
183 UsableLinearEstimate(), subtractor_output,
184 EchoPathGain());
peah86afe9d2017-04-06 15:45:32 -0700185
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200186 // Update the decision on whether to use the initial state parameter set.
187 initial_state_.Update(active_render, SaturatedCapture());
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100188
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200189 // Detect whether the transparent mode should be activated.
190 transparent_state_.Update(delay_state_.DirectPathFilterDelay(),
191 filter_analyzer_.Consistent(),
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200192 subtractor_output_analyzers_[0].ConvergedFilter(),
193 subtractor_output_analyzers_[0].DivergedFilter(),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200194 active_render, SaturatedCapture());
Per Åhgren5c532d32018-03-22 00:29:25 +0100195
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200196 // Analyze the quality of the filter.
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200197 filter_quality_state_.Update(
198 active_render, TransparentMode(), SaturatedCapture(),
199 filter_analyzer_.Consistent(), external_delay,
200 subtractor_output_analyzers_[0].ConvergedFilter());
Per Åhgrena98c8072018-01-15 19:17:16 +0100201
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200202 // Update the reverb estimate.
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200203 const bool stationary_block =
Jesús de Vicente Peña70a59632019-04-16 12:32:15 +0200204 config_.echo_audibility.use_stationarity_properties &&
Per Åhgrenf4801a12018-09-27 13:14:02 +0200205 echo_audibility_.IsBlockStationary();
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200206
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200207 reverb_model_estimator_.Update(filter_analyzer_.GetAdjustedFilter(),
208 adaptive_filter_frequency_response,
209 erle_estimator_.GetInstLinearQualityEstimate(),
210 delay_state_.DirectPathFilterDelay(),
211 UsableLinearEstimate(), stationary_block);
Jesús de Vicente Peña075cb2b2018-06-13 15:13:55 +0200212
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200213 erle_estimator_.Dump(data_dumper_);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200214 reverb_model_estimator_.Dump(data_dumper_.get());
Per Åhgren5c532d32018-03-22 00:29:25 +0100215 data_dumper_->DumpRaw("aec3_erl", Erl());
Per Åhgren5c532d32018-03-22 00:29:25 +0100216 data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
Per Åhgrenb4161d32019-10-08 12:35:47 +0200217 data_dumper_->DumpRaw("aec3_erle", Erle()[0]);
Per Åhgren5c532d32018-03-22 00:29:25 +0100218 data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200219 data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode());
Per Åhgren5c532d32018-03-22 00:29:25 +0100220 data_dumper_->DumpRaw("aec3_filter_delay", filter_analyzer_.DelayBlocks());
221
222 data_dumper_->DumpRaw("aec3_consistent_filter",
223 filter_analyzer_.Consistent());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200224 data_dumper_->DumpRaw("aec3_initial_state",
225 initial_state_.InitialStateActive());
Per Åhgren5c532d32018-03-22 00:29:25 +0100226 data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200227 data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200228 data_dumper_->DumpRaw("aec3_converged_filter",
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200229 subtractor_output_analyzers_[0].ConvergedFilter());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200230 data_dumper_->DumpRaw("aec3_diverged_filter",
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200231 subtractor_output_analyzers_[0].DivergedFilter());
Per Åhgren5c532d32018-03-22 00:29:25 +0100232
233 data_dumper_->DumpRaw("aec3_external_delay_avaliable",
234 external_delay ? 1 : 0);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200235 data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
236 GetReverbFrequencyResponse());
peah29103572017-07-11 02:54:02 -0700237}
238
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200239AecState::InitialState::InitialState(const EchoCanceller3Config& config)
240 : conservative_initial_phase_(config.filter.conservative_initial_phase),
241 initial_state_seconds_(config.filter.initial_state_seconds) {
242 Reset();
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100243}
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200244void AecState::InitialState::InitialState::Reset() {
245 initial_state_ = true;
246 strong_not_saturated_render_blocks_ = 0;
247}
248void AecState::InitialState::InitialState::Update(bool active_render,
249 bool saturated_capture) {
250 strong_not_saturated_render_blocks_ +=
251 active_render && !saturated_capture ? 1 : 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100252
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200253 // Flag whether the initial state is still active.
254 bool prev_initial_state = initial_state_;
255 if (conservative_initial_phase_) {
256 initial_state_ =
257 strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200258 } else {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200259 initial_state_ = strong_not_saturated_render_blocks_ <
260 initial_state_seconds_ * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200261 }
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100262
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200263 // Flag whether the transition from the initial state has started.
264 transition_triggered_ = !initial_state_ && prev_initial_state;
265}
266
267AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config)
Gustaf Ullberg9249fbf2019-03-14 11:24:54 +0100268 : delay_headroom_samples_(config.delay.delay_headroom_samples) {}
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200269
270void AecState::FilterDelay::Update(
271 const FilterAnalyzer& filter_analyzer,
272 const absl::optional<DelayEstimate>& external_delay,
273 size_t blocks_with_proper_filter_adaptation) {
274 // Update the delay based on the external delay.
275 if (external_delay &&
276 (!external_delay_ || external_delay_->delay != external_delay->delay)) {
277 external_delay_ = external_delay;
278 external_delay_reported_ = true;
279 }
280
281 // Override the estimated delay if it is not certain that the filter has had
282 // time to converge.
283 const bool delay_estimator_may_not_have_converged =
284 blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
285 if (delay_estimator_may_not_have_converged && external_delay_) {
Gustaf Ullberg9249fbf2019-03-14 11:24:54 +0100286 filter_delay_blocks_ = delay_headroom_samples_ / kBlockSize;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200287 } else {
288 filter_delay_blocks_ = filter_analyzer.DelayBlocks();
289 }
290}
291
292AecState::TransparentMode::TransparentMode(const EchoCanceller3Config& config)
293 : bounded_erl_(config.ep_strength.bounded_erl),
294 linear_and_stable_echo_path_(
295 config.echo_removal_control.linear_and_stable_echo_path),
296 active_blocks_since_sane_filter_(kBlocksSinceConsistentEstimateInit),
297 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
298
299void AecState::TransparentMode::Reset() {
300 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
301 diverged_sequence_size_ = 0;
302 strong_not_saturated_render_blocks_ = 0;
303 if (linear_and_stable_echo_path_) {
304 recent_convergence_during_activity_ = false;
305 }
306}
307
308void AecState::TransparentMode::Update(int filter_delay_blocks,
309 bool consistent_filter,
310 bool converged_filter,
311 bool diverged_filter,
312 bool active_render,
313 bool saturated_capture) {
314 ++capture_block_counter_;
315 strong_not_saturated_render_blocks_ +=
316 active_render && !saturated_capture ? 1 : 0;
317
318 if (consistent_filter && filter_delay_blocks < 5) {
319 sane_filter_observed_ = true;
320 active_blocks_since_sane_filter_ = 0;
321 } else if (active_render) {
322 ++active_blocks_since_sane_filter_;
323 }
324
325 bool sane_filter_recently_seen;
326 if (!sane_filter_observed_) {
327 sane_filter_recently_seen =
328 capture_block_counter_ <= 5 * kNumBlocksPerSecond;
329 } else {
330 sane_filter_recently_seen =
331 active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond;
332 }
333
334 if (converged_filter) {
335 recent_convergence_during_activity_ = true;
336 active_non_converged_sequence_size_ = 0;
337 non_converged_sequence_size_ = 0;
338 ++num_converged_blocks_;
339 } else {
340 if (++non_converged_sequence_size_ > 20 * kNumBlocksPerSecond) {
341 num_converged_blocks_ = 0;
342 }
343
344 if (active_render &&
345 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
346 recent_convergence_during_activity_ = false;
347 }
348 }
349
350 if (!diverged_filter) {
351 diverged_sequence_size_ = 0;
352 } else if (++diverged_sequence_size_ >= 60) {
353 // TODO(peah): Change these lines to ensure proper triggering of usable
354 // filter.
355 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
356 }
357
358 if (active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
359 finite_erl_recently_detected_ = false;
360 }
361 if (num_converged_blocks_ > 50) {
362 finite_erl_recently_detected_ = true;
363 }
364
365 if (bounded_erl_) {
366 transparency_activated_ = false;
367 } else if (finite_erl_recently_detected_) {
368 transparency_activated_ = false;
369 } else if (sane_filter_recently_seen && recent_convergence_during_activity_) {
370 transparency_activated_ = false;
371 } else {
372 const bool filter_should_have_converged =
373 strong_not_saturated_render_blocks_ > 6 * kNumBlocksPerSecond;
374 transparency_activated_ = filter_should_have_converged;
375 }
376}
377
378AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer(
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200379 const EchoCanceller3Config& config) {}
380
381void AecState::FilteringQualityAnalyzer::Reset() {
382 usable_linear_estimate_ = false;
383 filter_update_blocks_since_reset_ = 0;
384}
385
386void AecState::FilteringQualityAnalyzer::Update(
387 bool active_render,
388 bool transparent_mode,
389 bool saturated_capture,
390 bool consistent_estimate_,
391 const absl::optional<DelayEstimate>& external_delay,
392 bool converged_filter) {
393 // Update blocks counter.
394 const bool filter_update = active_render && !saturated_capture;
395 filter_update_blocks_since_reset_ += filter_update ? 1 : 0;
396 filter_update_blocks_since_start_ += filter_update ? 1 : 0;
397
398 // Store convergence flag when observed.
399 convergence_seen_ = convergence_seen_ || converged_filter;
400
401 // Verify requirements for achieving a decent filter. The requirements for
402 // filter adaptation at call startup are more restrictive than after an
403 // in-call reset.
404 const bool sufficient_data_to_converge_at_startup =
405 filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f;
406 const bool sufficient_data_to_converge_at_reset =
407 sufficient_data_to_converge_at_startup &&
408 filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f;
409
410 // The linear filter can only be used it has had time to converge.
411 usable_linear_estimate_ = sufficient_data_to_converge_at_startup &&
412 sufficient_data_to_converge_at_reset;
413
414 // The linear filter can only be used if an external delay or convergence have
415 // been identified
416 usable_linear_estimate_ =
417 usable_linear_estimate_ && (external_delay || convergence_seen_);
418
419 // If transparent mode is on, deactivate usign the linear filter.
420 usable_linear_estimate_ = usable_linear_estimate_ && !transparent_mode;
421}
422
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200423void AecState::SaturationDetector::Update(
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200424 rtc::ArrayView<const std::vector<float>> x,
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200425 bool saturated_capture,
426 bool usable_linear_estimate,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200427 rtc::ArrayView<const SubtractorOutput> subtractor_output,
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200428 float echo_path_gain) {
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200429 saturated_echo_ = false;
430 if (!saturated_capture) {
431 return;
432 }
433
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200434 if (usable_linear_estimate) {
435 constexpr float kSaturationThreshold = 20000.f;
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200436 for (size_t ch = 0; ch < subtractor_output.size(); ++ch) {
437 saturated_echo_ =
438 saturated_echo_ ||
439 (subtractor_output[ch].s_main_max_abs > kSaturationThreshold ||
440 subtractor_output[ch].s_shadow_max_abs > kSaturationThreshold);
441 }
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200442 } else {
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200443 float max_sample = 0.f;
444 for (auto& channel : x) {
445 for (float sample : channel) {
446 max_sample = std::max(max_sample, fabsf(sample));
447 }
448 }
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200449
450 const float kMargin = 10.f;
451 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200452 saturated_echo_ = saturated_echo_ || peak_echo_amplitude > 32000;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200453 }
454}
455
peah522d71b2017-02-23 05:16:26 -0800456} // namespace webrtc