blob: f44c744660172d66d4c28b81ebb1036112b753ad [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>
Raphael Kubo da Costa07438142017-10-16 17:00:02 +020014
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"
22#include "rtc_base/atomicops.h"
23#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),
94 erle_estimator_(2 * kNumBlocksPerSecond,
95 config_.erle.min,
96 config_.erle.max_l,
97 config_.erle.max_h),
Per Åhgren5c532d32018-03-22 00:29:25 +010098 suppression_gain_limiter_(config_),
99 filter_analyzer_(config_),
Jesús de Vicente Peña836a7a22018-08-31 15:03:04 +0200100 echo_audibility_(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200101 config_.echo_audibility.use_stationarity_properties_at_init),
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200102 reverb_model_estimator_(config_) {}
peah522d71b2017-02-23 05:16:26 -0800103
104AecState::~AecState() = default;
105
peah86afe9d2017-04-06 15:45:32 -0700106void AecState::HandleEchoPathChange(
107 const EchoPathVariability& echo_path_variability) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100108 const auto full_reset = [&]() {
Per Åhgren5c532d32018-03-22 00:29:25 +0100109 filter_analyzer_.Reset();
peah86afe9d2017-04-06 15:45:32 -0700110 capture_signal_saturation_ = false;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200111 strong_not_saturated_render_blocks_ = 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100112 blocks_with_active_render_ = 0;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200113 if (use_suppressor_gain_limiter_) {
114 suppression_gain_limiter_.Reset();
115 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200116 initial_state_.Reset();
117 transparent_state_.Reset();
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200118 if (use_legacy_saturation_behavior_) {
119 legacy_saturation_detector_.Reset();
120 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200121 erle_estimator_.Reset(true);
122 erl_estimator_.Reset();
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200123 if (use_legacy_filter_quality_) {
124 legacy_filter_quality_state_.Reset();
125 } else {
126 filter_quality_state_.Reset();
127 }
Per Åhgren8ba58612017-12-01 23:01:44 +0100128 };
peah6d822ad2017-04-10 13:52:14 -0700129
Per Åhgren8ba58612017-12-01 23:01:44 +0100130 // TODO(peah): Refine the reset scheme according to the type of gain and
131 // delay adjustment.
Per Åhgren8ba58612017-12-01 23:01:44 +0100132
133 if (echo_path_variability.delay_change !=
Per Åhgren88cf0502018-07-16 17:08:41 +0200134 EchoPathVariability::DelayAdjustment::kNone) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100135 full_reset();
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200136 } else if (enable_erle_resets_at_gain_changes_ &&
137 echo_path_variability.gain_change) {
138 erle_estimator_.Reset(false);
Per Åhgrend2650d12018-10-02 17:00:59 +0200139 }
Per Åhgrenb20b9372018-07-13 00:22:54 +0200140 subtractor_output_analyzer_.HandleEchoPathChange();
peah86afe9d2017-04-06 15:45:32 -0700141}
142
Per Åhgren09a718a2017-12-11 22:28:45 +0100143void AecState::Update(
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +0200144 const absl::optional<DelayEstimate>& external_delay,
Per Åhgren09a718a2017-12-11 22:28:45 +0100145 const std::vector<std::array<float, kFftLengthBy2Plus1>>&
146 adaptive_filter_frequency_response,
147 const std::vector<float>& adaptive_filter_impulse_response,
Per Åhgren09a718a2017-12-11 22:28:45 +0100148 const RenderBuffer& render_buffer,
149 const std::array<float, kFftLengthBy2Plus1>& E2_main,
150 const std::array<float, kFftLengthBy2Plus1>& Y2,
Per Åhgrenb20b9372018-07-13 00:22:54 +0200151 const SubtractorOutput& subtractor_output,
152 rtc::ArrayView<const float> y) {
153 // Analyze the filter output.
Per Åhgrene4db6a12018-07-26 15:32:24 +0200154 subtractor_output_analyzer_.Update(subtractor_output);
Per Åhgrenb20b9372018-07-13 00:22:54 +0200155
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200156 // Analyze the properties of the filter.
Jesús de Vicente Peñae58bd8a2018-06-26 17:19:15 +0200157 filter_analyzer_.Update(adaptive_filter_impulse_response,
158 adaptive_filter_frequency_response, render_buffer);
peah86afe9d2017-04-06 15:45:32 -0700159
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200160 // Estimate the direct path delay of the filter.
161 delay_state_.Update(filter_analyzer_, external_delay,
162 strong_not_saturated_render_blocks_);
Per Åhgren5c532d32018-03-22 00:29:25 +0100163
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200164 const std::vector<float>& aligned_render_block =
165 render_buffer.Block(-delay_state_.DirectPathFilterDelay())[0];
Per Åhgren5c532d32018-03-22 00:29:25 +0100166
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200167 // Update render counters.
168 const float render_energy = std::inner_product(
169 aligned_render_block.begin(), aligned_render_block.end(),
170 aligned_render_block.begin(), 0.f);
171 const bool active_render =
172 render_energy > (config_.render_levels.active_render_limit *
173 config_.render_levels.active_render_limit) *
174 kFftLengthBy2;
175 blocks_with_active_render_ += active_render ? 1 : 0;
176 strong_not_saturated_render_blocks_ +=
177 active_render && !SaturatedCapture() ? 1 : 0;
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100178
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200179 if (use_suppressor_gain_limiter_) {
180 // Update the limit on the echo suppression after an echo path change to
181 // avoid an initial echo burst.
182 suppression_gain_limiter_.Update(render_buffer.GetRenderActivity(),
183 TransparentMode());
184
185 if (subtractor_output_analyzer_.ConvergedFilter()) {
186 suppression_gain_limiter_.Deactivate();
187 }
Per Åhgren6204adf2018-08-19 11:12:00 +0200188 }
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100189
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200190 std::array<float, kFftLengthBy2Plus1> X2_reverb;
191 render_reverb_.Apply(
192 render_buffer.GetSpectrumBuffer(), delay_state_.DirectPathFilterDelay(),
193 config_.ep_strength.reverb_based_on_render ? ReverbDecay() : 0.f,
194 X2_reverb);
195
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200196 if (config_.echo_audibility.use_stationary_properties) {
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200197 // Update the echo audibility evaluator.
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200198 echo_audibility_.Update(render_buffer,
199 render_reverb_.GetReverbContributionPowerSpectrum(),
200 delay_state_.DirectPathFilterDelay(),
201 delay_state_.ExternalDelayReported());
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200202 }
203
peah86afe9d2017-04-06 15:45:32 -0700204 // Update the ERL and ERLE measures.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200205 if (initial_state_.TransitionTriggered()) {
206 erle_estimator_.Reset(false);
Jesús de Vicente Peña02e9e442018-08-29 13:34:07 +0200207 }
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200208
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200209 const auto& X2 = render_buffer.Spectrum(delay_state_.DirectPathFilterDelay());
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200210 const auto& X2_input_erle =
211 enable_erle_updates_during_reverb_ ? X2_reverb : X2;
212
213 erle_estimator_.Update(X2_input_erle, Y2, E2_main,
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200214 subtractor_output_analyzer_.ConvergedFilter(),
215 config_.erle.onset_detection);
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200216
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200217 erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilter(), X2, Y2);
peah86afe9d2017-04-06 15:45:32 -0700218
Per Åhgren63b494d2017-12-06 11:32:38 +0100219 // Detect and flag echo saturation.
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200220 if (use_legacy_saturation_behavior_) {
221 legacy_saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
222 EchoPathGain());
223 } else {
224 saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
225 UsableLinearEstimate(), subtractor_output,
226 EchoPathGain());
227 }
peah86afe9d2017-04-06 15:45:32 -0700228
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200229 // Update the decision on whether to use the initial state parameter set.
230 initial_state_.Update(active_render, SaturatedCapture());
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100231
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200232 // Detect whether the transparent mode should be activated.
233 transparent_state_.Update(delay_state_.DirectPathFilterDelay(),
234 filter_analyzer_.Consistent(),
235 subtractor_output_analyzer_.ConvergedFilter(),
236 subtractor_output_analyzer_.DivergedFilter(),
237 active_render, SaturatedCapture());
Per Åhgren5c532d32018-03-22 00:29:25 +0100238
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200239 // Analyze the quality of the filter.
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200240 if (use_legacy_filter_quality_) {
241 legacy_filter_quality_state_.Update(
242 SaturatedEcho(), active_render, SaturatedCapture(), TransparentMode(),
243 external_delay, subtractor_output_analyzer_.ConvergedFilter(),
244 subtractor_output_analyzer_.DivergedFilter());
245 } else {
246 filter_quality_state_.Update(active_render, TransparentMode(),
247 SaturatedCapture(),
248 filter_analyzer_.Consistent(), external_delay,
249 subtractor_output_analyzer_.ConvergedFilter());
250 }
Per Åhgrena98c8072018-01-15 19:17:16 +0100251
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200252 // Update the reverb estimate.
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200253 const bool stationary_block =
Per Åhgrenf4801a12018-09-27 13:14:02 +0200254 config_.echo_audibility.use_stationary_properties &&
255 echo_audibility_.IsBlockStationary();
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200256
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200257 reverb_model_estimator_.Update(filter_analyzer_.GetAdjustedFilter(),
258 adaptive_filter_frequency_response,
259 erle_estimator_.GetInstLinearQualityEstimate(),
260 delay_state_.DirectPathFilterDelay(),
261 UsableLinearEstimate(), stationary_block);
Jesús de Vicente Peña075cb2b2018-06-13 15:13:55 +0200262
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200263 erle_estimator_.Dump(data_dumper_);
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200264 reverb_model_estimator_.Dump(data_dumper_.get());
Per Åhgren5c532d32018-03-22 00:29:25 +0100265 data_dumper_->DumpRaw("aec3_erl", Erl());
Per Åhgren5c532d32018-03-22 00:29:25 +0100266 data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
267 data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200268 data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode());
Per Åhgren5c532d32018-03-22 00:29:25 +0100269 data_dumper_->DumpRaw("aec3_filter_delay", filter_analyzer_.DelayBlocks());
270
271 data_dumper_->DumpRaw("aec3_consistent_filter",
272 filter_analyzer_.Consistent());
273 data_dumper_->DumpRaw("aec3_suppression_gain_limit", SuppressionGainLimit());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200274 data_dumper_->DumpRaw("aec3_initial_state",
275 initial_state_.InitialStateActive());
Per Åhgren5c532d32018-03-22 00:29:25 +0100276 data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200277 data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho());
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200278 data_dumper_->DumpRaw("aec3_converged_filter",
279 subtractor_output_analyzer_.ConvergedFilter());
280 data_dumper_->DumpRaw("aec3_diverged_filter",
281 subtractor_output_analyzer_.DivergedFilter());
Per Åhgren5c532d32018-03-22 00:29:25 +0100282
283 data_dumper_->DumpRaw("aec3_external_delay_avaliable",
284 external_delay ? 1 : 0);
Jesús de Vicente Peñadd092872018-05-25 16:55:11 +0200285 data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running",
286 IsSuppressionGainLimitActive());
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200287 data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
288 GetReverbFrequencyResponse());
peah29103572017-07-11 02:54:02 -0700289}
290
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200291AecState::InitialState::InitialState(const EchoCanceller3Config& config)
292 : conservative_initial_phase_(config.filter.conservative_initial_phase),
293 initial_state_seconds_(config.filter.initial_state_seconds) {
294 Reset();
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100295}
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200296void AecState::InitialState::InitialState::Reset() {
297 initial_state_ = true;
298 strong_not_saturated_render_blocks_ = 0;
299}
300void AecState::InitialState::InitialState::Update(bool active_render,
301 bool saturated_capture) {
302 strong_not_saturated_render_blocks_ +=
303 active_render && !saturated_capture ? 1 : 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100304
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200305 // Flag whether the initial state is still active.
306 bool prev_initial_state = initial_state_;
307 if (conservative_initial_phase_) {
308 initial_state_ =
309 strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200310 } else {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200311 initial_state_ = strong_not_saturated_render_blocks_ <
312 initial_state_seconds_ * kNumBlocksPerSecond;
Per Åhgren31122d62018-04-10 16:33:55 +0200313 }
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100314
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200315 // Flag whether the transition from the initial state has started.
316 transition_triggered_ = !initial_state_ && prev_initial_state;
317}
318
319AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config)
320 : delay_headroom_blocks_(config.delay.delay_headroom_blocks) {}
321
322void AecState::FilterDelay::Update(
323 const FilterAnalyzer& filter_analyzer,
324 const absl::optional<DelayEstimate>& external_delay,
325 size_t blocks_with_proper_filter_adaptation) {
326 // Update the delay based on the external delay.
327 if (external_delay &&
328 (!external_delay_ || external_delay_->delay != external_delay->delay)) {
329 external_delay_ = external_delay;
330 external_delay_reported_ = true;
331 }
332
333 // Override the estimated delay if it is not certain that the filter has had
334 // time to converge.
335 const bool delay_estimator_may_not_have_converged =
336 blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
337 if (delay_estimator_may_not_have_converged && external_delay_) {
338 filter_delay_blocks_ = delay_headroom_blocks_;
339 } else {
340 filter_delay_blocks_ = filter_analyzer.DelayBlocks();
341 }
342}
343
344AecState::TransparentMode::TransparentMode(const EchoCanceller3Config& config)
345 : bounded_erl_(config.ep_strength.bounded_erl),
346 linear_and_stable_echo_path_(
347 config.echo_removal_control.linear_and_stable_echo_path),
348 active_blocks_since_sane_filter_(kBlocksSinceConsistentEstimateInit),
349 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
350
351void AecState::TransparentMode::Reset() {
352 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
353 diverged_sequence_size_ = 0;
354 strong_not_saturated_render_blocks_ = 0;
355 if (linear_and_stable_echo_path_) {
356 recent_convergence_during_activity_ = false;
357 }
358}
359
360void AecState::TransparentMode::Update(int filter_delay_blocks,
361 bool consistent_filter,
362 bool converged_filter,
363 bool diverged_filter,
364 bool active_render,
365 bool saturated_capture) {
366 ++capture_block_counter_;
367 strong_not_saturated_render_blocks_ +=
368 active_render && !saturated_capture ? 1 : 0;
369
370 if (consistent_filter && filter_delay_blocks < 5) {
371 sane_filter_observed_ = true;
372 active_blocks_since_sane_filter_ = 0;
373 } else if (active_render) {
374 ++active_blocks_since_sane_filter_;
375 }
376
377 bool sane_filter_recently_seen;
378 if (!sane_filter_observed_) {
379 sane_filter_recently_seen =
380 capture_block_counter_ <= 5 * kNumBlocksPerSecond;
381 } else {
382 sane_filter_recently_seen =
383 active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond;
384 }
385
386 if (converged_filter) {
387 recent_convergence_during_activity_ = true;
388 active_non_converged_sequence_size_ = 0;
389 non_converged_sequence_size_ = 0;
390 ++num_converged_blocks_;
391 } else {
392 if (++non_converged_sequence_size_ > 20 * kNumBlocksPerSecond) {
393 num_converged_blocks_ = 0;
394 }
395
396 if (active_render &&
397 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
398 recent_convergence_during_activity_ = false;
399 }
400 }
401
402 if (!diverged_filter) {
403 diverged_sequence_size_ = 0;
404 } else if (++diverged_sequence_size_ >= 60) {
405 // TODO(peah): Change these lines to ensure proper triggering of usable
406 // filter.
407 non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
408 }
409
410 if (active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
411 finite_erl_recently_detected_ = false;
412 }
413 if (num_converged_blocks_ > 50) {
414 finite_erl_recently_detected_ = true;
415 }
416
417 if (bounded_erl_) {
418 transparency_activated_ = false;
419 } else if (finite_erl_recently_detected_) {
420 transparency_activated_ = false;
421 } else if (sane_filter_recently_seen && recent_convergence_during_activity_) {
422 transparency_activated_ = false;
423 } else {
424 const bool filter_should_have_converged =
425 strong_not_saturated_render_blocks_ > 6 * kNumBlocksPerSecond;
426 transparency_activated_ = filter_should_have_converged;
427 }
428}
429
430AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer(
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200431 const EchoCanceller3Config& config) {}
432
433void AecState::FilteringQualityAnalyzer::Reset() {
434 usable_linear_estimate_ = false;
435 filter_update_blocks_since_reset_ = 0;
436}
437
438void AecState::FilteringQualityAnalyzer::Update(
439 bool active_render,
440 bool transparent_mode,
441 bool saturated_capture,
442 bool consistent_estimate_,
443 const absl::optional<DelayEstimate>& external_delay,
444 bool converged_filter) {
445 // Update blocks counter.
446 const bool filter_update = active_render && !saturated_capture;
447 filter_update_blocks_since_reset_ += filter_update ? 1 : 0;
448 filter_update_blocks_since_start_ += filter_update ? 1 : 0;
449
450 // Store convergence flag when observed.
451 convergence_seen_ = convergence_seen_ || converged_filter;
452
453 // Verify requirements for achieving a decent filter. The requirements for
454 // filter adaptation at call startup are more restrictive than after an
455 // in-call reset.
456 const bool sufficient_data_to_converge_at_startup =
457 filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f;
458 const bool sufficient_data_to_converge_at_reset =
459 sufficient_data_to_converge_at_startup &&
460 filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f;
461
462 // The linear filter can only be used it has had time to converge.
463 usable_linear_estimate_ = sufficient_data_to_converge_at_startup &&
464 sufficient_data_to_converge_at_reset;
465
466 // The linear filter can only be used if an external delay or convergence have
467 // been identified
468 usable_linear_estimate_ =
469 usable_linear_estimate_ && (external_delay || convergence_seen_);
470
471 // If transparent mode is on, deactivate usign the linear filter.
472 usable_linear_estimate_ = usable_linear_estimate_ && !transparent_mode;
473}
474
475AecState::LegacyFilteringQualityAnalyzer::LegacyFilteringQualityAnalyzer(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200476 const EchoCanceller3Config& config)
477 : conservative_initial_phase_(config.filter.conservative_initial_phase),
478 required_blocks_for_convergence_(
479 kNumBlocksPerSecond * (conservative_initial_phase_ ? 1.5f : 0.8f)),
480 linear_and_stable_echo_path_(
481 config.echo_removal_control.linear_and_stable_echo_path),
482 non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
483
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200484void AecState::LegacyFilteringQualityAnalyzer::Reset() {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200485 usable_linear_estimate_ = false;
486 strong_not_saturated_render_blocks_ = 0;
487 if (linear_and_stable_echo_path_) {
488 recent_convergence_during_activity_ = false;
489 }
490 diverged_sequence_size_ = 0;
491 // TODO(peah): Change to ensure proper triggering of usable filter.
492 non_converged_sequence_size_ = 10000;
493 recent_convergence_ = true;
494}
495
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200496void AecState::LegacyFilteringQualityAnalyzer::Update(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200497 bool saturated_echo,
498 bool active_render,
499 bool saturated_capture,
500 bool transparent_mode,
501 const absl::optional<DelayEstimate>& external_delay,
502 bool converged_filter,
503 bool diverged_filter) {
504 diverged_sequence_size_ = diverged_filter ? diverged_sequence_size_ + 1 : 0;
505 if (diverged_sequence_size_ >= 60) {
506 // TODO(peah): Change these lines to ensure proper triggering of usable
507 // filter.
508 non_converged_sequence_size_ = 10000;
509 recent_convergence_ = true;
510 }
511
512 if (converged_filter) {
513 non_converged_sequence_size_ = 0;
514 recent_convergence_ = true;
515 active_non_converged_sequence_size_ = 0;
516 recent_convergence_during_activity_ = true;
517 } else {
518 if (++non_converged_sequence_size_ >= 60 * kNumBlocksPerSecond) {
519 recent_convergence_ = false;
520 }
521
522 if (active_render &&
523 ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
524 recent_convergence_during_activity_ = false;
525 }
526 }
527
528 strong_not_saturated_render_blocks_ +=
529 active_render && !saturated_capture ? 1 : 0;
530 const bool filter_has_had_time_to_converge =
531 strong_not_saturated_render_blocks_ > required_blocks_for_convergence_;
532
533 usable_linear_estimate_ = filter_has_had_time_to_converge && external_delay;
534
535 if (!conservative_initial_phase_ && recent_convergence_during_activity_) {
536 usable_linear_estimate_ = true;
537 }
538
539 if (!linear_and_stable_echo_path_ && !recent_convergence_) {
540 usable_linear_estimate_ = false;
541 }
542
543 if (saturated_echo || transparent_mode) {
544 usable_linear_estimate_ = false;
545 }
546}
547
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200548void AecState::SaturationDetector::Update(
549 rtc::ArrayView<const float> x,
550 bool saturated_capture,
551 bool usable_linear_estimate,
552 const SubtractorOutput& subtractor_output,
553 float echo_path_gain) {
554 saturated_echo_ = saturated_capture;
555 if (usable_linear_estimate) {
556 constexpr float kSaturationThreshold = 20000.f;
557 saturated_echo_ =
558 saturated_echo_ &&
559 (subtractor_output.s_main_max_abs > kSaturationThreshold ||
560 subtractor_output.s_shadow_max_abs > kSaturationThreshold);
561 } else {
562 const float max_sample = fabs(*std::max_element(
563 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; }));
564
565 const float kMargin = 10.f;
566 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
567 saturated_echo_ = saturated_echo_ && peak_echo_amplitude > 32000;
568 }
569}
570
571AecState::LegacySaturationDetector::LegacySaturationDetector(
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200572 const EchoCanceller3Config& config)
573 : echo_can_saturate_(config.ep_strength.echo_can_saturate),
574 not_saturated_sequence_size_(1000) {}
575
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200576void AecState::LegacySaturationDetector::Reset() {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200577 not_saturated_sequence_size_ = 0;
578}
579
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200580void AecState::LegacySaturationDetector::Update(rtc::ArrayView<const float> x,
581 bool saturated_capture,
582 float echo_path_gain) {
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200583 if (!echo_can_saturate_) {
584 saturated_echo_ = false;
585 return;
586 }
587
588 RTC_DCHECK_LT(0, x.size());
589 if (saturated_capture) {
590 const float max_sample = fabs(*std::max_element(
591 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; }));
592
593 // Set flag for potential presence of saturated echo
594 const float kMargin = 10.f;
595 float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
596 if (peak_echo_amplitude > 32000) {
597 not_saturated_sequence_size_ = 0;
598 saturated_echo_ = true;
599 return;
600 }
601 }
602
603 saturated_echo_ = ++not_saturated_sequence_size_ < 5;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100604}
605
peah522d71b2017-02-23 05:16:26 -0800606} // namespace webrtc