peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 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 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #include "modules/audio_processing/aec3/aec_state.h" |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 12 | |
| 13 | #include <math.h> |
Yves Gerey | 988cc08 | 2018-10-23 12:03:01 +0200 | [diff] [blame] | 14 | #include <algorithm> |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 15 | #include <numeric> |
| 16 | #include <vector> |
| 17 | |
Jesús de Vicente Peña | 496cedf | 2018-07-04 11:02:09 +0200 | [diff] [blame] | 18 | #include "absl/types/optional.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 19 | #include "api/array_view.h" |
Jesús de Vicente Peña | 496cedf | 2018-07-04 11:02:09 +0200 | [diff] [blame] | 20 | #include "modules/audio_processing/aec3/aec3_common.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 21 | #include "modules/audio_processing/logging/apm_data_dumper.h" |
Steve Anton | 10542f2 | 2019-01-11 09:11:00 -0800 | [diff] [blame^] | 22 | #include "rtc_base/atomic_ops.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 23 | #include "rtc_base/checks.h" |
Per Åhgren | d18e87e | 2018-05-09 12:07:26 +0200 | [diff] [blame] | 24 | #include "system_wrappers/include/field_trial.h" |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 25 | |
| 26 | namespace webrtc { |
| 27 | namespace { |
| 28 | |
Per Åhgren | d2650d1 | 2018-10-02 17:00:59 +0200 | [diff] [blame] | 29 | bool EnableErleResetsAtGainChanges() { |
| 30 | return !field_trial::IsEnabled("WebRTC-Aec3ResetErleAtGainChangesKillSwitch"); |
| 31 | } |
| 32 | |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 33 | bool UseLegacyFilterQualityState() { |
| 34 | return field_trial::IsEnabled("WebRTC-Aec3FilterQualityStateKillSwitch"); |
| 35 | } |
| 36 | |
| 37 | bool EnableLegacySaturationBehavior() { |
| 38 | return field_trial::IsEnabled("WebRTC-Aec3NewSaturationBehaviorKillSwitch"); |
| 39 | } |
| 40 | |
| 41 | bool UseSuppressionGainLimiter() { |
| 42 | return field_trial::IsEnabled("WebRTC-Aec3GainLimiterDeactivationKillSwitch"); |
| 43 | } |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 44 | bool EnableErleUpdatesDuringReverb() { |
| 45 | return !field_trial::IsEnabled( |
| 46 | "WebRTC-Aec3EnableErleUpdatesDuringReverbKillSwitch"); |
| 47 | } |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 48 | |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 49 | constexpr size_t kBlocksSinceConvergencedFilterInit = 10000; |
| 50 | constexpr size_t kBlocksSinceConsistentEstimateInit = 10000; |
| 51 | |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 52 | } // namespace |
| 53 | |
| 54 | int AecState::instance_count_ = 0; |
| 55 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 56 | void 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 | |
| 70 | absl::optional<float> AecState::ErleUncertainty() const { |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 71 | if (SaturatedEcho() && use_legacy_saturation_behavior_) { |
| 72 | return 1.f; |
| 73 | } |
| 74 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 75 | return absl::nullopt; |
| 76 | } |
| 77 | |
Gustaf Ullberg | bd83b91 | 2017-10-18 12:32:42 +0200 | [diff] [blame] | 78 | AecState::AecState(const EchoCanceller3Config& config) |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 79 | : data_dumper_( |
| 80 | new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), |
peah | 8cee56f | 2017-08-24 22:36:53 -0700 | [diff] [blame] | 81 | config_(config), |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 82 | use_legacy_saturation_behavior_(EnableLegacySaturationBehavior()), |
| 83 | enable_erle_resets_at_gain_changes_(EnableErleResetsAtGainChanges()), |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 84 | enable_erle_updates_during_reverb_(EnableErleUpdatesDuringReverb()), |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 85 | use_legacy_filter_quality_(UseLegacyFilterQualityState()), |
| 86 | use_suppressor_gain_limiter_(UseSuppressionGainLimiter()), |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 87 | initial_state_(config_), |
| 88 | delay_state_(config_), |
| 89 | transparent_state_(config_), |
| 90 | filter_quality_state_(config_), |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 91 | legacy_filter_quality_state_(config_), |
| 92 | legacy_saturation_detector_(config_), |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 93 | erl_estimator_(2 * kNumBlocksPerSecond), |
Jesús de Vicente Peña | 44974e1 | 2018-11-20 12:54:23 +0100 | [diff] [blame] | 94 | erle_estimator_(2 * kNumBlocksPerSecond, config_), |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 95 | suppression_gain_limiter_(config_), |
| 96 | filter_analyzer_(config_), |
Jesús de Vicente Peña | 836a7a2 | 2018-08-31 15:03:04 +0200 | [diff] [blame] | 97 | echo_audibility_( |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 98 | config_.echo_audibility.use_stationarity_properties_at_init), |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 99 | reverb_model_estimator_(config_) {} |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 100 | |
| 101 | AecState::~AecState() = default; |
| 102 | |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 103 | void AecState::HandleEchoPathChange( |
| 104 | const EchoPathVariability& echo_path_variability) { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 105 | const auto full_reset = [&]() { |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 106 | filter_analyzer_.Reset(); |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 107 | capture_signal_saturation_ = false; |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 108 | strong_not_saturated_render_blocks_ = 0; |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 109 | blocks_with_active_render_ = 0; |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 110 | if (use_suppressor_gain_limiter_) { |
| 111 | suppression_gain_limiter_.Reset(); |
| 112 | } |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 113 | initial_state_.Reset(); |
| 114 | transparent_state_.Reset(); |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 115 | if (use_legacy_saturation_behavior_) { |
| 116 | legacy_saturation_detector_.Reset(); |
| 117 | } |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 118 | erle_estimator_.Reset(true); |
| 119 | erl_estimator_.Reset(); |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 120 | if (use_legacy_filter_quality_) { |
| 121 | legacy_filter_quality_state_.Reset(); |
| 122 | } else { |
| 123 | filter_quality_state_.Reset(); |
| 124 | } |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 125 | }; |
peah | 6d822ad | 2017-04-10 13:52:14 -0700 | [diff] [blame] | 126 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 127 | // TODO(peah): Refine the reset scheme according to the type of gain and |
| 128 | // delay adjustment. |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 129 | |
| 130 | if (echo_path_variability.delay_change != |
Per Åhgren | 88cf050 | 2018-07-16 17:08:41 +0200 | [diff] [blame] | 131 | EchoPathVariability::DelayAdjustment::kNone) { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 132 | full_reset(); |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 133 | } else if (enable_erle_resets_at_gain_changes_ && |
| 134 | echo_path_variability.gain_change) { |
| 135 | erle_estimator_.Reset(false); |
Per Åhgren | d2650d1 | 2018-10-02 17:00:59 +0200 | [diff] [blame] | 136 | } |
Per Åhgren | b20b937 | 2018-07-13 00:22:54 +0200 | [diff] [blame] | 137 | subtractor_output_analyzer_.HandleEchoPathChange(); |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 138 | } |
| 139 | |
Per Åhgren | 09a718a | 2017-12-11 22:28:45 +0100 | [diff] [blame] | 140 | void AecState::Update( |
Danil Chapovalov | db9f7ab | 2018-06-19 10:50:11 +0200 | [diff] [blame] | 141 | const absl::optional<DelayEstimate>& external_delay, |
Per Åhgren | 09a718a | 2017-12-11 22:28:45 +0100 | [diff] [blame] | 142 | const std::vector<std::array<float, kFftLengthBy2Plus1>>& |
| 143 | adaptive_filter_frequency_response, |
| 144 | const std::vector<float>& adaptive_filter_impulse_response, |
Per Åhgren | 09a718a | 2017-12-11 22:28:45 +0100 | [diff] [blame] | 145 | const RenderBuffer& render_buffer, |
| 146 | const std::array<float, kFftLengthBy2Plus1>& E2_main, |
| 147 | const std::array<float, kFftLengthBy2Plus1>& Y2, |
Per Åhgren | b20b937 | 2018-07-13 00:22:54 +0200 | [diff] [blame] | 148 | const SubtractorOutput& subtractor_output, |
| 149 | rtc::ArrayView<const float> y) { |
| 150 | // Analyze the filter output. |
Per Åhgren | e4db6a1 | 2018-07-26 15:32:24 +0200 | [diff] [blame] | 151 | subtractor_output_analyzer_.Update(subtractor_output); |
Per Åhgren | b20b937 | 2018-07-13 00:22:54 +0200 | [diff] [blame] | 152 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 153 | // Analyze the properties of the filter. |
Jesús de Vicente Peña | cf69d22 | 2018-11-27 09:24:29 +0100 | [diff] [blame] | 154 | filter_analyzer_.Update(adaptive_filter_impulse_response, render_buffer); |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 155 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 156 | // Estimate the direct path delay of the filter. |
| 157 | delay_state_.Update(filter_analyzer_, external_delay, |
| 158 | strong_not_saturated_render_blocks_); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 159 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 160 | const std::vector<float>& aligned_render_block = |
| 161 | render_buffer.Block(-delay_state_.DirectPathFilterDelay())[0]; |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 162 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 163 | // 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 Åhgren | 0e6d2f5 | 2017-12-20 22:19:56 +0100 | [diff] [blame] | 174 | |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 175 | 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 Åhgren | 6204adf | 2018-08-19 11:12:00 +0200 | [diff] [blame] | 184 | } |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 185 | |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 186 | 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 Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 192 | if (config_.echo_audibility.use_stationary_properties) { |
Jesús de Vicente Peña | d5cb477 | 2018-04-25 13:58:45 +0200 | [diff] [blame] | 193 | // Update the echo audibility evaluator. |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 194 | echo_audibility_.Update(render_buffer, |
| 195 | render_reverb_.GetReverbContributionPowerSpectrum(), |
| 196 | delay_state_.DirectPathFilterDelay(), |
| 197 | delay_state_.ExternalDelayReported()); |
Jesús de Vicente Peña | d5cb477 | 2018-04-25 13:58:45 +0200 | [diff] [blame] | 198 | } |
| 199 | |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 200 | // Update the ERL and ERLE measures. |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 201 | if (initial_state_.TransitionTriggered()) { |
| 202 | erle_estimator_.Reset(false); |
Jesús de Vicente Peña | 02e9e44 | 2018-08-29 13:34:07 +0200 | [diff] [blame] | 203 | } |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 204 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 205 | const auto& X2 = render_buffer.Spectrum(delay_state_.DirectPathFilterDelay()); |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 206 | const auto& X2_input_erle = |
| 207 | enable_erle_updates_during_reverb_ ? X2_reverb : X2; |
| 208 | |
Jesús de Vicente Peña | 44974e1 | 2018-11-20 12:54:23 +0100 | [diff] [blame] | 209 | erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response, |
| 210 | X2_input_erle, Y2, E2_main, |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 211 | subtractor_output_analyzer_.ConvergedFilter(), |
| 212 | config_.erle.onset_detection); |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 213 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 214 | erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilter(), X2, Y2); |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 215 | |
Per Åhgren | 63b494d | 2017-12-06 11:32:38 +0100 | [diff] [blame] | 216 | // Detect and flag echo saturation. |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 217 | 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 | } |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 225 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 226 | // Update the decision on whether to use the initial state parameter set. |
| 227 | initial_state_.Update(active_render, SaturatedCapture()); |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 228 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 229 | // 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 Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 235 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 236 | // Analyze the quality of the filter. |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 237 | 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 Åhgren | a98c807 | 2018-01-15 19:17:16 +0100 | [diff] [blame] | 248 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 249 | // Update the reverb estimate. |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 250 | const bool stationary_block = |
Per Åhgren | f4801a1 | 2018-09-27 13:14:02 +0200 | [diff] [blame] | 251 | config_.echo_audibility.use_stationary_properties && |
| 252 | echo_audibility_.IsBlockStationary(); |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 253 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 254 | 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ña | 075cb2b | 2018-06-13 15:13:55 +0200 | [diff] [blame] | 259 | |
Jesús de Vicente Peña | 496cedf | 2018-07-04 11:02:09 +0200 | [diff] [blame] | 260 | erle_estimator_.Dump(data_dumper_); |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 261 | reverb_model_estimator_.Dump(data_dumper_.get()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 262 | data_dumper_->DumpRaw("aec3_erl", Erl()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 263 | data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain()); |
Jesús de Vicente Peña | c0a67ba | 2018-12-21 10:50:06 +0100 | [diff] [blame] | 264 | data_dumper_->DumpRaw("aec3_erle", Erle()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 265 | data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate()); |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 266 | data_dumper_->DumpRaw("aec3_transparent_mode", TransparentMode()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 267 | 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 Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 272 | data_dumper_->DumpRaw("aec3_initial_state", |
| 273 | initial_state_.InitialStateActive()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 274 | data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture()); |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 275 | data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho()); |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 276 | data_dumper_->DumpRaw("aec3_converged_filter", |
| 277 | subtractor_output_analyzer_.ConvergedFilter()); |
| 278 | data_dumper_->DumpRaw("aec3_diverged_filter", |
| 279 | subtractor_output_analyzer_.DivergedFilter()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 280 | |
| 281 | data_dumper_->DumpRaw("aec3_external_delay_avaliable", |
| 282 | external_delay ? 1 : 0); |
Jesús de Vicente Peña | dd09287 | 2018-05-25 16:55:11 +0200 | [diff] [blame] | 283 | data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running", |
| 284 | IsSuppressionGainLimitActive()); |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 285 | data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est", |
| 286 | GetReverbFrequencyResponse()); |
peah | 2910357 | 2017-07-11 02:54:02 -0700 | [diff] [blame] | 287 | } |
| 288 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 289 | AecState::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 Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 293 | } |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 294 | void AecState::InitialState::InitialState::Reset() { |
| 295 | initial_state_ = true; |
| 296 | strong_not_saturated_render_blocks_ = 0; |
| 297 | } |
| 298 | void 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 Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 302 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 303 | // 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 Åhgren | 31122d6 | 2018-04-10 16:33:55 +0200 | [diff] [blame] | 308 | } else { |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 309 | initial_state_ = strong_not_saturated_render_blocks_ < |
| 310 | initial_state_seconds_ * kNumBlocksPerSecond; |
Per Åhgren | 31122d6 | 2018-04-10 16:33:55 +0200 | [diff] [blame] | 311 | } |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 312 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 313 | // Flag whether the transition from the initial state has started. |
| 314 | transition_triggered_ = !initial_state_ && prev_initial_state; |
| 315 | } |
| 316 | |
| 317 | AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config) |
| 318 | : delay_headroom_blocks_(config.delay.delay_headroom_blocks) {} |
| 319 | |
| 320 | void 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 | |
| 342 | AecState::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 | |
| 349 | void 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 | |
| 358 | void 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 | |
| 428 | AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer( |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 429 | const EchoCanceller3Config& config) {} |
| 430 | |
| 431 | void AecState::FilteringQualityAnalyzer::Reset() { |
| 432 | usable_linear_estimate_ = false; |
| 433 | filter_update_blocks_since_reset_ = 0; |
| 434 | } |
| 435 | |
| 436 | void 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 | |
| 473 | AecState::LegacyFilteringQualityAnalyzer::LegacyFilteringQualityAnalyzer( |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 474 | 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 Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 482 | void AecState::LegacyFilteringQualityAnalyzer::Reset() { |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 483 | 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 Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 494 | void AecState::LegacyFilteringQualityAnalyzer::Update( |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 495 | 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 Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 546 | void 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 | |
| 569 | AecState::LegacySaturationDetector::LegacySaturationDetector( |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 570 | const EchoCanceller3Config& config) |
| 571 | : echo_can_saturate_(config.ep_strength.echo_can_saturate), |
| 572 | not_saturated_sequence_size_(1000) {} |
| 573 | |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 574 | void AecState::LegacySaturationDetector::Reset() { |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 575 | not_saturated_sequence_size_ = 0; |
| 576 | } |
| 577 | |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 578 | void AecState::LegacySaturationDetector::Update(rtc::ArrayView<const float> x, |
| 579 | bool saturated_capture, |
| 580 | float echo_path_gain) { |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 581 | 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 Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 602 | } |
| 603 | |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 604 | } // namespace webrtc |