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