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