blob: 27cc424e076caf1316756fa41bc524c071db1686 [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/subtractor.h"
peah522d71b2017-02-23 05:16:26 -080012
13#include <algorithm>
Yves Gerey988cc082018-10-23 12:03:01 +020014#include <utility>
peah522d71b2017-02-23 05:16:26 -080015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "api/array_view.h"
Per Åhgrend4e69042019-09-05 15:55:58 +020017#include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h"
Yves Gerey988cc082018-10-23 12:03:01 +020018#include "modules/audio_processing/aec3/fft_data.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/audio_processing/logging/apm_data_dumper.h"
20#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010021#include "rtc_base/numerics/safe_minmax.h"
peah522d71b2017-02-23 05:16:26 -080022
23namespace webrtc {
24
25namespace {
26
peah86afe9d2017-04-06 15:45:32 -070027void PredictionError(const Aec3Fft& fft,
28 const FftData& S,
29 rtc::ArrayView<const float> y,
30 std::array<float, kBlockSize>* e,
Per Åhgren45231be2019-05-16 14:43:57 +020031 std::array<float, kBlockSize>* s) {
Per Åhgren7634c162017-12-18 15:45:49 +010032 std::array<float, kFftLength> tmp;
33 fft.Ifft(S, &tmp);
peah522d71b2017-02-23 05:16:26 -080034 constexpr float kScale = 1.0f / kFftLengthBy2;
Per Åhgren7634c162017-12-18 15:45:49 +010035 std::transform(y.begin(), y.end(), tmp.begin() + kFftLengthBy2, e->begin(),
36 [&](float a, float b) { return a - b * kScale; });
peah29103572017-07-11 02:54:02 -070037
38 if (s) {
39 for (size_t k = 0; k < s->size(); ++k) {
Per Åhgren7634c162017-12-18 15:45:49 +010040 (*s)[k] = kScale * tmp[k + kFftLengthBy2];
peah29103572017-07-11 02:54:02 -070041 }
Per Åhgren9845a672018-01-15 13:09:02 +010042 }
peah522d71b2017-02-23 05:16:26 -080043}
Per Åhgrenec22e3f2017-12-20 15:20:37 +010044
Per Åhgren7f5175a2018-07-25 16:30:54 +020045void ScaleFilterOutput(rtc::ArrayView<const float> y,
46 float factor,
47 rtc::ArrayView<float> e,
48 rtc::ArrayView<float> s) {
49 RTC_DCHECK_EQ(y.size(), e.size());
50 RTC_DCHECK_EQ(y.size(), s.size());
51 for (size_t k = 0; k < y.size(); ++k) {
52 s[k] *= factor;
53 e[k] = y[k] - s[k];
54 }
55}
56
peah522d71b2017-02-23 05:16:26 -080057} // namespace
58
Per Åhgren09a718a2017-12-11 22:28:45 +010059Subtractor::Subtractor(const EchoCanceller3Config& config,
Per Åhgrena33dc012019-09-03 23:59:52 +020060 size_t num_render_channels,
61 size_t num_capture_channels,
Per Åhgren09a718a2017-12-11 22:28:45 +010062 ApmDataDumper* data_dumper,
peah522d71b2017-02-23 05:16:26 -080063 Aec3Optimization optimization)
aleloi88b82b52017-02-23 06:27:03 -080064 : fft_(),
65 data_dumper_(data_dumper),
peah522d71b2017-02-23 05:16:26 -080066 optimization_(optimization),
Per Åhgrena98c8072018-01-15 19:17:16 +010067 config_(config),
Per Åhgren7bdf0732019-09-25 14:53:30 +020068 num_capture_channels_(num_capture_channels),
Per Åhgren119e2192019-10-18 08:50:50 +020069 main_filters_(num_capture_channels_),
Per Åhgren7bdf0732019-09-25 14:53:30 +020070 shadow_filter_(num_capture_channels_),
Per Åhgren119e2192019-10-18 08:50:50 +020071 main_gains_(num_capture_channels_),
72 shadow_gains_(num_capture_channels_),
73 filter_misadjustment_estimators_(num_capture_channels_),
74 poor_shadow_filter_counters_(num_capture_channels_, 0),
75 main_frequency_responses_(
Per Åhgren7bdf0732019-09-25 14:53:30 +020076 num_capture_channels_,
77 std::vector<std::array<float, kFftLengthBy2Plus1>>(
78 std::max(config_.filter.main_initial.length_blocks,
79 config_.filter.main.length_blocks),
80 std::array<float, kFftLengthBy2Plus1>())),
Per Åhgren119e2192019-10-18 08:50:50 +020081 main_impulse_responses_(
Per Åhgren7bdf0732019-09-25 14:53:30 +020082 num_capture_channels_,
83 std::vector<float>(GetTimeDomainLength(std::max(
84 config_.filter.main_initial.length_blocks,
85 config_.filter.main.length_blocks)),
86 0.f)) {
87 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
Per Åhgren119e2192019-10-18 08:50:50 +020088 main_filters_[ch] = std::make_unique<AdaptiveFirFilter>(
Per Åhgren7bdf0732019-09-25 14:53:30 +020089 config_.filter.main.length_blocks,
90 config_.filter.main_initial.length_blocks,
91 config.filter.config_change_duration_blocks, num_render_channels,
Per Åhgrenb441acf2019-10-05 09:07:24 +020092 optimization, data_dumper_);
Per Åhgren7bdf0732019-09-25 14:53:30 +020093
94 shadow_filter_[ch] = std::make_unique<AdaptiveFirFilter>(
95 config_.filter.shadow.length_blocks,
96 config_.filter.shadow_initial.length_blocks,
97 config.filter.config_change_duration_blocks, num_render_channels,
Per Åhgrenb441acf2019-10-05 09:07:24 +020098 optimization, data_dumper_);
Per Åhgren119e2192019-10-18 08:50:50 +020099 main_gains_[ch] = std::make_unique<MainFilterUpdateGain>(
Per Åhgren7bdf0732019-09-25 14:53:30 +0200100 config_.filter.main_initial,
101 config_.filter.config_change_duration_blocks);
Per Åhgren119e2192019-10-18 08:50:50 +0200102 shadow_gains_[ch] = std::make_unique<ShadowFilterUpdateGain>(
Per Åhgren7bdf0732019-09-25 14:53:30 +0200103 config_.filter.shadow_initial,
104 config.filter.config_change_duration_blocks);
105 }
106
peah522d71b2017-02-23 05:16:26 -0800107 RTC_DCHECK(data_dumper_);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200108 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
Per Åhgren119e2192019-10-18 08:50:50 +0200109 for (auto& H2_k : main_frequency_responses_[ch]) {
Per Åhgren7bdf0732019-09-25 14:53:30 +0200110 H2_k.fill(0.f);
111 }
Per Åhgrend4e69042019-09-05 15:55:58 +0200112 }
peah522d71b2017-02-23 05:16:26 -0800113}
114
peah29103572017-07-11 02:54:02 -0700115Subtractor::~Subtractor() = default;
peah522d71b2017-02-23 05:16:26 -0800116
117void Subtractor::HandleEchoPathChange(
118 const EchoPathVariability& echo_path_variability) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100119 const auto full_reset = [&]() {
Per Åhgren7bdf0732019-09-25 14:53:30 +0200120 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
Per Åhgren119e2192019-10-18 08:50:50 +0200121 main_filters_[ch]->HandleEchoPathChange();
Per Åhgren7bdf0732019-09-25 14:53:30 +0200122 shadow_filter_[ch]->HandleEchoPathChange();
Per Åhgren119e2192019-10-18 08:50:50 +0200123 main_gains_[ch]->HandleEchoPathChange(echo_path_variability);
124 shadow_gains_[ch]->HandleEchoPathChange();
125 main_gains_[ch]->SetConfig(config_.filter.main_initial, true);
126 shadow_gains_[ch]->SetConfig(config_.filter.shadow_initial, true);
127 main_filters_[ch]->SetSizePartitions(
Per Åhgren7bdf0732019-09-25 14:53:30 +0200128 config_.filter.main_initial.length_blocks, true);
129 shadow_filter_[ch]->SetSizePartitions(
130 config_.filter.shadow_initial.length_blocks, true);
131 }
Per Åhgren8ba58612017-12-01 23:01:44 +0100132 };
133
Per Åhgren88cf0502018-07-16 17:08:41 +0200134 if (echo_path_variability.delay_change !=
135 EchoPathVariability::DelayAdjustment::kNone) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100136 full_reset();
Per Åhgren88cf0502018-07-16 17:08:41 +0200137 }
138
Gustaf Ullberg68d6d442019-01-29 10:08:15 +0100139 if (echo_path_variability.gain_change) {
Per Åhgren7bdf0732019-09-25 14:53:30 +0200140 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
Per Åhgren119e2192019-10-18 08:50:50 +0200141 main_gains_[ch]->HandleEchoPathChange(echo_path_variability);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200142 }
peah522d71b2017-02-23 05:16:26 -0800143 }
144}
145
Per Åhgrena98c8072018-01-15 19:17:16 +0100146void Subtractor::ExitInitialState() {
Per Åhgren7bdf0732019-09-25 14:53:30 +0200147 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
Per Åhgren119e2192019-10-18 08:50:50 +0200148 main_gains_[ch]->SetConfig(config_.filter.main, false);
149 shadow_gains_[ch]->SetConfig(config_.filter.shadow, false);
150 main_filters_[ch]->SetSizePartitions(config_.filter.main.length_blocks,
151 false);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200152 shadow_filter_[ch]->SetSizePartitions(config_.filter.shadow.length_blocks,
153 false);
154 }
Per Åhgrena98c8072018-01-15 19:17:16 +0100155}
156
peahcf02cf12017-04-05 14:18:07 -0700157void Subtractor::Process(const RenderBuffer& render_buffer,
Per Åhgren7bdf0732019-09-25 14:53:30 +0200158 const std::vector<std::vector<float>>& capture,
peah522d71b2017-02-23 05:16:26 -0800159 const RenderSignalAnalyzer& render_signal_analyzer,
peah86afe9d2017-04-06 15:45:32 -0700160 const AecState& aec_state,
Per Åhgren7bdf0732019-09-25 14:53:30 +0200161 rtc::ArrayView<SubtractorOutput> outputs) {
162 RTC_DCHECK_EQ(num_capture_channels_, capture.size());
Per Åhgrenb5adc9e2018-01-15 13:20:20 +0100163
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200164 // Compute the render powers.
Per Åhgrenb441acf2019-10-05 09:07:24 +0200165 const bool same_filter_sizes =
Per Åhgren119e2192019-10-18 08:50:50 +0200166 main_filters_[0]->SizePartitions() == shadow_filter_[0]->SizePartitions();
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200167 std::array<float, kFftLengthBy2Plus1> X2_main;
168 std::array<float, kFftLengthBy2Plus1> X2_shadow_data;
Per Åhgrenb441acf2019-10-05 09:07:24 +0200169 auto& X2_shadow = same_filter_sizes ? X2_main : X2_shadow_data;
170 if (same_filter_sizes) {
Per Åhgren119e2192019-10-18 08:50:50 +0200171 render_buffer.SpectralSum(main_filters_[0]->SizePartitions(), &X2_main);
172 } else if (main_filters_[0]->SizePartitions() >
Per Åhgren7bdf0732019-09-25 14:53:30 +0200173 shadow_filter_[0]->SizePartitions()) {
174 render_buffer.SpectralSums(shadow_filter_[0]->SizePartitions(),
Per Åhgren119e2192019-10-18 08:50:50 +0200175 main_filters_[0]->SizePartitions(), &X2_shadow,
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200176 &X2_main);
177 } else {
Per Åhgren119e2192019-10-18 08:50:50 +0200178 render_buffer.SpectralSums(main_filters_[0]->SizePartitions(),
Per Åhgren7bdf0732019-09-25 14:53:30 +0200179 shadow_filter_[0]->SizePartitions(), &X2_main,
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200180 &X2_shadow);
181 }
182
Per Åhgren7bdf0732019-09-25 14:53:30 +0200183 // Process all capture channels
184 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
185 RTC_DCHECK_EQ(kBlockSize, capture[ch].size());
186 SubtractorOutput& output = outputs[ch];
187 rtc::ArrayView<const float> y = capture[ch];
188 FftData& E_main = output.E_main;
189 FftData E_shadow;
190 std::array<float, kBlockSize>& e_main = output.e_main;
191 std::array<float, kBlockSize>& e_shadow = output.e_shadow;
192
193 FftData S;
194 FftData& G = S;
195
196 // Form the outputs of the main and shadow filters.
Per Åhgren119e2192019-10-18 08:50:50 +0200197 main_filters_[ch]->Filter(render_buffer, &S);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200198 PredictionError(fft_, S, y, &e_main, &output.s_main);
199
200 shadow_filter_[ch]->Filter(render_buffer, &S);
201 PredictionError(fft_, S, y, &e_shadow, &output.s_shadow);
202
203 // Compute the signal powers in the subtractor output.
204 output.ComputeMetrics(y);
205
206 // Adjust the filter if needed.
Per Åhgren119e2192019-10-18 08:50:50 +0200207 bool main_filters_adjusted = false;
208 filter_misadjustment_estimators_[ch].Update(output);
209 if (filter_misadjustment_estimators_[ch].IsAdjustmentNeeded()) {
210 float scale = filter_misadjustment_estimators_[ch].GetMisadjustment();
211 main_filters_[ch]->ScaleFilter(scale);
212 for (auto& h_k : main_impulse_responses_[ch]) {
Per Åhgren7bdf0732019-09-25 14:53:30 +0200213 h_k *= scale;
214 }
215 ScaleFilterOutput(y, scale, e_main, output.s_main);
Per Åhgren119e2192019-10-18 08:50:50 +0200216 filter_misadjustment_estimators_[ch].Reset();
217 main_filters_adjusted = true;
Per Åhgren7bdf0732019-09-25 14:53:30 +0200218 }
219
220 // Compute the FFts of the main and shadow filter outputs.
221 fft_.ZeroPaddedFft(e_main, Aec3Fft::Window::kHanning, &E_main);
222 fft_.ZeroPaddedFft(e_shadow, Aec3Fft::Window::kHanning, &E_shadow);
223
224 // Compute spectra for future use.
225 E_shadow.Spectrum(optimization_, output.E2_shadow);
226 E_main.Spectrum(optimization_, output.E2_main);
227
228 // Update the main filter.
Per Åhgren119e2192019-10-18 08:50:50 +0200229 if (!main_filters_adjusted) {
Per Åhgren7bdf0732019-09-25 14:53:30 +0200230 std::array<float, kFftLengthBy2Plus1> erl;
Per Åhgren119e2192019-10-18 08:50:50 +0200231 ComputeErl(optimization_, main_frequency_responses_[ch], erl);
232 main_gains_[ch]->Compute(X2_main, render_signal_analyzer, output, erl,
233 main_filters_[ch]->SizePartitions(),
234 aec_state.SaturatedCapture(), &G);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200235 } else {
236 G.re.fill(0.f);
237 G.im.fill(0.f);
238 }
Per Åhgren119e2192019-10-18 08:50:50 +0200239 main_filters_[ch]->Adapt(render_buffer, G, &main_impulse_responses_[ch]);
240 main_filters_[ch]->ComputeFrequencyResponse(&main_frequency_responses_[ch]);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200241
242 if (ch == 0) {
243 data_dumper_->DumpRaw("aec3_subtractor_G_main", G.re);
244 data_dumper_->DumpRaw("aec3_subtractor_G_main", G.im);
245 }
246
247 // Update the shadow filter.
Per Åhgren119e2192019-10-18 08:50:50 +0200248 poor_shadow_filter_counters_[ch] =
249 output.e2_main < output.e2_shadow ? poor_shadow_filter_counters_[ch] + 1
Per Åhgren7bdf0732019-09-25 14:53:30 +0200250 : 0;
Per Åhgren119e2192019-10-18 08:50:50 +0200251 if (poor_shadow_filter_counters_[ch] < 5) {
252 shadow_gains_[ch]->Compute(X2_shadow, render_signal_analyzer, E_shadow,
253 shadow_filter_[ch]->SizePartitions(),
254 aec_state.SaturatedCapture(), &G);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200255 } else {
Per Åhgren119e2192019-10-18 08:50:50 +0200256 poor_shadow_filter_counters_[ch] = 0;
257 shadow_filter_[ch]->SetFilter(main_filters_[ch]->SizePartitions(),
258 main_filters_[ch]->GetFilter());
259 shadow_gains_[ch]->Compute(X2_shadow, render_signal_analyzer, E_main,
260 shadow_filter_[ch]->SizePartitions(),
261 aec_state.SaturatedCapture(), &G);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200262 }
263
264 shadow_filter_[ch]->Adapt(render_buffer, G);
265 if (ch == 0) {
266 data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.re);
267 data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.im);
Per Åhgren119e2192019-10-18 08:50:50 +0200268 filter_misadjustment_estimators_[ch].Dump(data_dumper_);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200269 DumpFilters();
270 }
271
272 std::for_each(e_main.begin(), e_main.end(),
273 [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
274
275 if (ch == 0) {
Per Åhgren119e2192019-10-18 08:50:50 +0200276 data_dumper_->DumpWav("aec3_main_filters_output", kBlockSize, &e_main[0],
Per Åhgren7bdf0732019-09-25 14:53:30 +0200277 16000, 1);
278 data_dumper_->DumpWav("aec3_shadow_filter_output", kBlockSize,
279 &e_shadow[0], 16000, 1);
280 }
Per Åhgren7f5175a2018-07-25 16:30:54 +0200281 }
peah522d71b2017-02-23 05:16:26 -0800282}
283
Per Åhgrenb20b9372018-07-13 00:22:54 +0200284void Subtractor::FilterMisadjustmentEstimator::Update(
Per Åhgrene4db6a12018-07-26 15:32:24 +0200285 const SubtractorOutput& output) {
286 e2_acum_ += output.e2_main;
287 y2_acum_ += output.y2;
Jesús de Vicente Peña2e79d2b2018-06-29 16:35:08 +0200288 if (++n_blocks_acum_ == n_blocks_) {
289 if (y2_acum_ > n_blocks_ * 200.f * 200.f * kBlockSize) {
290 float update = (e2_acum_ / y2_acum_);
291 if (e2_acum_ > n_blocks_ * 7500.f * 7500.f * kBlockSize) {
Per Åhgrene4db6a12018-07-26 15:32:24 +0200292 // Duration equal to blockSizeMs * n_blocks_ * 4.
293 overhang_ = 4;
Jesús de Vicente Peña2e79d2b2018-06-29 16:35:08 +0200294 } else {
295 overhang_ = std::max(overhang_ - 1, 0);
296 }
297
298 if ((update < inv_misadjustment_) || (overhang_ > 0)) {
299 inv_misadjustment_ += 0.1f * (update - inv_misadjustment_);
300 }
301 }
302 e2_acum_ = 0.f;
303 y2_acum_ = 0.f;
304 n_blocks_acum_ = 0;
305 }
306}
307
308void Subtractor::FilterMisadjustmentEstimator::Reset() {
309 e2_acum_ = 0.f;
310 y2_acum_ = 0.f;
311 n_blocks_acum_ = 0;
312 inv_misadjustment_ = 0.f;
313 overhang_ = 0.f;
314}
315
316void Subtractor::FilterMisadjustmentEstimator::Dump(
317 ApmDataDumper* data_dumper) const {
318 data_dumper->DumpRaw("aec3_inv_misadjustment_factor", inv_misadjustment_);
319}
320
peah522d71b2017-02-23 05:16:26 -0800321} // namespace webrtc