• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
11 #ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
12 #define MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
13 
14 #include <stddef.h>
15 
16 #include <array>
17 #include <atomic>
18 #include <memory>
19 #include <vector>
20 
21 #include "absl/types/optional.h"
22 #include "api/array_view.h"
23 #include "api/audio/echo_canceller3_config.h"
24 #include "modules/audio_processing/aec3/aec3_common.h"
25 #include "modules/audio_processing/aec3/delay_estimate.h"
26 #include "modules/audio_processing/aec3/echo_audibility.h"
27 #include "modules/audio_processing/aec3/echo_path_variability.h"
28 #include "modules/audio_processing/aec3/erl_estimator.h"
29 #include "modules/audio_processing/aec3/erle_estimator.h"
30 #include "modules/audio_processing/aec3/filter_analyzer.h"
31 #include "modules/audio_processing/aec3/render_buffer.h"
32 #include "modules/audio_processing/aec3/reverb_model_estimator.h"
33 #include "modules/audio_processing/aec3/subtractor_output.h"
34 #include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
35 #include "modules/audio_processing/aec3/transparent_mode.h"
36 
37 namespace webrtc {
38 
39 class ApmDataDumper;
40 
41 // Handles the state and the conditions for the echo removal functionality.
42 class AecState {
43  public:
44   AecState(const EchoCanceller3Config& config, size_t num_capture_channels);
45   ~AecState();
46 
47   // Returns whether the echo subtractor can be used to determine the residual
48   // echo.
UsableLinearEstimate()49   bool UsableLinearEstimate() const {
50     return filter_quality_state_.LinearFilterUsable() &&
51            config_.filter.use_linear_filter;
52   }
53 
54   // Returns whether the echo subtractor output should be used as output.
UseLinearFilterOutput()55   bool UseLinearFilterOutput() const {
56     return filter_quality_state_.LinearFilterUsable() &&
57            config_.filter.use_linear_filter;
58   }
59 
60   // Returns whether the render signal is currently active.
ActiveRender()61   bool ActiveRender() const { return blocks_with_active_render_ > 200; }
62 
63   // Returns the appropriate scaling of the residual echo to match the
64   // audibility.
65   void GetResidualEchoScaling(rtc::ArrayView<float> residual_scaling) const;
66 
67   // Returns whether the stationary properties of the signals are used in the
68   // aec.
UseStationarityProperties()69   bool UseStationarityProperties() const {
70     return config_.echo_audibility.use_stationarity_properties;
71   }
72 
73   // Returns the ERLE.
Erle(bool onset_compensated)74   rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle(
75       bool onset_compensated) const {
76     return erle_estimator_.Erle(onset_compensated);
77   }
78 
79   // Returns the non-capped ERLE.
ErleUnbounded()80   rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> ErleUnbounded()
81       const {
82     return erle_estimator_.ErleUnbounded();
83   }
84 
85   // Returns the fullband ERLE estimate in log2 units.
FullBandErleLog2()86   float FullBandErleLog2() const { return erle_estimator_.FullbandErleLog2(); }
87 
88   // Returns the ERL.
Erl()89   const std::array<float, kFftLengthBy2Plus1>& Erl() const {
90     return erl_estimator_.Erl();
91   }
92 
93   // Returns the time-domain ERL.
ErlTimeDomain()94   float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); }
95 
96   // Returns the delay estimate based on the linear filter.
MinDirectPathFilterDelay()97   int MinDirectPathFilterDelay() const {
98     return delay_state_.MinDirectPathFilterDelay();
99   }
100 
101   // Returns whether the capture signal is saturated.
SaturatedCapture()102   bool SaturatedCapture() const { return capture_signal_saturation_; }
103 
104   // Returns whether the echo signal is saturated.
SaturatedEcho()105   bool SaturatedEcho() const { return saturation_detector_.SaturatedEcho(); }
106 
107   // Updates the capture signal saturation.
UpdateCaptureSaturation(bool capture_signal_saturation)108   void UpdateCaptureSaturation(bool capture_signal_saturation) {
109     capture_signal_saturation_ = capture_signal_saturation;
110   }
111 
112   // Returns whether the transparent mode is active
TransparentModeActive()113   bool TransparentModeActive() const {
114     return transparent_state_ && transparent_state_->Active();
115   }
116 
117   // Takes appropriate action at an echo path change.
118   void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
119 
120   // Returns the decay factor for the echo reverberation. The parameter `mild`
121   // indicates which exponential decay to return. The default one or a milder
122   // one that can be used during nearend regions.
ReverbDecay(bool mild)123   float ReverbDecay(bool mild) const {
124     return reverb_model_estimator_.ReverbDecay(mild);
125   }
126 
127   // Return the frequency response of the reverberant echo.
GetReverbFrequencyResponse()128   rtc::ArrayView<const float> GetReverbFrequencyResponse() const {
129     return reverb_model_estimator_.GetReverbFrequencyResponse();
130   }
131 
132   // Returns whether the transition for going out of the initial stated has
133   // been triggered.
TransitionTriggered()134   bool TransitionTriggered() const {
135     return initial_state_.TransitionTriggered();
136   }
137 
138   // Updates the aec state.
139   // TODO(bugs.webrtc.org/10913): Compute multi-channel ERL.
140   void Update(
141       const absl::optional<DelayEstimate>& external_delay,
142       rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
143           adaptive_filter_frequency_responses,
144       rtc::ArrayView<const std::vector<float>>
145           adaptive_filter_impulse_responses,
146       const RenderBuffer& render_buffer,
147       rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2_refined,
148       rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
149       rtc::ArrayView<const SubtractorOutput> subtractor_output);
150 
151   // Returns filter length in blocks.
FilterLengthBlocks()152   int FilterLengthBlocks() const {
153     // All filters have the same length, so arbitrarily return channel 0 length.
154     return filter_analyzer_.FilterLengthBlocks();
155   }
156 
157  private:
158   static std::atomic<int> instance_count_;
159   std::unique_ptr<ApmDataDumper> data_dumper_;
160   const EchoCanceller3Config config_;
161   const size_t num_capture_channels_;
162   const bool deactivate_initial_state_reset_at_echo_path_change_;
163   const bool full_reset_at_echo_path_change_;
164   const bool subtractor_analyzer_reset_at_echo_path_change_;
165 
166   // Class for controlling the transition from the intial state, which in turn
167   // controls when the filter parameters for the initial state should be used.
168   class InitialState {
169    public:
170     explicit InitialState(const EchoCanceller3Config& config);
171     // Resets the state to again begin in the initial state.
172     void Reset();
173 
174     // Updates the state based on new data.
175     void Update(bool active_render, bool saturated_capture);
176 
177     // Returns whether the initial state is active or not.
InitialStateActive()178     bool InitialStateActive() const { return initial_state_; }
179 
180     // Returns that the transition from the initial state has was started.
TransitionTriggered()181     bool TransitionTriggered() const { return transition_triggered_; }
182 
183    private:
184     const bool conservative_initial_phase_;
185     const float initial_state_seconds_;
186     bool transition_triggered_ = false;
187     bool initial_state_ = true;
188     size_t strong_not_saturated_render_blocks_ = 0;
189   } initial_state_;
190 
191   // Class for choosing the direct-path delay relative to the beginning of the
192   // filter, as well as any other data related to the delay used within
193   // AecState.
194   class FilterDelay {
195    public:
196     FilterDelay(const EchoCanceller3Config& config,
197                 size_t num_capture_channels);
198 
199     // Returns whether an external delay has been reported to the AecState (from
200     // the delay estimator).
ExternalDelayReported()201     bool ExternalDelayReported() const { return external_delay_reported_; }
202 
203     // Returns the delay in blocks relative to the beginning of the filter that
204     // corresponds to the direct path of the echo.
DirectPathFilterDelays()205     rtc::ArrayView<const int> DirectPathFilterDelays() const {
206       return filter_delays_blocks_;
207     }
208 
209     // Returns the minimum delay among the direct path delays relative to the
210     // beginning of the filter
MinDirectPathFilterDelay()211     int MinDirectPathFilterDelay() const { return min_filter_delay_; }
212 
213     // Updates the delay estimates based on new data.
214     void Update(
215         rtc::ArrayView<const int> analyzer_filter_delay_estimates_blocks,
216         const absl::optional<DelayEstimate>& external_delay,
217         size_t blocks_with_proper_filter_adaptation);
218 
219    private:
220     const int delay_headroom_blocks_;
221     bool external_delay_reported_ = false;
222     std::vector<int> filter_delays_blocks_;
223     int min_filter_delay_;
224     absl::optional<DelayEstimate> external_delay_;
225   } delay_state_;
226 
227   // Classifier for toggling transparent mode when there is no echo.
228   std::unique_ptr<TransparentMode> transparent_state_;
229 
230   // Class for analyzing how well the linear filter is, and can be expected to,
231   // perform on the current signals. The purpose of this is for using to
232   // select the echo suppression functionality as well as the input to the echo
233   // suppressor.
234   class FilteringQualityAnalyzer {
235    public:
236     FilteringQualityAnalyzer(const EchoCanceller3Config& config,
237                              size_t num_capture_channels);
238 
239     // Returns whether the linear filter can be used for the echo
240     // canceller output.
LinearFilterUsable()241     bool LinearFilterUsable() const { return overall_usable_linear_estimates_; }
242 
243     // Returns whether an individual filter output can be used for the echo
244     // canceller output.
UsableLinearFilterOutputs()245     const std::vector<bool>& UsableLinearFilterOutputs() const {
246       return usable_linear_filter_estimates_;
247     }
248 
249     // Resets the state of the analyzer.
250     void Reset();
251 
252     // Updates the analysis based on new data.
253     void Update(bool active_render,
254                 bool transparent_mode,
255                 bool saturated_capture,
256                 const absl::optional<DelayEstimate>& external_delay,
257                 bool any_filter_converged);
258 
259    private:
260     const bool use_linear_filter_;
261     bool overall_usable_linear_estimates_ = false;
262     size_t filter_update_blocks_since_reset_ = 0;
263     size_t filter_update_blocks_since_start_ = 0;
264     bool convergence_seen_ = false;
265     std::vector<bool> usable_linear_filter_estimates_;
266   } filter_quality_state_;
267 
268   // Class for detecting whether the echo is to be considered to be
269   // saturated.
270   class SaturationDetector {
271    public:
272     // Returns whether the echo is to be considered saturated.
SaturatedEcho()273     bool SaturatedEcho() const { return saturated_echo_; }
274 
275     // Updates the detection decision based on new data.
276     void Update(const Block& x,
277                 bool saturated_capture,
278                 bool usable_linear_estimate,
279                 rtc::ArrayView<const SubtractorOutput> subtractor_output,
280                 float echo_path_gain);
281 
282    private:
283     bool saturated_echo_ = false;
284   } saturation_detector_;
285 
286   ErlEstimator erl_estimator_;
287   ErleEstimator erle_estimator_;
288   size_t strong_not_saturated_render_blocks_ = 0;
289   size_t blocks_with_active_render_ = 0;
290   bool capture_signal_saturation_ = false;
291   FilterAnalyzer filter_analyzer_;
292   EchoAudibility echo_audibility_;
293   ReverbModelEstimator reverb_model_estimator_;
294   ReverbModel avg_render_reverb_;
295   SubtractorOutputAnalyzer subtractor_output_analyzer_;
296 };
297 
298 }  // namespace webrtc
299 
300 #endif  // MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
301