blob: 6405d71c2d4c38118d1816550c8fa376a888e6de [file] [log] [blame]
peah522d71b2017-02-23 05:16:26 -08001/*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/aec3/suppression_gain.h"
peah522d71b2017-02-23 05:16:26 -080012
peah522d71b2017-02-23 05:16:26 -080013#include <math.h>
Yves Gerey988cc082018-10-23 12:03:01 +020014#include <stddef.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020015
peah522d71b2017-02-23 05:16:26 -080016#include <algorithm>
peah86afe9d2017-04-06 15:45:32 -070017#include <numeric>
peah522d71b2017-02-23 05:16:26 -080018
Gustaf Ullbergf534a642019-11-25 16:13:58 +010019#include "modules/audio_processing/aec3/dominant_nearend_detector.h"
Gustaf Ullberg8406c432018-06-19 12:31:33 +020020#include "modules/audio_processing/aec3/moving_average.h"
Gustaf Ullbergf534a642019-11-25 16:13:58 +010021#include "modules/audio_processing/aec3/subband_nearend_detector.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/audio_processing/aec3/vector_math.h"
Gustaf Ullberg216af842018-04-26 12:39:11 +020023#include "modules/audio_processing/logging/apm_data_dumper.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "rtc_base/atomic_ops.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "rtc_base/checks.h"
Gustaf Ullberga63d1522021-06-11 14:02:53 +020026#include "system_wrappers/include/field_trial.h"
peahcf02cf12017-04-05 14:18:07 -070027
peah522d71b2017-02-23 05:16:26 -080028namespace webrtc {
29namespace {
30
Gustaf Ullberga63d1522021-06-11 14:02:53 +020031bool UseUnboundedEchoSpectrum() {
32 return field_trial::IsEnabled("WebRTC-Aec3UseUnboundedEchoSpectrum");
33}
34
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +020035void LimitLowFrequencyGains(std::array<float, kFftLengthBy2Plus1>* gain) {
peaha2376e72017-02-27 01:15:24 -080036 // Limit the low frequency gains to avoid the impact of the high-pass filter
37 // on the lower-frequency gain influencing the overall achieved gain.
peah1d680892017-05-23 04:07:10 -070038 (*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]);
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +020039}
peaha2376e72017-02-27 01:15:24 -080040
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +020041void LimitHighFrequencyGains(bool conservative_hf_suppression,
42 std::array<float, kFftLengthBy2Plus1>* gain) {
43 // Limit the high frequency gains to avoid echo leakage due to an imperfect
44 // filter.
45 constexpr size_t kFirstBandToLimit = (64 * 2000) / 8000;
46 const float min_upper_gain = (*gain)[kFirstBandToLimit];
peah1d680892017-05-23 04:07:10 -070047 std::for_each(
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +020048 gain->begin() + kFirstBandToLimit + 1, gain->end(),
peah1d680892017-05-23 04:07:10 -070049 [min_upper_gain](float& a) { a = std::min(a, min_upper_gain); });
50 (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1];
Gustaf Ullberg5ea57492019-11-05 15:19:02 +010051
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +020052 if (conservative_hf_suppression) {
53 // Limits the gain in the frequencies for which the adaptive filter has not
54 // converged.
55 // TODO(peah): Make adaptive to take the actual filter error into account.
56 constexpr size_t kUpperAccurateBandPlus1 = 29;
Gustaf Ullberg5ea57492019-11-05 15:19:02 +010057
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +020058 constexpr float oneByBandsInSum =
59 1 / static_cast<float>(kUpperAccurateBandPlus1 - 20);
60 const float hf_gain_bound =
61 std::accumulate(gain->begin() + 20,
62 gain->begin() + kUpperAccurateBandPlus1, 0.f) *
63 oneByBandsInSum;
Gustaf Ullberg5ea57492019-11-05 15:19:02 +010064
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +020065 std::for_each(
66 gain->begin() + kUpperAccurateBandPlus1, gain->end(),
67 [hf_gain_bound](float& a) { a = std::min(a, hf_gain_bound); });
68 }
peaha2376e72017-02-27 01:15:24 -080069}
70
Per Åhgrenb02644f2018-04-17 11:52:17 +020071// Scales the echo according to assessed audibility at the other end.
72void WeightEchoForAudibility(const EchoCanceller3Config& config,
73 rtc::ArrayView<const float> echo,
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +020074 rtc::ArrayView<float> weighted_echo) {
Per Åhgrenb02644f2018-04-17 11:52:17 +020075 RTC_DCHECK_EQ(kFftLengthBy2Plus1, echo.size());
76 RTC_DCHECK_EQ(kFftLengthBy2Plus1, weighted_echo.size());
Per Åhgrenb02644f2018-04-17 11:52:17 +020077
78 auto weigh = [](float threshold, float normalizer, size_t begin, size_t end,
79 rtc::ArrayView<const float> echo,
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +020080 rtc::ArrayView<float> weighted_echo) {
Per Åhgrenb02644f2018-04-17 11:52:17 +020081 for (size_t k = begin; k < end; ++k) {
82 if (echo[k] < threshold) {
83 float tmp = (threshold - echo[k]) * normalizer;
84 weighted_echo[k] = echo[k] * std::max(0.f, 1.f - tmp * tmp);
85 } else {
86 weighted_echo[k] = echo[k];
87 }
Per Åhgrenb02644f2018-04-17 11:52:17 +020088 }
89 };
90
91 float threshold = config.echo_audibility.floor_power *
92 config.echo_audibility.audibility_threshold_lf;
93 float normalizer = 1.f / (threshold - config.echo_audibility.floor_power);
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +020094 weigh(threshold, normalizer, 0, 3, echo, weighted_echo);
Per Åhgrenb02644f2018-04-17 11:52:17 +020095
96 threshold = config.echo_audibility.floor_power *
97 config.echo_audibility.audibility_threshold_mf;
98 normalizer = 1.f / (threshold - config.echo_audibility.floor_power);
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +020099 weigh(threshold, normalizer, 3, 7, echo, weighted_echo);
Per Åhgrenb02644f2018-04-17 11:52:17 +0200100
101 threshold = config.echo_audibility.floor_power *
102 config.echo_audibility.audibility_threshold_hf;
103 normalizer = 1.f / (threshold - config.echo_audibility.floor_power);
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200104 weigh(threshold, normalizer, 7, kFftLengthBy2Plus1, echo, weighted_echo);
Per Åhgrenb02644f2018-04-17 11:52:17 +0200105}
106
peah1d680892017-05-23 04:07:10 -0700107} // namespace
108
Gustaf Ullberg216af842018-04-26 12:39:11 +0200109int SuppressionGain::instance_count_ = 0;
110
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200111float SuppressionGain::UpperBandsGain(
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100112 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> echo_spectrum,
113 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
114 comfort_noise_spectrum,
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200115 const absl::optional<int>& narrow_peak_band,
116 bool saturated_echo,
Per Åhgrence202a02019-09-02 17:01:19 +0200117 const std::vector<std::vector<std::vector<float>>>& render,
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200118 const std::array<float, kFftLengthBy2Plus1>& low_band_gain) const {
119 RTC_DCHECK_LT(0, render.size());
120 if (render.size() == 1) {
121 return 1.f;
122 }
Per Åhgren119e2192019-10-18 08:50:50 +0200123 const size_t num_render_channels = render[0].size();
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200124
125 if (narrow_peak_band &&
126 (*narrow_peak_band > static_cast<int>(kFftLengthBy2Plus1 - 10))) {
127 return 0.001f;
128 }
129
130 constexpr size_t kLowBandGainLimit = kFftLengthBy2 / 2;
131 const float gain_below_8_khz = *std::min_element(
132 low_band_gain.begin() + kLowBandGainLimit, low_band_gain.end());
133
134 // Always attenuate the upper bands when there is saturated echo.
135 if (saturated_echo) {
136 return std::min(0.001f, gain_below_8_khz);
137 }
138
139 // Compute the upper and lower band energies.
140 const auto sum_of_squares = [](float a, float b) { return a + b * b; };
Per Åhgren119e2192019-10-18 08:50:50 +0200141 float low_band_energy = 0.f;
142 for (size_t ch = 0; ch < num_render_channels; ++ch) {
143 const float channel_energy = std::accumulate(
144 render[0][0].begin(), render[0][0].end(), 0.f, sum_of_squares);
145 low_band_energy = std::max(low_band_energy, channel_energy);
146 }
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200147 float high_band_energy = 0.f;
148 for (size_t k = 1; k < render.size(); ++k) {
Per Åhgren119e2192019-10-18 08:50:50 +0200149 for (size_t ch = 0; ch < num_render_channels; ++ch) {
150 const float energy = std::accumulate(
151 render[k][ch].begin(), render[k][ch].end(), 0.f, sum_of_squares);
152 high_band_energy = std::max(high_band_energy, energy);
153 }
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200154 }
155
156 // If there is more power in the lower frequencies than the upper frequencies,
157 // or if the power in upper frequencies is low, do not bound the gain in the
158 // upper bands.
159 float anti_howling_gain;
Per Åhgren17e4c582019-11-27 08:13:24 +0100160 const float activation_threshold =
161 kBlockSize * config_.suppressor.high_bands_suppression
162 .anti_howling_activation_threshold;
163 if (high_band_energy < std::max(low_band_energy, activation_threshold)) {
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200164 anti_howling_gain = 1.f;
165 } else {
166 // In all other cases, bound the gain for upper frequencies.
167 RTC_DCHECK_LE(low_band_energy, high_band_energy);
168 RTC_DCHECK_NE(0.f, high_band_energy);
Per Åhgren17e4c582019-11-27 08:13:24 +0100169 anti_howling_gain =
170 config_.suppressor.high_bands_suppression.anti_howling_gain *
171 sqrtf(low_band_energy / high_band_energy);
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200172 }
173
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200174 float gain_bound = 1.f;
Gustaf Ullbergf534a642019-11-25 16:13:58 +0100175 if (!dominant_nearend_detector_->IsNearendState()) {
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100176 // Bound the upper gain during significant echo activity.
177 const auto& cfg = config_.suppressor.high_bands_suppression;
178 auto low_frequency_energy = [](rtc::ArrayView<const float> spectrum) {
179 RTC_DCHECK_LE(16, spectrum.size());
180 return std::accumulate(spectrum.begin() + 1, spectrum.begin() + 16, 0.f);
181 };
182 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
183 const float echo_sum = low_frequency_energy(echo_spectrum[ch]);
184 const float noise_sum = low_frequency_energy(comfort_noise_spectrum[ch]);
185 if (echo_sum > cfg.enr_threshold * noise_sum) {
186 gain_bound = cfg.max_gain_during_echo;
187 break;
188 }
189 }
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200190 }
191
192 // Choose the gain as the minimum of the lower and upper gains.
193 return std::min(std::min(gain_below_8_khz, anti_howling_gain), gain_bound);
194}
195
Gustaf Ullbergec642172018-07-03 13:48:32 +0200196// Computes the gain to reduce the echo to a non audible level.
197void SuppressionGain::GainToNoAudibleEcho(
198 const std::array<float, kFftLengthBy2Plus1>& nearend,
199 const std::array<float, kFftLengthBy2Plus1>& echo,
200 const std::array<float, kFftLengthBy2Plus1>& masker,
Gustaf Ullbergec642172018-07-03 13:48:32 +0200201 std::array<float, kFftLengthBy2Plus1>* gain) const {
Gustaf Ullbergf534a642019-11-25 16:13:58 +0100202 const auto& p = dominant_nearend_detector_->IsNearendState() ? nearend_params_
203 : normal_params_;
Gustaf Ullbergec642172018-07-03 13:48:32 +0200204 for (size_t k = 0; k < gain->size(); ++k) {
205 float enr = echo[k] / (nearend[k] + 1.f); // Echo-to-nearend ratio.
206 float emr = echo[k] / (masker[k] + 1.f); // Echo-to-masker (noise) ratio.
207 float g = 1.0f;
Per Åhgren524e8782018-08-24 22:48:49 +0200208 if (enr > p.enr_transparent_[k] && emr > p.emr_transparent_[k]) {
209 g = (p.enr_suppress_[k] - enr) /
210 (p.enr_suppress_[k] - p.enr_transparent_[k]);
211 g = std::max(g, p.emr_transparent_[k] / emr);
Gustaf Ullbergec642172018-07-03 13:48:32 +0200212 }
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100213 (*gain)[k] = g;
Gustaf Ullbergec642172018-07-03 13:48:32 +0200214 }
215}
216
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200217// Compute the minimum gain as the attenuating gain to put the signal just
218// above the zero sample values.
219void SuppressionGain::GetMinGain(
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200220 rtc::ArrayView<const float> weighted_residual_echo,
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100221 rtc::ArrayView<const float> last_nearend,
222 rtc::ArrayView<const float> last_echo,
peah1d680892017-05-23 04:07:10 -0700223 bool low_noise_render,
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200224 bool saturated_echo,
225 rtc::ArrayView<float> min_gain) const {
Per Åhgren31122d62018-04-10 16:33:55 +0200226 if (!saturated_echo) {
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200227 const float min_echo_power =
228 low_noise_render ? config_.echo_audibility.low_render_limit
229 : config_.echo_audibility.normal_render_limit;
230
Gustaf Ullberg2bab5ad2019-04-15 17:15:37 +0200231 for (size_t k = 0; k < min_gain.size(); ++k) {
232 min_gain[k] = weighted_residual_echo[k] > 0.f
233 ? min_echo_power / weighted_residual_echo[k]
234 : 1.f;
peah1d680892017-05-23 04:07:10 -0700235 min_gain[k] = std::min(min_gain[k], 1.f);
236 }
Gustaf Ullbergf534a642019-11-25 16:13:58 +0100237
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000238 if (!initial_state_ ||
239 config_.suppressor.lf_smoothing_during_initial_phase) {
240 const float& dec = dominant_nearend_detector_->IsNearendState()
241 ? nearend_params_.max_dec_factor_lf
242 : normal_params_.max_dec_factor_lf;
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200243
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000244 for (int k = 0; k <= config_.suppressor.last_lf_smoothing_band; ++k) {
245 // Make sure the gains of the low frequencies do not decrease too
246 // quickly after strong nearend.
247 if (last_nearend[k] > last_echo[k] ||
248 k <= config_.suppressor.last_permanent_lf_smoothing_band) {
249 min_gain[k] = std::max(min_gain[k], last_gain_[k] * dec);
250 min_gain[k] = std::min(min_gain[k], 1.f);
251 }
Gustaf Ullberg0e6375e2018-05-04 11:29:02 +0200252 }
253 }
peah1d680892017-05-23 04:07:10 -0700254 } else {
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200255 std::fill(min_gain.begin(), min_gain.end(), 0.f);
peah1d680892017-05-23 04:07:10 -0700256 }
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200257}
peah1d680892017-05-23 04:07:10 -0700258
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200259// Compute the maximum gain by limiting the gain increase from the previous
260// gain.
261void SuppressionGain::GetMaxGain(rtc::ArrayView<float> max_gain) const {
Gustaf Ullbergf534a642019-11-25 16:13:58 +0100262 const auto& inc = dominant_nearend_detector_->IsNearendState()
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200263 ? nearend_params_.max_inc_factor
264 : normal_params_.max_inc_factor;
265 const auto& floor = config_.suppressor.floor_first_increase;
266 for (size_t k = 0; k < max_gain.size(); ++k) {
267 max_gain[k] = std::min(std::max(last_gain_[k] * inc, floor), 1.f);
peah1d680892017-05-23 04:07:10 -0700268 }
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200269}
270
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200271void SuppressionGain::LowerBandGain(
272 bool low_noise_render,
273 const AecState& aec_state,
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100274 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
275 suppressor_input,
276 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo,
277 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise,
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +0200278 bool clock_drift,
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200279 std::array<float, kFftLengthBy2Plus1>* gain) {
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100280 gain->fill(1.f);
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200281 const bool saturated_echo = aec_state.SaturatedEcho();
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200282 std::array<float, kFftLengthBy2Plus1> max_gain;
283 GetMaxGain(max_gain);
peah1d680892017-05-23 04:07:10 -0700284
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100285 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
286 std::array<float, kFftLengthBy2Plus1> G;
287 std::array<float, kFftLengthBy2Plus1> nearend;
288 nearend_smoothers_[ch].Average(suppressor_input[ch], nearend);
peah1d680892017-05-23 04:07:10 -0700289
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100290 // Weight echo power in terms of audibility.
291 std::array<float, kFftLengthBy2Plus1> weighted_residual_echo;
292 WeightEchoForAudibility(config_, residual_echo[ch], weighted_residual_echo);
Per Åhgren85a11a32017-10-02 14:42:06 +0200293
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100294 std::array<float, kFftLengthBy2Plus1> min_gain;
295 GetMinGain(weighted_residual_echo, last_nearend_[ch], last_echo_[ch],
296 low_noise_render, saturated_echo, min_gain);
297
298 GainToNoAudibleEcho(nearend, weighted_residual_echo, comfort_noise[0], &G);
299
300 // Clamp gains.
301 for (size_t k = 0; k < gain->size(); ++k) {
302 G[k] = std::max(std::min(G[k], max_gain[k]), min_gain[k]);
303 (*gain)[k] = std::min((*gain)[k], G[k]);
304 }
305
306 // Store data required for the gain computation of the next block.
307 std::copy(nearend.begin(), nearend.end(), last_nearend_[ch].begin());
308 std::copy(weighted_residual_echo.begin(), weighted_residual_echo.end(),
309 last_echo_[ch].begin());
310 }
311
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +0200312 LimitLowFrequencyGains(gain);
313 // Use conservative high-frequency gains during clock-drift or when not in
314 // dominant nearend.
315 if (!dominant_nearend_detector_->IsNearendState() || clock_drift ||
316 config_.suppressor.conservative_hf_suppression) {
317 LimitHighFrequencyGains(config_.suppressor.conservative_hf_suppression,
318 gain);
319 }
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100320
321 // Store computed gains.
peah1d680892017-05-23 04:07:10 -0700322 std::copy(gain->begin(), gain->end(), last_gain_.begin());
Gustaf Ullberg216af842018-04-26 12:39:11 +0200323
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100324 // Transform gains to amplitude domain.
325 aec3::VectorMath(optimization_).Sqrt(*gain);
peah86afe9d2017-04-06 15:45:32 -0700326}
327
Gustaf Ullbergbd83b912017-10-18 12:32:42 +0200328SuppressionGain::SuppressionGain(const EchoCanceller3Config& config,
Per Åhgren47d7fbd2018-04-24 12:44:29 +0200329 Aec3Optimization optimization,
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100330 int sample_rate_hz,
331 size_t num_capture_channels)
Gustaf Ullberg216af842018-04-26 12:39:11 +0200332 : data_dumper_(
333 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
334 optimization_(optimization),
Per Åhgren5f1a31c2018-03-08 15:54:41 +0100335 config_(config),
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100336 num_capture_channels_(num_capture_channels),
Per Åhgren5f1a31c2018-03-08 15:54:41 +0100337 state_change_duration_blocks_(
Per Åhgren47d7fbd2018-04-24 12:44:29 +0200338 static_cast<int>(config_.filter.config_change_duration_blocks)),
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100339 last_nearend_(num_capture_channels_, {0}),
340 last_echo_(num_capture_channels_, {0}),
341 nearend_smoothers_(
342 num_capture_channels_,
343 aec3::MovingAverage(kFftLengthBy2Plus1,
344 config.suppressor.nearend_average_blocks)),
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000345 nearend_params_(config_.suppressor.last_lf_band,
346 config_.suppressor.first_hf_band,
347 config_.suppressor.nearend_tuning),
348 normal_params_(config_.suppressor.last_lf_band,
349 config_.suppressor.first_hf_band,
Gustaf Ullberga63d1522021-06-11 14:02:53 +0200350 config_.suppressor.normal_tuning),
351 use_unbounded_echo_spectrum_(UseUnboundedEchoSpectrum()) {
Per Åhgren5f1a31c2018-03-08 15:54:41 +0100352 RTC_DCHECK_LT(0, state_change_duration_blocks_);
peah1d680892017-05-23 04:07:10 -0700353 last_gain_.fill(1.f);
Gustaf Ullbergf534a642019-11-25 16:13:58 +0100354 if (config_.suppressor.use_subband_nearend_detection) {
355 dominant_nearend_detector_ = std::make_unique<SubbandNearendDetector>(
356 config_.suppressor.subband_nearend_detection, num_capture_channels_);
357 } else {
358 dominant_nearend_detector_ = std::make_unique<DominantNearendDetector>(
359 config_.suppressor.dominant_nearend_detection, num_capture_channels_);
360 }
361 RTC_DCHECK(dominant_nearend_detector_);
peah522d71b2017-02-23 05:16:26 -0800362}
363
Per Åhgren47d7fbd2018-04-24 12:44:29 +0200364SuppressionGain::~SuppressionGain() = default;
365
peah522d71b2017-02-23 05:16:26 -0800366void SuppressionGain::GetGain(
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100367 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
368 nearend_spectrum,
369 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> echo_spectrum,
370 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
371 residual_echo_spectrum,
372 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
Gustaf Ullberga63d1522021-06-11 14:02:53 +0200373 residual_echo_spectrum_unbounded,
374 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100375 comfort_noise_spectrum,
peah14c11a42017-07-11 06:13:43 -0700376 const RenderSignalAnalyzer& render_signal_analyzer,
Per Åhgren7ddd4632017-10-25 02:59:45 +0200377 const AecState& aec_state,
Per Åhgrence202a02019-09-02 17:01:19 +0200378 const std::vector<std::vector<std::vector<float>>>& render,
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +0200379 bool clock_drift,
peah86afe9d2017-04-06 15:45:32 -0700380 float* high_bands_gain,
381 std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
382 RTC_DCHECK(high_bands_gain);
383 RTC_DCHECK(low_band_gain);
384
Gustaf Ullberga63d1522021-06-11 14:02:53 +0200385 // Choose residual echo spectrum for the dominant nearend detector.
386 const auto echo = use_unbounded_echo_spectrum_
387 ? residual_echo_spectrum_unbounded
388 : residual_echo_spectrum;
389
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100390 // Update the nearend state selection.
Gustaf Ullberga63d1522021-06-11 14:02:53 +0200391 dominant_nearend_detector_->Update(nearend_spectrum, echo,
Gustaf Ullbergf534a642019-11-25 16:13:58 +0100392 comfort_noise_spectrum, initial_state_);
Per Åhgren524e8782018-08-24 22:48:49 +0200393
peah1d680892017-05-23 04:07:10 -0700394 // Compute gain for the lower band.
Per Åhgren5f1a31c2018-03-08 15:54:41 +0100395 bool low_noise_render = low_render_detector_.Detect(render);
Gustaf Ullberg5ea57492019-11-05 15:19:02 +0100396 LowerBandGain(low_noise_render, aec_state, nearend_spectrum,
Gustaf Ullberg7e4ad822020-10-22 14:36:37 +0200397 residual_echo_spectrum, comfort_noise_spectrum, clock_drift,
398 low_band_gain);
peah86afe9d2017-04-06 15:45:32 -0700399
Gustaf Ullberg0cb4a252018-04-26 15:45:44 +0200400 // Compute the gain for the upper bands.
Jesús de Vicente Peña0faf0822018-09-24 12:48:28 +0200401 const absl::optional<int> narrow_peak_band =
402 render_signal_analyzer.NarrowPeakBand();
403
Per Åhgrenfde4aa92018-08-27 14:19:35 +0200404 *high_bands_gain =
405 UpperBandsGain(echo_spectrum, comfort_noise_spectrum, narrow_peak_band,
406 aec_state.SaturatedEcho(), render, *low_band_gain);
Gustaf Ullberga63d1522021-06-11 14:02:53 +0200407
408 data_dumper_->DumpRaw("aec3_dominant_nearend",
409 dominant_nearend_detector_->IsNearendState());
Per Åhgren5f1a31c2018-03-08 15:54:41 +0100410}
411
412void SuppressionGain::SetInitialState(bool state) {
413 initial_state_ = state;
414 if (state) {
415 initial_state_change_counter_ = state_change_duration_blocks_;
416 } else {
417 initial_state_change_counter_ = 0;
418 }
419}
420
peah1d680892017-05-23 04:07:10 -0700421// Detects when the render signal can be considered to have low power and
422// consist of stationary noise.
423bool SuppressionGain::LowNoiseRenderDetector::Detect(
Per Åhgrence202a02019-09-02 17:01:19 +0200424 const std::vector<std::vector<std::vector<float>>>& render) {
peah1d680892017-05-23 04:07:10 -0700425 float x2_sum = 0.f;
426 float x2_max = 0.f;
Per Åhgren0618cbc2020-02-13 21:08:54 +0100427 for (const auto& x_ch : render[0]) {
428 for (const auto& x_k : x_ch) {
Per Åhgren119e2192019-10-18 08:50:50 +0200429 const float x2 = x_k * x_k;
430 x2_sum += x2;
431 x2_max = std::max(x2_max, x2);
432 }
peah522d71b2017-02-23 05:16:26 -0800433 }
Per Åhgren119e2192019-10-18 08:50:50 +0200434 const size_t num_render_channels = render[0].size();
435 x2_sum = x2_sum / num_render_channels;
436 ;
peah1d680892017-05-23 04:07:10 -0700437
438 constexpr float kThreshold = 50.f * 50.f * 64.f;
439 const bool low_noise_render =
440 average_power_ < kThreshold && x2_max < 3 * average_power_;
441 average_power_ = average_power_ * 0.9f + x2_sum * 0.1f;
442 return low_noise_render;
peah522d71b2017-02-23 05:16:26 -0800443}
444
Per Åhgren524e8782018-08-24 22:48:49 +0200445SuppressionGain::GainParameters::GainParameters(
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000446 int last_lf_band,
447 int first_hf_band,
Per Åhgren524e8782018-08-24 22:48:49 +0200448 const EchoCanceller3Config::Suppressor::Tuning& tuning)
449 : max_inc_factor(tuning.max_inc_factor),
450 max_dec_factor_lf(tuning.max_dec_factor_lf) {
451 // Compute per-band masking thresholds.
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000452 RTC_DCHECK_LT(last_lf_band, first_hf_band);
Per Åhgren524e8782018-08-24 22:48:49 +0200453 auto& lf = tuning.mask_lf;
454 auto& hf = tuning.mask_hf;
455 RTC_DCHECK_LT(lf.enr_transparent, lf.enr_suppress);
456 RTC_DCHECK_LT(hf.enr_transparent, hf.enr_suppress);
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000457 for (int k = 0; k < static_cast<int>(kFftLengthBy2Plus1); k++) {
Per Åhgren524e8782018-08-24 22:48:49 +0200458 float a;
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000459 if (k <= last_lf_band) {
Per Åhgren524e8782018-08-24 22:48:49 +0200460 a = 0.f;
Per Åhgrencbdbb8c2021-05-07 23:17:28 +0000461 } else if (k < first_hf_band) {
462 a = (k - last_lf_band) / static_cast<float>(first_hf_band - last_lf_band);
Per Åhgren524e8782018-08-24 22:48:49 +0200463 } else {
464 a = 1.f;
465 }
466 enr_transparent_[k] = (1 - a) * lf.enr_transparent + a * hf.enr_transparent;
467 enr_suppress_[k] = (1 - a) * lf.enr_suppress + a * hf.enr_suppress;
468 emr_transparent_[k] = (1 - a) * lf.emr_transparent + a * hf.emr_transparent;
469 }
470}
471
peah522d71b2017-02-23 05:16:26 -0800472} // namespace webrtc