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