blob: c9d9cf3f3a0bd28c4ab6f6622772c7858b2157ea [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#ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
12#define MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
peah522d71b2017-02-23 05:16:26 -080013
Yves Gerey988cc082018-10-23 12:03:01 +020014#include <stddef.h>
15#include <array>
peah522d71b2017-02-23 05:16:26 -080016#include <memory>
17#include <vector>
18
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +020019#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "api/array_view.h"
Gustaf Ullberg3646f972018-02-14 15:19:04 +010021#include "api/audio/echo_canceller3_config.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/audio_processing/aec3/aec3_common.h"
Per Åhgren3ab308f2018-02-21 08:46:03 +010023#include "modules/audio_processing/aec3/delay_estimate.h"
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +020024#include "modules/audio_processing/aec3/echo_audibility.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/audio_processing/aec3/echo_path_variability.h"
26#include "modules/audio_processing/aec3/erl_estimator.h"
27#include "modules/audio_processing/aec3/erle_estimator.h"
Per Åhgren5c532d32018-03-22 00:29:25 +010028#include "modules/audio_processing/aec3/filter_analyzer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "modules/audio_processing/aec3/render_buffer.h"
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +020030#include "modules/audio_processing/aec3/render_reverb_model.h"
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +020031#include "modules/audio_processing/aec3/reverb_model_estimator.h"
Per Åhgrenb20b9372018-07-13 00:22:54 +020032#include "modules/audio_processing/aec3/subtractor_output.h"
33#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
Per Åhgren12eb8582018-03-06 10:40:51 +010034#include "modules/audio_processing/aec3/suppression_gain_limiter.h"
peah522d71b2017-02-23 05:16:26 -080035
36namespace webrtc {
37
38class ApmDataDumper;
39
40// Handles the state and the conditions for the echo removal functionality.
41class AecState {
42 public:
Gustaf Ullbergbd83b912017-10-18 12:32:42 +020043 explicit AecState(const EchoCanceller3Config& config);
peah522d71b2017-02-23 05:16:26 -080044 ~AecState();
45
Per Åhgren4b3bc0f2017-12-20 15:26:13 +010046 // Returns whether the echo subtractor can be used to determine the residual
47 // echo.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020048 bool UsableLinearEstimate() const {
Per Åhgren3e7b7b12018-10-16 14:38:10 +020049 if (use_legacy_filter_quality_) {
50 return legacy_filter_quality_state_.LinearFilterUsable();
51 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020052 return filter_quality_state_.LinearFilterUsable();
53 }
peah522d71b2017-02-23 05:16:26 -080054
Per Åhgren5c532d32018-03-22 00:29:25 +010055 // Returns whether the echo subtractor output should be used as output.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020056 bool UseLinearFilterOutput() const {
Per Åhgren3e7b7b12018-10-16 14:38:10 +020057 if (use_legacy_filter_quality_) {
58 return legacy_filter_quality_state_.LinearFilterUsable();
59 }
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020060 return filter_quality_state_.LinearFilterUsable();
61 }
Per Åhgren5c532d32018-03-22 00:29:25 +010062
63 // Returns the estimated echo path gain.
Per Åhgrenced31ba2018-05-09 11:48:49 +020064 float EchoPathGain() const { return filter_analyzer_.Gain(); }
peah522d71b2017-02-23 05:16:26 -080065
peah522d71b2017-02-23 05:16:26 -080066 // Returns whether the render signal is currently active.
Per Åhgren4b3bc0f2017-12-20 15:26:13 +010067 bool ActiveRender() const { return blocks_with_active_render_ > 200; }
peahebe77782017-02-27 07:29:21 -080068
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +020069 // Returns the appropriate scaling of the residual echo to match the
70 // audibility.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020071 void GetResidualEchoScaling(rtc::ArrayView<float> residual_scaling) const;
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +020072
73 // Returns whether the stationary properties of the signals are used in the
74 // aec.
Per Åhgrenf4801a12018-09-27 13:14:02 +020075 bool UseStationaryProperties() const {
76 return config_.echo_audibility.use_stationary_properties;
77 }
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +020078
peah522d71b2017-02-23 05:16:26 -080079 // Returns the ERLE.
80 const std::array<float, kFftLengthBy2Plus1>& Erle() const {
81 return erle_estimator_.Erle();
82 }
83
Per Åhgrenc5a38ad2018-10-04 15:37:54 +020084 // Returns an offset to apply to the estimation of the residual echo
85 // computation. Returning nullopt means that no offset should be used, while
86 // any other value will be applied as a multiplier to the estimated residual
87 // echo.
88 absl::optional<float> ErleUncertainty() const;
Gustaf Ullberg6c618c72018-06-28 14:21:16 +020089
Jesús de Vicente Peñae9a7e902018-09-27 11:49:39 +020090 // Returns the fullband ERLE estimate in log2 units.
91 float FullBandErleLog2() const { return erle_estimator_.FullbandErleLog2(); }
Gustaf Ullberg332150d2017-11-22 14:17:39 +010092
peah522d71b2017-02-23 05:16:26 -080093 // Returns the ERL.
94 const std::array<float, kFftLengthBy2Plus1>& Erl() const {
95 return erl_estimator_.Erl();
96 }
97
Gustaf Ullberg332150d2017-11-22 14:17:39 +010098 // Returns the time-domain ERL.
99 float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); }
100
peah522d71b2017-02-23 05:16:26 -0800101 // Returns the delay estimate based on the linear filter.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200102 int FilterDelayBlocks() const { return delay_state_.DirectPathFilterDelay(); }
peah522d71b2017-02-23 05:16:26 -0800103
peah522d71b2017-02-23 05:16:26 -0800104 // Returns whether the capture signal is saturated.
105 bool SaturatedCapture() const { return capture_signal_saturation_; }
106
peah86afe9d2017-04-06 15:45:32 -0700107 // Returns whether the echo signal is saturated.
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200108 bool SaturatedEcho() const {
109 return use_legacy_saturation_behavior_
110 ? legacy_saturation_detector_.SaturatedEcho()
111 : saturation_detector_.SaturatedEcho();
112 }
peah86afe9d2017-04-06 15:45:32 -0700113
peah522d71b2017-02-23 05:16:26 -0800114 // Updates the capture signal saturation.
115 void UpdateCaptureSaturation(bool capture_signal_saturation) {
116 capture_signal_saturation_ = capture_signal_saturation;
117 }
118
Per Åhgren1b4059e2017-10-15 20:19:21 +0200119 // Returns whether the transparent mode is active
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200120 bool TransparentMode() const { return transparent_state_.Active(); }
peah522d71b2017-02-23 05:16:26 -0800121
peah86afe9d2017-04-06 15:45:32 -0700122 // Takes appropriate action at an echo path change.
123 void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
124
peah89420452017-04-07 06:13:39 -0700125 // Returns the decay factor for the echo reverberation.
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200126 float ReverbDecay() const { return reverb_model_estimator_.ReverbDecay(); }
peah89420452017-04-07 06:13:39 -0700127
Per Åhgrenef5d5af2018-07-31 00:03:46 +0200128 // Return the frequency response of the reverberant echo.
129 rtc::ArrayView<const float> GetReverbFrequencyResponse() const {
130 return reverb_model_estimator_.GetReverbFrequencyResponse();
131 }
132
Per Åhgrenb6b00dc2018-02-20 22:18:27 +0100133 // Returns the upper limit for the echo suppression gain.
Per Åhgren12eb8582018-03-06 10:40:51 +0100134 float SuppressionGainLimit() const {
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200135 if (use_suppressor_gain_limiter_) {
136 return suppression_gain_limiter_.Limit();
137 } else {
138 return 1.f;
139 }
Per Åhgren12eb8582018-03-06 10:40:51 +0100140 }
peah6d822ad2017-04-10 13:52:14 -0700141
Jesús de Vicente Peñadd092872018-05-25 16:55:11 +0200142 // Returns whether the suppression gain limiter is active.
143 bool IsSuppressionGainLimitActive() const {
144 return suppression_gain_limiter_.IsActive();
145 }
146
Jesús de Vicente Peña02e9e442018-08-29 13:34:07 +0200147 // Returns whether the transition for going out of the initial stated has
148 // been triggered.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200149 bool TransitionTriggered() const {
150 return initial_state_.TransitionTriggered();
151 }
Per Åhgrena98c8072018-01-15 19:17:16 +0100152
peah522d71b2017-02-23 05:16:26 -0800153 // Updates the aec state.
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +0200154 void Update(const absl::optional<DelayEstimate>& external_delay,
Per Åhgren3ab308f2018-02-21 08:46:03 +0100155 const std::vector<std::array<float, kFftLengthBy2Plus1>>&
peah86afe9d2017-04-06 15:45:32 -0700156 adaptive_filter_frequency_response,
Per Åhgren09a718a2017-12-11 22:28:45 +0100157 const std::vector<float>& adaptive_filter_impulse_response,
peah86afe9d2017-04-06 15:45:32 -0700158 const RenderBuffer& render_buffer,
peah522d71b2017-02-23 05:16:26 -0800159 const std::array<float, kFftLengthBy2Plus1>& E2_main,
peah522d71b2017-02-23 05:16:26 -0800160 const std::array<float, kFftLengthBy2Plus1>& Y2,
Per Åhgrenb20b9372018-07-13 00:22:54 +0200161 const SubtractorOutput& subtractor_output,
162 rtc::ArrayView<const float> y);
peah522d71b2017-02-23 05:16:26 -0800163
Jesús de Vicente Peña075cb2b2018-06-13 15:13:55 +0200164 // Returns filter length in blocks.
165 int FilterLengthBlocks() const {
166 return filter_analyzer_.FilterLengthBlocks();
167 }
168
peah522d71b2017-02-23 05:16:26 -0800169 private:
170 static int instance_count_;
171 std::unique_ptr<ApmDataDumper> data_dumper_;
Per Åhgren90e3fbd2018-05-16 15:25:04 +0200172 const EchoCanceller3Config config_;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200173 const bool use_legacy_saturation_behavior_;
174 const bool enable_erle_resets_at_gain_changes_;
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200175 const bool enable_erle_updates_during_reverb_;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200176 const bool use_legacy_filter_quality_;
177 const bool use_suppressor_gain_limiter_;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200178
179 // Class for controlling the transition from the intial state, which in turn
180 // controls when the filter parameters for the initial state should be used.
181 class InitialState {
182 public:
183 explicit InitialState(const EchoCanceller3Config& config);
184 // Resets the state to again begin in the initial state.
185 void Reset();
186
187 // Updates the state based on new data.
188 void Update(bool active_render, bool saturated_capture);
189
190 // Returns whether the initial state is active or not.
191 bool InitialStateActive() const { return initial_state_; }
192
193 // Returns that the transition from the initial state has was started.
194 bool TransitionTriggered() const { return transition_triggered_; }
195
196 private:
197 const bool conservative_initial_phase_;
198 const float initial_state_seconds_;
199 bool transition_triggered_ = false;
200 bool initial_state_ = true;
201 size_t strong_not_saturated_render_blocks_ = 0;
202 } initial_state_;
203
204 // Class for choosing the direct-path delay relative to the beginning of the
205 // filter, as well as any other data related to the delay used within
206 // AecState.
207 class FilterDelay {
208 public:
209 explicit FilterDelay(const EchoCanceller3Config& config);
210
211 // Returns whether an external delay has been reported to the AecState (from
212 // the delay estimator).
213 bool ExternalDelayReported() const { return external_delay_reported_; }
214
215 // Returns the delay in blocks relative to the beginning of the filter that
216 // corresponds to the direct path of the echo.
217 int DirectPathFilterDelay() const { return filter_delay_blocks_; }
218
219 // Updates the delay estimates based on new data.
220 void Update(const FilterAnalyzer& filter_analyzer,
221 const absl::optional<DelayEstimate>& external_delay,
222 size_t blocks_with_proper_filter_adaptation);
223
224 private:
225 const int delay_headroom_blocks_;
226 bool external_delay_reported_ = false;
227 int filter_delay_blocks_ = 0;
228 absl::optional<DelayEstimate> external_delay_;
229 } delay_state_;
230
231 // Class for detecting and toggling the transparent mode which causes the
232 // suppressor to apply no suppression.
233 class TransparentMode {
234 public:
235 explicit TransparentMode(const EchoCanceller3Config& config);
236
237 // Returns whether the transparent mode should be active.
238 bool Active() const { return transparency_activated_; }
239
240 // Resets the state of the detector.
241 void Reset();
242
243 // Updates the detection deciscion based on new data.
244 void Update(int filter_delay_blocks,
245 bool consistent_filter,
246 bool converged_filter,
247 bool diverged_filter,
248 bool active_render,
249 bool saturated_capture);
250
251 private:
252 const bool bounded_erl_;
253 const bool linear_and_stable_echo_path_;
254 size_t capture_block_counter_ = 0;
255 bool transparency_activated_ = false;
256 size_t active_blocks_since_sane_filter_;
257 bool sane_filter_observed_ = false;
258 bool finite_erl_recently_detected_ = false;
259 size_t non_converged_sequence_size_;
260 size_t diverged_sequence_size_ = 0;
261 size_t active_non_converged_sequence_size_ = 0;
262 size_t num_converged_blocks_ = 0;
263 bool recent_convergence_during_activity_ = false;
264 size_t strong_not_saturated_render_blocks_ = 0;
265 } transparent_state_;
266
267 // Class for analyzing how well the linear filter is, and can be expected to,
268 // perform on the current signals. The purpose of this is for using to
269 // select the echo suppression functionality as well as the input to the echo
270 // suppressor.
271 class FilteringQualityAnalyzer {
272 public:
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200273 FilteringQualityAnalyzer(const EchoCanceller3Config& config);
274
275 // Returns whether the the linear filter can be used for the echo
276 // canceller output.
277 bool LinearFilterUsable() const { return usable_linear_estimate_; }
278
279 // Resets the state of the analyzer.
280 void Reset();
281
282 // Updates the analysis based on new data.
283 void Update(bool active_render,
284 bool transparent_mode,
285 bool saturated_capture,
286 bool consistent_estimate_,
287 const absl::optional<DelayEstimate>& external_delay,
288 bool converged_filter);
289
290 private:
291 bool usable_linear_estimate_ = false;
292 size_t filter_update_blocks_since_reset_ = 0;
293 size_t filter_update_blocks_since_start_ = 0;
294 bool convergence_seen_ = false;
295 } filter_quality_state_;
296
297 // Class containing the legacy functionality for analyzing how well the linear
298 // filter is, and can be expected to perform on the current signals. The
299 // purpose of this is for using to select the echo suppression functionality
300 // as well as the input to the echo suppressor.
301 class LegacyFilteringQualityAnalyzer {
302 public:
303 explicit LegacyFilteringQualityAnalyzer(const EchoCanceller3Config& config);
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200304
305 // Returns whether the the linear filter is can be used for the echo
306 // canceller output.
307 bool LinearFilterUsable() const { return usable_linear_estimate_; }
308
309 // Resets the state of the analyzer.
310 void Reset();
311
312 // Updates the analysis based on new data.
313 void Update(bool saturated_echo,
314 bool active_render,
315 bool saturated_capture,
316 bool transparent_mode,
317 const absl::optional<DelayEstimate>& external_delay,
318 bool converged_filter,
319 bool diverged_filter);
320
321 private:
322 const bool conservative_initial_phase_;
323 const float required_blocks_for_convergence_;
324 const bool linear_and_stable_echo_path_;
325 bool usable_linear_estimate_ = false;
326 size_t strong_not_saturated_render_blocks_ = 0;
327 size_t non_converged_sequence_size_;
328 size_t diverged_sequence_size_ = 0;
329 size_t active_non_converged_sequence_size_ = 0;
330 bool recent_convergence_during_activity_ = false;
331 bool recent_convergence_ = false;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200332 } legacy_filter_quality_state_;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200333
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200334 // Class for detecting whether the echo is to be considered to be
335 // saturated.
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200336 class SaturationDetector {
337 public:
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200338 // Returns whether the echo is to be considered saturated.
339 bool SaturatedEcho() const { return saturated_echo_; };
340
341 // Updates the detection decision based on new data.
342 void Update(rtc::ArrayView<const float> x,
343 bool saturated_capture,
344 bool usable_linear_estimate,
345 const SubtractorOutput& subtractor_output,
346 float echo_path_gain);
347
348 private:
349 bool saturated_echo_ = false;
350 } saturation_detector_;
351
352 // Legacy class for detecting whether the echo is to be considered to be
353 // saturated. This is kept as a fallback solution to use instead of the class
354 // SaturationDetector,
355 class LegacySaturationDetector {
356 public:
357 explicit LegacySaturationDetector(const EchoCanceller3Config& config);
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200358
359 // Returns whether the echo is to be considered saturated.
360 bool SaturatedEcho() const { return saturated_echo_; };
361
362 // Resets the state of the detector.
363 void Reset();
364
365 // Updates the detection decision based on new data.
366 void Update(rtc::ArrayView<const float> x,
367 bool saturated_capture,
368 float echo_path_gain);
369
370 private:
371 const bool echo_can_saturate_;
372 size_t not_saturated_sequence_size_;
373 bool saturated_echo_ = false;
Per Åhgren3e7b7b12018-10-16 14:38:10 +0200374 } legacy_saturation_detector_;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200375
peah522d71b2017-02-23 05:16:26 -0800376 ErlEstimator erl_estimator_;
377 ErleEstimator erle_estimator_;
Per Åhgrenc5a38ad2018-10-04 15:37:54 +0200378 size_t strong_not_saturated_render_blocks_ = 0;
Per Åhgren4b3bc0f2017-12-20 15:26:13 +0100379 size_t blocks_with_active_render_ = 0;
peah522d71b2017-02-23 05:16:26 -0800380 bool capture_signal_saturation_ = false;
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200381
Per Åhgren12eb8582018-03-06 10:40:51 +0100382 SuppressionGainUpperLimiter suppression_gain_limiter_;
Per Åhgren5c532d32018-03-22 00:29:25 +0100383 FilterAnalyzer filter_analyzer_;
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +0200384 absl::optional<DelayEstimate> external_delay_;
Jesús de Vicente Peñad5cb4772018-04-25 13:58:45 +0200385 EchoAudibility echo_audibility_;
Jesús de Vicente Peña496cedf2018-07-04 11:02:09 +0200386 ReverbModelEstimator reverb_model_estimator_;
Jesús de Vicente Peñac98849c2018-10-22 11:41:05 +0200387 RenderReverbModel render_reverb_;
Per Åhgrenb20b9372018-07-13 00:22:54 +0200388 SubtractorOutputAnalyzer subtractor_output_analyzer_;
peah522d71b2017-02-23 05:16:26 -0800389};
390
391} // namespace webrtc
392
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200393#endif // MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_