1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 /*
12 * The core AEC algorithm, which is presented with time-aligned signals.
13 */
14
15 #include "modules/audio_processing/aec/aec_core.h"
16
17 #include <algorithm>
18 #include <math.h>
19 #include <stddef.h> // size_t
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "rtc_base/checks.h"
24 extern "C" {
25 #include "common_audio/ring_buffer.h"
26 }
27 #include "common_audio/signal_processing/include/signal_processing_library.h"
28 #include "modules/audio_processing/aec/aec_common.h"
29 #include "modules/audio_processing/aec/aec_core_optimized_methods.h"
30 #include "modules/audio_processing/logging/apm_data_dumper.h"
31 #include "modules/audio_processing/utility/delay_estimator_wrapper.h"
32 #include "rtc_base/checks.h"
33 #include "system_wrappers/include/cpu_features_wrapper.h"
34 #include "system_wrappers/include/metrics.h"
35 #include "typedefs.h" // NOLINT(build/include)
36 #include "rtc_base/criticalsection.h"
37
38 namespace webrtc {
39 namespace {
40 enum class DelaySource {
41 kSystemDelay, // The delay values come from the OS.
42 kDelayAgnostic, // The delay values come from the DA-AEC.
43 };
44
45 constexpr int kMinDelayLogValue = -200;
46 constexpr int kMaxDelayLogValue = 200;
47 constexpr int kNumDelayLogBuckets = 100;
48
MaybeLogDelayAdjustment(int moved_ms,DelaySource source)49 void MaybeLogDelayAdjustment(int moved_ms, DelaySource source) {
50 if (moved_ms == 0)
51 return;
52 switch (source) {
53 case DelaySource::kSystemDelay:
54 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AecDelayAdjustmentMsSystemValue",
55 moved_ms, kMinDelayLogValue, kMaxDelayLogValue,
56 kNumDelayLogBuckets);
57 return;
58 case DelaySource::kDelayAgnostic:
59 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AecDelayAdjustmentMsAgnosticValue",
60 moved_ms, kMinDelayLogValue, kMaxDelayLogValue,
61 kNumDelayLogBuckets);
62 return;
63 }
64 }
65 } // namespace
66
67 // Buffer size (samples)
68 static const size_t kBufferSizeBlocks = 250; // 1 second of audio in 16 kHz.
69
70 // Metrics
71 static const size_t kSubCountLen = 4;
72 static const size_t kCountLen = 50;
73 static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz.
74
75 // Divergence metric is based on audio level, which gets updated every
76 // |kSubCountLen + 1| * PART_LEN samples. Divergence metric takes the statistics
77 // of |kDivergentFilterFractionAggregationWindowSize| audio levels. The
78 // following value corresponds to 1 second at 16 kHz.
79 static const int kDivergentFilterFractionAggregationWindowSize = 50;
80
81 // Quantities to control H band scaling for SWB input
82 static const float cnScaleHband = 0.4f; // scale for comfort noise in H band.
83 // Initial bin for averaging nlp gain in low band
84 static const int freqAvgIc = PART_LEN / 2;
85
86 // Matlab code to produce table:
87 // win = sqrt(hanning(63)); win = [0 ; win(1:32)];
88 // fprintf(1, '\t%.14f, %.14f, %.14f,\n', win);
89 ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = {
90 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
91 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
92 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
93 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
94 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
95 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
96 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
97 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
98 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
99 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
100 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
101 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
102 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
103 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
104 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
105 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
106 1.00000000000000f};
107
108 // Matlab code to produce table:
109 // weightCurve = [0 ; 0.3 * sqrt(linspace(0,1,64))' + 0.1];
110 // fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', weightCurve);
111 ALIGN16_BEG const float ALIGN16_END WebRtcAec_weightCurve[65] = {
112 0.0000f, 0.1000f, 0.1378f, 0.1535f, 0.1655f, 0.1756f, 0.1845f, 0.1926f,
113 0.2000f, 0.2069f, 0.2134f, 0.2195f, 0.2254f, 0.2309f, 0.2363f, 0.2414f,
114 0.2464f, 0.2512f, 0.2558f, 0.2604f, 0.2648f, 0.2690f, 0.2732f, 0.2773f,
115 0.2813f, 0.2852f, 0.2890f, 0.2927f, 0.2964f, 0.3000f, 0.3035f, 0.3070f,
116 0.3104f, 0.3138f, 0.3171f, 0.3204f, 0.3236f, 0.3268f, 0.3299f, 0.3330f,
117 0.3360f, 0.3390f, 0.3420f, 0.3449f, 0.3478f, 0.3507f, 0.3535f, 0.3563f,
118 0.3591f, 0.3619f, 0.3646f, 0.3673f, 0.3699f, 0.3726f, 0.3752f, 0.3777f,
119 0.3803f, 0.3828f, 0.3854f, 0.3878f, 0.3903f, 0.3928f, 0.3952f, 0.3976f,
120 0.4000f};
121
122 // Matlab code to produce table:
123 // overDriveCurve = [sqrt(linspace(0,1,65))' + 1];
124 // fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', overDriveCurve);
125 ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65] = {
126 1.0000f, 1.1250f, 1.1768f, 1.2165f, 1.2500f, 1.2795f, 1.3062f, 1.3307f,
127 1.3536f, 1.3750f, 1.3953f, 1.4146f, 1.4330f, 1.4507f, 1.4677f, 1.4841f,
128 1.5000f, 1.5154f, 1.5303f, 1.5449f, 1.5590f, 1.5728f, 1.5863f, 1.5995f,
129 1.6124f, 1.6250f, 1.6374f, 1.6495f, 1.6614f, 1.6731f, 1.6847f, 1.6960f,
130 1.7071f, 1.7181f, 1.7289f, 1.7395f, 1.7500f, 1.7603f, 1.7706f, 1.7806f,
131 1.7906f, 1.8004f, 1.8101f, 1.8197f, 1.8292f, 1.8385f, 1.8478f, 1.8570f,
132 1.8660f, 1.8750f, 1.8839f, 1.8927f, 1.9014f, 1.9100f, 1.9186f, 1.9270f,
133 1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f,
134 2.0000f};
135
136 // Delay Agnostic AEC parameters, still under development and may change.
137 static const float kDelayQualityThresholdMax = 0.07f;
138 static const float kDelayQualityThresholdMin = 0.01f;
139 static const int kInitialShiftOffset = 5;
140 #if !defined(WEBRTC_ANDROID)
141 static const int kDelayCorrectionStart = 1500; // 10 ms chunks
142 #endif
143
144 // Target suppression levels for nlp modes.
145 // log{0.001, 0.00001, 0.00000001}
146 static const float kTargetSupp[3] = {-6.9f, -11.5f, -18.4f};
147
148 // Two sets of parameters, one for the extended filter mode.
149 static const float kExtendedMinOverDrive[3] = {3.0f, 6.0f, 15.0f};
150 static const float kNormalMinOverDrive[3] = {1.0f, 2.0f, 5.0f};
151 const float WebRtcAec_kExtendedSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
152 {0.92f, 0.08f}};
153 const float WebRtcAec_kNormalSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
154 {0.93f, 0.07f}};
155
156 // Number of partitions forming the NLP's "preferred" bands.
157 enum { kPrefBandSize = 24 };
158
159 rtc::CriticalSection WebRtcAec_CriticalSection;
160 WebRtcAecFilterFar WebRtcAec_FilterFar;
161 WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
162 WebRtcAecFilterAdaptation WebRtcAec_FilterAdaptation;
163 WebRtcAecOverdrive WebRtcAec_Overdrive;
164 WebRtcAecSuppress WebRtcAec_Suppress;
165 WebRtcAecComputeCoherence WebRtcAec_ComputeCoherence;
166 WebRtcAecUpdateCoherenceSpectra WebRtcAec_UpdateCoherenceSpectra;
167 WebRtcAecStoreAsComplex WebRtcAec_StoreAsComplex;
168 WebRtcAecPartitionDelay WebRtcAec_PartitionDelay;
169 WebRtcAecWindowData WebRtcAec_WindowData;
170
MulRe(float aRe,float aIm,float bRe,float bIm)171 __inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
172 return aRe * bRe - aIm * bIm;
173 }
174
MulIm(float aRe,float aIm,float bRe,float bIm)175 __inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
176 return aRe * bIm + aIm * bRe;
177 }
178
179 // TODO(minyue): Due to a legacy bug, |framelevel| and |averagelevel| use a
180 // window, of which the length is 1 unit longer than indicated. Remove "+1" when
181 // the code is refactored.
PowerLevel()182 PowerLevel::PowerLevel()
183 : framelevel(kSubCountLen + 1),
184 averagelevel(kCountLen + 1) {
185 }
186
BlockBuffer()187 BlockBuffer::BlockBuffer() {
188 buffer_ = WebRtc_CreateBuffer(kBufferSizeBlocks, sizeof(float) * PART_LEN);
189 RTC_CHECK(buffer_);
190 ReInit();
191 }
192
~BlockBuffer()193 BlockBuffer::~BlockBuffer() {
194 WebRtc_FreeBuffer(buffer_);
195 }
196
ReInit()197 void BlockBuffer::ReInit() {
198 WebRtc_InitBuffer(buffer_);
199 }
200
Insert(const float block[PART_LEN])201 void BlockBuffer::Insert(const float block[PART_LEN]) {
202 WebRtc_WriteBuffer(buffer_, block, 1);
203 }
204
ExtractExtendedBlock(float extended_block[PART_LEN2])205 void BlockBuffer::ExtractExtendedBlock(float extended_block[PART_LEN2]) {
206 float* block_ptr = NULL;
207 RTC_DCHECK_LT(0, AvaliableSpace());
208
209 // Extract the previous block.
210 WebRtc_MoveReadPtr(buffer_, -1);
211 size_t read_elements = WebRtc_ReadBuffer(
212 buffer_, reinterpret_cast<void**>(&block_ptr), &extended_block[0], 1);
213 if (read_elements == 0u) {
214 std::fill_n(&extended_block[0], PART_LEN, 0.0f);
215 } else if (block_ptr != &extended_block[0]) {
216 memcpy(&extended_block[0], block_ptr, PART_LEN * sizeof(float));
217 }
218
219 // Extract the current block.
220 read_elements =
221 WebRtc_ReadBuffer(buffer_, reinterpret_cast<void**>(&block_ptr),
222 &extended_block[PART_LEN], 1);
223 if (read_elements == 0u) {
224 std::fill_n(&extended_block[PART_LEN], PART_LEN, 0.0f);
225 } else if (block_ptr != &extended_block[PART_LEN]) {
226 memcpy(&extended_block[PART_LEN], block_ptr, PART_LEN * sizeof(float));
227 }
228 }
229
AdjustSize(int buffer_size_decrease)230 int BlockBuffer::AdjustSize(int buffer_size_decrease) {
231 return WebRtc_MoveReadPtr(buffer_, buffer_size_decrease);
232 }
233
Size()234 size_t BlockBuffer::Size() {
235 return static_cast<int>(WebRtc_available_read(buffer_));
236 }
237
AvaliableSpace()238 size_t BlockBuffer::AvaliableSpace() {
239 return WebRtc_available_write(buffer_);
240 }
241
DivergentFilterFraction()242 DivergentFilterFraction::DivergentFilterFraction()
243 : count_(0),
244 occurrence_(0),
245 fraction_(-1.0) {
246 }
247
Reset()248 void DivergentFilterFraction::Reset() {
249 Clear();
250 fraction_ = -1.0;
251 }
252
AddObservation(const PowerLevel & nearlevel,const PowerLevel & linoutlevel,const PowerLevel & nlpoutlevel)253 void DivergentFilterFraction::AddObservation(const PowerLevel& nearlevel,
254 const PowerLevel& linoutlevel,
255 const PowerLevel& nlpoutlevel) {
256 const float near_level = nearlevel.framelevel.GetLatestMean();
257 const float level_increase =
258 linoutlevel.framelevel.GetLatestMean() - near_level;
259 const bool output_signal_active = nlpoutlevel.framelevel.GetLatestMean() >
260 40.0 * nlpoutlevel.minlevel;
261 // Level increase should be, in principle, negative, when the filter
262 // does not diverge. Here we allow some margin (0.01 * near end level) and
263 // numerical error (1.0). We count divergence only when the AEC output
264 // signal is active.
265 if (output_signal_active &&
266 level_increase > std::max(0.01 * near_level, 1.0))
267 occurrence_++;
268 ++count_;
269 if (count_ == kDivergentFilterFractionAggregationWindowSize) {
270 fraction_ = static_cast<float>(occurrence_) /
271 kDivergentFilterFractionAggregationWindowSize;
272 Clear();
273 }
274 }
275
GetLatestFraction() const276 float DivergentFilterFraction::GetLatestFraction() const {
277 return fraction_;
278 }
279
Clear()280 void DivergentFilterFraction::Clear() {
281 count_ = 0;
282 occurrence_ = 0;
283 }
284
285 // TODO(minyue): Moving some initialization from WebRtcAec_CreateAec() to ctor.
AecCore(int instance_index)286 AecCore::AecCore(int instance_index)
287 : data_dumper(new ApmDataDumper(instance_index)) {}
288
~AecCore()289 AecCore::~AecCore() {}
290
CmpFloat(const void * a,const void * b)291 static int CmpFloat(const void* a, const void* b) {
292 const float* da = (const float*)a;
293 const float* db = (const float*)b;
294
295 return (*da > *db) - (*da < *db);
296 }
297
FilterFar(int num_partitions,int x_fft_buf_block_pos,float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],float y_fft[2][PART_LEN1])298 static void FilterFar(int num_partitions,
299 int x_fft_buf_block_pos,
300 float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
301 float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
302 float y_fft[2][PART_LEN1]) {
303 int i;
304 for (i = 0; i < num_partitions; i++) {
305 int j;
306 int xPos = (i + x_fft_buf_block_pos) * PART_LEN1;
307 int pos = i * PART_LEN1;
308 // Check for wrap
309 if (i + x_fft_buf_block_pos >= num_partitions) {
310 xPos -= num_partitions * (PART_LEN1);
311 }
312
313 for (j = 0; j < PART_LEN1; j++) {
314 y_fft[0][j] += MulRe(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
315 h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
316 y_fft[1][j] += MulIm(x_fft_buf[0][xPos + j], x_fft_buf[1][xPos + j],
317 h_fft_buf[0][pos + j], h_fft_buf[1][pos + j]);
318 }
319 }
320 }
321
ScaleErrorSignal(float mu,float error_threshold,float x_pow[PART_LEN1],float ef[2][PART_LEN1])322 static void ScaleErrorSignal(float mu,
323 float error_threshold,
324 float x_pow[PART_LEN1],
325 float ef[2][PART_LEN1]) {
326 int i;
327 float abs_ef;
328 for (i = 0; i < (PART_LEN1); i++) {
329 ef[0][i] /= (x_pow[i] + 1e-10f);
330 ef[1][i] /= (x_pow[i] + 1e-10f);
331 abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
332
333 if (abs_ef > error_threshold) {
334 abs_ef = error_threshold / (abs_ef + 1e-10f);
335 ef[0][i] *= abs_ef;
336 ef[1][i] *= abs_ef;
337 }
338
339 // Stepsize factor
340 ef[0][i] *= mu;
341 ef[1][i] *= mu;
342 }
343 }
344
FilterAdaptation(const OouraFft & ooura_fft,int num_partitions,int x_fft_buf_block_pos,float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],float e_fft[2][PART_LEN1],float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1])345 static void FilterAdaptation(
346 const OouraFft& ooura_fft,
347 int num_partitions,
348 int x_fft_buf_block_pos,
349 float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
350 float e_fft[2][PART_LEN1],
351 float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
352 int i, j;
353 float fft[PART_LEN2];
354 for (i = 0; i < num_partitions; i++) {
355 int xPos = (i + x_fft_buf_block_pos) * (PART_LEN1);
356 int pos;
357 // Check for wrap
358 if (i + x_fft_buf_block_pos >= num_partitions) {
359 xPos -= num_partitions * PART_LEN1;
360 }
361
362 pos = i * PART_LEN1;
363
364 for (j = 0; j < PART_LEN; j++) {
365 fft[2 * j] = MulRe(x_fft_buf[0][xPos + j], -x_fft_buf[1][xPos + j],
366 e_fft[0][j], e_fft[1][j]);
367 fft[2 * j + 1] = MulIm(x_fft_buf[0][xPos + j], -x_fft_buf[1][xPos + j],
368 e_fft[0][j], e_fft[1][j]);
369 }
370 fft[1] =
371 MulRe(x_fft_buf[0][xPos + PART_LEN], -x_fft_buf[1][xPos + PART_LEN],
372 e_fft[0][PART_LEN], e_fft[1][PART_LEN]);
373
374 ooura_fft.InverseFft(fft);
375 memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
376
377 // fft scaling
378 {
379 float scale = 2.0f / PART_LEN2;
380 for (j = 0; j < PART_LEN; j++) {
381 fft[j] *= scale;
382 }
383 }
384 ooura_fft.Fft(fft);
385
386 h_fft_buf[0][pos] += fft[0];
387 h_fft_buf[0][pos + PART_LEN] += fft[1];
388
389 for (j = 1; j < PART_LEN; j++) {
390 h_fft_buf[0][pos + j] += fft[2 * j];
391 h_fft_buf[1][pos + j] += fft[2 * j + 1];
392 }
393 }
394 }
395
Overdrive(float overdrive_scaling,const float hNlFb,float hNl[PART_LEN1])396 static void Overdrive(float overdrive_scaling,
397 const float hNlFb,
398 float hNl[PART_LEN1]) {
399 for (int i = 0; i < PART_LEN1; ++i) {
400 // Weight subbands
401 if (hNl[i] > hNlFb) {
402 hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
403 (1 - WebRtcAec_weightCurve[i]) * hNl[i];
404 }
405 hNl[i] = powf(hNl[i], overdrive_scaling * WebRtcAec_overDriveCurve[i]);
406 }
407 }
408
Suppress(const float hNl[PART_LEN1],float efw[2][PART_LEN1])409 static void Suppress(const float hNl[PART_LEN1], float efw[2][PART_LEN1]) {
410 for (int i = 0; i < PART_LEN1; ++i) {
411 // Suppress error signal
412 efw[0][i] *= hNl[i];
413 efw[1][i] *= hNl[i];
414
415 // Ooura fft returns incorrect sign on imaginary component. It matters here
416 // because we are making an additive change with comfort noise.
417 efw[1][i] *= -1;
418 }
419 }
420
PartitionDelay(int num_partitions,float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1])421 static int PartitionDelay(int num_partitions,
422 float h_fft_buf[2]
423 [kExtendedNumPartitions * PART_LEN1]) {
424 // Measures the energy in each filter partition and returns the partition with
425 // highest energy.
426 // TODO(bjornv): Spread computational cost by computing one partition per
427 // block?
428 float wfEnMax = 0;
429 int i;
430 int delay = 0;
431
432 for (i = 0; i < num_partitions; i++) {
433 int j;
434 int pos = i * PART_LEN1;
435 float wfEn = 0;
436 for (j = 0; j < PART_LEN1; j++) {
437 wfEn += h_fft_buf[0][pos + j] * h_fft_buf[0][pos + j] +
438 h_fft_buf[1][pos + j] * h_fft_buf[1][pos + j];
439 }
440
441 if (wfEn > wfEnMax) {
442 wfEnMax = wfEn;
443 delay = i;
444 }
445 }
446 return delay;
447 }
448
449 // Update metric with 10 * log10(numerator / denominator).
UpdateLogRatioMetric(Stats * metric,float numerator,float denominator)450 static void UpdateLogRatioMetric(Stats* metric, float numerator,
451 float denominator) {
452 RTC_DCHECK(metric);
453 RTC_CHECK(numerator >= 0);
454 RTC_CHECK(denominator >= 0);
455
456 const float log_numerator = log10(numerator + 1e-10f);
457 const float log_denominator = log10(denominator + 1e-10f);
458 metric->instant = 10.0f * (log_numerator - log_denominator);
459
460 // Max.
461 if (metric->instant > metric->max)
462 metric->max = metric->instant;
463
464 // Min.
465 if (metric->instant < metric->min)
466 metric->min = metric->instant;
467
468 // Average.
469 metric->counter++;
470 // This is to protect overflow, which should almost never happen.
471 RTC_CHECK_NE(0, metric->counter);
472 metric->sum += metric->instant;
473 metric->average = metric->sum / metric->counter;
474
475 // Upper mean.
476 if (metric->instant > metric->average) {
477 metric->hicounter++;
478 // This is to protect overflow, which should almost never happen.
479 RTC_CHECK_NE(0, metric->hicounter);
480 metric->hisum += metric->instant;
481 metric->himean = metric->hisum / metric->hicounter;
482 }
483 }
484
485 // Threshold to protect against the ill-effects of a zero far-end.
486 const float WebRtcAec_kMinFarendPSD = 15;
487
488 // Updates the following smoothed Power Spectral Densities (PSD):
489 // - sd : near-end
490 // - se : residual echo
491 // - sx : far-end
492 // - sde : cross-PSD of near-end and residual echo
493 // - sxd : cross-PSD of near-end and far-end
494 //
495 // In addition to updating the PSDs, also the filter diverge state is
496 // determined.
UpdateCoherenceSpectra(int mult,bool extended_filter_enabled,float efw[2][PART_LEN1],float dfw[2][PART_LEN1],float xfw[2][PART_LEN1],CoherenceState * coherence_state,short * filter_divergence_state,int * extreme_filter_divergence)497 static void UpdateCoherenceSpectra(int mult,
498 bool extended_filter_enabled,
499 float efw[2][PART_LEN1],
500 float dfw[2][PART_LEN1],
501 float xfw[2][PART_LEN1],
502 CoherenceState* coherence_state,
503 short* filter_divergence_state,
504 int* extreme_filter_divergence) {
505 // Power estimate smoothing coefficients.
506 const float* ptrGCoh =
507 extended_filter_enabled
508 ? WebRtcAec_kExtendedSmoothingCoefficients[mult - 1]
509 : WebRtcAec_kNormalSmoothingCoefficients[mult - 1];
510 int i;
511 float sdSum = 0, seSum = 0;
512
513 for (i = 0; i < PART_LEN1; i++) {
514 coherence_state->sd[i] =
515 ptrGCoh[0] * coherence_state->sd[i] +
516 ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
517 coherence_state->se[i] =
518 ptrGCoh[0] * coherence_state->se[i] +
519 ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
520 // We threshold here to protect against the ill-effects of a zero farend.
521 // The threshold is not arbitrarily chosen, but balances protection and
522 // adverse interaction with the algorithm's tuning.
523 // TODO(bjornv): investigate further why this is so sensitive.
524 coherence_state->sx[i] =
525 ptrGCoh[0] * coherence_state->sx[i] +
526 ptrGCoh[1] *
527 WEBRTC_SPL_MAX(xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
528 WebRtcAec_kMinFarendPSD);
529
530 coherence_state->sde[i][0] =
531 ptrGCoh[0] * coherence_state->sde[i][0] +
532 ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
533 coherence_state->sde[i][1] =
534 ptrGCoh[0] * coherence_state->sde[i][1] +
535 ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
536
537 coherence_state->sxd[i][0] =
538 ptrGCoh[0] * coherence_state->sxd[i][0] +
539 ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
540 coherence_state->sxd[i][1] =
541 ptrGCoh[0] * coherence_state->sxd[i][1] +
542 ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
543
544 sdSum += coherence_state->sd[i];
545 seSum += coherence_state->se[i];
546 }
547
548 // Divergent filter safeguard update.
549 *filter_divergence_state =
550 (*filter_divergence_state ? 1.05f : 1.0f) * seSum > sdSum;
551
552 // Signal extreme filter divergence if the error is significantly larger
553 // than the nearend (13 dB).
554 *extreme_filter_divergence = (seSum > (19.95f * sdSum));
555 }
556
557 // Window time domain data to be used by the fft.
WindowData(float * x_windowed,const float * x)558 __inline static void WindowData(float* x_windowed, const float* x) {
559 int i;
560 for (i = 0; i < PART_LEN; i++) {
561 x_windowed[i] = x[i] * WebRtcAec_sqrtHanning[i];
562 x_windowed[PART_LEN + i] =
563 x[PART_LEN + i] * WebRtcAec_sqrtHanning[PART_LEN - i];
564 }
565 }
566
567 // Puts fft output data into a complex valued array.
StoreAsComplex(const float * data,float data_complex[2][PART_LEN1])568 __inline static void StoreAsComplex(const float* data,
569 float data_complex[2][PART_LEN1]) {
570 int i;
571 data_complex[0][0] = data[0];
572 data_complex[1][0] = 0;
573 for (i = 1; i < PART_LEN; i++) {
574 data_complex[0][i] = data[2 * i];
575 data_complex[1][i] = data[2 * i + 1];
576 }
577 data_complex[0][PART_LEN] = data[1];
578 data_complex[1][PART_LEN] = 0;
579 }
580
ComputeCoherence(const CoherenceState * coherence_state,float * cohde,float * cohxd)581 static void ComputeCoherence(const CoherenceState* coherence_state,
582 float* cohde,
583 float* cohxd) {
584 // Subband coherence
585 for (int i = 0; i < PART_LEN1; i++) {
586 cohde[i] = (coherence_state->sde[i][0] * coherence_state->sde[i][0] +
587 coherence_state->sde[i][1] * coherence_state->sde[i][1]) /
588 (coherence_state->sd[i] * coherence_state->se[i] + 1e-10f);
589 cohxd[i] = (coherence_state->sxd[i][0] * coherence_state->sxd[i][0] +
590 coherence_state->sxd[i][1] * coherence_state->sxd[i][1]) /
591 (coherence_state->sx[i] * coherence_state->sd[i] + 1e-10f);
592 }
593 }
594
GetHighbandGain(const float * lambda,float * nlpGainHband)595 static void GetHighbandGain(const float* lambda, float* nlpGainHband) {
596 int i;
597
598 *nlpGainHband = 0.0f;
599 for (i = freqAvgIc; i < PART_LEN1 - 1; i++) {
600 *nlpGainHband += lambda[i];
601 }
602 *nlpGainHband /= static_cast<float>(PART_LEN1 - 1 - freqAvgIc);
603 }
604
GenerateComplexNoise(uint32_t * seed,float noise[2][PART_LEN1])605 static void GenerateComplexNoise(uint32_t* seed, float noise[2][PART_LEN1]) {
606 const float kPi2 = 6.28318530717959f;
607 int16_t randW16[PART_LEN];
608 WebRtcSpl_RandUArray(randW16, PART_LEN, seed);
609
610 noise[0][0] = 0;
611 noise[1][0] = 0;
612 for (size_t i = 1; i < PART_LEN1; i++) {
613 float tmp = kPi2 * randW16[i - 1] / 32768.f;
614 noise[0][i] = cosf(tmp);
615 noise[1][i] = -sinf(tmp);
616 }
617 noise[1][PART_LEN] = 0;
618 }
619
ComfortNoise(bool generate_high_frequency_noise,uint32_t * seed,float e_fft[2][PART_LEN1],float high_frequency_comfort_noise[2][PART_LEN1],const float * noise_spectrum,const float * suppressor_gain)620 static void ComfortNoise(bool generate_high_frequency_noise,
621 uint32_t* seed,
622 float e_fft[2][PART_LEN1],
623 float high_frequency_comfort_noise[2][PART_LEN1],
624 const float* noise_spectrum,
625 const float* suppressor_gain) {
626 float complex_noise[2][PART_LEN1];
627
628 GenerateComplexNoise(seed, complex_noise);
629
630 // Shape, scale and add comfort noise.
631 for (int i = 1; i < PART_LEN1; ++i) {
632 float noise_scaling =
633 sqrtf(WEBRTC_SPL_MAX(1 - suppressor_gain[i] * suppressor_gain[i], 0)) *
634 sqrtf(noise_spectrum[i]);
635 e_fft[0][i] += noise_scaling * complex_noise[0][i];
636 e_fft[1][i] += noise_scaling * complex_noise[1][i];
637 }
638
639 // Form comfort noise for higher frequencies.
640 if (generate_high_frequency_noise) {
641 // Compute average noise power and nlp gain over the second half of freq
642 // spectrum (i.e., 4->8khz).
643 int start_avg_band = PART_LEN1 / 2;
644 float upper_bands_noise_power = 0.f;
645 float upper_bands_suppressor_gain = 0.f;
646 for (int i = start_avg_band; i < PART_LEN1; ++i) {
647 upper_bands_noise_power += sqrtf(noise_spectrum[i]);
648 upper_bands_suppressor_gain +=
649 sqrtf(WEBRTC_SPL_MAX(1 - suppressor_gain[i] * suppressor_gain[i], 0));
650 }
651 upper_bands_noise_power /= (PART_LEN1 - start_avg_band);
652 upper_bands_suppressor_gain /= (PART_LEN1 - start_avg_band);
653
654 // Shape, scale and add comfort noise.
655 float noise_scaling = upper_bands_suppressor_gain * upper_bands_noise_power;
656 high_frequency_comfort_noise[0][0] = 0;
657 high_frequency_comfort_noise[1][0] = 0;
658 for (int i = 1; i < PART_LEN1; ++i) {
659 high_frequency_comfort_noise[0][i] = noise_scaling * complex_noise[0][i];
660 high_frequency_comfort_noise[1][i] = noise_scaling * complex_noise[1][i];
661 }
662 high_frequency_comfort_noise[1][PART_LEN] = 0;
663 } else {
664 memset(high_frequency_comfort_noise, 0,
665 2 * PART_LEN1 * sizeof(high_frequency_comfort_noise[0][0]));
666 }
667 }
668
InitLevel(PowerLevel * level)669 static void InitLevel(PowerLevel* level) {
670 const float kBigFloat = 1E17f;
671 level->averagelevel.Reset();
672 level->framelevel.Reset();
673 level->minlevel = kBigFloat;
674 }
675
InitStats(Stats * stats)676 static void InitStats(Stats* stats) {
677 stats->instant = kOffsetLevel;
678 stats->average = kOffsetLevel;
679 stats->max = kOffsetLevel;
680 stats->min = kOffsetLevel * (-1);
681 stats->sum = 0;
682 stats->hisum = 0;
683 stats->himean = kOffsetLevel;
684 stats->counter = 0;
685 stats->hicounter = 0;
686 }
687
InitMetrics(AecCore * self)688 static void InitMetrics(AecCore* self) {
689 self->stateCounter = 0;
690 InitLevel(&self->farlevel);
691 InitLevel(&self->nearlevel);
692 InitLevel(&self->linoutlevel);
693 InitLevel(&self->nlpoutlevel);
694
695 InitStats(&self->erl);
696 InitStats(&self->erle);
697 InitStats(&self->aNlp);
698 InitStats(&self->rerl);
699
700 self->divergent_filter_fraction.Reset();
701 }
702
CalculatePower(const float * in,size_t num_samples)703 static float CalculatePower(const float* in, size_t num_samples) {
704 size_t k;
705 float energy = 0.0f;
706
707 for (k = 0; k < num_samples; ++k) {
708 energy += in[k] * in[k];
709 }
710 return energy / num_samples;
711 }
712
UpdateLevel(PowerLevel * level,float power)713 static void UpdateLevel(PowerLevel* level, float power) {
714 level->framelevel.AddValue(power);
715 if (level->framelevel.EndOfBlock()) {
716 const float new_frame_level = level->framelevel.GetLatestMean();
717 if (new_frame_level > 0) {
718 if (new_frame_level < level->minlevel) {
719 level->minlevel = new_frame_level; // New minimum.
720 } else {
721 level->minlevel *= (1 + 0.001f); // Small increase.
722 }
723 }
724 level->averagelevel.AddValue(new_frame_level);
725 }
726 }
727
UpdateMetrics(AecCore * aec)728 static void UpdateMetrics(AecCore* aec) {
729 const float actThresholdNoisy = 8.0f;
730 const float actThresholdClean = 40.0f;
731
732 const float noisyPower = 300000.0f;
733
734 float actThreshold;
735
736 if (aec->echoState) { // Check if echo is likely present
737 aec->stateCounter++;
738 }
739
740 if (aec->linoutlevel.framelevel.EndOfBlock()) {
741 aec->divergent_filter_fraction.AddObservation(aec->nearlevel,
742 aec->linoutlevel,
743 aec->nlpoutlevel);
744 }
745
746 if (aec->farlevel.averagelevel.EndOfBlock()) {
747 if (aec->farlevel.minlevel < noisyPower) {
748 actThreshold = actThresholdClean;
749 } else {
750 actThreshold = actThresholdNoisy;
751 }
752
753 const float far_average_level = aec->farlevel.averagelevel.GetLatestMean();
754
755 // The last condition is to let estimation be made in active far-end
756 // segments only.
757 if ((aec->stateCounter > (0.5f * kCountLen * kSubCountLen)) &&
758 (aec->farlevel.framelevel.EndOfBlock()) &&
759 (far_average_level > (actThreshold * aec->farlevel.minlevel))) {
760
761 // ERL: error return loss.
762 const float near_average_level =
763 aec->nearlevel.averagelevel.GetLatestMean();
764 UpdateLogRatioMetric(&aec->erl, far_average_level, near_average_level);
765
766 // A_NLP: error return loss enhanced before the nonlinear suppression.
767 const float linout_average_level =
768 aec->linoutlevel.averagelevel.GetLatestMean();
769 UpdateLogRatioMetric(&aec->aNlp, near_average_level,
770 linout_average_level);
771
772 // ERLE: error return loss enhanced.
773 const float nlpout_average_level =
774 aec->nlpoutlevel.averagelevel.GetLatestMean();
775 UpdateLogRatioMetric(&aec->erle, near_average_level,
776 nlpout_average_level);
777 }
778
779 aec->stateCounter = 0;
780 }
781 }
782
UpdateDelayMetrics(AecCore * self)783 static void UpdateDelayMetrics(AecCore* self) {
784 int i = 0;
785 int delay_values = 0;
786 int median = 0;
787 int lookahead = WebRtc_lookahead(self->delay_estimator);
788 const int kMsPerBlock = PART_LEN / (self->mult * 8);
789 int64_t l1_norm = 0;
790
791 if (self->num_delay_values == 0) {
792 // We have no new delay value data. Even though -1 is a valid |median| in
793 // the sense that we allow negative values, it will practically never be
794 // used since multiples of |kMsPerBlock| will always be returned.
795 // We therefore use -1 to indicate in the logs that the delay estimator was
796 // not able to estimate the delay.
797 self->delay_median = -1;
798 self->delay_std = -1;
799 self->fraction_poor_delays = -1;
800 return;
801 }
802
803 // Start value for median count down.
804 delay_values = self->num_delay_values >> 1;
805 // Get median of delay values since last update.
806 for (i = 0; i < kHistorySizeBlocks; i++) {
807 delay_values -= self->delay_histogram[i];
808 if (delay_values < 0) {
809 median = i;
810 break;
811 }
812 }
813 // Account for lookahead.
814 self->delay_median = (median - lookahead) * kMsPerBlock;
815
816 // Calculate the L1 norm, with median value as central moment.
817 for (i = 0; i < kHistorySizeBlocks; i++) {
818 l1_norm += abs(i - median) * self->delay_histogram[i];
819 }
820 self->delay_std =
821 static_cast<int>((l1_norm + self->num_delay_values / 2) /
822 self->num_delay_values) * kMsPerBlock;
823
824 // Determine fraction of delays that are out of bounds, that is, either
825 // negative (anti-causal system) or larger than the AEC filter length.
826 {
827 int num_delays_out_of_bounds = self->num_delay_values;
828 const int histogram_length =
829 sizeof(self->delay_histogram) / sizeof(self->delay_histogram[0]);
830 for (i = lookahead; i < lookahead + self->num_partitions; ++i) {
831 if (i < histogram_length)
832 num_delays_out_of_bounds -= self->delay_histogram[i];
833 }
834 self->fraction_poor_delays =
835 static_cast<float>(num_delays_out_of_bounds) / self->num_delay_values;
836 }
837
838 // Reset histogram.
839 memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
840 self->num_delay_values = 0;
841 }
842
ScaledInverseFft(const OouraFft & ooura_fft,float freq_data[2][PART_LEN1],float time_data[PART_LEN2],float scale,int conjugate)843 static void ScaledInverseFft(const OouraFft& ooura_fft,
844 float freq_data[2][PART_LEN1],
845 float time_data[PART_LEN2],
846 float scale,
847 int conjugate) {
848 int i;
849 const float normalization = scale / static_cast<float>(PART_LEN2);
850 const float sign = (conjugate ? -1 : 1);
851 time_data[0] = freq_data[0][0] * normalization;
852 time_data[1] = freq_data[0][PART_LEN] * normalization;
853 for (i = 1; i < PART_LEN; i++) {
854 time_data[2 * i] = freq_data[0][i] * normalization;
855 time_data[2 * i + 1] = sign * freq_data[1][i] * normalization;
856 }
857 ooura_fft.InverseFft(time_data);
858 }
859
Fft(const OouraFft & ooura_fft,float time_data[PART_LEN2],float freq_data[2][PART_LEN1])860 static void Fft(const OouraFft& ooura_fft,
861 float time_data[PART_LEN2],
862 float freq_data[2][PART_LEN1]) {
863 int i;
864 ooura_fft.Fft(time_data);
865
866 // Reorder fft output data.
867 freq_data[1][0] = 0;
868 freq_data[1][PART_LEN] = 0;
869 freq_data[0][0] = time_data[0];
870 freq_data[0][PART_LEN] = time_data[1];
871 for (i = 1; i < PART_LEN; i++) {
872 freq_data[0][i] = time_data[2 * i];
873 freq_data[1][i] = time_data[2 * i + 1];
874 }
875 }
876
SignalBasedDelayCorrection(AecCore * self)877 static int SignalBasedDelayCorrection(AecCore* self) {
878 int delay_correction = 0;
879 int last_delay = -2;
880 RTC_DCHECK(self);
881 #if !defined(WEBRTC_ANDROID)
882 // On desktops, turn on correction after |kDelayCorrectionStart| frames. This
883 // is to let the delay estimation get a chance to converge. Also, if the
884 // playout audio volume is low (or even muted) the delay estimation can return
885 // a very large delay, which will break the AEC if it is applied.
886 if (self->frame_count < kDelayCorrectionStart) {
887 self->data_dumper->DumpRaw("aec_da_reported_delay", 1, &last_delay);
888 return 0;
889 }
890 #endif
891
892 // 1. Check for non-negative delay estimate. Note that the estimates we get
893 // from the delay estimation are not compensated for lookahead. Hence, a
894 // negative |last_delay| is an invalid one.
895 // 2. Verify that there is a delay change. In addition, only allow a change
896 // if the delay is outside a certain region taking the AEC filter length
897 // into account.
898 // TODO(bjornv): Investigate if we can remove the non-zero delay change check.
899 // 3. Only allow delay correction if the delay estimation quality exceeds
900 // |delay_quality_threshold|.
901 // 4. Finally, verify that the proposed |delay_correction| is feasible by
902 // comparing with the size of the far-end buffer.
903 last_delay = WebRtc_last_delay(self->delay_estimator);
904 self->data_dumper->DumpRaw("aec_da_reported_delay", 1, &last_delay);
905 if ((last_delay >= 0) && (last_delay != self->previous_delay) &&
906 (WebRtc_last_delay_quality(self->delay_estimator) >
907 self->delay_quality_threshold)) {
908 int delay = last_delay - WebRtc_lookahead(self->delay_estimator);
909 // Allow for a slack in the actual delay, defined by a |lower_bound| and an
910 // |upper_bound|. The adaptive echo cancellation filter is currently
911 // |num_partitions| (of 64 samples) long. If the delay estimate is negative
912 // or at least 3/4 of the filter length we open up for correction.
913 const int lower_bound = 0;
914 const int upper_bound = self->num_partitions * 3 / 4;
915 const int do_correction = delay <= lower_bound || delay > upper_bound;
916 if (do_correction == 1) {
917 int available_read = self->farend_block_buffer_.Size();
918 // With |shift_offset| we gradually rely on the delay estimates. For
919 // positive delays we reduce the correction by |shift_offset| to lower the
920 // risk of pushing the AEC into a non causal state. For negative delays
921 // we rely on the values up to a rounding error, hence compensate by 1
922 // element to make sure to push the delay into the causal region.
923 delay_correction = -delay;
924 delay_correction += delay > self->shift_offset ? self->shift_offset : 1;
925 self->shift_offset--;
926 self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset);
927 if (delay_correction > available_read - self->mult - 1) {
928 // There is not enough data in the buffer to perform this shift. Hence,
929 // we do not rely on the delay estimate and do nothing.
930 delay_correction = 0;
931 } else {
932 self->previous_delay = last_delay;
933 ++self->delay_correction_count;
934 }
935 }
936 }
937 // Update the |delay_quality_threshold| once we have our first delay
938 // correction.
939 if (self->delay_correction_count > 0) {
940 float delay_quality = WebRtc_last_delay_quality(self->delay_estimator);
941 delay_quality =
942 (delay_quality > kDelayQualityThresholdMax ? kDelayQualityThresholdMax
943 : delay_quality);
944 self->delay_quality_threshold =
945 (delay_quality > self->delay_quality_threshold
946 ? delay_quality
947 : self->delay_quality_threshold);
948 }
949 self->data_dumper->DumpRaw("aec_da_delay_correction", 1, &delay_correction);
950
951 return delay_correction;
952 }
953
RegressorPower(int num_partitions,int latest_added_partition,float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],float x_pow[PART_LEN1])954 static void RegressorPower(int num_partitions,
955 int latest_added_partition,
956 float x_fft_buf[2]
957 [kExtendedNumPartitions * PART_LEN1],
958 float x_pow[PART_LEN1]) {
959 RTC_DCHECK_LT(latest_added_partition, num_partitions);
960 memset(x_pow, 0, PART_LEN1 * sizeof(x_pow[0]));
961
962 int partition = latest_added_partition;
963 int x_fft_buf_position = partition * PART_LEN1;
964 for (int i = 0; i < num_partitions; ++i) {
965 for (int bin = 0; bin < PART_LEN1; ++bin) {
966 float re = x_fft_buf[0][x_fft_buf_position];
967 float im = x_fft_buf[1][x_fft_buf_position];
968 x_pow[bin] += re * re + im * im;
969 ++x_fft_buf_position;
970 }
971
972 ++partition;
973 if (partition == num_partitions) {
974 partition = 0;
975 RTC_DCHECK_EQ(num_partitions * PART_LEN1, x_fft_buf_position);
976 x_fft_buf_position = 0;
977 }
978 }
979 }
980
EchoSubtraction(const OouraFft & ooura_fft,int num_partitions,int extended_filter_enabled,int * extreme_filter_divergence,float filter_step_size,float error_threshold,float * x_fft,int * x_fft_buf_block_pos,float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],float * const y,float x_pow[PART_LEN1],float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],float echo_subtractor_output[PART_LEN])981 static void EchoSubtraction(const OouraFft& ooura_fft,
982 int num_partitions,
983 int extended_filter_enabled,
984 int* extreme_filter_divergence,
985 float filter_step_size,
986 float error_threshold,
987 float* x_fft,
988 int* x_fft_buf_block_pos,
989 float x_fft_buf[2]
990 [kExtendedNumPartitions * PART_LEN1],
991 float* const y,
992 float x_pow[PART_LEN1],
993 float h_fft_buf[2]
994 [kExtendedNumPartitions * PART_LEN1],
995 float echo_subtractor_output[PART_LEN]) {
996 float s_fft[2][PART_LEN1];
997 float e_extended[PART_LEN2];
998 float s_extended[PART_LEN2];
999 float* s;
1000 float e[PART_LEN];
1001 float e_fft[2][PART_LEN1];
1002 int i;
1003
1004 // Update the x_fft_buf block position.
1005 (*x_fft_buf_block_pos)--;
1006 if ((*x_fft_buf_block_pos) == -1) {
1007 *x_fft_buf_block_pos = num_partitions - 1;
1008 }
1009
1010 // Buffer x_fft.
1011 memcpy(x_fft_buf[0] + (*x_fft_buf_block_pos) * PART_LEN1, x_fft,
1012 sizeof(float) * PART_LEN1);
1013 memcpy(x_fft_buf[1] + (*x_fft_buf_block_pos) * PART_LEN1, &x_fft[PART_LEN1],
1014 sizeof(float) * PART_LEN1);
1015
1016 memset(s_fft, 0, sizeof(s_fft));
1017
1018 // Conditionally reset the echo subtraction filter if the filter has diverged
1019 // significantly.
1020 if (!extended_filter_enabled && *extreme_filter_divergence) {
1021 memset(h_fft_buf, 0,
1022 2 * kExtendedNumPartitions * PART_LEN1 * sizeof(h_fft_buf[0][0]));
1023 *extreme_filter_divergence = 0;
1024 }
1025
1026 // Produce echo estimate s_fft.
1027 WebRtcAec_FilterFar(num_partitions, *x_fft_buf_block_pos, x_fft_buf,
1028 h_fft_buf, s_fft);
1029
1030 // Compute the time-domain echo estimate s.
1031 ScaledInverseFft(ooura_fft, s_fft, s_extended, 2.0f, 0);
1032 s = &s_extended[PART_LEN];
1033
1034 // Compute the time-domain echo prediction error.
1035 for (i = 0; i < PART_LEN; ++i) {
1036 e[i] = y[i] - s[i];
1037 }
1038
1039 // Compute the frequency domain echo prediction error.
1040 memset(e_extended, 0, sizeof(float) * PART_LEN);
1041 memcpy(e_extended + PART_LEN, e, sizeof(float) * PART_LEN);
1042 Fft(ooura_fft, e_extended, e_fft);
1043
1044 // Scale error signal inversely with far power.
1045 WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft);
1046 WebRtcAec_FilterAdaptation(ooura_fft, num_partitions, *x_fft_buf_block_pos,
1047 x_fft_buf, e_fft, h_fft_buf);
1048 memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN);
1049 }
1050
FormSuppressionGain(AecCore * aec,float cohde[PART_LEN1],float cohxd[PART_LEN1],float hNl[PART_LEN1])1051 static void FormSuppressionGain(AecCore* aec,
1052 float cohde[PART_LEN1],
1053 float cohxd[PART_LEN1],
1054 float hNl[PART_LEN1]) {
1055 float hNlDeAvg, hNlXdAvg;
1056 float hNlPref[kPrefBandSize];
1057 float hNlFb = 0, hNlFbLow = 0;
1058 const int prefBandSize = kPrefBandSize / aec->mult;
1059 const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f;
1060 const int minPrefBand = 4 / aec->mult;
1061 // Power estimate smoothing coefficients.
1062 const float* min_overdrive = aec->extended_filter_enabled
1063 ? kExtendedMinOverDrive
1064 : kNormalMinOverDrive;
1065
1066 hNlXdAvg = 0;
1067 for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
1068 hNlXdAvg += cohxd[i];
1069 }
1070 hNlXdAvg /= prefBandSize;
1071 hNlXdAvg = 1 - hNlXdAvg;
1072
1073 hNlDeAvg = 0;
1074 for (int i = minPrefBand; i < prefBandSize + minPrefBand; ++i) {
1075 hNlDeAvg += cohde[i];
1076 }
1077 hNlDeAvg /= prefBandSize;
1078
1079 if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) {
1080 aec->hNlXdAvgMin = hNlXdAvg;
1081 }
1082
1083 if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) {
1084 aec->stNearState = 1;
1085 } else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) {
1086 aec->stNearState = 0;
1087 }
1088
1089 if (aec->hNlXdAvgMin == 1) {
1090 aec->echoState = 0;
1091 aec->overDrive = min_overdrive[aec->nlp_mode];
1092
1093 if (aec->stNearState == 1) {
1094 memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
1095 hNlFb = hNlDeAvg;
1096 hNlFbLow = hNlDeAvg;
1097 } else {
1098 for (int i = 0; i < PART_LEN1; ++i) {
1099 hNl[i] = 1 - cohxd[i];
1100 }
1101 hNlFb = hNlXdAvg;
1102 hNlFbLow = hNlXdAvg;
1103 }
1104 } else {
1105 if (aec->stNearState == 1) {
1106 aec->echoState = 0;
1107 memcpy(hNl, cohde, sizeof(hNl[0]) * PART_LEN1);
1108 hNlFb = hNlDeAvg;
1109 hNlFbLow = hNlDeAvg;
1110 } else {
1111 aec->echoState = 1;
1112 for (int i = 0; i < PART_LEN1; ++i) {
1113 hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]);
1114 }
1115
1116 // Select an order statistic from the preferred bands.
1117 // TODO(peah): Using quicksort now, but a selection algorithm may be
1118 // preferred.
1119 memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize);
1120 qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat);
1121 hNlFb = hNlPref[static_cast<int>(floor(prefBandQuant *
1122 (prefBandSize - 1)))];
1123 hNlFbLow = hNlPref[static_cast<int>(floor(prefBandQuantLow *
1124 (prefBandSize - 1)))];
1125 }
1126 }
1127
1128 // Track the local filter minimum to determine suppression overdrive.
1129 if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) {
1130 aec->hNlFbLocalMin = hNlFbLow;
1131 aec->hNlFbMin = hNlFbLow;
1132 aec->hNlNewMin = 1;
1133 aec->hNlMinCtr = 0;
1134 }
1135 aec->hNlFbLocalMin =
1136 WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1);
1137 aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1);
1138
1139 if (aec->hNlNewMin == 1) {
1140 aec->hNlMinCtr++;
1141 }
1142 if (aec->hNlMinCtr == 2) {
1143 aec->hNlNewMin = 0;
1144 aec->hNlMinCtr = 0;
1145 aec->overDrive =
1146 WEBRTC_SPL_MAX(kTargetSupp[aec->nlp_mode] /
1147 static_cast<float>(log(aec->hNlFbMin + 1e-10f) + 1e-10f),
1148 min_overdrive[aec->nlp_mode]);
1149 }
1150
1151 // Smooth the overdrive.
1152 if (aec->overDrive < aec->overdrive_scaling) {
1153 aec->overdrive_scaling =
1154 0.99f * aec->overdrive_scaling + 0.01f * aec->overDrive;
1155 } else {
1156 aec->overdrive_scaling =
1157 0.9f * aec->overdrive_scaling + 0.1f * aec->overDrive;
1158 }
1159
1160 // Apply the overdrive.
1161 WebRtcAec_Overdrive(aec->overdrive_scaling, hNlFb, hNl);
1162 }
1163
EchoSuppression(const OouraFft & ooura_fft,AecCore * aec,float * nearend_extended_block_lowest_band,float farend_extended_block[PART_LEN2],float * echo_subtractor_output,float output[NUM_HIGH_BANDS_MAX+1][PART_LEN])1164 static void EchoSuppression(const OouraFft& ooura_fft,
1165 AecCore* aec,
1166 float* nearend_extended_block_lowest_band,
1167 float farend_extended_block[PART_LEN2],
1168 float* echo_subtractor_output,
1169 float output[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
1170 float efw[2][PART_LEN1];
1171 float xfw[2][PART_LEN1];
1172 float dfw[2][PART_LEN1];
1173 float comfortNoiseHband[2][PART_LEN1];
1174 float fft[PART_LEN2];
1175 float nlpGainHband;
1176 int i;
1177 size_t j;
1178
1179 // Coherence and non-linear filter
1180 float cohde[PART_LEN1], cohxd[PART_LEN1];
1181 float hNl[PART_LEN1];
1182
1183 // Filter energy
1184 const int delayEstInterval = 10 * aec->mult;
1185
1186 float* xfw_ptr = NULL;
1187
1188 // Update eBuf with echo subtractor output.
1189 memcpy(aec->eBuf + PART_LEN, echo_subtractor_output,
1190 sizeof(float) * PART_LEN);
1191
1192 // Analysis filter banks for the echo suppressor.
1193 // Windowed near-end ffts.
1194 WindowData(fft, nearend_extended_block_lowest_band);
1195 ooura_fft.Fft(fft);
1196 StoreAsComplex(fft, dfw);
1197
1198 // Windowed echo suppressor output ffts.
1199 WindowData(fft, aec->eBuf);
1200 ooura_fft.Fft(fft);
1201 StoreAsComplex(fft, efw);
1202
1203 // NLP
1204
1205 // Convert far-end partition to the frequency domain with windowing.
1206 WindowData(fft, farend_extended_block);
1207 Fft(ooura_fft, fft, xfw);
1208 xfw_ptr = &xfw[0][0];
1209
1210 // Buffer far.
1211 memcpy(aec->xfwBuf, xfw_ptr, sizeof(float) * 2 * PART_LEN1);
1212
1213 aec->delayEstCtr++;
1214 if (aec->delayEstCtr == delayEstInterval) {
1215 aec->delayEstCtr = 0;
1216 aec->delayIdx = WebRtcAec_PartitionDelay(aec->num_partitions, aec->wfBuf);
1217 }
1218
1219 aec->data_dumper->DumpRaw("aec_nlp_delay", 1, &aec->delayIdx);
1220
1221 // Use delayed far.
1222 memcpy(xfw, aec->xfwBuf + aec->delayIdx * PART_LEN1,
1223 sizeof(xfw[0][0]) * 2 * PART_LEN1);
1224
1225 WebRtcAec_UpdateCoherenceSpectra(aec->mult, aec->extended_filter_enabled == 1,
1226 efw, dfw, xfw, &aec->coherence_state,
1227 &aec->divergeState,
1228 &aec->extreme_filter_divergence);
1229
1230 WebRtcAec_ComputeCoherence(&aec->coherence_state, cohde, cohxd);
1231
1232 // Select the microphone signal as output if the filter is deemed to have
1233 // diverged.
1234 if (aec->divergeState) {
1235 memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
1236 }
1237
1238 FormSuppressionGain(aec, cohde, cohxd, hNl);
1239
1240 aec->data_dumper->DumpRaw("aec_nlp_gain", PART_LEN1, hNl);
1241
1242 WebRtcAec_Suppress(hNl, efw);
1243
1244 // Add comfort noise.
1245 ComfortNoise(aec->num_bands > 1, &aec->seed, efw, comfortNoiseHband,
1246 aec->noisePow, hNl);
1247
1248 // Inverse error fft.
1249 ScaledInverseFft(ooura_fft, efw, fft, 2.0f, 1);
1250
1251 // Overlap and add to obtain output.
1252 for (i = 0; i < PART_LEN; i++) {
1253 output[0][i] = (fft[i] * WebRtcAec_sqrtHanning[i] +
1254 aec->outBuf[i] * WebRtcAec_sqrtHanning[PART_LEN - i]);
1255
1256 // Saturate output to keep it in the allowed range.
1257 output[0][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[0][i],
1258 WEBRTC_SPL_WORD16_MIN);
1259 }
1260 memcpy(aec->outBuf, &fft[PART_LEN], PART_LEN * sizeof(aec->outBuf[0]));
1261
1262 // For H band
1263 if (aec->num_bands > 1) {
1264 // H band gain
1265 // average nlp over low band: average over second half of freq spectrum
1266 // (4->8khz)
1267 GetHighbandGain(hNl, &nlpGainHband);
1268
1269 // Inverse comfort_noise
1270 ScaledInverseFft(ooura_fft, comfortNoiseHband, fft, 2.0f, 0);
1271
1272 // compute gain factor
1273 for (j = 1; j < aec->num_bands; ++j) {
1274 for (i = 0; i < PART_LEN; i++) {
1275 output[j][i] = aec->previous_nearend_block[j][i] * nlpGainHband;
1276 }
1277 }
1278
1279 // Add some comfort noise where Hband is attenuated.
1280 for (i = 0; i < PART_LEN; i++) {
1281 output[1][i] += cnScaleHband * fft[i];
1282 }
1283
1284 // Saturate output to keep it in the allowed range.
1285 for (j = 1; j < aec->num_bands; ++j) {
1286 for (i = 0; i < PART_LEN; i++) {
1287 output[j][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[j][i],
1288 WEBRTC_SPL_WORD16_MIN);
1289 }
1290 }
1291 }
1292
1293 // Copy the current block to the old position.
1294 memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN);
1295
1296 memmove(aec->xfwBuf + PART_LEN1, aec->xfwBuf,
1297 sizeof(aec->xfwBuf) - sizeof(complex_t) * PART_LEN1);
1298 }
1299
ProcessNearendBlock(AecCore * aec,float farend_extended_block_lowest_band[PART_LEN2],float nearend_block[NUM_HIGH_BANDS_MAX+1][PART_LEN],float output_block[NUM_HIGH_BANDS_MAX+1][PART_LEN])1300 static void ProcessNearendBlock(
1301 AecCore* aec,
1302 float farend_extended_block_lowest_band[PART_LEN2],
1303 float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN],
1304 float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
1305 size_t i;
1306
1307 float fft[PART_LEN2];
1308 float nearend_extended_block_lowest_band[PART_LEN2];
1309 float farend_fft[2][PART_LEN1];
1310 float nearend_fft[2][PART_LEN1];
1311 float far_spectrum = 0.0f;
1312 float near_spectrum = 0.0f;
1313 float abs_far_spectrum[PART_LEN1];
1314 float abs_near_spectrum[PART_LEN1];
1315
1316 const float gPow[2] = {0.9f, 0.1f};
1317
1318 // Noise estimate constants.
1319 const int noiseInitBlocks = 500 * aec->mult;
1320 const float step = 0.1f;
1321 const float ramp = 1.0002f;
1322 const float gInitNoise[2] = {0.999f, 0.001f};
1323
1324 float echo_subtractor_output[PART_LEN];
1325
1326 aec->data_dumper->DumpWav("aec_far", PART_LEN,
1327 &farend_extended_block_lowest_band[PART_LEN],
1328 std::min(aec->sampFreq, 16000), 1);
1329 aec->data_dumper->DumpWav("aec_near", PART_LEN, &nearend_block[0][0],
1330 std::min(aec->sampFreq, 16000), 1);
1331
1332 if (aec->metricsMode == 1) {
1333 // Update power levels
1334 UpdateLevel(
1335 &aec->farlevel,
1336 CalculatePower(&farend_extended_block_lowest_band[PART_LEN], PART_LEN));
1337 UpdateLevel(&aec->nearlevel,
1338 CalculatePower(&nearend_block[0][0], PART_LEN));
1339 }
1340
1341 // Convert far-end signal to the frequency domain.
1342 memcpy(fft, farend_extended_block_lowest_band, sizeof(float) * PART_LEN2);
1343 Fft(aec->ooura_fft, fft, farend_fft);
1344
1345 // Form extended nearend frame.
1346 memcpy(&nearend_extended_block_lowest_band[0],
1347 &aec->previous_nearend_block[0][0], sizeof(float) * PART_LEN);
1348 memcpy(&nearend_extended_block_lowest_band[PART_LEN], &nearend_block[0][0],
1349 sizeof(float) * PART_LEN);
1350
1351 // Convert near-end signal to the frequency domain.
1352 memcpy(fft, nearend_extended_block_lowest_band, sizeof(float) * PART_LEN2);
1353 Fft(aec->ooura_fft, fft, nearend_fft);
1354
1355 // Power smoothing.
1356 if (aec->refined_adaptive_filter_enabled) {
1357 for (i = 0; i < PART_LEN1; ++i) {
1358 far_spectrum = farend_fft[0][i] * farend_fft[0][i] +
1359 farend_fft[1][i] * farend_fft[1][i];
1360 // Calculate the magnitude spectrum.
1361 abs_far_spectrum[i] = sqrtf(far_spectrum);
1362 }
1363 RegressorPower(aec->num_partitions, aec->xfBufBlockPos, aec->xfBuf,
1364 aec->xPow);
1365 } else {
1366 for (i = 0; i < PART_LEN1; ++i) {
1367 far_spectrum = farend_fft[0][i] * farend_fft[0][i] +
1368 farend_fft[1][i] * farend_fft[1][i];
1369 aec->xPow[i] =
1370 gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
1371 // Calculate the magnitude spectrum.
1372 abs_far_spectrum[i] = sqrtf(far_spectrum);
1373 }
1374 }
1375
1376 for (i = 0; i < PART_LEN1; ++i) {
1377 near_spectrum = nearend_fft[0][i] * nearend_fft[0][i] +
1378 nearend_fft[1][i] * nearend_fft[1][i];
1379 aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum;
1380 // Calculate the magnitude spectrum.
1381 abs_near_spectrum[i] = sqrtf(near_spectrum);
1382 }
1383
1384 // Estimate noise power. Wait until dPow is more stable.
1385 if (aec->noiseEstCtr > 50) {
1386 for (i = 0; i < PART_LEN1; i++) {
1387 if (aec->dPow[i] < aec->dMinPow[i]) {
1388 aec->dMinPow[i] =
1389 (aec->dPow[i] + step * (aec->dMinPow[i] - aec->dPow[i])) * ramp;
1390 } else {
1391 aec->dMinPow[i] *= ramp;
1392 }
1393 }
1394 }
1395
1396 // Smooth increasing noise power from zero at the start,
1397 // to avoid a sudden burst of comfort noise.
1398 if (aec->noiseEstCtr < noiseInitBlocks) {
1399 aec->noiseEstCtr++;
1400 for (i = 0; i < PART_LEN1; i++) {
1401 if (aec->dMinPow[i] > aec->dInitMinPow[i]) {
1402 aec->dInitMinPow[i] = gInitNoise[0] * aec->dInitMinPow[i] +
1403 gInitNoise[1] * aec->dMinPow[i];
1404 } else {
1405 aec->dInitMinPow[i] = aec->dMinPow[i];
1406 }
1407 }
1408 aec->noisePow = aec->dInitMinPow;
1409 } else {
1410 aec->noisePow = aec->dMinPow;
1411 }
1412
1413 // Block wise delay estimation used for logging
1414 if (aec->delay_logging_enabled) {
1415 if (WebRtc_AddFarSpectrumFloat(aec->delay_estimator_farend,
1416 abs_far_spectrum, PART_LEN1) == 0) {
1417 int delay_estimate = WebRtc_DelayEstimatorProcessFloat(
1418 aec->delay_estimator, abs_near_spectrum, PART_LEN1);
1419 if (delay_estimate >= 0) {
1420 // Update delay estimate buffer.
1421 aec->delay_histogram[delay_estimate]++;
1422 aec->num_delay_values++;
1423 }
1424 if (aec->delay_metrics_delivered == 1 &&
1425 aec->num_delay_values >= kDelayMetricsAggregationWindow) {
1426 UpdateDelayMetrics(aec);
1427 }
1428 }
1429 }
1430
1431 // Perform echo subtraction.
1432 EchoSubtraction(
1433 aec->ooura_fft, aec->num_partitions, aec->extended_filter_enabled,
1434 &aec->extreme_filter_divergence, aec->filter_step_size,
1435 aec->error_threshold, &farend_fft[0][0], &aec->xfBufBlockPos, aec->xfBuf,
1436 &nearend_block[0][0], aec->xPow, aec->wfBuf, echo_subtractor_output);
1437 aec->data_dumper->DumpRaw("aec_h_fft", PART_LEN1 * aec->num_partitions,
1438 &aec->wfBuf[0][0]);
1439 aec->data_dumper->DumpRaw("aec_h_fft", PART_LEN1 * aec->num_partitions,
1440 &aec->wfBuf[1][0]);
1441
1442 aec->data_dumper->DumpWav("aec_out_linear", PART_LEN, echo_subtractor_output,
1443 std::min(aec->sampFreq, 16000), 1);
1444
1445 if (aec->metricsMode == 1) {
1446 UpdateLevel(&aec->linoutlevel,
1447 CalculatePower(echo_subtractor_output, PART_LEN));
1448 }
1449
1450 // Perform echo suppression.
1451 EchoSuppression(aec->ooura_fft, aec, nearend_extended_block_lowest_band,
1452 farend_extended_block_lowest_band, echo_subtractor_output,
1453 output_block);
1454
1455 if (aec->metricsMode == 1) {
1456 UpdateLevel(&aec->nlpoutlevel,
1457 CalculatePower(&output_block[0][0], PART_LEN));
1458 UpdateMetrics(aec);
1459 }
1460
1461 // Store the nearend signal until the next frame.
1462 for (i = 0; i < aec->num_bands; ++i) {
1463 memcpy(&aec->previous_nearend_block[i][0], &nearend_block[i][0],
1464 sizeof(float) * PART_LEN);
1465 }
1466
1467 aec->data_dumper->DumpWav("aec_out", PART_LEN, &output_block[0][0],
1468 std::min(aec->sampFreq, 16000), 1);
1469 }
1470
WebRtcAec_CreateAec(int instance_count)1471 AecCore* WebRtcAec_CreateAec(int instance_count) {
1472 AecCore* aec = new AecCore(instance_count);
1473
1474 if (!aec) {
1475 return NULL;
1476 }
1477 aec->nearend_buffer_size = 0;
1478 memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer));
1479 // Start the output buffer with zeros to be able to produce
1480 // a full output frame in the first frame.
1481 aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN);
1482 memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer));
1483
1484 aec->delay_estimator_farend =
1485 WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
1486 if (aec->delay_estimator_farend == NULL) {
1487 WebRtcAec_FreeAec(aec);
1488 return NULL;
1489 }
1490 // We create the delay_estimator with the same amount of maximum lookahead as
1491 // the delay history size (kHistorySizeBlocks) for symmetry reasons.
1492 aec->delay_estimator = WebRtc_CreateDelayEstimator(
1493 aec->delay_estimator_farend, kHistorySizeBlocks);
1494 if (aec->delay_estimator == NULL) {
1495 WebRtcAec_FreeAec(aec);
1496 return NULL;
1497 }
1498 #ifdef WEBRTC_ANDROID
1499 aec->delay_agnostic_enabled = 1; // DA-AEC enabled by default.
1500 // DA-AEC assumes the system is causal from the beginning and will self adjust
1501 // the lookahead when shifting is required.
1502 WebRtc_set_lookahead(aec->delay_estimator, 0);
1503 #else
1504 aec->delay_agnostic_enabled = 0;
1505 WebRtc_set_lookahead(aec->delay_estimator, kLookaheadBlocks);
1506 #endif
1507 aec->extended_filter_enabled = 0;
1508 aec->refined_adaptive_filter_enabled = false;
1509
1510 rtc::CritScope cs_init(&WebRtcAec_CriticalSection);
1511 static bool initted = false;
1512 if (!initted) {
1513 // Assembly optimization
1514 WebRtcAec_FilterFar = FilterFar;
1515 WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
1516 WebRtcAec_FilterAdaptation = FilterAdaptation;
1517 WebRtcAec_Overdrive = Overdrive;
1518 WebRtcAec_Suppress = Suppress;
1519 WebRtcAec_ComputeCoherence = ComputeCoherence;
1520 WebRtcAec_UpdateCoherenceSpectra = UpdateCoherenceSpectra;
1521 WebRtcAec_StoreAsComplex = StoreAsComplex;
1522 WebRtcAec_PartitionDelay = PartitionDelay;
1523 WebRtcAec_WindowData = WindowData;
1524
1525 #if defined(WEBRTC_ARCH_X86_FAMILY)
1526 if (WebRtc_GetCPUInfo(kSSE2)) {
1527 WebRtcAec_InitAec_SSE2();
1528 }
1529 #endif
1530
1531 #if defined(MIPS_FPU_LE)
1532 WebRtcAec_InitAec_mips();
1533 #endif
1534
1535 #if defined(WEBRTC_HAS_NEON)
1536 WebRtcAec_InitAec_neon();
1537 #endif
1538 initted = true;
1539 }
1540
1541 return aec;
1542 }
1543
WebRtcAec_FreeAec(AecCore * aec)1544 void WebRtcAec_FreeAec(AecCore* aec) {
1545 if (aec == NULL) {
1546 return;
1547 }
1548
1549 WebRtc_FreeDelayEstimator(aec->delay_estimator);
1550 WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
1551
1552 delete aec;
1553 }
1554
SetAdaptiveFilterStepSize(AecCore * aec)1555 static void SetAdaptiveFilterStepSize(AecCore* aec) {
1556 // Extended filter adaptation parameter.
1557 // TODO(ajm): No narrowband tuning yet.
1558 const float kExtendedMu = 0.4f;
1559
1560 if (aec->refined_adaptive_filter_enabled) {
1561 aec->filter_step_size = 0.05f;
1562 } else {
1563 if (aec->extended_filter_enabled) {
1564 aec->filter_step_size = kExtendedMu;
1565 } else {
1566 if (aec->sampFreq == 8000) {
1567 aec->filter_step_size = 0.6f;
1568 } else {
1569 aec->filter_step_size = 0.5f;
1570 }
1571 }
1572 }
1573 }
1574
SetErrorThreshold(AecCore * aec)1575 static void SetErrorThreshold(AecCore* aec) {
1576 // Extended filter adaptation parameter.
1577 // TODO(ajm): No narrowband tuning yet.
1578 static const float kExtendedErrorThreshold = 1.0e-6f;
1579
1580 if (aec->extended_filter_enabled) {
1581 aec->error_threshold = kExtendedErrorThreshold;
1582 } else {
1583 if (aec->sampFreq == 8000) {
1584 aec->error_threshold = 2e-6f;
1585 } else {
1586 aec->error_threshold = 1.5e-6f;
1587 }
1588 }
1589 }
1590
WebRtcAec_InitAec(AecCore * aec,int sampFreq)1591 int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
1592 int i;
1593 aec->data_dumper->InitiateNewSetOfRecordings();
1594
1595 aec->sampFreq = sampFreq;
1596
1597 SetAdaptiveFilterStepSize(aec);
1598 SetErrorThreshold(aec);
1599
1600 if (sampFreq == 8000) {
1601 aec->num_bands = 1;
1602 } else {
1603 aec->num_bands = (size_t)(sampFreq / 16000);
1604 }
1605
1606 // Start the output buffer with zeros to be able to produce
1607 // a full output frame in the first frame.
1608 aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN);
1609 memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer));
1610 aec->nearend_buffer_size = 0;
1611 memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer));
1612
1613 // Initialize far-end buffer.
1614 aec->farend_block_buffer_.ReInit();
1615
1616 aec->system_delay = 0;
1617
1618 if (WebRtc_InitDelayEstimatorFarend(aec->delay_estimator_farend) != 0) {
1619 return -1;
1620 }
1621 if (WebRtc_InitDelayEstimator(aec->delay_estimator) != 0) {
1622 return -1;
1623 }
1624 aec->delay_logging_enabled = 0;
1625 aec->delay_metrics_delivered = 0;
1626 memset(aec->delay_histogram, 0, sizeof(aec->delay_histogram));
1627 aec->num_delay_values = 0;
1628 aec->delay_median = -1;
1629 aec->delay_std = -1;
1630 aec->fraction_poor_delays = -1.0f;
1631
1632 aec->previous_delay = -2; // (-2): Uninitialized.
1633 aec->delay_correction_count = 0;
1634 aec->shift_offset = kInitialShiftOffset;
1635 aec->delay_quality_threshold = kDelayQualityThresholdMin;
1636
1637 aec->num_partitions = kNormalNumPartitions;
1638
1639 // Update the delay estimator with filter length. We use half the
1640 // |num_partitions| to take the echo path into account. In practice we say
1641 // that the echo has a duration of maximum half |num_partitions|, which is not
1642 // true, but serves as a crude measure.
1643 WebRtc_set_allowed_offset(aec->delay_estimator, aec->num_partitions / 2);
1644 // TODO(bjornv): I currently hard coded the enable. Once we've established
1645 // that AECM has no performance regression, robust_validation will be enabled
1646 // all the time and the APIs to turn it on/off will be removed. Hence, remove
1647 // this line then.
1648 WebRtc_enable_robust_validation(aec->delay_estimator, 1);
1649 aec->frame_count = 0;
1650
1651 // Default target suppression mode.
1652 aec->nlp_mode = 1;
1653
1654 // Sampling frequency multiplier w.r.t. 8 kHz.
1655 // In case of multiple bands we process the lower band in 16 kHz, hence the
1656 // multiplier is always 2.
1657 if (aec->num_bands > 1) {
1658 aec->mult = 2;
1659 } else {
1660 aec->mult = static_cast<int16_t>(aec->sampFreq) / 8000;
1661 }
1662
1663 aec->farBufWritePos = 0;
1664 aec->farBufReadPos = 0;
1665
1666 aec->inSamples = 0;
1667 aec->outSamples = 0;
1668 aec->knownDelay = 0;
1669
1670 // Initialize buffers
1671 memset(aec->previous_nearend_block, 0, sizeof(aec->previous_nearend_block));
1672 memset(aec->eBuf, 0, sizeof(aec->eBuf));
1673
1674 memset(aec->xPow, 0, sizeof(aec->xPow));
1675 memset(aec->dPow, 0, sizeof(aec->dPow));
1676 memset(aec->dInitMinPow, 0, sizeof(aec->dInitMinPow));
1677 aec->noisePow = aec->dInitMinPow;
1678 aec->noiseEstCtr = 0;
1679
1680 // Initial comfort noise power
1681 for (i = 0; i < PART_LEN1; i++) {
1682 aec->dMinPow[i] = 1.0e6f;
1683 }
1684
1685 // Holds the last block written to
1686 aec->xfBufBlockPos = 0;
1687 // TODO(peah): Investigate need for these initializations. Deleting them
1688 // doesn't change the output at all and yields 0.4% overall speedup.
1689 memset(aec->xfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
1690 memset(aec->wfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
1691 memset(aec->coherence_state.sde, 0, sizeof(complex_t) * PART_LEN1);
1692 memset(aec->coherence_state.sxd, 0, sizeof(complex_t) * PART_LEN1);
1693 memset(aec->xfwBuf, 0,
1694 sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
1695 memset(aec->coherence_state.se, 0, sizeof(float) * PART_LEN1);
1696
1697 // To prevent numerical instability in the first block.
1698 for (i = 0; i < PART_LEN1; i++) {
1699 aec->coherence_state.sd[i] = 1;
1700 }
1701 for (i = 0; i < PART_LEN1; i++) {
1702 aec->coherence_state.sx[i] = 1;
1703 }
1704
1705 memset(aec->hNs, 0, sizeof(aec->hNs));
1706 memset(aec->outBuf, 0, sizeof(float) * PART_LEN);
1707
1708 aec->hNlFbMin = 1;
1709 aec->hNlFbLocalMin = 1;
1710 aec->hNlXdAvgMin = 1;
1711 aec->hNlNewMin = 0;
1712 aec->hNlMinCtr = 0;
1713 aec->overDrive = 2;
1714 aec->overdrive_scaling = 2;
1715 aec->delayIdx = 0;
1716 aec->stNearState = 0;
1717 aec->echoState = 0;
1718 aec->divergeState = 0;
1719
1720 aec->seed = 777;
1721 aec->delayEstCtr = 0;
1722
1723 aec->extreme_filter_divergence = 0;
1724
1725 // Metrics disabled by default
1726 aec->metricsMode = 0;
1727 InitMetrics(aec);
1728
1729 return 0;
1730 }
1731
WebRtcAec_BufferFarendBlock(AecCore * aec,const float * farend)1732 void WebRtcAec_BufferFarendBlock(AecCore* aec, const float* farend) {
1733 // Check if the buffer is full, and in that case flush the oldest data.
1734 if (aec->farend_block_buffer_.AvaliableSpace() < 1) {
1735 aec->farend_block_buffer_.AdjustSize(1);
1736 }
1737 aec->farend_block_buffer_.Insert(farend);
1738 }
1739
WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(AecCore * aec,int buffer_size_decrease)1740 int WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(AecCore* aec,
1741 int buffer_size_decrease) {
1742 int achieved_buffer_size_decrease =
1743 aec->farend_block_buffer_.AdjustSize(buffer_size_decrease);
1744 aec->system_delay -= achieved_buffer_size_decrease * PART_LEN;
1745 return achieved_buffer_size_decrease;
1746 }
1747
FormNearendBlock(size_t nearend_start_index,size_t num_bands,const float * const * nearend_frame,size_t num_samples_from_nearend_frame,const float nearend_buffer[NUM_HIGH_BANDS_MAX+1][PART_LEN-(FRAME_LEN-PART_LEN)],float nearend_block[NUM_HIGH_BANDS_MAX+1][PART_LEN])1748 void FormNearendBlock(
1749 size_t nearend_start_index,
1750 size_t num_bands,
1751 const float* const* nearend_frame,
1752 size_t num_samples_from_nearend_frame,
1753 const float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
1754 [PART_LEN - (FRAME_LEN - PART_LEN)],
1755 float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) {
1756 RTC_DCHECK_LE(num_samples_from_nearend_frame, PART_LEN);
1757 const int num_samples_from_buffer = PART_LEN - num_samples_from_nearend_frame;
1758
1759 if (num_samples_from_buffer > 0) {
1760 for (size_t i = 0; i < num_bands; ++i) {
1761 memcpy(&nearend_block[i][0], &nearend_buffer[i][0],
1762 num_samples_from_buffer * sizeof(float));
1763 }
1764 }
1765
1766 for (size_t i = 0; i < num_bands; ++i) {
1767 memcpy(&nearend_block[i][num_samples_from_buffer],
1768 &nearend_frame[i][nearend_start_index],
1769 num_samples_from_nearend_frame * sizeof(float));
1770 }
1771 }
1772
BufferNearendFrame(size_t nearend_start_index,size_t num_bands,const float * const * nearend_frame,size_t num_samples_to_buffer,float nearend_buffer[NUM_HIGH_BANDS_MAX+1][PART_LEN-(FRAME_LEN-PART_LEN)])1773 void BufferNearendFrame(
1774 size_t nearend_start_index,
1775 size_t num_bands,
1776 const float* const* nearend_frame,
1777 size_t num_samples_to_buffer,
1778 float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
1779 [PART_LEN - (FRAME_LEN - PART_LEN)]) {
1780 for (size_t i = 0; i < num_bands; ++i) {
1781 memcpy(
1782 &nearend_buffer[i][0],
1783 &nearend_frame[i]
1784 [nearend_start_index + FRAME_LEN - num_samples_to_buffer],
1785 num_samples_to_buffer * sizeof(float));
1786 }
1787 }
1788
BufferOutputBlock(size_t num_bands,const float output_block[NUM_HIGH_BANDS_MAX+1][PART_LEN],size_t * output_buffer_size,float output_buffer[NUM_HIGH_BANDS_MAX+1][2* PART_LEN])1789 void BufferOutputBlock(size_t num_bands,
1790 const float output_block[NUM_HIGH_BANDS_MAX + 1]
1791 [PART_LEN],
1792 size_t* output_buffer_size,
1793 float output_buffer[NUM_HIGH_BANDS_MAX + 1]
1794 [2 * PART_LEN]) {
1795 for (size_t i = 0; i < num_bands; ++i) {
1796 memcpy(&output_buffer[i][*output_buffer_size], &output_block[i][0],
1797 PART_LEN * sizeof(float));
1798 }
1799 (*output_buffer_size) += PART_LEN;
1800 }
1801
FormOutputFrame(size_t output_start_index,size_t num_bands,size_t * output_buffer_size,float output_buffer[NUM_HIGH_BANDS_MAX+1][2* PART_LEN],float * const * output_frame)1802 void FormOutputFrame(size_t output_start_index,
1803 size_t num_bands,
1804 size_t* output_buffer_size,
1805 float output_buffer[NUM_HIGH_BANDS_MAX + 1][2 * PART_LEN],
1806 float* const* output_frame) {
1807 RTC_DCHECK_LE(FRAME_LEN, *output_buffer_size);
1808 for (size_t i = 0; i < num_bands; ++i) {
1809 memcpy(&output_frame[i][output_start_index], &output_buffer[i][0],
1810 FRAME_LEN * sizeof(float));
1811 }
1812 (*output_buffer_size) -= FRAME_LEN;
1813 if (*output_buffer_size > 0) {
1814 RTC_DCHECK_GE(2 * PART_LEN - FRAME_LEN, (*output_buffer_size));
1815 for (size_t i = 0; i < num_bands; ++i) {
1816 memcpy(&output_buffer[i][0], &output_buffer[i][FRAME_LEN],
1817 (*output_buffer_size) * sizeof(float));
1818 }
1819 }
1820 }
1821
WebRtcAec_ProcessFrames(AecCore * aec,const float * const * nearend,size_t num_bands,size_t num_samples,int knownDelay,float * const * out)1822 void WebRtcAec_ProcessFrames(AecCore* aec,
1823 const float* const* nearend,
1824 size_t num_bands,
1825 size_t num_samples,
1826 int knownDelay,
1827 float* const* out) {
1828 RTC_DCHECK(num_samples == 80 || num_samples == 160);
1829
1830 aec->frame_count++;
1831 // For each frame the process is as follows:
1832 // 1) If the system_delay indicates on being too small for processing a
1833 // frame we stuff the buffer with enough data for 10 ms.
1834 // 2 a) Adjust the buffer to the system delay, by moving the read pointer.
1835 // b) Apply signal based delay correction, if we have detected poor AEC
1836 // performance.
1837 // 3) TODO(bjornv): Investigate if we need to add this:
1838 // If we can't move read pointer due to buffer size limitations we
1839 // flush/stuff the buffer.
1840 // 4) Process as many partitions as possible.
1841 // 5) Update the |system_delay| with respect to a full frame of FRAME_LEN
1842 // samples. Even though we will have data left to process (we work with
1843 // partitions) we consider updating a whole frame, since that's the
1844 // amount of data we input and output in audio_processing.
1845 // 6) Update the outputs.
1846
1847 // The AEC has two different delay estimation algorithms built in. The
1848 // first relies on delay input values from the user and the amount of
1849 // shifted buffer elements is controlled by |knownDelay|. This delay will
1850 // give a guess on how much we need to shift far-end buffers to align with
1851 // the near-end signal. The other delay estimation algorithm uses the
1852 // far- and near-end signals to find the offset between them. This one
1853 // (called "signal delay") is then used to fine tune the alignment, or
1854 // simply compensate for errors in the system based one.
1855 // Note that the two algorithms operate independently. Currently, we only
1856 // allow one algorithm to be turned on.
1857
1858 RTC_DCHECK_EQ(aec->num_bands, num_bands);
1859
1860 for (size_t j = 0; j < num_samples; j += FRAME_LEN) {
1861 // 1) At most we process |aec->mult|+1 partitions in 10 ms. Make sure we
1862 // have enough far-end data for that by stuffing the buffer if the
1863 // |system_delay| indicates others.
1864 if (aec->system_delay < FRAME_LEN) {
1865 // We don't have enough data so we rewind 10 ms.
1866 WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec, -(aec->mult + 1));
1867 }
1868
1869 if (!aec->delay_agnostic_enabled) {
1870 // 2 a) Compensate for a possible change in the system delay.
1871
1872 // TODO(bjornv): Investigate how we should round the delay difference;
1873 // right now we know that incoming |knownDelay| is underestimated when
1874 // it's less than |aec->knownDelay|. We therefore, round (-32) in that
1875 // direction. In the other direction, we don't have this situation, but
1876 // might flush one partition too little. This can cause non-causality,
1877 // which should be investigated. Maybe, allow for a non-symmetric
1878 // rounding, like -16.
1879 int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN;
1880 int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements);
1881 MaybeLogDelayAdjustment(moved_elements * (aec->sampFreq == 8000 ? 8 : 4),
1882 DelaySource::kSystemDelay);
1883 aec->knownDelay -= moved_elements * PART_LEN;
1884 } else {
1885 // 2 b) Apply signal based delay correction.
1886 int move_elements = SignalBasedDelayCorrection(aec);
1887 int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements);
1888 MaybeLogDelayAdjustment(moved_elements * (aec->sampFreq == 8000 ? 8 : 4),
1889 DelaySource::kDelayAgnostic);
1890 int far_near_buffer_diff =
1891 aec->farend_block_buffer_.Size() -
1892 (aec->nearend_buffer_size + FRAME_LEN) / PART_LEN;
1893 WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements);
1894 WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend,
1895 moved_elements);
1896 // If we rely on reported system delay values only, a buffer underrun here
1897 // can never occur since we've taken care of that in 1) above. Here, we
1898 // apply signal based delay correction and can therefore end up with
1899 // buffer underruns since the delay estimation can be wrong. We therefore
1900 // stuff the buffer with enough elements if needed.
1901 if (far_near_buffer_diff < 0) {
1902 WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec,
1903 far_near_buffer_diff);
1904 }
1905 }
1906
1907 static_assert(
1908 16 == (FRAME_LEN - PART_LEN),
1909 "These constants need to be properly related for this code to work");
1910 float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN];
1911 float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN];
1912 float farend_extended_block_lowest_band[PART_LEN2];
1913
1914 // Form and process a block of nearend samples, buffer the output block of
1915 // samples.
1916 aec->farend_block_buffer_.ExtractExtendedBlock(
1917 farend_extended_block_lowest_band);
1918 FormNearendBlock(j, num_bands, nearend, PART_LEN - aec->nearend_buffer_size,
1919 aec->nearend_buffer, nearend_block);
1920 ProcessNearendBlock(aec, farend_extended_block_lowest_band, nearend_block,
1921 output_block);
1922 BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size,
1923 aec->output_buffer);
1924
1925 if ((FRAME_LEN - PART_LEN + aec->nearend_buffer_size) == PART_LEN) {
1926 // When possible (every fourth frame) form and process a second block of
1927 // nearend samples, buffer the output block of samples.
1928 aec->farend_block_buffer_.ExtractExtendedBlock(
1929 farend_extended_block_lowest_band);
1930 FormNearendBlock(j + FRAME_LEN - PART_LEN, num_bands, nearend, PART_LEN,
1931 aec->nearend_buffer, nearend_block);
1932 ProcessNearendBlock(aec, farend_extended_block_lowest_band, nearend_block,
1933 output_block);
1934 BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size,
1935 aec->output_buffer);
1936
1937 // Reset the buffer size as there are no samples left in the nearend input
1938 // to buffer.
1939 aec->nearend_buffer_size = 0;
1940 } else {
1941 // Buffer the remaining samples in the nearend input.
1942 aec->nearend_buffer_size += FRAME_LEN - PART_LEN;
1943 BufferNearendFrame(j, num_bands, nearend, aec->nearend_buffer_size,
1944 aec->nearend_buffer);
1945 }
1946
1947 // 5) Update system delay with respect to the entire frame.
1948 aec->system_delay -= FRAME_LEN;
1949
1950 // 6) Form the output frame.
1951 FormOutputFrame(j, num_bands, &aec->output_buffer_size, aec->output_buffer,
1952 out);
1953 }
1954 }
1955
WebRtcAec_GetDelayMetricsCore(AecCore * self,int * median,int * std,float * fraction_poor_delays)1956 int WebRtcAec_GetDelayMetricsCore(AecCore* self,
1957 int* median,
1958 int* std,
1959 float* fraction_poor_delays) {
1960 RTC_DCHECK(self);
1961 RTC_DCHECK(median);
1962 RTC_DCHECK(std);
1963
1964 if (self->delay_logging_enabled == 0) {
1965 // Logging disabled.
1966 return -1;
1967 }
1968
1969 if (self->delay_metrics_delivered == 0) {
1970 UpdateDelayMetrics(self);
1971 self->delay_metrics_delivered = 1;
1972 }
1973 *median = self->delay_median;
1974 *std = self->delay_std;
1975 *fraction_poor_delays = self->fraction_poor_delays;
1976
1977 return 0;
1978 }
1979
WebRtcAec_echo_state(AecCore * self)1980 int WebRtcAec_echo_state(AecCore* self) {
1981 return self->echoState;
1982 }
1983
WebRtcAec_GetEchoStats(AecCore * self,Stats * erl,Stats * erle,Stats * a_nlp,float * divergent_filter_fraction)1984 void WebRtcAec_GetEchoStats(AecCore* self,
1985 Stats* erl,
1986 Stats* erle,
1987 Stats* a_nlp,
1988 float* divergent_filter_fraction) {
1989 RTC_DCHECK(erl);
1990 RTC_DCHECK(erle);
1991 RTC_DCHECK(a_nlp);
1992 *erl = self->erl;
1993 *erle = self->erle;
1994 *a_nlp = self->aNlp;
1995 *divergent_filter_fraction =
1996 self->divergent_filter_fraction.GetLatestFraction();
1997 }
1998
WebRtcAec_SetConfigCore(AecCore * self,int nlp_mode,int metrics_mode,int delay_logging)1999 void WebRtcAec_SetConfigCore(AecCore* self,
2000 int nlp_mode,
2001 int metrics_mode,
2002 int delay_logging) {
2003 RTC_DCHECK_GE(nlp_mode, 0);
2004 RTC_DCHECK_LT(nlp_mode, 3);
2005 self->nlp_mode = nlp_mode;
2006 self->metricsMode = metrics_mode;
2007 if (self->metricsMode) {
2008 InitMetrics(self);
2009 }
2010 // Turn on delay logging if it is either set explicitly or if delay agnostic
2011 // AEC is enabled (which requires delay estimates).
2012 self->delay_logging_enabled = delay_logging || self->delay_agnostic_enabled;
2013 if (self->delay_logging_enabled) {
2014 memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
2015 }
2016 }
2017
WebRtcAec_enable_delay_agnostic(AecCore * self,int enable)2018 void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable) {
2019 self->delay_agnostic_enabled = enable;
2020 }
2021
WebRtcAec_delay_agnostic_enabled(AecCore * self)2022 int WebRtcAec_delay_agnostic_enabled(AecCore* self) {
2023 return self->delay_agnostic_enabled;
2024 }
2025
WebRtcAec_enable_refined_adaptive_filter(AecCore * self,bool enable)2026 void WebRtcAec_enable_refined_adaptive_filter(AecCore* self, bool enable) {
2027 self->refined_adaptive_filter_enabled = enable;
2028 SetAdaptiveFilterStepSize(self);
2029 SetErrorThreshold(self);
2030 }
2031
WebRtcAec_refined_adaptive_filter_enabled(const AecCore * self)2032 bool WebRtcAec_refined_adaptive_filter_enabled(const AecCore* self) {
2033 return self->refined_adaptive_filter_enabled;
2034 }
2035
WebRtcAec_enable_extended_filter(AecCore * self,int enable)2036 void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
2037 self->extended_filter_enabled = enable;
2038 SetAdaptiveFilterStepSize(self);
2039 SetErrorThreshold(self);
2040 self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
2041 // Update the delay estimator with filter length. See InitAEC() for details.
2042 WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);
2043 }
2044
WebRtcAec_extended_filter_enabled(AecCore * self)2045 int WebRtcAec_extended_filter_enabled(AecCore* self) {
2046 return self->extended_filter_enabled;
2047 }
2048
WebRtcAec_system_delay(AecCore * self)2049 int WebRtcAec_system_delay(AecCore* self) {
2050 return self->system_delay;
2051 }
2052
WebRtcAec_SetSystemDelay(AecCore * self,int delay)2053 void WebRtcAec_SetSystemDelay(AecCore* self, int delay) {
2054 RTC_DCHECK_GE(delay, 0);
2055 self->system_delay = delay;
2056 }
2057 } // namespace webrtc
2058