blob: bf47e2e0a77beda41dc9603fae33a5b8ab1f0f92 [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"
Per Åhgrend18e87e2018-05-09 12:07:26 +020024#include "system_wrappers/include/field_trial.h"
peah522d71b2017-02-23 05:16:26 -080025
26namespace webrtc {
27namespace {
28
Per Åhgrend2650d12018-10-02 17:00:59 +020029bool EnableErleResetsAtGainChanges() {
30 return !field_trial::IsEnabled("WebRTC-Aec3ResetErleAtGainChangesKillSwitch");
31}
32
Per Åhgren3e7b7b12018-10-16 14:38:10 +020033bool UseLegacyFilterQualityState() {
34 return field_trial::IsEnabled("WebRTC-Aec3FilterQualityStateKillSwitch");
35}
36
37bool EnableLegacySaturationBehavior() {
38 return field_trial::IsEnabled("WebRTC-Aec3NewSaturationBehaviorKillSwitch");
39}
40
41bool UseSuppressionGainLimiter() {
42 return field_trial::IsEnabled("WebRTC-Aec3GainLimiterDeactivationKillSwitch");
43}
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +020044bool EnableErleUpdatesDuringReverb() {
45 return !field_trial::IsEnabled(
46 "WebRTC-Aec3EnableErleUpdatesDuringReverbKillSwitch");
47}
Per Åhgren3e7b7b12018-10-16 14:38:10 +020048
Per Åhgren5c532d32018-03-22 00:29:25 +010049constexpr size_t kBlocksSinceConvergencedFilterInit = 10000;
50constexpr size_t kBlocksSinceConsistentEstimateInit = 10000;
51
peah522d71b2017-02-23 05:16:26 -080052} // namespace
53
54int AecState::instance_count_ = 0;
55
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020056void AecState::GetResidualEchoScaling(
57 rtc::ArrayView<float> residual_scaling) const {
58 bool filter_has_had_time_to_converge;
59 if (config_.filter.conservative_initial_phase) {
60 filter_has_had_time_to_converge =
61 strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond;
62 } else {
63 filter_has_had_time_to_converge =
64 strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond;
65 }
66 echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge,
67 residual_scaling);
68}
69
70absl::optional<float> AecState::ErleUncertainty() const {
Per Åhgren3e7b7b12018-10-16 14:38:10 +020071 if (SaturatedEcho() && use_legacy_saturation_behavior_) {
72 return 1.f;
73 }
74
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020075 return absl::nullopt;
76}
77
Gustaf Ullbergbd83b912017-10-18 12:32:42 +020078AecState::AecState(const EchoCanceller3Config& config)
peah522d71b2017-02-23 05:16:26 -080079 : data_dumper_(
80 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
peah8cee56f2017-08-24 22:36:53 -070081 config_(config),
Per Åhgren3e7b7b12018-10-16 14:38:10 +020082 use_legacy_saturation_behavior_(EnableLegacySaturationBehavior()),
83 enable_erle_resets_at_gain_changes_(EnableErleResetsAtGainChanges()),
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +020084 enable_erle_updates_during_reverb_(EnableErleUpdatesDuringReverb()),
Per Åhgren3e7b7b12018-10-16 14:38:10 +020085 use_legacy_filter_quality_(UseLegacyFilterQualityState()),
86 use_suppressor_gain_limiter_(UseSuppressionGainLimiter()),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020087 initial_state_(config_),
88 delay_state_(config_),
89 transparent_state_(config_),
90 filter_quality_state_(config_),
Per Åhgren3e7b7b12018-10-16 14:38:10 +020091 legacy_filter_quality_state_(config_),
92 legacy_saturation_detector_(config_),
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020093 erl_estimator_(2 * kNumBlocksPerSecond),
Jesús de Vicente Peña44974e12018-11-20 12:54:23 +010094 erle_estimator_(2 * kNumBlocksPerSecond, config_),
Per Åhgren5c532d32018-03-22 00:29:25 +010095 suppression_gain_limiter_(config_),
96 filter_analyzer_(config_),
Jesús de Vicente Peña836a7a22018-08-31 15:03:04 +020097 echo_audibility_(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020098 config_.echo_audibility.use_stationarity_properties_at_init),
Per Åhgren3e7b7b12018-10-16 14:38:10 +020099 reverb_model_estimator_(config_) {}
peah522d71b2017-02-23 05:16:26 -0800100
101AecState::~AecState() = default;
102
peah86afe9d2017-04-06 15:45:32 -0700103void AecState::HandleEchoPathChange(
104 const EchoPathVariability& echo_path_variability) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100105 const auto full_reset = [&]() {
Per Åhgren5c532d32018-03-22 00:29:25 +0100106 filter_analyzer_.Reset();
peah86afe9d2017-04-06 15:45:32 -0700107 capture_signal_saturation_ = false;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200108 strong_not_saturated_render_blocks_ = 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100109 blocks_with_active_render_ = 0;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200110 if (use_suppressor_gain_limiter_) {
111 suppression_gain_limiter_.Reset();
112 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200113 initial_state_.Reset();
114 transparent_state_.Reset();
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200115 if (use_legacy_saturation_behavior_) {
116 legacy_saturation_detector_.Reset();
117 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200118 erle_estimator_.Reset(true);
119 erl_estimator_.Reset();
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200120 if (use_legacy_filter_quality_) {
121 legacy_filter_quality_state_.Reset();
122 } else {
123 filter_quality_state_.Reset();
124 }
Per Åhgren8ba58612017-12-01 23:01:44 +0100125 };
peah6d822ad2017-04-10 13:52:14 -0700126
Per Åhgren8ba58612017-12-01 23:01:44 +0100127 // TODO(peah): Refine the reset scheme according to the type of gain and
128 // delay adjustment.
Per Åhgren8ba58612017-12-01 23:01:44 +0100129
130 if (echo_path_variability.delay_change !=
Per Åhgren88cf0502018-07-16 17:08:41 +0200131 EchoPathVariability::DelayAdjustment::kNone) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100132 full_reset();
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200133 } else if (enable_erle_resets_at_gain_changes_ &&
134 echo_path_variability.gain_change) {
135 erle_estimator_.Reset(false);
Per Åhgrend2650d12018-10-02 17:00:59 +0200136 }
Per Åhgrenb20b9372018-07-13 00:22:54 +0200137 subtractor_output_analyzer_.HandleEchoPathChange();
peah86afe9d2017-04-06 15:45:32 -0700138}
139
Per Åhgren09a718a2017-12-11 22:28:45 +0100140void AecState::Update(
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +0200141 const absl::optional<DelayEstimate>& external_delay,
Per Åhgren09a718a2017-12-11 22:28:45 +0100142 const std::vector<std::array<float, kFftLengthBy2Plus1>>&
143 adaptive_filter_frequency_response,
144 const std::vector<float>& adaptive_filter_impulse_response,
Per Åhgren09a718a2017-12-11 22:28:45 +0100145 const RenderBuffer& render_buffer,
146 const std::array<float, kFftLengthBy2Plus1>& E2_main,
147 const std::array<float, kFftLengthBy2Plus1>& Y2,
Per Åhgrenb20b9372018-07-13 00:22:54 +0200148 const SubtractorOutput& subtractor_output,
149 rtc::ArrayView<const float> y) {
150 // Analyze the filter output.
Per Åhgrene4db6a12018-07-26 15:32:24 +0200151 subtractor_output_analyzer_.Update(subtractor_output);
Per Åhgrenb20b9372018-07-13 00:22:54 +0200152
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200153 // Analyze the properties of the filter.
Jesús de Vicente Peñacf69d222018-11-27 09:24:29 +0100154 filter_analyzer_.Update(adaptive_filter_impulse_response, render_buffer);
peah86afe9d2017-04-06 15:45:32 -0700155
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200156 // Estimate the direct path delay of the filter.
157 delay_state_.Update(filter_analyzer_, external_delay,
158 strong_not_saturated_render_blocks_);
Per Åhgren5c532d32018-03-22 00:29:25 +0100159
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200160 const std::vector<float>& aligned_render_block =
161 render_buffer.Block(-delay_state_.DirectPathFilterDelay())[0];
Per Åhgren5c532d32018-03-22 00:29:25 +0100162
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200163 // Update render counters.
164 const float render_energy = std::inner_product(
165 aligned_render_block.begin(), aligned_render_block.end(),
166 aligned_render_block.begin(), 0.f);
167 const bool active_render =
168 render_energy > (config_.render_levels.active_render_limit *
169 config_.render_levels.active_render_limit) *
170 kFftLengthBy2;
171 blocks_with_active_render_ += active_render ? 1 : 0;
172 strong_not_saturated_render_blocks_ +=
173 active_render && !SaturatedCapture() ? 1 : 0;
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100174
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200175 if (use_suppressor_gain_limiter_) {
176 // Update the limit on the echo suppression after an echo path change to
177 // avoid an initial echo burst.
178 suppression_gain_limiter_.Update(render_buffer.GetRenderActivity(),
179 TransparentMode());
180
181 if (subtractor_output_analyzer_.ConvergedFilter()) {
182 suppression_gain_limiter_.Deactivate();
183 }
Per Åhgren6204adf2018-08-19 11:12:00 +0200184 }
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100185
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200186 std::array<float, kFftLengthBy2Plus1> X2_reverb;
187 render_reverb_.Apply(
188 render_buffer.GetSpectrumBuffer(), delay_state_.DirectPathFilterDelay(),
189 config_.ep_strength.reverb_based_on_render ? ReverbDecay() : 0.f,
190 X2_reverb);
191
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200192 if (config_.echo_audibility.use_stationary_properties) {
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200193 // Update the echo audibility evaluator.
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200194 echo_audibility_.Update(render_buffer,
195 render_reverb_.GetReverbContributionPowerSpectrum(),
196 delay_state_.DirectPathFilterDelay(),
197 delay_state_.ExternalDelayReported());
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200198 }
199
peah86afe9d2017-04-06 15:45:32 -0700200 // Update the ERL and ERLE measures.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200201 if (initial_state_.TransitionTriggered()) {
202 erle_estimator_.Reset(false);
Jesús de Vicente Peña02e9e442018-08-29 13:34:07 +0200203 }
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200204
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200205 const auto& X2 = render_buffer.Spectrum(delay_state_.DirectPathFilterDelay());
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200206 const auto& X2_input_erle =
207 enable_erle_updates_during_reverb_ ? X2_reverb : X2;
208
Jesús de Vicente Peña44974e12018-11-20 12:54:23 +0100209 erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response,
210 X2_input_erle, Y2, E2_main,
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200211 subtractor_output_analyzer_.ConvergedFilter(),
212 config_.erle.onset_detection);
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200213
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200214 erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilter(), X2, Y2);
peah86afe9d2017-04-06 15:45:32 -0700215
Per Åhgren63b494d2017-12-06 11:32:38 +0100216 // Detect and flag echo saturation.
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200217 if (use_legacy_saturation_behavior_) {
218 legacy_saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
219 EchoPathGain());
220 } else {
221 saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
222 UsableLinearEstimate(), subtractor_output,
223 EchoPathGain());
224 }
peah86afe9d2017-04-06 15:45:32 -0700225
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200226 // Update the decision on whether to use the initial state parameter set.
227 initial_state_.Update(active_render, SaturatedCapture());
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100228
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200229 // Detect whether the transparent mode should be activated.
230 transparent_state_.Update(delay_state_.DirectPathFilterDelay(),
231 filter_analyzer_.Consistent(),
232 subtractor_output_analyzer_.ConvergedFilter(),
233 subtractor_output_analyzer_.DivergedFilter(),
234 active_render, SaturatedCapture());
Per Åhgren5c532d32018-03-22 00:29:25 +0100235
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200236 // Analyze the quality of the filter.
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200237 if (use_legacy_filter_quality_) {
238 legacy_filter_quality_state_.Update(
239 SaturatedEcho(), active_render, SaturatedCapture(), TransparentMode(),
240 external_delay, subtractor_output_analyzer_.ConvergedFilter(),
241 subtractor_output_analyzer_.DivergedFilter());
242 } else {
243 filter_quality_state_.Update(active_render, TransparentMode(),
244 SaturatedCapture(),
245 filter_analyzer_.Consistent(), external_delay,
246 subtractor_output_analyzer_.ConvergedFilter());
247 }
Per Åhgrena98c8072018-01-15 19:17:16 +0100248
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200249 // Update the reverb estimate.
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200250 const bool stationary_block =
Per Åhgrenf4801a12018-09-27 13:14:02 +0200251 config_.echo_audibility.use_stationary_properties &&
252 echo_audibility_.IsBlockStationary();
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200253
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200254 reverb_model_estimator_.Update(filter_analyzer_.GetAdjustedFilter(),
255 adaptive_filter_frequency_response,
256 erle_estimator_.GetInstLinearQualityEstimate(),
257 delay_state_.DirectPathFilterDelay(),
258 UsableLinearEstimate(), stationary_block);
Jesús de Vicente Peña075cb2b2018-06-13 15:13:55 +0200259
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200260 erle_estimator_.Dump(data_dumper_);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200261 reverb_model_estimator_.Dump(data_dumper_.get());
Per Åhgren5c532d32018-03-22 00:29:25 +0100262 data_dumper_->DumpRaw("aec3_erl", Erl());
Per Åhgren5c532d32018-03-22 00:29:25 +0100263 data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
Jesús de Vicente Peñac0a67ba2018-12-21 10:50:06 +0100264 data_dumper_->DumpRaw("aec3_erle", Erle());
Per Åhgren5c532d32018-03-22 00:29:25 +0100265 data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200266 data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode());
Per Åhgren5c532d32018-03-22 00:29:25 +0100267 data_dumper_->DumpRaw("aec3_filter_delay", filter_analyzer_.DelayBlocks());
268
269 data_dumper_->DumpRaw("aec3_consistent_filter",
270 filter_analyzer_.Consistent());
271 data_dumper_->DumpRaw("aec3_suppression_gain_limit", SuppressionGainLimit());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200272 data_dumper_->DumpRaw("aec3_initial_state",
273 initial_state_.InitialStateActive());
Per Åhgren5c532d32018-03-22 00:29:25 +0100274 data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200275 data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200276 data_dumper_->DumpRaw("aec3_converged_filter",
277 subtractor_output_analyzer_.ConvergedFilter());
278 data_dumper_->DumpRaw("aec3_diverged_filter",
279 subtractor_output_analyzer_.DivergedFilter());
Per Åhgren5c532d32018-03-22 00:29:25 +0100280
281 data_dumper_->DumpRaw("aec3_external_delay_avaliable",
282 external_delay ? 1 : 0);
Jesús de Vicente Peñadd092872018-05-25 16:55:11 +0200283 data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running",
284 IsSuppressionGainLimitActive());
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200285 data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
286 GetReverbFrequencyResponse());
peah29103572017-07-11 02:54:02 -0700287}
288
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200289AecState::InitialState::InitialState(const EchoCanceller3Config& config)
290 : conservative_initial_phase_(config.filter.conservative_initial_phase),
291 initial_state_seconds_(config.filter.initial_state_seconds) {
292 Reset();
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100293}
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200294void AecState::InitialState::InitialState::Reset() {
295 initial_state_ = true;
296 strong_not_saturated_render_blocks_ = 0;
297}
298void AecState::InitialState::InitialState::Update(bool active_render,
299 bool saturated_capture) {
300 strong_not_saturated_render_blocks_ +=
301 active_render && !saturated_capture ? 1 : 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100302
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200303 // Flag whether the initial state is still active.
304 bool prev_initial_state = initial_state_;
305 if (conservative_initial_phase_) {
306 initial_state_ =
307 strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200308 } else {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200309 initial_state_ = strong_not_saturated_render_blocks_ <
310 initial_state_seconds_ * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200311 }
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100312
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200313 // Flag whether the transition from the initial state has started.
314 transition_triggered_ = !initial_state_ && prev_initial_state;
315}
316
317AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config)
318 : delay_headroom_blocks_(config.delay.delay_headroom_blocks) {}
319
320void AecState::FilterDelay::Update(
321 const FilterAnalyzer& filter_analyzer,
322 const absl::optional<DelayEstimate>& external_delay,
323 size_t blocks_with_proper_filter_adaptation) {
324 // Update the delay based on the external delay.
325 if (external_delay &&
326 (!external_delay_ || external_delay_->delay != external_delay->delay)) {
327 external_delay_ = external_delay;
328 external_delay_reported_ = true;
329 }
330
331 // Override the estimated delay if it is not certain that the filter has had
332 // time to converge.
333 const bool delay_estimator_may_not_have_converged =
334 blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
335 if (delay_estimator_may_not_have_converged && external_delay_) {
336 filter_delay_blocks_ = delay_headroom_blocks_;
337 } else {
338 filter_delay_blocks_ = filter_analyzer.DelayBlocks();
339 }
340}
341
342AecState::TransparentMode::TransparentMode(const EchoCanceller3Config& config)
343 : bounded_erl_(config.ep_strength.bounded_erl),
344 linear_and_stable_echo_path_(
345 config.echo_removal_control.linear_and_stable_echo_path),
346 active_blocks_since_sane_filter_(kBlocksSinceConsistentEstimateInit),
347 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
348
349void AecState::TransparentMode::Reset() {
350 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
351 diverged_sequence_size_ = 0;
352 strong_not_saturated_render_blocks_ = 0;
353 if (linear_and_stable_echo_path_) {
354 recent_convergence_during_activity_ = false;
355 }
356}
357
358void AecState::TransparentMode::Update(int filter_delay_blocks,
359 bool consistent_filter,
360 bool converged_filter,
361 bool diverged_filter,
362 bool active_render,
363 bool saturated_capture) {
364 ++capture_block_counter_;
365 strong_not_saturated_render_blocks_ +=
366 active_render && !saturated_capture ? 1 : 0;
367
368 if (consistent_filter && filter_delay_blocks < 5) {
369 sane_filter_observed_ = true;
370 active_blocks_since_sane_filter_ = 0;
371 } else if (active_render) {
372 ++active_blocks_since_sane_filter_;
373 }
374
375 bool sane_filter_recently_seen;
376 if (!sane_filter_observed_) {
377 sane_filter_recently_seen =
378 capture_block_counter_ <= 5 * kNumBlocksPerSecond;
379 } else {
380 sane_filter_recently_seen =
381 active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond;
382 }
383
384 if (converged_filter) {
385 recent_convergence_during_activity_ = true;
386 active_non_converged_sequence_size_ = 0;
387 non_converged_sequence_size_ = 0;
388 ++num_converged_blocks_;
389 } else {
390 if (++non_converged_sequence_size_ > 20 * kNumBlocksPerSecond) {
391 num_converged_blocks_ = 0;
392 }
393
394 if (active_render &&
395 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
396 recent_convergence_during_activity_ = false;
397 }
398 }
399
400 if (!diverged_filter) {
401 diverged_sequence_size_ = 0;
402 } else if (++diverged_sequence_size_ >= 60) {
403 // TODO(peah): Change these lines to ensure proper triggering of usable
404 // filter.
405 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
406 }
407
408 if (active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
409 finite_erl_recently_detected_ = false;
410 }
411 if (num_converged_blocks_ > 50) {
412 finite_erl_recently_detected_ = true;
413 }
414
415 if (bounded_erl_) {
416 transparency_activated_ = false;
417 } else if (finite_erl_recently_detected_) {
418 transparency_activated_ = false;
419 } else if (sane_filter_recently_seen && recent_convergence_during_activity_) {
420 transparency_activated_ = false;
421 } else {
422 const bool filter_should_have_converged =
423 strong_not_saturated_render_blocks_ > 6 * kNumBlocksPerSecond;
424 transparency_activated_ = filter_should_have_converged;
425 }
426}
427
428AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer(
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200429 const EchoCanceller3Config& config) {}
430
431void AecState::FilteringQualityAnalyzer::Reset() {
432 usable_linear_estimate_ = false;
433 filter_update_blocks_since_reset_ = 0;
434}
435
436void AecState::FilteringQualityAnalyzer::Update(
437 bool active_render,
438 bool transparent_mode,
439 bool saturated_capture,
440 bool consistent_estimate_,
441 const absl::optional<DelayEstimate>& external_delay,
442 bool converged_filter) {
443 // Update blocks counter.
444 const bool filter_update = active_render && !saturated_capture;
445 filter_update_blocks_since_reset_ += filter_update ? 1 : 0;
446 filter_update_blocks_since_start_ += filter_update ? 1 : 0;
447
448 // Store convergence flag when observed.
449 convergence_seen_ = convergence_seen_ || converged_filter;
450
451 // Verify requirements for achieving a decent filter. The requirements for
452 // filter adaptation at call startup are more restrictive than after an
453 // in-call reset.
454 const bool sufficient_data_to_converge_at_startup =
455 filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f;
456 const bool sufficient_data_to_converge_at_reset =
457 sufficient_data_to_converge_at_startup &&
458 filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f;
459
460 // The linear filter can only be used it has had time to converge.
461 usable_linear_estimate_ = sufficient_data_to_converge_at_startup &&
462 sufficient_data_to_converge_at_reset;
463
464 // The linear filter can only be used if an external delay or convergence have
465 // been identified
466 usable_linear_estimate_ =
467 usable_linear_estimate_ && (external_delay || convergence_seen_);
468
469 // If transparent mode is on, deactivate usign the linear filter.
470 usable_linear_estimate_ = usable_linear_estimate_ && !transparent_mode;
471}
472
473AecState::LegacyFilteringQualityAnalyzer::LegacyFilteringQualityAnalyzer(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200474 const EchoCanceller3Config& config)
475 : conservative_initial_phase_(config.filter.conservative_initial_phase),
476 required_blocks_for_convergence_(
477 kNumBlocksPerSecond * (conservative_initial_phase_ ? 1.5f : 0.8f)),
478 linear_and_stable_echo_path_(
479 config.echo_removal_control.linear_and_stable_echo_path),
480 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
481
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200482void AecState::LegacyFilteringQualityAnalyzer::Reset() {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200483 usable_linear_estimate_ = false;
484 strong_not_saturated_render_blocks_ = 0;
485 if (linear_and_stable_echo_path_) {
486 recent_convergence_during_activity_ = false;
487 }
488 diverged_sequence_size_ = 0;
489 // TODO(peah): Change to ensure proper triggering of usable filter.
490 non_converged_sequence_size_ = 10000;
491 recent_convergence_ = true;
492}
493
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200494void AecState::LegacyFilteringQualityAnalyzer::Update(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200495 bool saturated_echo,
496 bool active_render,
497 bool saturated_capture,
498 bool transparent_mode,
499 const absl::optional<DelayEstimate>& external_delay,
500 bool converged_filter,
501 bool diverged_filter) {
502 diverged_sequence_size_ = diverged_filter ? diverged_sequence_size_ + 1 : 0;
503 if (diverged_sequence_size_ >= 60) {
504 // TODO(peah): Change these lines to ensure proper triggering of usable
505 // filter.
506 non_converged_sequence_size_ = 10000;
507 recent_convergence_ = true;
508 }
509
510 if (converged_filter) {
511 non_converged_sequence_size_ = 0;
512 recent_convergence_ = true;
513 active_non_converged_sequence_size_ = 0;
514 recent_convergence_during_activity_ = true;
515 } else {
516 if (++non_converged_sequence_size_ >= 60 * kNumBlocksPerSecond) {
517 recent_convergence_ = false;
518 }
519
520 if (active_render &&
521 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
522 recent_convergence_during_activity_ = false;
523 }
524 }
525
526 strong_not_saturated_render_blocks_ +=
527 active_render && !saturated_capture ? 1 : 0;
528 const bool filter_has_had_time_to_converge =
529 strong_not_saturated_render_blocks_ > required_blocks_for_convergence_;
530
531 usable_linear_estimate_ = filter_has_had_time_to_converge && external_delay;
532
533 if (!conservative_initial_phase_ && recent_convergence_during_activity_) {
534 usable_linear_estimate_ = true;
535 }
536
537 if (!linear_and_stable_echo_path_ && !recent_convergence_) {
538 usable_linear_estimate_ = false;
539 }
540
541 if (saturated_echo || transparent_mode) {
542 usable_linear_estimate_ = false;
543 }
544}
545
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200546void AecState::SaturationDetector::Update(
547 rtc::ArrayView<const float> x,
548 bool saturated_capture,
549 bool usable_linear_estimate,
550 const SubtractorOutput& subtractor_output,
551 float echo_path_gain) {
552 saturated_echo_ = saturated_capture;
553 if (usable_linear_estimate) {
554 constexpr float kSaturationThreshold = 20000.f;
555 saturated_echo_ =
556 saturated_echo_ &&
557 (subtractor_output.s_main_max_abs > kSaturationThreshold ||
558 subtractor_output.s_shadow_max_abs > kSaturationThreshold);
559 } else {
560 const float max_sample = fabs(*std::max_element(
561 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; }));
562
563 const float kMargin = 10.f;
564 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
565 saturated_echo_ = saturated_echo_ && peak_echo_amplitude > 32000;
566 }
567}
568
569AecState::LegacySaturationDetector::LegacySaturationDetector(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200570 const EchoCanceller3Config& config)
571 : echo_can_saturate_(config.ep_strength.echo_can_saturate),
572 not_saturated_sequence_size_(1000) {}
573
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200574void AecState::LegacySaturationDetector::Reset() {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200575 not_saturated_sequence_size_ = 0;
576}
577
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200578void AecState::LegacySaturationDetector::Update(rtc::ArrayView<const float> x,
579 bool saturated_capture,
580 float echo_path_gain) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200581 if (!echo_can_saturate_) {
582 saturated_echo_ = false;
583 return;
584 }
585
586 RTC_DCHECK_LT(0, x.size());
587 if (saturated_capture) {
588 const float max_sample = fabs(*std::max_element(
589 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; }));
590
591 // Set flag for potential presence of saturated echo
592 const float kMargin = 10.f;
593 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
594 if (peak_echo_amplitude > 32000) {
595 not_saturated_sequence_size_ = 0;
596 saturated_echo_ = true;
597 return;
598 }
599 }
600
601 saturated_echo_ = ++not_saturated_sequence_size_ < 5;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100602}
603
peah522d71b2017-02-23 05:16:26 -0800604} // namespace webrtc