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> |
Jonas Olsson | a4d8737 | 2019-07-05 19:08:33 +0200 | [diff] [blame] | 14 | |
Yves Gerey | 988cc08 | 2018-10-23 12:03:01 +0200 | [diff] [blame] | 15 | #include <algorithm> |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 16 | #include <numeric> |
| 17 | #include <vector> |
| 18 | |
Jesús de Vicente Peña | 496cedf | 2018-07-04 11:02:09 +0200 | [diff] [blame] | 19 | #include "absl/types/optional.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 20 | #include "api/array_view.h" |
Jesús de Vicente Peña | 496cedf | 2018-07-04 11:02:09 +0200 | [diff] [blame] | 21 | #include "modules/audio_processing/aec3/aec3_common.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 22 | #include "modules/audio_processing/logging/apm_data_dumper.h" |
Steve Anton | 10542f2 | 2019-01-11 09:11:00 -0800 | [diff] [blame] | 23 | #include "rtc_base/atomic_ops.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 24 | #include "rtc_base/checks.h" |
Per Åhgren | d8d09c3 | 2020-04-01 17:30:18 +0200 | [diff] [blame] | 25 | #include "system_wrappers/include/field_trial.h" |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 26 | |
| 27 | namespace webrtc { |
| 28 | namespace { |
| 29 | |
Per Åhgren | d8d09c3 | 2020-04-01 17:30:18 +0200 | [diff] [blame] | 30 | bool DeactivateInitialStateResetAtEchoPathChange() { |
| 31 | return field_trial::IsEnabled( |
| 32 | "WebRTC-Aec3DeactivateInitialStateResetKillSwitch"); |
| 33 | } |
| 34 | |
| 35 | bool FullResetAtEchoPathChange() { |
| 36 | return !field_trial::IsEnabled("WebRTC-Aec3AecStateFullResetKillSwitch"); |
| 37 | } |
| 38 | |
| 39 | bool SubtractorAnalyzerResetAtEchoPathChange() { |
| 40 | return !field_trial::IsEnabled( |
| 41 | "WebRTC-Aec3AecStateSubtractorAnalyzerResetKillSwitch"); |
| 42 | } |
| 43 | |
Per Åhgren | 8718afb | 2019-10-15 10:31:35 +0200 | [diff] [blame] | 44 | void ComputeAvgRenderReverb( |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 45 | const SpectrumBuffer& spectrum_buffer, |
| 46 | int delay_blocks, |
| 47 | float reverb_decay, |
| 48 | ReverbModel* reverb_model, |
| 49 | rtc::ArrayView<float, kFftLengthBy2Plus1> reverb_power_spectrum) { |
| 50 | RTC_DCHECK(reverb_model); |
| 51 | const size_t num_render_channels = spectrum_buffer.buffer[0].size(); |
| 52 | int idx_at_delay = |
| 53 | spectrum_buffer.OffsetIndex(spectrum_buffer.read, delay_blocks); |
| 54 | int idx_past = spectrum_buffer.IncIndex(idx_at_delay); |
| 55 | |
| 56 | std::array<float, kFftLengthBy2Plus1> X2_data; |
| 57 | rtc::ArrayView<const float> X2; |
| 58 | if (num_render_channels > 1) { |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 59 | auto average_channels = |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 60 | [](size_t num_render_channels, |
Sam Zackrisson | 98872dc | 2019-10-18 08:20:09 +0200 | [diff] [blame] | 61 | rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> |
| 62 | spectrum_band_0, |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 63 | rtc::ArrayView<float, kFftLengthBy2Plus1> render_power) { |
| 64 | std::fill(render_power.begin(), render_power.end(), 0.f); |
| 65 | for (size_t ch = 0; ch < num_render_channels; ++ch) { |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 66 | for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { |
| 67 | render_power[k] += spectrum_band_0[ch][k]; |
| 68 | } |
| 69 | } |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 70 | const float normalizer = 1.f / num_render_channels; |
| 71 | for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { |
| 72 | render_power[k] *= normalizer; |
| 73 | } |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 74 | }; |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 75 | average_channels(num_render_channels, spectrum_buffer.buffer[idx_past], |
| 76 | X2_data); |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 77 | reverb_model->UpdateReverbNoFreqShaping( |
| 78 | X2_data, /*power_spectrum_scaling=*/1.0f, reverb_decay); |
| 79 | |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 80 | average_channels(num_render_channels, spectrum_buffer.buffer[idx_at_delay], |
| 81 | X2_data); |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 82 | X2 = X2_data; |
| 83 | } else { |
| 84 | reverb_model->UpdateReverbNoFreqShaping( |
| 85 | spectrum_buffer.buffer[idx_past][/*channel=*/0], |
| 86 | /*power_spectrum_scaling=*/1.0f, reverb_decay); |
| 87 | |
| 88 | X2 = spectrum_buffer.buffer[idx_at_delay][/*channel=*/0]; |
| 89 | } |
| 90 | |
| 91 | rtc::ArrayView<const float, kFftLengthBy2Plus1> reverb_power = |
| 92 | reverb_model->reverb(); |
| 93 | for (size_t k = 0; k < X2.size(); ++k) { |
| 94 | reverb_power_spectrum[k] = X2[k] + reverb_power[k]; |
| 95 | } |
| 96 | } |
| 97 | |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 98 | } // namespace |
| 99 | |
| 100 | int AecState::instance_count_ = 0; |
| 101 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 102 | void AecState::GetResidualEchoScaling( |
| 103 | rtc::ArrayView<float> residual_scaling) const { |
| 104 | bool filter_has_had_time_to_converge; |
| 105 | if (config_.filter.conservative_initial_phase) { |
| 106 | filter_has_had_time_to_converge = |
| 107 | strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond; |
| 108 | } else { |
| 109 | filter_has_had_time_to_converge = |
| 110 | strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond; |
| 111 | } |
| 112 | echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge, |
| 113 | residual_scaling); |
| 114 | } |
| 115 | |
| 116 | absl::optional<float> AecState::ErleUncertainty() const { |
Gustaf Ullberg | 68d6d44 | 2019-01-29 10:08:15 +0100 | [diff] [blame] | 117 | if (SaturatedEcho()) { |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 118 | return 1.f; |
| 119 | } |
| 120 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 121 | return absl::nullopt; |
| 122 | } |
| 123 | |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 124 | AecState::AecState(const EchoCanceller3Config& config, |
| 125 | size_t num_capture_channels) |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 126 | : data_dumper_( |
| 127 | new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), |
peah | 8cee56f | 2017-08-24 22:36:53 -0700 | [diff] [blame] | 128 | config_(config), |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 129 | num_capture_channels_(num_capture_channels), |
Per Åhgren | d8d09c3 | 2020-04-01 17:30:18 +0200 | [diff] [blame] | 130 | deactivate_initial_state_reset_at_echo_path_change_( |
| 131 | DeactivateInitialStateResetAtEchoPathChange()), |
| 132 | full_reset_at_echo_path_change_(FullResetAtEchoPathChange()), |
| 133 | subtractor_analyzer_reset_at_echo_path_change_( |
| 134 | SubtractorAnalyzerResetAtEchoPathChange()), |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 135 | initial_state_(config_), |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 136 | delay_state_(config_, num_capture_channels_), |
Gustaf Ullberg | afef7a7 | 2020-09-24 09:21:49 +0200 | [diff] [blame] | 137 | transparent_state_(TransparentMode::Create(config_)), |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 138 | filter_quality_state_(config_, num_capture_channels_), |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 139 | erl_estimator_(2 * kNumBlocksPerSecond), |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 140 | erle_estimator_(2 * kNumBlocksPerSecond, config_, num_capture_channels_), |
| 141 | filter_analyzer_(config_, num_capture_channels_), |
Jesús de Vicente Peña | 836a7a2 | 2018-08-31 15:03:04 +0200 | [diff] [blame] | 142 | echo_audibility_( |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 143 | config_.echo_audibility.use_stationarity_properties_at_init), |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 144 | reverb_model_estimator_(config_, num_capture_channels_), |
| 145 | subtractor_output_analyzer_(num_capture_channels_) {} |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 146 | |
| 147 | AecState::~AecState() = default; |
| 148 | |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 149 | void AecState::HandleEchoPathChange( |
| 150 | const EchoPathVariability& echo_path_variability) { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 151 | const auto full_reset = [&]() { |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 152 | filter_analyzer_.Reset(); |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 153 | capture_signal_saturation_ = false; |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 154 | strong_not_saturated_render_blocks_ = 0; |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 155 | blocks_with_active_render_ = 0; |
Per Åhgren | d8d09c3 | 2020-04-01 17:30:18 +0200 | [diff] [blame] | 156 | if (!deactivate_initial_state_reset_at_echo_path_change_) { |
| 157 | initial_state_.Reset(); |
| 158 | } |
Gustaf Ullberg | afef7a7 | 2020-09-24 09:21:49 +0200 | [diff] [blame] | 159 | if (transparent_state_) { |
| 160 | transparent_state_->Reset(); |
| 161 | } |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 162 | erle_estimator_.Reset(true); |
| 163 | erl_estimator_.Reset(); |
Jesús de Vicente Peña | 70a5963 | 2019-04-16 12:32:15 +0200 | [diff] [blame] | 164 | filter_quality_state_.Reset(); |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 165 | }; |
peah | 6d822ad | 2017-04-10 13:52:14 -0700 | [diff] [blame] | 166 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 167 | // TODO(peah): Refine the reset scheme according to the type of gain and |
| 168 | // delay adjustment. |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 169 | |
Per Åhgren | d8d09c3 | 2020-04-01 17:30:18 +0200 | [diff] [blame] | 170 | if (full_reset_at_echo_path_change_ && |
| 171 | echo_path_variability.delay_change != |
| 172 | EchoPathVariability::DelayAdjustment::kNone) { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame] | 173 | full_reset(); |
Gustaf Ullberg | 68d6d44 | 2019-01-29 10:08:15 +0100 | [diff] [blame] | 174 | } else if (echo_path_variability.gain_change) { |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 175 | erle_estimator_.Reset(false); |
Per Åhgren | d2650d1 | 2018-10-02 17:00:59 +0200 | [diff] [blame] | 176 | } |
Per Åhgren | d8d09c3 | 2020-04-01 17:30:18 +0200 | [diff] [blame] | 177 | if (subtractor_analyzer_reset_at_echo_path_change_) { |
| 178 | subtractor_output_analyzer_.HandleEchoPathChange(); |
| 179 | } |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 180 | } |
| 181 | |
Per Åhgren | 09a718a | 2017-12-11 22:28:45 +0100 | [diff] [blame] | 182 | void AecState::Update( |
Danil Chapovalov | db9f7ab | 2018-06-19 10:50:11 +0200 | [diff] [blame] | 183 | const absl::optional<DelayEstimate>& external_delay, |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 184 | rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>> |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 185 | adaptive_filter_frequency_responses, |
| 186 | rtc::ArrayView<const std::vector<float>> adaptive_filter_impulse_responses, |
Per Åhgren | 09a718a | 2017-12-11 22:28:45 +0100 | [diff] [blame] | 187 | const RenderBuffer& render_buffer, |
Per Åhgren | ff04511 | 2020-03-20 11:20:39 +0100 | [diff] [blame] | 188 | rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2_refined, |
Per Åhgren | f980725 | 2019-10-09 13:57:07 +0200 | [diff] [blame] | 189 | rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2, |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 190 | rtc::ArrayView<const SubtractorOutput> subtractor_output) { |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 191 | RTC_DCHECK_EQ(num_capture_channels_, Y2.size()); |
| 192 | RTC_DCHECK_EQ(num_capture_channels_, subtractor_output.size()); |
| 193 | RTC_DCHECK_EQ(num_capture_channels_, |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 194 | adaptive_filter_frequency_responses.size()); |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 195 | RTC_DCHECK_EQ(num_capture_channels_, |
| 196 | adaptive_filter_impulse_responses.size()); |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 197 | |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 198 | // Analyze the filter outputs and filters. |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 199 | bool any_filter_converged; |
Gustaf Ullberg | 7481ba0 | 2020-10-21 11:44:18 +0200 | [diff] [blame] | 200 | bool any_coarse_filter_converged; |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 201 | bool all_filters_diverged; |
| 202 | subtractor_output_analyzer_.Update(subtractor_output, &any_filter_converged, |
Gustaf Ullberg | 7481ba0 | 2020-10-21 11:44:18 +0200 | [diff] [blame] | 203 | &any_coarse_filter_converged, |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 204 | &all_filters_diverged); |
| 205 | |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 206 | bool any_filter_consistent; |
| 207 | float max_echo_path_gain; |
| 208 | filter_analyzer_.Update(adaptive_filter_impulse_responses, render_buffer, |
| 209 | &any_filter_consistent, &max_echo_path_gain); |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 210 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 211 | // Estimate the direct path delay of the filter. |
Gustaf Ullberg | 9466b66 | 2019-04-15 09:53:03 +0200 | [diff] [blame] | 212 | if (config_.filter.use_linear_filter) { |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 213 | delay_state_.Update(filter_analyzer_.FilterDelaysBlocks(), external_delay, |
Gustaf Ullberg | 9466b66 | 2019-04-15 09:53:03 +0200 | [diff] [blame] | 214 | strong_not_saturated_render_blocks_); |
| 215 | } |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 216 | |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 217 | const std::vector<std::vector<float>>& aligned_render_block = |
Per Åhgren | 88d662a | 2019-10-16 15:32:39 +0200 | [diff] [blame] | 218 | render_buffer.Block(-delay_state_.MinDirectPathFilterDelay())[0]; |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 219 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 220 | // Update render counters. |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 221 | bool active_render = false; |
| 222 | for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) { |
| 223 | const float render_energy = std::inner_product( |
| 224 | aligned_render_block[ch].begin(), aligned_render_block[ch].end(), |
| 225 | aligned_render_block[ch].begin(), 0.f); |
| 226 | if (render_energy > (config_.render_levels.active_render_limit * |
| 227 | config_.render_levels.active_render_limit) * |
| 228 | kFftLengthBy2) { |
| 229 | active_render = true; |
| 230 | break; |
| 231 | } |
| 232 | } |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 233 | blocks_with_active_render_ += active_render ? 1 : 0; |
| 234 | strong_not_saturated_render_blocks_ += |
| 235 | active_render && !SaturatedCapture() ? 1 : 0; |
Per Åhgren | 0e6d2f5 | 2017-12-20 22:19:56 +0100 | [diff] [blame] | 236 | |
Per Åhgren | 8718afb | 2019-10-15 10:31:35 +0200 | [diff] [blame] | 237 | std::array<float, kFftLengthBy2Plus1> avg_render_spectrum_with_reverb; |
Per Åhgren | 1d3008b | 2019-10-09 12:54:43 +0200 | [diff] [blame] | 238 | |
Per Åhgren | 8718afb | 2019-10-15 10:31:35 +0200 | [diff] [blame] | 239 | ComputeAvgRenderReverb(render_buffer.GetSpectrumBuffer(), |
| 240 | delay_state_.MinDirectPathFilterDelay(), ReverbDecay(), |
| 241 | &avg_render_reverb_, avg_render_spectrum_with_reverb); |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 242 | |
Jesús de Vicente Peña | 70a5963 | 2019-04-16 12:32:15 +0200 | [diff] [blame] | 243 | if (config_.echo_audibility.use_stationarity_properties) { |
Jesús de Vicente Peña | d5cb477 | 2018-04-25 13:58:45 +0200 | [diff] [blame] | 244 | // Update the echo audibility evaluator. |
Per Åhgren | 8718afb | 2019-10-15 10:31:35 +0200 | [diff] [blame] | 245 | echo_audibility_.Update(render_buffer, avg_render_reverb_.reverb(), |
| 246 | delay_state_.MinDirectPathFilterDelay(), |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 247 | delay_state_.ExternalDelayReported()); |
Jesús de Vicente Peña | d5cb477 | 2018-04-25 13:58:45 +0200 | [diff] [blame] | 248 | } |
| 249 | |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 250 | // Update the ERL and ERLE measures. |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 251 | if (initial_state_.TransitionTriggered()) { |
| 252 | erle_estimator_.Reset(false); |
Jesús de Vicente Peña | 02e9e44 | 2018-08-29 13:34:07 +0200 | [diff] [blame] | 253 | } |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 254 | |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 255 | erle_estimator_.Update(render_buffer, adaptive_filter_frequency_responses, |
Per Åhgren | ff04511 | 2020-03-20 11:20:39 +0100 | [diff] [blame] | 256 | avg_render_spectrum_with_reverb, Y2, E2_refined, |
Per Åhgren | 785d4c4 | 2019-10-17 14:40:54 +0200 | [diff] [blame] | 257 | subtractor_output_analyzer_.ConvergedFilters()); |
Jesús de Vicente Peña | c98849c | 2018-10-22 11:41:05 +0200 | [diff] [blame] | 258 | |
Sam Zackrisson | 6e5433c | 2019-10-18 16:49:13 +0200 | [diff] [blame] | 259 | erl_estimator_.Update( |
| 260 | subtractor_output_analyzer_.ConvergedFilters(), |
| 261 | render_buffer.Spectrum(delay_state_.MinDirectPathFilterDelay()), Y2); |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 262 | |
Per Åhgren | 63b494d | 2017-12-06 11:32:38 +0100 | [diff] [blame] | 263 | // Detect and flag echo saturation. |
Per Åhgren | d8d09c3 | 2020-04-01 17:30:18 +0200 | [diff] [blame] | 264 | if (config_.ep_strength.echo_can_saturate) { |
| 265 | saturation_detector_.Update(aligned_render_block, SaturatedCapture(), |
| 266 | UsableLinearEstimate(), subtractor_output, |
| 267 | max_echo_path_gain); |
| 268 | } else { |
| 269 | RTC_DCHECK(!saturation_detector_.SaturatedEcho()); |
| 270 | } |
peah | 86afe9d | 2017-04-06 15:45:32 -0700 | [diff] [blame] | 271 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 272 | // Update the decision on whether to use the initial state parameter set. |
| 273 | initial_state_.Update(active_render, SaturatedCapture()); |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 274 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 275 | // Detect whether the transparent mode should be activated. |
Gustaf Ullberg | afef7a7 | 2020-09-24 09:21:49 +0200 | [diff] [blame] | 276 | if (transparent_state_) { |
Gustaf Ullberg | 7481ba0 | 2020-10-21 11:44:18 +0200 | [diff] [blame] | 277 | transparent_state_->Update( |
| 278 | delay_state_.MinDirectPathFilterDelay(), any_filter_consistent, |
| 279 | any_filter_converged, any_coarse_filter_converged, all_filters_diverged, |
| 280 | active_render, SaturatedCapture()); |
Gustaf Ullberg | afef7a7 | 2020-09-24 09:21:49 +0200 | [diff] [blame] | 281 | } |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 282 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 283 | // Analyze the quality of the filter. |
Gustaf Ullberg | afef7a7 | 2020-09-24 09:21:49 +0200 | [diff] [blame] | 284 | filter_quality_state_.Update(active_render, TransparentModeActive(), |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 285 | SaturatedCapture(), external_delay, |
| 286 | any_filter_converged); |
Per Åhgren | a98c807 | 2018-01-15 19:17:16 +0100 | [diff] [blame] | 287 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 288 | // Update the reverb estimate. |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 289 | const bool stationary_block = |
Jesús de Vicente Peña | 70a5963 | 2019-04-16 12:32:15 +0200 | [diff] [blame] | 290 | config_.echo_audibility.use_stationarity_properties && |
Per Åhgren | f4801a1 | 2018-09-27 13:14:02 +0200 | [diff] [blame] | 291 | echo_audibility_.IsBlockStationary(); |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 292 | |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 293 | reverb_model_estimator_.Update( |
| 294 | filter_analyzer_.GetAdjustedFilters(), |
| 295 | adaptive_filter_frequency_responses, |
| 296 | erle_estimator_.GetInstLinearQualityEstimates(), |
| 297 | delay_state_.DirectPathFilterDelays(), |
| 298 | filter_quality_state_.UsableLinearFilterOutputs(), stationary_block); |
Jesús de Vicente Peña | 075cb2b | 2018-06-13 15:13:55 +0200 | [diff] [blame] | 299 | |
Jesús de Vicente Peña | 496cedf | 2018-07-04 11:02:09 +0200 | [diff] [blame] | 300 | erle_estimator_.Dump(data_dumper_); |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 301 | reverb_model_estimator_.Dump(data_dumper_.get()); |
Gustaf Ullberg | afef7a7 | 2020-09-24 09:21:49 +0200 | [diff] [blame] | 302 | data_dumper_->DumpRaw("aec3_active_render", active_render); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 303 | data_dumper_->DumpRaw("aec3_erl", Erl()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 304 | data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain()); |
Per Åhgren | b4161d3 | 2019-10-08 12:35:47 +0200 | [diff] [blame] | 305 | data_dumper_->DumpRaw("aec3_erle", Erle()[0]); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 306 | data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate()); |
Gustaf Ullberg | afef7a7 | 2020-09-24 09:21:49 +0200 | [diff] [blame] | 307 | data_dumper_->DumpRaw("aec3_transparent_mode", TransparentModeActive()); |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 308 | data_dumper_->DumpRaw("aec3_filter_delay", |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 309 | filter_analyzer_.MinFilterDelayBlocks()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 310 | |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 311 | data_dumper_->DumpRaw("aec3_any_filter_consistent", any_filter_consistent); |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 312 | data_dumper_->DumpRaw("aec3_initial_state", |
| 313 | initial_state_.InitialStateActive()); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 314 | data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture()); |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 315 | data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho()); |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 316 | data_dumper_->DumpRaw("aec3_any_filter_converged", any_filter_converged); |
Gustaf Ullberg | 7481ba0 | 2020-10-21 11:44:18 +0200 | [diff] [blame] | 317 | data_dumper_->DumpRaw("aec3_any_coarse_filter_converged", |
| 318 | any_coarse_filter_converged); |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 319 | data_dumper_->DumpRaw("aec3_all_filters_diverged", all_filters_diverged); |
Per Åhgren | 5c532d3 | 2018-03-22 00:29:25 +0100 | [diff] [blame] | 320 | |
| 321 | data_dumper_->DumpRaw("aec3_external_delay_avaliable", |
| 322 | external_delay ? 1 : 0); |
Per Åhgren | ef5d5af | 2018-07-31 00:03:46 +0200 | [diff] [blame] | 323 | data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est", |
| 324 | GetReverbFrequencyResponse()); |
Gustaf Ullberg | 992a96f | 2020-12-08 13:03:55 +0100 | [diff] [blame^] | 325 | data_dumper_->DumpRaw("aec3_subtractor_y2", subtractor_output[0].y2); |
| 326 | data_dumper_->DumpRaw("aec3_subtractor_e2_coarse", |
| 327 | subtractor_output[0].e2_coarse); |
| 328 | data_dumper_->DumpRaw("aec3_subtractor_e2_refined", |
| 329 | subtractor_output[0].e2_refined); |
peah | 2910357 | 2017-07-11 02:54:02 -0700 | [diff] [blame] | 330 | } |
| 331 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 332 | AecState::InitialState::InitialState(const EchoCanceller3Config& config) |
| 333 | : conservative_initial_phase_(config.filter.conservative_initial_phase), |
| 334 | initial_state_seconds_(config.filter.initial_state_seconds) { |
| 335 | Reset(); |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 336 | } |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 337 | void AecState::InitialState::InitialState::Reset() { |
| 338 | initial_state_ = true; |
| 339 | strong_not_saturated_render_blocks_ = 0; |
| 340 | } |
| 341 | void AecState::InitialState::InitialState::Update(bool active_render, |
| 342 | bool saturated_capture) { |
| 343 | strong_not_saturated_render_blocks_ += |
| 344 | active_render && !saturated_capture ? 1 : 0; |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 345 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 346 | // Flag whether the initial state is still active. |
| 347 | bool prev_initial_state = initial_state_; |
| 348 | if (conservative_initial_phase_) { |
| 349 | initial_state_ = |
| 350 | strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond; |
Per Åhgren | 31122d6 | 2018-04-10 16:33:55 +0200 | [diff] [blame] | 351 | } else { |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 352 | initial_state_ = strong_not_saturated_render_blocks_ < |
| 353 | initial_state_seconds_ * kNumBlocksPerSecond; |
Per Åhgren | 31122d6 | 2018-04-10 16:33:55 +0200 | [diff] [blame] | 354 | } |
Per Åhgren | 4b3bc0f | 2017-12-20 15:26:13 +0100 | [diff] [blame] | 355 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 356 | // Flag whether the transition from the initial state has started. |
| 357 | transition_triggered_ = !initial_state_ && prev_initial_state; |
| 358 | } |
| 359 | |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 360 | AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config, |
| 361 | size_t num_capture_channels) |
Sam Zackrisson | fa29279 | 2020-10-05 15:23:04 +0200 | [diff] [blame] | 362 | : delay_headroom_blocks_(config.delay.delay_headroom_samples / kBlockSize), |
| 363 | filter_delays_blocks_(num_capture_channels, delay_headroom_blocks_), |
| 364 | min_filter_delay_(delay_headroom_blocks_) {} |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 365 | |
| 366 | void AecState::FilterDelay::Update( |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 367 | rtc::ArrayView<const int> analyzer_filter_delay_estimates_blocks, |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 368 | const absl::optional<DelayEstimate>& external_delay, |
| 369 | size_t blocks_with_proper_filter_adaptation) { |
| 370 | // Update the delay based on the external delay. |
| 371 | if (external_delay && |
| 372 | (!external_delay_ || external_delay_->delay != external_delay->delay)) { |
| 373 | external_delay_ = external_delay; |
| 374 | external_delay_reported_ = true; |
| 375 | } |
| 376 | |
| 377 | // Override the estimated delay if it is not certain that the filter has had |
| 378 | // time to converge. |
| 379 | const bool delay_estimator_may_not_have_converged = |
| 380 | blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond; |
| 381 | if (delay_estimator_may_not_have_converged && external_delay_) { |
Sam Zackrisson | fa29279 | 2020-10-05 15:23:04 +0200 | [diff] [blame] | 382 | const int delay_guess = delay_headroom_blocks_; |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 383 | std::fill(filter_delays_blocks_.begin(), filter_delays_blocks_.end(), |
| 384 | delay_guess); |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 385 | } else { |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 386 | RTC_DCHECK_EQ(filter_delays_blocks_.size(), |
| 387 | analyzer_filter_delay_estimates_blocks.size()); |
| 388 | std::copy(analyzer_filter_delay_estimates_blocks.begin(), |
| 389 | analyzer_filter_delay_estimates_blocks.end(), |
| 390 | filter_delays_blocks_.begin()); |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 391 | } |
Per Åhgren | 8718afb | 2019-10-15 10:31:35 +0200 | [diff] [blame] | 392 | |
| 393 | min_filter_delay_ = *std::min_element(filter_delays_blocks_.begin(), |
| 394 | filter_delays_blocks_.end()); |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 395 | } |
| 396 | |
Per Åhgren | c5a38ad | 2018-10-04 15:37:54 +0200 | [diff] [blame] | 397 | AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer( |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 398 | const EchoCanceller3Config& config, |
| 399 | size_t num_capture_channels) |
| 400 | : use_linear_filter_(config.filter.use_linear_filter), |
| 401 | usable_linear_filter_estimates_(num_capture_channels, false) {} |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 402 | |
| 403 | void AecState::FilteringQualityAnalyzer::Reset() { |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 404 | std::fill(usable_linear_filter_estimates_.begin(), |
| 405 | usable_linear_filter_estimates_.end(), false); |
| 406 | overall_usable_linear_estimates_ = false; |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 407 | filter_update_blocks_since_reset_ = 0; |
| 408 | } |
| 409 | |
| 410 | void AecState::FilteringQualityAnalyzer::Update( |
| 411 | bool active_render, |
| 412 | bool transparent_mode, |
| 413 | bool saturated_capture, |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 414 | const absl::optional<DelayEstimate>& external_delay, |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 415 | bool any_filter_converged) { |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 416 | // Update blocks counter. |
| 417 | const bool filter_update = active_render && !saturated_capture; |
| 418 | filter_update_blocks_since_reset_ += filter_update ? 1 : 0; |
| 419 | filter_update_blocks_since_start_ += filter_update ? 1 : 0; |
| 420 | |
| 421 | // Store convergence flag when observed. |
Sam Zackrisson | 46b0140 | 2019-10-08 16:17:48 +0200 | [diff] [blame] | 422 | convergence_seen_ = convergence_seen_ || any_filter_converged; |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 423 | |
| 424 | // Verify requirements for achieving a decent filter. The requirements for |
| 425 | // filter adaptation at call startup are more restrictive than after an |
| 426 | // in-call reset. |
| 427 | const bool sufficient_data_to_converge_at_startup = |
| 428 | filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f; |
| 429 | const bool sufficient_data_to_converge_at_reset = |
| 430 | sufficient_data_to_converge_at_startup && |
| 431 | filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f; |
| 432 | |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 433 | // The linear filter can only be used if it has had time to converge. |
| 434 | overall_usable_linear_estimates_ = sufficient_data_to_converge_at_startup && |
| 435 | sufficient_data_to_converge_at_reset; |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 436 | |
| 437 | // The linear filter can only be used if an external delay or convergence have |
| 438 | // been identified |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 439 | overall_usable_linear_estimates_ = |
| 440 | overall_usable_linear_estimates_ && (external_delay || convergence_seen_); |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 441 | |
| 442 | // If transparent mode is on, deactivate usign the linear filter. |
Per Åhgren | 8be669f | 2019-10-11 23:02:26 +0200 | [diff] [blame] | 443 | overall_usable_linear_estimates_ = |
| 444 | overall_usable_linear_estimates_ && !transparent_mode; |
| 445 | |
| 446 | if (use_linear_filter_) { |
| 447 | std::fill(usable_linear_filter_estimates_.begin(), |
| 448 | usable_linear_filter_estimates_.end(), |
| 449 | overall_usable_linear_estimates_); |
| 450 | } |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 451 | } |
| 452 | |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 453 | void AecState::SaturationDetector::Update( |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 454 | rtc::ArrayView<const std::vector<float>> x, |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 455 | bool saturated_capture, |
| 456 | bool usable_linear_estimate, |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 457 | rtc::ArrayView<const SubtractorOutput> subtractor_output, |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 458 | float echo_path_gain) { |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 459 | saturated_echo_ = false; |
| 460 | if (!saturated_capture) { |
| 461 | return; |
| 462 | } |
| 463 | |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 464 | if (usable_linear_estimate) { |
| 465 | constexpr float kSaturationThreshold = 20000.f; |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 466 | for (size_t ch = 0; ch < subtractor_output.size(); ++ch) { |
| 467 | saturated_echo_ = |
| 468 | saturated_echo_ || |
Per Åhgren | ff04511 | 2020-03-20 11:20:39 +0100 | [diff] [blame] | 469 | (subtractor_output[ch].s_refined_max_abs > kSaturationThreshold || |
Per Åhgren | 9d66198 | 2020-03-20 11:26:48 +0100 | [diff] [blame] | 470 | subtractor_output[ch].s_coarse_max_abs > kSaturationThreshold); |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 471 | } |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 472 | } else { |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 473 | float max_sample = 0.f; |
| 474 | for (auto& channel : x) { |
| 475 | for (float sample : channel) { |
| 476 | max_sample = std::max(max_sample, fabsf(sample)); |
| 477 | } |
| 478 | } |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 479 | |
| 480 | const float kMargin = 10.f; |
| 481 | float peak_echo_amplitude = max_sample * echo_path_gain * kMargin; |
Sam Zackrisson | 8f736c0 | 2019-10-01 12:47:53 +0200 | [diff] [blame] | 482 | saturated_echo_ = saturated_echo_ || peak_echo_amplitude > 32000; |
Per Åhgren | 3e7b7b1 | 2018-10-16 14:38:10 +0200 | [diff] [blame] | 483 | } |
| 484 | } |
| 485 | |
peah | 522d71b | 2017-02-23 05:16:26 -0800 | [diff] [blame] | 486 | } // namespace webrtc |