blob: bd5985a69b1ccc690567b5a7a0f3ac2cf0e02587 [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>
Yves Gerey988cc082018-10-23 12:03:01 +020014#include <algorithm>
peah522d71b2017-02-23 05:16:26 -080015#include <numeric>
16#include <vector>
17
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +020018#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/array_view.h"
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +020020#include "modules/audio_processing/aec3/aec3_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "modules/audio_processing/logging/apm_data_dumper.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/checks.h"
peah522d71b2017-02-23 05:16:26 -080024
25namespace webrtc {
26namespace {
27
Per Åhgren5c532d32018-03-22 00:29:25 +010028constexpr size_t kBlocksSinceConvergencedFilterInit = 10000;
29constexpr size_t kBlocksSinceConsistentEstimateInit = 10000;
30
peah522d71b2017-02-23 05:16:26 -080031} // namespace
32
33int AecState::instance_count_ = 0;
34
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020035void AecState::GetResidualEchoScaling(
36 rtc::ArrayView<float> residual_scaling) const {
37 bool filter_has_had_time_to_converge;
38 if (config_.filter.conservative_initial_phase) {
39 filter_has_had_time_to_converge =
40 strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond;
41 } else {
42 filter_has_had_time_to_converge =
43 strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond;
44 }
45 echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge,
46 residual_scaling);
47}
48
49absl::optional<float> AecState::ErleUncertainty() const {
Gustaf Ullberg68d6d442019-01-29 10:08:15 +010050 if (SaturatedEcho()) {
Per Åhgren3e7b7b12018-10-16 14:38:10 +020051 return 1.f;
52 }
53
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020054 return absl::nullopt;
55}
56
Gustaf Ullbergbd83b912017-10-18 12:32:42 +020057AecState::AecState(const EchoCanceller3Config& config)
peah522d71b2017-02-23 05:16:26 -080058 : data_dumper_(
59 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
peah8cee56f2017-08-24 22:36:53 -070060 config_(config),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020061 initial_state_(config_),
62 delay_state_(config_),
63 transparent_state_(config_),
64 filter_quality_state_(config_),
Per Åhgren3e7b7b12018-10-16 14:38:10 +020065 legacy_filter_quality_state_(config_),
66 legacy_saturation_detector_(config_),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020067 erl_estimator_(2 * kNumBlocksPerSecond),
Jesús de Vicente Peña44974e12018-11-20 12:54:23 +010068 erle_estimator_(2 * kNumBlocksPerSecond, config_),
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),
Per Åhgren3e7b7b12018-10-16 14:38:10 +020072 reverb_model_estimator_(config_) {}
peah522d71b2017-02-23 05:16:26 -080073
74AecState::~AecState() = default;
75
peah86afe9d2017-04-06 15:45:32 -070076void AecState::HandleEchoPathChange(
77 const EchoPathVariability& echo_path_variability) {
Per Åhgren8ba58612017-12-01 23:01:44 +010078 const auto full_reset = [&]() {
Per Åhgren5c532d32018-03-22 00:29:25 +010079 filter_analyzer_.Reset();
peah86afe9d2017-04-06 15:45:32 -070080 capture_signal_saturation_ = false;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020081 strong_not_saturated_render_blocks_ = 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +010082 blocks_with_active_render_ = 0;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020083 initial_state_.Reset();
84 transparent_state_.Reset();
Per Åhgren3e7b7b12018-10-16 14:38:10 +020085 legacy_saturation_detector_.Reset();
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020086 erle_estimator_.Reset(true);
87 erl_estimator_.Reset();
Per Åhgren3e7b7b12018-10-16 14:38:10 +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 }
Per Åhgrenb20b9372018-07-13 00:22:54 +0200100 subtractor_output_analyzer_.HandleEchoPathChange();
peah86afe9d2017-04-06 15:45:32 -0700101}
102
Per Åhgren09a718a2017-12-11 22:28:45 +0100103void AecState::Update(
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +0200104 const absl::optional<DelayEstimate>& external_delay,
Per Åhgren09a718a2017-12-11 22:28:45 +0100105 const std::vector<std::array<float, kFftLengthBy2Plus1>>&
106 adaptive_filter_frequency_response,
107 const std::vector<float>& adaptive_filter_impulse_response,
Per Åhgren09a718a2017-12-11 22:28:45 +0100108 const RenderBuffer& render_buffer,
109 const std::array<float, kFftLengthBy2Plus1>& E2_main,
110 const std::array<float, kFftLengthBy2Plus1>& Y2,
Per Åhgrenb20b9372018-07-13 00:22:54 +0200111 const SubtractorOutput& subtractor_output,
112 rtc::ArrayView<const float> y) {
113 // Analyze the filter output.
Per Åhgrene4db6a12018-07-26 15:32:24 +0200114 subtractor_output_analyzer_.Update(subtractor_output);
Per Åhgrenb20b9372018-07-13 00:22:54 +0200115
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200116 // Analyze the properties of the filter.
Jesús de Vicente Peñacf69d222018-11-27 09:24:29 +0100117 filter_analyzer_.Update(adaptive_filter_impulse_response, render_buffer);
peah86afe9d2017-04-06 15:45:32 -0700118
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200119 // Estimate the direct path delay of the filter.
120 delay_state_.Update(filter_analyzer_, external_delay,
121 strong_not_saturated_render_blocks_);
Per Åhgren5c532d32018-03-22 00:29:25 +0100122
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200123 const std::vector<float>& aligned_render_block =
124 render_buffer.Block(-delay_state_.DirectPathFilterDelay())[0];
Per Åhgren5c532d32018-03-22 00:29:25 +0100125
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200126 // Update render counters.
127 const float render_energy = std::inner_product(
128 aligned_render_block.begin(), aligned_render_block.end(),
129 aligned_render_block.begin(), 0.f);
130 const bool active_render =
131 render_energy > (config_.render_levels.active_render_limit *
132 config_.render_levels.active_render_limit) *
133 kFftLengthBy2;
134 blocks_with_active_render_ += active_render ? 1 : 0;
135 strong_not_saturated_render_blocks_ +=
136 active_render && !SaturatedCapture() ? 1 : 0;
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100137
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200138 std::array<float, kFftLengthBy2Plus1> X2_reverb;
139 render_reverb_.Apply(
140 render_buffer.GetSpectrumBuffer(), delay_state_.DirectPathFilterDelay(),
141 config_.ep_strength.reverb_based_on_render ? ReverbDecay() : 0.f,
142 X2_reverb);
143
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200144 if (config_.echo_audibility.use_stationary_properties) {
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200145 // Update the echo audibility evaluator.
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200146 echo_audibility_.Update(render_buffer,
147 render_reverb_.GetReverbContributionPowerSpectrum(),
148 delay_state_.DirectPathFilterDelay(),
149 delay_state_.ExternalDelayReported());
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200150 }
151
peah86afe9d2017-04-06 15:45:32 -0700152 // Update the ERL and ERLE measures.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200153 if (initial_state_.TransitionTriggered()) {
154 erle_estimator_.Reset(false);
Jesús de Vicente Peña02e9e442018-08-29 13:34:07 +0200155 }
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200156
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200157 const auto& X2 = render_buffer.Spectrum(delay_state_.DirectPathFilterDelay());
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100158 const auto& X2_input_erle = X2_reverb;
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200159
Jesús de Vicente Peña44974e12018-11-20 12:54:23 +0100160 erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response,
161 X2_input_erle, Y2, E2_main,
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200162 subtractor_output_analyzer_.ConvergedFilter(),
163 config_.erle.onset_detection);
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200164
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200165 erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilter(), X2, Y2);
peah86afe9d2017-04-06 15:45:32 -0700166
Per Åhgren63b494d2017-12-06 11:32:38 +0100167 // Detect and flag echo saturation.
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100168 saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
169 UsableLinearEstimate(), subtractor_output,
170 EchoPathGain());
peah86afe9d2017-04-06 15:45:32 -0700171
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200172 // Update the decision on whether to use the initial state parameter set.
173 initial_state_.Update(active_render, SaturatedCapture());
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100174
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200175 // Detect whether the transparent mode should be activated.
176 transparent_state_.Update(delay_state_.DirectPathFilterDelay(),
177 filter_analyzer_.Consistent(),
178 subtractor_output_analyzer_.ConvergedFilter(),
179 subtractor_output_analyzer_.DivergedFilter(),
180 active_render, SaturatedCapture());
Per Åhgren5c532d32018-03-22 00:29:25 +0100181
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200182 // Analyze the quality of the filter.
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100183 filter_quality_state_.Update(active_render, TransparentMode(),
184 SaturatedCapture(),
185 filter_analyzer_.Consistent(), external_delay,
186 subtractor_output_analyzer_.ConvergedFilter());
Per Åhgrena98c8072018-01-15 19:17:16 +0100187
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200188 // Update the reverb estimate.
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200189 const bool stationary_block =
Per Åhgrenf4801a12018-09-27 13:14:02 +0200190 config_.echo_audibility.use_stationary_properties &&
191 echo_audibility_.IsBlockStationary();
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200192
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200193 reverb_model_estimator_.Update(filter_analyzer_.GetAdjustedFilter(),
194 adaptive_filter_frequency_response,
195 erle_estimator_.GetInstLinearQualityEstimate(),
196 delay_state_.DirectPathFilterDelay(),
197 UsableLinearEstimate(), stationary_block);
Jesús de Vicente Peña075cb2b2018-06-13 15:13:55 +0200198
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200199 erle_estimator_.Dump(data_dumper_);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200200 reverb_model_estimator_.Dump(data_dumper_.get());
Per Åhgren5c532d32018-03-22 00:29:25 +0100201 data_dumper_->DumpRaw("aec3_erl", Erl());
Per Åhgren5c532d32018-03-22 00:29:25 +0100202 data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
Jesús de Vicente Peñac0a67ba2018-12-21 10:50:06 +0100203 data_dumper_->DumpRaw("aec3_erle", Erle());
Per Åhgren5c532d32018-03-22 00:29:25 +0100204 data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200205 data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode());
Per Åhgren5c532d32018-03-22 00:29:25 +0100206 data_dumper_->DumpRaw("aec3_filter_delay", filter_analyzer_.DelayBlocks());
207
208 data_dumper_->DumpRaw("aec3_consistent_filter",
209 filter_analyzer_.Consistent());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200210 data_dumper_->DumpRaw("aec3_initial_state",
211 initial_state_.InitialStateActive());
Per Åhgren5c532d32018-03-22 00:29:25 +0100212 data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200213 data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200214 data_dumper_->DumpRaw("aec3_converged_filter",
215 subtractor_output_analyzer_.ConvergedFilter());
216 data_dumper_->DumpRaw("aec3_diverged_filter",
217 subtractor_output_analyzer_.DivergedFilter());
Per Åhgren5c532d32018-03-22 00:29:25 +0100218
219 data_dumper_->DumpRaw("aec3_external_delay_avaliable",
220 external_delay ? 1 : 0);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200221 data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
222 GetReverbFrequencyResponse());
peah29103572017-07-11 02:54:02 -0700223}
224
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200225AecState::InitialState::InitialState(const EchoCanceller3Config& config)
226 : conservative_initial_phase_(config.filter.conservative_initial_phase),
227 initial_state_seconds_(config.filter.initial_state_seconds) {
228 Reset();
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100229}
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200230void AecState::InitialState::InitialState::Reset() {
231 initial_state_ = true;
232 strong_not_saturated_render_blocks_ = 0;
233}
234void AecState::InitialState::InitialState::Update(bool active_render,
235 bool saturated_capture) {
236 strong_not_saturated_render_blocks_ +=
237 active_render && !saturated_capture ? 1 : 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100238
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200239 // Flag whether the initial state is still active.
240 bool prev_initial_state = initial_state_;
241 if (conservative_initial_phase_) {
242 initial_state_ =
243 strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200244 } else {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200245 initial_state_ = strong_not_saturated_render_blocks_ <
246 initial_state_seconds_ * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200247 }
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100248
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200249 // Flag whether the transition from the initial state has started.
250 transition_triggered_ = !initial_state_ && prev_initial_state;
251}
252
253AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config)
254 : delay_headroom_blocks_(config.delay.delay_headroom_blocks) {}
255
256void AecState::FilterDelay::Update(
257 const FilterAnalyzer& filter_analyzer,
258 const absl::optional<DelayEstimate>& external_delay,
259 size_t blocks_with_proper_filter_adaptation) {
260 // Update the delay based on the external delay.
261 if (external_delay &&
262 (!external_delay_ || external_delay_->delay != external_delay->delay)) {
263 external_delay_ = external_delay;
264 external_delay_reported_ = true;
265 }
266
267 // Override the estimated delay if it is not certain that the filter has had
268 // time to converge.
269 const bool delay_estimator_may_not_have_converged =
270 blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
271 if (delay_estimator_may_not_have_converged && external_delay_) {
272 filter_delay_blocks_ = delay_headroom_blocks_;
273 } else {
274 filter_delay_blocks_ = filter_analyzer.DelayBlocks();
275 }
276}
277
278AecState::TransparentMode::TransparentMode(const EchoCanceller3Config& config)
279 : bounded_erl_(config.ep_strength.bounded_erl),
280 linear_and_stable_echo_path_(
281 config.echo_removal_control.linear_and_stable_echo_path),
282 active_blocks_since_sane_filter_(kBlocksSinceConsistentEstimateInit),
283 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
284
285void AecState::TransparentMode::Reset() {
286 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
287 diverged_sequence_size_ = 0;
288 strong_not_saturated_render_blocks_ = 0;
289 if (linear_and_stable_echo_path_) {
290 recent_convergence_during_activity_ = false;
291 }
292}
293
294void AecState::TransparentMode::Update(int filter_delay_blocks,
295 bool consistent_filter,
296 bool converged_filter,
297 bool diverged_filter,
298 bool active_render,
299 bool saturated_capture) {
300 ++capture_block_counter_;
301 strong_not_saturated_render_blocks_ +=
302 active_render && !saturated_capture ? 1 : 0;
303
304 if (consistent_filter && filter_delay_blocks < 5) {
305 sane_filter_observed_ = true;
306 active_blocks_since_sane_filter_ = 0;
307 } else if (active_render) {
308 ++active_blocks_since_sane_filter_;
309 }
310
311 bool sane_filter_recently_seen;
312 if (!sane_filter_observed_) {
313 sane_filter_recently_seen =
314 capture_block_counter_ <= 5 * kNumBlocksPerSecond;
315 } else {
316 sane_filter_recently_seen =
317 active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond;
318 }
319
320 if (converged_filter) {
321 recent_convergence_during_activity_ = true;
322 active_non_converged_sequence_size_ = 0;
323 non_converged_sequence_size_ = 0;
324 ++num_converged_blocks_;
325 } else {
326 if (++non_converged_sequence_size_ > 20 * kNumBlocksPerSecond) {
327 num_converged_blocks_ = 0;
328 }
329
330 if (active_render &&
331 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
332 recent_convergence_during_activity_ = false;
333 }
334 }
335
336 if (!diverged_filter) {
337 diverged_sequence_size_ = 0;
338 } else if (++diverged_sequence_size_ >= 60) {
339 // TODO(peah): Change these lines to ensure proper triggering of usable
340 // filter.
341 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
342 }
343
344 if (active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
345 finite_erl_recently_detected_ = false;
346 }
347 if (num_converged_blocks_ > 50) {
348 finite_erl_recently_detected_ = true;
349 }
350
351 if (bounded_erl_) {
352 transparency_activated_ = false;
353 } else if (finite_erl_recently_detected_) {
354 transparency_activated_ = false;
355 } else if (sane_filter_recently_seen && recent_convergence_during_activity_) {
356 transparency_activated_ = false;
357 } else {
358 const bool filter_should_have_converged =
359 strong_not_saturated_render_blocks_ > 6 * kNumBlocksPerSecond;
360 transparency_activated_ = filter_should_have_converged;
361 }
362}
363
364AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer(
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200365 const EchoCanceller3Config& config) {}
366
367void AecState::FilteringQualityAnalyzer::Reset() {
368 usable_linear_estimate_ = false;
369 filter_update_blocks_since_reset_ = 0;
370}
371
372void AecState::FilteringQualityAnalyzer::Update(
373 bool active_render,
374 bool transparent_mode,
375 bool saturated_capture,
376 bool consistent_estimate_,
377 const absl::optional<DelayEstimate>& external_delay,
378 bool converged_filter) {
379 // Update blocks counter.
380 const bool filter_update = active_render && !saturated_capture;
381 filter_update_blocks_since_reset_ += filter_update ? 1 : 0;
382 filter_update_blocks_since_start_ += filter_update ? 1 : 0;
383
384 // Store convergence flag when observed.
385 convergence_seen_ = convergence_seen_ || converged_filter;
386
387 // Verify requirements for achieving a decent filter. The requirements for
388 // filter adaptation at call startup are more restrictive than after an
389 // in-call reset.
390 const bool sufficient_data_to_converge_at_startup =
391 filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f;
392 const bool sufficient_data_to_converge_at_reset =
393 sufficient_data_to_converge_at_startup &&
394 filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f;
395
396 // The linear filter can only be used it has had time to converge.
397 usable_linear_estimate_ = sufficient_data_to_converge_at_startup &&
398 sufficient_data_to_converge_at_reset;
399
400 // The linear filter can only be used if an external delay or convergence have
401 // been identified
402 usable_linear_estimate_ =
403 usable_linear_estimate_ && (external_delay || convergence_seen_);
404
405 // If transparent mode is on, deactivate usign the linear filter.
406 usable_linear_estimate_ = usable_linear_estimate_ && !transparent_mode;
407}
408
409AecState::LegacyFilteringQualityAnalyzer::LegacyFilteringQualityAnalyzer(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200410 const EchoCanceller3Config& config)
411 : conservative_initial_phase_(config.filter.conservative_initial_phase),
412 required_blocks_for_convergence_(
413 kNumBlocksPerSecond * (conservative_initial_phase_ ? 1.5f : 0.8f)),
414 linear_and_stable_echo_path_(
415 config.echo_removal_control.linear_and_stable_echo_path),
416 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
417
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200418void AecState::LegacyFilteringQualityAnalyzer::Reset() {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200419 usable_linear_estimate_ = false;
420 strong_not_saturated_render_blocks_ = 0;
421 if (linear_and_stable_echo_path_) {
422 recent_convergence_during_activity_ = false;
423 }
424 diverged_sequence_size_ = 0;
425 // TODO(peah): Change to ensure proper triggering of usable filter.
426 non_converged_sequence_size_ = 10000;
427 recent_convergence_ = true;
428}
429
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200430void AecState::LegacyFilteringQualityAnalyzer::Update(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200431 bool saturated_echo,
432 bool active_render,
433 bool saturated_capture,
434 bool transparent_mode,
435 const absl::optional<DelayEstimate>& external_delay,
436 bool converged_filter,
437 bool diverged_filter) {
438 diverged_sequence_size_ = diverged_filter ? diverged_sequence_size_ + 1 : 0;
439 if (diverged_sequence_size_ >= 60) {
440 // TODO(peah): Change these lines to ensure proper triggering of usable
441 // filter.
442 non_converged_sequence_size_ = 10000;
443 recent_convergence_ = true;
444 }
445
446 if (converged_filter) {
447 non_converged_sequence_size_ = 0;
448 recent_convergence_ = true;
449 active_non_converged_sequence_size_ = 0;
450 recent_convergence_during_activity_ = true;
451 } else {
452 if (++non_converged_sequence_size_ >= 60 * kNumBlocksPerSecond) {
453 recent_convergence_ = false;
454 }
455
456 if (active_render &&
457 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
458 recent_convergence_during_activity_ = false;
459 }
460 }
461
462 strong_not_saturated_render_blocks_ +=
463 active_render && !saturated_capture ? 1 : 0;
464 const bool filter_has_had_time_to_converge =
465 strong_not_saturated_render_blocks_ > required_blocks_for_convergence_;
466
467 usable_linear_estimate_ = filter_has_had_time_to_converge && external_delay;
468
469 if (!conservative_initial_phase_ && recent_convergence_during_activity_) {
470 usable_linear_estimate_ = true;
471 }
472
473 if (!linear_and_stable_echo_path_ && !recent_convergence_) {
474 usable_linear_estimate_ = false;
475 }
476
477 if (saturated_echo || transparent_mode) {
478 usable_linear_estimate_ = false;
479 }
480}
481
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200482void AecState::SaturationDetector::Update(
483 rtc::ArrayView<const float> x,
484 bool saturated_capture,
485 bool usable_linear_estimate,
486 const SubtractorOutput& subtractor_output,
487 float echo_path_gain) {
488 saturated_echo_ = saturated_capture;
489 if (usable_linear_estimate) {
490 constexpr float kSaturationThreshold = 20000.f;
491 saturated_echo_ =
492 saturated_echo_ &&
493 (subtractor_output.s_main_max_abs > kSaturationThreshold ||
494 subtractor_output.s_shadow_max_abs > kSaturationThreshold);
495 } else {
496 const float max_sample = fabs(*std::max_element(
497 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; }));
498
499 const float kMargin = 10.f;
500 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
501 saturated_echo_ = saturated_echo_ && peak_echo_amplitude > 32000;
502 }
503}
504
505AecState::LegacySaturationDetector::LegacySaturationDetector(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200506 const EchoCanceller3Config& config)
507 : echo_can_saturate_(config.ep_strength.echo_can_saturate),
508 not_saturated_sequence_size_(1000) {}
509
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200510void AecState::LegacySaturationDetector::Reset() {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200511 not_saturated_sequence_size_ = 0;
512}
513
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200514void AecState::LegacySaturationDetector::Update(rtc::ArrayView<const float> x,
515 bool saturated_capture,
516 float echo_path_gain) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200517 if (!echo_can_saturate_) {
518 saturated_echo_ = false;
519 return;
520 }
521
522 RTC_DCHECK_LT(0, x.size());
523 if (saturated_capture) {
524 const float max_sample = fabs(*std::max_element(
525 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; }));
526
527 // Set flag for potential presence of saturated echo
528 const float kMargin = 10.f;
529 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
530 if (peak_echo_amplitude > 32000) {
531 not_saturated_sequence_size_ = 0;
532 saturated_echo_ = true;
533 return;
534 }
535 }
536
537 saturated_echo_ = ++not_saturated_sequence_size_ < 5;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100538}
539
peah522d71b2017-02-23 05:16:26 -0800540} // namespace webrtc