1/*
2 *  Copyright (c) 2011 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#include "aecm_core.h"
12
13#include <assert.h>
14#include <stdlib.h>
15
16#include "cpu_features_wrapper.h"
17#include "delay_estimator_wrapper.h"
18#include "echo_control_mobile.h"
19#include "ring_buffer.h"
20#include "typedefs.h"
21
22#ifdef ARM_WINM_LOG
23#include <stdio.h>
24#include <windows.h>
25#endif
26
27#ifdef AEC_DEBUG
28FILE *dfile;
29FILE *testfile;
30#endif
31
32#ifdef _MSC_VER // visual c++
33#define ALIGN8_BEG __declspec(align(8))
34#define ALIGN8_END
35#else // gcc or icc
36#define ALIGN8_BEG
37#define ALIGN8_END __attribute__((aligned(8)))
38#endif
39
40#ifdef AECM_SHORT
41
42// Square root of Hanning window in Q14
43const WebRtc_Word16 WebRtcAecm_kSqrtHanning[] =
44{
45    0, 804, 1606, 2404, 3196, 3981, 4756, 5520,
46    6270, 7005, 7723, 8423, 9102, 9760, 10394, 11003,
47    11585, 12140, 12665, 13160, 13623, 14053, 14449, 14811,
48    15137, 15426, 15679, 15893, 16069, 16207, 16305, 16364,
49    16384
50};
51
52#else
53
54// Square root of Hanning window in Q14
55const ALIGN8_BEG WebRtc_Word16 WebRtcAecm_kSqrtHanning[] ALIGN8_END =
56{
57    0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
58    3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364,
59    8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335,
60    12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918,
61    15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237,
62    16286, 16325, 16354, 16373, 16384
63};
64
65#endif
66
67//Q15 alpha = 0.99439986968132  const Factor for magnitude approximation
68static const WebRtc_UWord16 kAlpha1 = 32584;
69//Q15 beta = 0.12967166976970   const Factor for magnitude approximation
70static const WebRtc_UWord16 kBeta1 = 4249;
71//Q15 alpha = 0.94234827210087  const Factor for magnitude approximation
72static const WebRtc_UWord16 kAlpha2 = 30879;
73//Q15 beta = 0.33787806009150   const Factor for magnitude approximation
74static const WebRtc_UWord16 kBeta2 = 11072;
75//Q15 alpha = 0.82247698684306  const Factor for magnitude approximation
76static const WebRtc_UWord16 kAlpha3 = 26951;
77//Q15 beta = 0.57762063060713   const Factor for magnitude approximation
78static const WebRtc_UWord16 kBeta3 = 18927;
79
80// Initialization table for echo channel in 8 kHz
81static const WebRtc_Word16 kChannelStored8kHz[PART_LEN1] = {
82    2040,   1815,   1590,   1498,   1405,   1395,   1385,   1418,
83    1451,   1506,   1562,   1644,   1726,   1804,   1882,   1918,
84    1953,   1982,   2010,   2025,   2040,   2034,   2027,   2021,
85    2014,   1997,   1980,   1925,   1869,   1800,   1732,   1683,
86    1635,   1604,   1572,   1545,   1517,   1481,   1444,   1405,
87    1367,   1331,   1294,   1270,   1245,   1239,   1233,   1247,
88    1260,   1282,   1303,   1338,   1373,   1407,   1441,   1470,
89    1499,   1524,   1549,   1565,   1582,   1601,   1621,   1649,
90    1676
91};
92
93// Initialization table for echo channel in 16 kHz
94static const WebRtc_Word16 kChannelStored16kHz[PART_LEN1] = {
95    2040,   1590,   1405,   1385,   1451,   1562,   1726,   1882,
96    1953,   2010,   2040,   2027,   2014,   1980,   1869,   1732,
97    1635,   1572,   1517,   1444,   1367,   1294,   1245,   1233,
98    1260,   1303,   1373,   1441,   1499,   1549,   1582,   1621,
99    1676,   1741,   1802,   1861,   1921,   1983,   2040,   2102,
100    2170,   2265,   2375,   2515,   2651,   2781,   2922,   3075,
101    3253,   3471,   3738,   3976,   4151,   4258,   4308,   4288,
102    4270,   4253,   4237,   4179,   4086,   3947,   3757,   3484,
103    3153
104};
105
106static const WebRtc_Word16 kCosTable[] = {
107    8192,  8190,  8187,  8180,  8172,  8160,  8147,  8130,  8112,
108    8091,  8067,  8041,  8012,  7982,  7948,  7912,  7874,  7834,
109    7791,  7745,  7697,  7647,  7595,  7540,  7483,  7424,  7362,
110    7299,  7233,  7164,  7094,  7021,  6947,  6870,  6791,  6710,
111    6627,  6542,  6455,  6366,  6275,  6182,  6087,  5991,  5892,
112    5792,  5690,  5586,  5481,  5374,  5265,  5155,  5043,  4930,
113    4815,  4698,  4580,  4461,  4341,  4219,  4096,  3971,  3845,
114    3719,  3591,  3462,  3331,  3200,  3068,  2935,  2801,  2667,
115    2531,  2395,  2258,  2120,  1981,  1842,  1703,  1563,  1422,
116    1281,  1140,   998,   856,   713,   571,   428,   285,   142,
117       0,  -142,  -285,  -428,  -571,  -713,  -856,  -998, -1140,
118   -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
119   -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591,
120   -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
121   -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690,
122   -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542,
123   -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233,
124   -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745,
125   -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067,
126   -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190,
127   -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112,
128   -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
129   -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
130   -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710,
131   -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892,
132   -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930,
133   -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845,
134   -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667,
135   -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422,
136   -1281, -1140,  -998,  -856,  -713,  -571,  -428,  -285,  -142,
137       0,   142,   285,   428,   571,   713,   856,   998,  1140,
138    1281,  1422,  1563,  1703,  1842,  1981,  2120,  2258,  2395,
139    2531,  2667,  2801,  2935,  3068,  3200,  3331,  3462,  3591,
140    3719,  3845,  3971,  4095,  4219,  4341,  4461,  4580,  4698,
141    4815,  4930,  5043,  5155,  5265,  5374,  5481,  5586,  5690,
142    5792,  5892,  5991,  6087,  6182,  6275,  6366,  6455,  6542,
143    6627,  6710,  6791,  6870,  6947,  7021,  7094,  7164,  7233,
144    7299,  7362,  7424,  7483,  7540,  7595,  7647,  7697,  7745,
145    7791,  7834,  7874,  7912,  7948,  7982,  8012,  8041,  8067,
146    8091,  8112,  8130,  8147,  8160,  8172,  8180,  8187,  8190
147};
148
149static const WebRtc_Word16 kSinTable[] = {
150       0,    142,    285,    428,    571,    713,    856,    998,
151    1140,   1281,   1422,   1563,   1703,   1842,   1981,   2120,
152    2258,   2395,   2531,   2667,   2801,   2935,   3068,   3200,
153    3331,   3462,   3591,   3719,   3845,   3971,   4095,   4219,
154    4341,   4461,   4580,   4698,   4815,   4930,   5043,   5155,
155    5265,   5374,   5481,   5586,   5690,   5792,   5892,   5991,
156    6087,   6182,   6275,   6366,   6455,   6542,   6627,   6710,
157    6791,   6870,   6947,   7021,   7094,   7164,   7233,   7299,
158    7362,   7424,   7483,   7540,   7595,   7647,   7697,   7745,
159    7791,   7834,   7874,   7912,   7948,   7982,   8012,   8041,
160    8067,   8091,   8112,   8130,   8147,   8160,   8172,   8180,
161    8187,   8190,   8191,   8190,   8187,   8180,   8172,   8160,
162    8147,   8130,   8112,   8091,   8067,   8041,   8012,   7982,
163    7948,   7912,   7874,   7834,   7791,   7745,   7697,   7647,
164    7595,   7540,   7483,   7424,   7362,   7299,   7233,   7164,
165    7094,   7021,   6947,   6870,   6791,   6710,   6627,   6542,
166    6455,   6366,   6275,   6182,   6087,   5991,   5892,   5792,
167    5690,   5586,   5481,   5374,   5265,   5155,   5043,   4930,
168    4815,   4698,   4580,   4461,   4341,   4219,   4096,   3971,
169    3845,   3719,   3591,   3462,   3331,   3200,   3068,   2935,
170    2801,   2667,   2531,   2395,   2258,   2120,   1981,   1842,
171    1703,   1563,   1422,   1281,   1140,    998,    856,    713,
172     571,    428,    285,    142,      0,   -142,   -285,   -428,
173    -571,   -713,   -856,   -998,  -1140,  -1281,  -1422,  -1563,
174   -1703,  -1842,  -1981,  -2120,  -2258,  -2395,  -2531,  -2667,
175   -2801,  -2935,  -3068,  -3200,  -3331,  -3462,  -3591,  -3719,
176   -3845,  -3971,  -4095,  -4219,  -4341,  -4461,  -4580,  -4698,
177   -4815,  -4930,  -5043,  -5155,  -5265,  -5374,  -5481,  -5586,
178   -5690,  -5792,  -5892,  -5991,  -6087,  -6182,  -6275,  -6366,
179   -6455,  -6542,  -6627,  -6710,  -6791,  -6870,  -6947,  -7021,
180   -7094,  -7164,  -7233,  -7299,  -7362,  -7424,  -7483,  -7540,
181   -7595,  -7647,  -7697,  -7745,  -7791,  -7834,  -7874,  -7912,
182   -7948,  -7982,  -8012,  -8041,  -8067,  -8091,  -8112,  -8130,
183   -8147,  -8160,  -8172,  -8180,  -8187,  -8190,  -8191,  -8190,
184   -8187,  -8180,  -8172,  -8160,  -8147,  -8130,  -8112,  -8091,
185   -8067,  -8041,  -8012,  -7982,  -7948,  -7912,  -7874,  -7834,
186   -7791,  -7745,  -7697,  -7647,  -7595,  -7540,  -7483,  -7424,
187   -7362,  -7299,  -7233,  -7164,  -7094,  -7021,  -6947,  -6870,
188   -6791,  -6710,  -6627,  -6542,  -6455,  -6366,  -6275,  -6182,
189   -6087,  -5991,  -5892,  -5792,  -5690,  -5586,  -5481,  -5374,
190   -5265,  -5155,  -5043,  -4930,  -4815,  -4698,  -4580,  -4461,
191   -4341,  -4219,  -4096,  -3971,  -3845,  -3719,  -3591,  -3462,
192   -3331,  -3200,  -3068,  -2935,  -2801,  -2667,  -2531,  -2395,
193   -2258,  -2120,  -1981,  -1842,  -1703,  -1563,  -1422,  -1281,
194   -1140,   -998,   -856,   -713,   -571,   -428,   -285,   -142
195};
196
197static const WebRtc_Word16 kNoiseEstQDomain = 15;
198static const WebRtc_Word16 kNoiseEstIncCount = 5;
199
200static void ComfortNoise(AecmCore_t* aecm,
201                         const WebRtc_UWord16* dfa,
202                         complex16_t* out,
203                         const WebRtc_Word16* lambda);
204
205static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm);
206
207// Moves the pointer to the next entry and inserts |far_spectrum| and
208// corresponding Q-domain in its buffer.
209//
210// Inputs:
211//      - self          : Pointer to the delay estimation instance
212//      - far_spectrum  : Pointer to the far end spectrum
213//      - far_q         : Q-domain of far end spectrum
214//
215static void UpdateFarHistory(AecmCore_t* self,
216                             uint16_t* far_spectrum,
217                             int far_q) {
218  // Get new buffer position
219  self->far_history_pos++;
220  if (self->far_history_pos >= MAX_DELAY) {
221    self->far_history_pos = 0;
222  }
223  // Update Q-domain buffer
224  self->far_q_domains[self->far_history_pos] = far_q;
225  // Update far end spectrum buffer
226  memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]),
227         far_spectrum,
228         sizeof(uint16_t) * PART_LEN1);
229}
230
231// Returns a pointer to the far end spectrum aligned to current near end
232// spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
233// called before AlignedFarend(...). Otherwise, you get the pointer to the
234// previous frame. The memory is only valid until the next call of
235// WebRtc_DelayEstimatorProcessFix(...).
236//
237// Inputs:
238//      - self              : Pointer to the AECM instance.
239//      - delay             : Current delay estimate.
240//
241// Output:
242//      - far_q             : The Q-domain of the aligned far end spectrum
243//
244// Return value:
245//      - far_spectrum      : Pointer to the aligned far end spectrum
246//                            NULL - Error
247//
248static const uint16_t* AlignedFarend(AecmCore_t* self, int* far_q, int delay) {
249  int buffer_position = 0;
250  assert(self != NULL);
251  buffer_position = self->far_history_pos - delay;
252
253  // Check buffer position
254  if (buffer_position < 0) {
255    buffer_position += MAX_DELAY;
256  }
257  // Get Q-domain
258  *far_q = self->far_q_domains[buffer_position];
259  // Return far end spectrum
260  return &(self->far_history[buffer_position * PART_LEN1]);
261}
262
263#ifdef ARM_WINM_LOG
264HANDLE logFile = NULL;
265#endif
266
267// Declare function pointers.
268CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
269StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
270ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
271WindowAndFFT WebRtcAecm_WindowAndFFT;
272InverseFFTAndWindow WebRtcAecm_InverseFFTAndWindow;
273
274int WebRtcAecm_CreateCore(AecmCore_t **aecmInst)
275{
276    AecmCore_t *aecm = malloc(sizeof(AecmCore_t));
277    *aecmInst = aecm;
278    if (aecm == NULL)
279    {
280        return -1;
281    }
282
283    if (WebRtc_CreateBuffer(&aecm->farFrameBuf, FRAME_LEN + PART_LEN,
284                            sizeof(int16_t)) == -1)
285    {
286        WebRtcAecm_FreeCore(aecm);
287        aecm = NULL;
288        return -1;
289    }
290
291    if (WebRtc_CreateBuffer(&aecm->nearNoisyFrameBuf, FRAME_LEN + PART_LEN,
292                            sizeof(int16_t)) == -1)
293    {
294        WebRtcAecm_FreeCore(aecm);
295        aecm = NULL;
296        return -1;
297    }
298
299    if (WebRtc_CreateBuffer(&aecm->nearCleanFrameBuf, FRAME_LEN + PART_LEN,
300                            sizeof(int16_t)) == -1)
301    {
302        WebRtcAecm_FreeCore(aecm);
303        aecm = NULL;
304        return -1;
305    }
306
307    if (WebRtc_CreateBuffer(&aecm->outFrameBuf, FRAME_LEN + PART_LEN,
308                            sizeof(int16_t)) == -1)
309    {
310        WebRtcAecm_FreeCore(aecm);
311        aecm = NULL;
312        return -1;
313    }
314
315    if (WebRtc_CreateDelayEstimator(&aecm->delay_estimator,
316                                    PART_LEN1,
317                                    MAX_DELAY,
318                                    0) == -1) {
319      WebRtcAecm_FreeCore(aecm);
320      aecm = NULL;
321      return -1;
322    }
323
324    // Init some aecm pointers. 16 and 32 byte alignment is only necessary
325    // for Neon code currently.
326    aecm->xBuf = (WebRtc_Word16*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
327    aecm->dBufClean = (WebRtc_Word16*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
328    aecm->dBufNoisy = (WebRtc_Word16*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
329    aecm->outBuf = (WebRtc_Word16*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
330    aecm->channelStored = (WebRtc_Word16*) (((uintptr_t)
331                                             aecm->channelStored_buf + 15) & ~ 15);
332    aecm->channelAdapt16 = (WebRtc_Word16*) (((uintptr_t)
333                                              aecm->channelAdapt16_buf + 15) & ~ 15);
334    aecm->channelAdapt32 = (WebRtc_Word32*) (((uintptr_t)
335                                              aecm->channelAdapt32_buf + 31) & ~ 31);
336
337    return 0;
338}
339
340void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_path)
341{
342    int i = 0;
343
344    // Reset the stored channel
345    memcpy(aecm->channelStored, echo_path, sizeof(WebRtc_Word16) * PART_LEN1);
346    // Reset the adapted channels
347    memcpy(aecm->channelAdapt16, echo_path, sizeof(WebRtc_Word16) * PART_LEN1);
348    for (i = 0; i < PART_LEN1; i++)
349    {
350        aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
351            (WebRtc_Word32)(aecm->channelAdapt16[i]), 16);
352    }
353
354    // Reset channel storing variables
355    aecm->mseAdaptOld = 1000;
356    aecm->mseStoredOld = 1000;
357    aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
358    aecm->mseChannelCount = 0;
359}
360
361static void WindowAndFFTC(WebRtc_Word16* fft,
362                          const WebRtc_Word16* time_signal,
363                          complex16_t* freq_signal,
364                          int time_signal_scaling)
365{
366    int i, j;
367
368    memset(fft, 0, sizeof(WebRtc_Word16) * PART_LEN4);
369    // FFT of signal
370    for (i = 0, j = 0; i < PART_LEN; i++, j += 2)
371    {
372        // Window time domain signal and insert into real part of
373        // transformation array |fft|
374        fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(
375            (time_signal[i] << time_signal_scaling),
376            WebRtcAecm_kSqrtHanning[i],
377            14);
378        fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(
379            (time_signal[i + PART_LEN] << time_signal_scaling),
380            WebRtcAecm_kSqrtHanning[PART_LEN - i],
381            14);
382        // Inserting zeros in imaginary parts not necessary since we
383        // initialized the array with all zeros
384    }
385
386    WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
387    WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
388
389    // Take only the first PART_LEN2 samples
390    for (i = 0, j = 0; j < PART_LEN2; i += 1, j += 2)
391    {
392        freq_signal[i].real = fft[j];
393
394        // The imaginary part has to switch sign
395        freq_signal[i].imag = - fft[j+1];
396    }
397}
398
399static void InverseFFTAndWindowC(AecmCore_t* aecm,
400                                 WebRtc_Word16* fft,
401                                 complex16_t* efw,
402                                 WebRtc_Word16* output,
403                                 const WebRtc_Word16* nearendClean)
404{
405    int i, j, outCFFT;
406    WebRtc_Word32 tmp32no1;
407
408    // Synthesis
409    for (i = 1; i < PART_LEN; i++)
410    {
411        j = WEBRTC_SPL_LSHIFT_W32(i, 1);
412        fft[j] = efw[i].real;
413
414        // mirrored data, even
415        fft[PART_LEN4 - j] = efw[i].real;
416        fft[j + 1] = -efw[i].imag;
417
418        //mirrored data, odd
419        fft[PART_LEN4 - (j - 1)] = efw[i].imag;
420    }
421    fft[0] = efw[0].real;
422    fft[1] = -efw[0].imag;
423
424    fft[PART_LEN2] = efw[PART_LEN].real;
425    fft[PART_LEN2 + 1] = -efw[PART_LEN].imag;
426
427    // inverse FFT, result should be scaled with outCFFT
428    WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
429    outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
430
431    //take only the real values and scale with outCFFT
432    for (i = 0; i < PART_LEN2; i++)
433    {
434        j = WEBRTC_SPL_LSHIFT_W32(i, 1);
435        fft[i] = fft[j];
436    }
437
438    for (i = 0; i < PART_LEN; i++)
439    {
440        fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
441                fft[i],
442                WebRtcAecm_kSqrtHanning[i],
443                14);
444        tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i],
445                outCFFT - aecm->dfaCleanQDomain);
446        fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
447                tmp32no1 + aecm->outBuf[i],
448                WEBRTC_SPL_WORD16_MIN);
449        output[i] = fft[i];
450
451        tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT(
452                fft[PART_LEN + i],
453                WebRtcAecm_kSqrtHanning[PART_LEN - i],
454                14);
455        tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1,
456                outCFFT - aecm->dfaCleanQDomain);
457        aecm->outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(
458                WEBRTC_SPL_WORD16_MAX,
459                tmp32no1,
460                WEBRTC_SPL_WORD16_MIN);
461    }
462
463#ifdef ARM_WINM_LOG_
464    // measure tick end
465    QueryPerformanceCounter((LARGE_INTEGER*)&end);
466    diff__ = ((end - start) * 1000) / (freq/1000);
467    milliseconds = (unsigned int)(diff__ & 0xffffffff);
468    WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
469#endif
470
471    // Copy the current block to the old position (aecm->outBuf is shifted elsewhere)
472    memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
473    memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
474    if (nearendClean != NULL)
475    {
476        memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
477    }
478}
479
480static void CalcLinearEnergiesC(AecmCore_t* aecm,
481                                const WebRtc_UWord16* far_spectrum,
482                                WebRtc_Word32* echo_est,
483                                WebRtc_UWord32* far_energy,
484                                WebRtc_UWord32* echo_energy_adapt,
485                                WebRtc_UWord32* echo_energy_stored)
486{
487    int i;
488
489    // Get energy for the delayed far end signal and estimated
490    // echo using both stored and adapted channels.
491    for (i = 0; i < PART_LEN1; i++)
492    {
493        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
494                                           far_spectrum[i]);
495        (*far_energy) += (WebRtc_UWord32)(far_spectrum[i]);
496        (*echo_energy_adapt) += WEBRTC_SPL_UMUL_16_16(aecm->channelAdapt16[i],
497                                          far_spectrum[i]);
498        (*echo_energy_stored) += (WebRtc_UWord32)echo_est[i];
499    }
500}
501
502static void StoreAdaptiveChannelC(AecmCore_t* aecm,
503                                  const WebRtc_UWord16* far_spectrum,
504                                  WebRtc_Word32* echo_est)
505{
506    int i;
507
508    // During startup we store the channel every block.
509    memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(WebRtc_Word16) * PART_LEN1);
510    // Recalculate echo estimate
511    for (i = 0; i < PART_LEN; i += 4)
512    {
513        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
514                                           far_spectrum[i]);
515        echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
516                                           far_spectrum[i + 1]);
517        echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
518                                           far_spectrum[i + 2]);
519        echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
520                                           far_spectrum[i + 3]);
521    }
522    echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
523                                       far_spectrum[i]);
524}
525
526static void ResetAdaptiveChannelC(AecmCore_t* aecm)
527{
528    int i;
529
530    // The stored channel has a significantly lower MSE than the adaptive one for
531    // two consecutive calculations. Reset the adaptive channel.
532    memcpy(aecm->channelAdapt16, aecm->channelStored,
533           sizeof(WebRtc_Word16) * PART_LEN1);
534    // Restore the W32 channel
535    for (i = 0; i < PART_LEN; i += 4)
536    {
537        aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
538                (WebRtc_Word32)aecm->channelStored[i], 16);
539        aecm->channelAdapt32[i + 1] = WEBRTC_SPL_LSHIFT_W32(
540                (WebRtc_Word32)aecm->channelStored[i + 1], 16);
541        aecm->channelAdapt32[i + 2] = WEBRTC_SPL_LSHIFT_W32(
542                (WebRtc_Word32)aecm->channelStored[i + 2], 16);
543        aecm->channelAdapt32[i + 3] = WEBRTC_SPL_LSHIFT_W32(
544                (WebRtc_Word32)aecm->channelStored[i + 3], 16);
545    }
546    aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
547}
548
549// WebRtcAecm_InitCore(...)
550//
551// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
552// Input:
553//      - aecm            : Pointer to the Echo Suppression instance
554//      - samplingFreq   : Sampling Frequency
555//
556// Output:
557//      - aecm            : Initialized instance
558//
559// Return value         :  0 - Ok
560//                        -1 - Error
561//
562int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq)
563{
564    int i = 0;
565    WebRtc_Word32 tmp32 = PART_LEN1 * PART_LEN1;
566    WebRtc_Word16 tmp16 = PART_LEN1;
567
568    if (samplingFreq != 8000 && samplingFreq != 16000)
569    {
570        samplingFreq = 8000;
571        return -1;
572    }
573    // sanity check of sampling frequency
574    aecm->mult = (WebRtc_Word16)samplingFreq / 8000;
575
576    aecm->farBufWritePos = 0;
577    aecm->farBufReadPos = 0;
578    aecm->knownDelay = 0;
579    aecm->lastKnownDelay = 0;
580
581    WebRtc_InitBuffer(aecm->farFrameBuf);
582    WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
583    WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
584    WebRtc_InitBuffer(aecm->outFrameBuf);
585
586    memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
587    memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
588    memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
589    memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
590
591    aecm->seed = 666;
592    aecm->totCount = 0;
593
594    if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
595      return -1;
596    }
597    // Set far end histories to zero
598    memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
599    memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
600    aecm->far_history_pos = MAX_DELAY;
601
602    aecm->nlpFlag = 1;
603    aecm->fixedDelay = -1;
604
605    aecm->dfaCleanQDomain = 0;
606    aecm->dfaCleanQDomainOld = 0;
607    aecm->dfaNoisyQDomain = 0;
608    aecm->dfaNoisyQDomainOld = 0;
609
610    memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
611    aecm->farLogEnergy = 0;
612    memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
613    memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
614
615    // Initialize the echo channels with a stored shape.
616    if (samplingFreq == 8000)
617    {
618        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
619    }
620    else
621    {
622        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
623    }
624
625    memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
626    memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
627    aecm->noiseEstCtr = 0;
628
629    aecm->cngMode = AecmTrue;
630
631    memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
632    memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
633    // Shape the initial noise level to an approximate pink noise.
634    for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
635    {
636        aecm->noiseEst[i] = (tmp32 << 8);
637        tmp16--;
638        tmp32 -= (WebRtc_Word32)((tmp16 << 1) + 1);
639    }
640    for (; i < PART_LEN1; i++)
641    {
642        aecm->noiseEst[i] = (tmp32 << 8);
643    }
644
645    aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
646    aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
647    aecm->farEnergyMaxMin = 0;
648    aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
649                                         // beginning.
650    aecm->farEnergyMSE = 0;
651    aecm->currentVADValue = 0;
652    aecm->vadUpdateCount = 0;
653    aecm->firstVAD = 1;
654
655    aecm->startupState = 0;
656    aecm->supGain = SUPGAIN_DEFAULT;
657    aecm->supGainOld = SUPGAIN_DEFAULT;
658
659    aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
660    aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
661    aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
662    aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
663
664    assert(PART_LEN % 16 == 0);
665
666    // Initialize function pointers.
667    WebRtcAecm_WindowAndFFT = WindowAndFFTC;
668    WebRtcAecm_InverseFFTAndWindow = InverseFFTAndWindowC;
669    WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
670    WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
671    WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
672
673#ifdef WEBRTC_DETECT_ARM_NEON
674    uint64_t features = WebRtc_GetCPUFeaturesARM();
675    if ((features & kCPUFeatureNEON) != 0)
676    {
677        WebRtcAecm_InitNeon();
678    }
679#elif defined(WEBRTC_ARCH_ARM_NEON)
680    WebRtcAecm_InitNeon();
681#endif
682
683    return 0;
684}
685
686// TODO(bjornv): This function is currently not used. Add support for these
687// parameters from a higher level
688int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag)
689{
690    aecm->nlpFlag = nlpFlag;
691    aecm->fixedDelay = delay;
692
693    return 0;
694}
695
696int WebRtcAecm_FreeCore(AecmCore_t *aecm)
697{
698    if (aecm == NULL)
699    {
700        return -1;
701    }
702
703    WebRtc_FreeBuffer(aecm->farFrameBuf);
704    WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
705    WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
706    WebRtc_FreeBuffer(aecm->outFrameBuf);
707
708    WebRtc_FreeDelayEstimator(aecm->delay_estimator);
709    free(aecm);
710
711    return 0;
712}
713
714int WebRtcAecm_ProcessFrame(AecmCore_t * aecm,
715                            const WebRtc_Word16 * farend,
716                            const WebRtc_Word16 * nearendNoisy,
717                            const WebRtc_Word16 * nearendClean,
718                            WebRtc_Word16 * out)
719{
720    WebRtc_Word16 outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
721    WebRtc_Word16* outBlock = (WebRtc_Word16*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
722
723    WebRtc_Word16 farFrame[FRAME_LEN];
724    const int16_t* out_ptr = NULL;
725    int size = 0;
726
727    // Buffer the current frame.
728    // Fetch an older one corresponding to the delay.
729    WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
730    WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
731
732    // Buffer the synchronized far and near frames,
733    // to pass the smaller blocks individually.
734    WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
735    WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
736    if (nearendClean != NULL)
737    {
738        WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
739    }
740
741    // Process as many blocks as possible.
742    while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
743    {
744        int16_t far_block[PART_LEN];
745        const int16_t* far_block_ptr = NULL;
746        int16_t near_noisy_block[PART_LEN];
747        const int16_t* near_noisy_block_ptr = NULL;
748
749        WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
750                          PART_LEN);
751        WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
752                          (void**) &near_noisy_block_ptr,
753                          near_noisy_block,
754                          PART_LEN);
755        if (nearendClean != NULL)
756        {
757            int16_t near_clean_block[PART_LEN];
758            const int16_t* near_clean_block_ptr = NULL;
759
760            WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
761                              (void**) &near_clean_block_ptr,
762                              near_clean_block,
763                              PART_LEN);
764            if (WebRtcAecm_ProcessBlock(aecm,
765                                        far_block_ptr,
766                                        near_noisy_block_ptr,
767                                        near_clean_block_ptr,
768                                        outBlock) == -1)
769            {
770                return -1;
771            }
772        } else
773        {
774            if (WebRtcAecm_ProcessBlock(aecm,
775                                        far_block_ptr,
776                                        near_noisy_block_ptr,
777                                        NULL,
778                                        outBlock) == -1)
779            {
780                return -1;
781            }
782        }
783
784        WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
785    }
786
787    // Stuff the out buffer if we have less than a frame to output.
788    // This should only happen for the first frame.
789    size = (int) WebRtc_available_read(aecm->outFrameBuf);
790    if (size < FRAME_LEN)
791    {
792        WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
793    }
794
795    // Obtain an output frame.
796    WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
797    if (out_ptr != out) {
798      // ReadBuffer() hasn't copied to |out| in this case.
799      memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
800    }
801
802    return 0;
803}
804
805// WebRtcAecm_AsymFilt(...)
806//
807// Performs asymmetric filtering.
808//
809// Inputs:
810//      - filtOld       : Previous filtered value.
811//      - inVal         : New input value.
812//      - stepSizePos   : Step size when we have a positive contribution.
813//      - stepSizeNeg   : Step size when we have a negative contribution.
814//
815// Output:
816//
817// Return: - Filtered value.
818//
819WebRtc_Word16 WebRtcAecm_AsymFilt(const WebRtc_Word16 filtOld, const WebRtc_Word16 inVal,
820                                  const WebRtc_Word16 stepSizePos,
821                                  const WebRtc_Word16 stepSizeNeg)
822{
823    WebRtc_Word16 retVal;
824
825    if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
826    {
827        return inVal;
828    }
829    retVal = filtOld;
830    if (filtOld > inVal)
831    {
832        retVal -= WEBRTC_SPL_RSHIFT_W16(filtOld - inVal, stepSizeNeg);
833    } else
834    {
835        retVal += WEBRTC_SPL_RSHIFT_W16(inVal - filtOld, stepSizePos);
836    }
837
838    return retVal;
839}
840
841// WebRtcAecm_CalcEnergies(...)
842//
843// This function calculates the log of energies for nearend, farend and estimated
844// echoes. There is also an update of energy decision levels, i.e. internal VAD.
845//
846//
847// @param  aecm         [i/o]   Handle of the AECM instance.
848// @param  far_spectrum [in]    Pointer to farend spectrum.
849// @param  far_q        [in]    Q-domain of farend spectrum.
850// @param  nearEner     [in]    Near end energy for current block in
851//                              Q(aecm->dfaQDomain).
852// @param  echoEst      [out]   Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
853//
854void WebRtcAecm_CalcEnergies(AecmCore_t * aecm,
855                             const WebRtc_UWord16* far_spectrum,
856                             const WebRtc_Word16 far_q,
857                             const WebRtc_UWord32 nearEner,
858                             WebRtc_Word32 * echoEst)
859{
860    // Local variables
861    WebRtc_UWord32 tmpAdapt = 0;
862    WebRtc_UWord32 tmpStored = 0;
863    WebRtc_UWord32 tmpFar = 0;
864
865    int i;
866
867    WebRtc_Word16 zeros, frac;
868    WebRtc_Word16 tmp16;
869    WebRtc_Word16 increase_max_shifts = 4;
870    WebRtc_Word16 decrease_max_shifts = 11;
871    WebRtc_Word16 increase_min_shifts = 11;
872    WebRtc_Word16 decrease_min_shifts = 3;
873    WebRtc_Word16 kLogLowValue = WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
874
875    // Get log of near end energy and store in buffer
876
877    // Shift buffer
878    memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
879            sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
880
881    // Logarithm of integrated magnitude spectrum (nearEner)
882    tmp16 = kLogLowValue;
883    if (nearEner)
884    {
885        zeros = WebRtcSpl_NormU32(nearEner);
886        frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(
887                              (WEBRTC_SPL_LSHIFT_U32(nearEner, zeros) & 0x7FFFFFFF),
888                              23);
889        // log2 in Q8
890        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
891        tmp16 -= WEBRTC_SPL_LSHIFT_W16(aecm->dfaNoisyQDomain, 8);
892    }
893    aecm->nearLogEnergy[0] = tmp16;
894    // END: Get log of near end energy
895
896    WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
897
898    // Shift buffers
899    memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
900            sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
901    memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
902            sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
903
904    // Logarithm of delayed far end energy
905    tmp16 = kLogLowValue;
906    if (tmpFar)
907    {
908        zeros = WebRtcSpl_NormU32(tmpFar);
909        frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpFar, zeros)
910                        & 0x7FFFFFFF), 23);
911        // log2 in Q8
912        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
913        tmp16 -= WEBRTC_SPL_LSHIFT_W16(far_q, 8);
914    }
915    aecm->farLogEnergy = tmp16;
916
917    // Logarithm of estimated echo energy through adapted channel
918    tmp16 = kLogLowValue;
919    if (tmpAdapt)
920    {
921        zeros = WebRtcSpl_NormU32(tmpAdapt);
922        frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpAdapt, zeros)
923                        & 0x7FFFFFFF), 23);
924        //log2 in Q8
925        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
926        tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
927    }
928    aecm->echoAdaptLogEnergy[0] = tmp16;
929
930    // Logarithm of estimated echo energy through stored channel
931    tmp16 = kLogLowValue;
932    if (tmpStored)
933    {
934        zeros = WebRtcSpl_NormU32(tmpStored);
935        frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpStored, zeros)
936                        & 0x7FFFFFFF), 23);
937        //log2 in Q8
938        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
939        tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
940    }
941    aecm->echoStoredLogEnergy[0] = tmp16;
942
943    // Update farend energy levels (min, max, vad, mse)
944    if (aecm->farLogEnergy > FAR_ENERGY_MIN)
945    {
946        if (aecm->startupState == 0)
947        {
948            increase_max_shifts = 2;
949            decrease_min_shifts = 2;
950            increase_min_shifts = 8;
951        }
952
953        aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
954                                                 increase_min_shifts, decrease_min_shifts);
955        aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
956                                                 increase_max_shifts, decrease_max_shifts);
957        aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
958
959        // Dynamic VAD region size
960        tmp16 = 2560 - aecm->farEnergyMin;
961        if (tmp16 > 0)
962        {
963            tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, FAR_ENERGY_VAD_REGION, 9);
964        } else
965        {
966            tmp16 = 0;
967        }
968        tmp16 += FAR_ENERGY_VAD_REGION;
969
970        if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
971        {
972            // In startup phase or VAD update halted
973            aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
974        } else
975        {
976            if (aecm->farEnergyVAD > aecm->farLogEnergy)
977            {
978                aecm->farEnergyVAD += WEBRTC_SPL_RSHIFT_W16(aecm->farLogEnergy +
979                                                            tmp16 -
980                                                            aecm->farEnergyVAD,
981                                                            6);
982                aecm->vadUpdateCount = 0;
983            } else
984            {
985                aecm->vadUpdateCount++;
986            }
987        }
988        // Put MSE threshold higher than VAD
989        aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
990    }
991
992    // Update VAD variables
993    if (aecm->farLogEnergy > aecm->farEnergyVAD)
994    {
995        if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
996        {
997            // We are in startup or have significant dynamics in input speech level
998            aecm->currentVADValue = 1;
999        }
1000    } else
1001    {
1002        aecm->currentVADValue = 0;
1003    }
1004    if ((aecm->currentVADValue) && (aecm->firstVAD))
1005    {
1006        aecm->firstVAD = 0;
1007        if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
1008        {
1009            // The estimated echo has higher energy than the near end signal.
1010            // This means that the initialization was too aggressive. Scale
1011            // down by a factor 8
1012            for (i = 0; i < PART_LEN1; i++)
1013            {
1014                aecm->channelAdapt16[i] >>= 3;
1015            }
1016            // Compensate the adapted echo energy level accordingly.
1017            aecm->echoAdaptLogEnergy[0] -= (3 << 8);
1018            aecm->firstVAD = 1;
1019        }
1020    }
1021}
1022
1023// WebRtcAecm_CalcStepSize(...)
1024//
1025// This function calculates the step size used in channel estimation
1026//
1027//
1028// @param  aecm  [in]    Handle of the AECM instance.
1029// @param  mu    [out]   (Return value) Stepsize in log2(), i.e. number of shifts.
1030//
1031//
1032WebRtc_Word16 WebRtcAecm_CalcStepSize(AecmCore_t * const aecm)
1033{
1034
1035    WebRtc_Word32 tmp32;
1036    WebRtc_Word16 tmp16;
1037    WebRtc_Word16 mu = MU_MAX;
1038
1039    // Here we calculate the step size mu used in the
1040    // following NLMS based Channel estimation algorithm
1041    if (!aecm->currentVADValue)
1042    {
1043        // Far end energy level too low, no channel update
1044        mu = 0;
1045    } else if (aecm->startupState > 0)
1046    {
1047        if (aecm->farEnergyMin >= aecm->farEnergyMax)
1048        {
1049            mu = MU_MIN;
1050        } else
1051        {
1052            tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
1053            tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, MU_DIFF);
1054            tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
1055            mu = MU_MIN - 1 - (WebRtc_Word16)(tmp32);
1056            // The -1 is an alternative to rounding. This way we get a larger
1057            // stepsize, so we in some sense compensate for truncation in NLMS
1058        }
1059        if (mu < MU_MAX)
1060        {
1061            mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
1062        }
1063    }
1064
1065    return mu;
1066}
1067
1068// WebRtcAecm_UpdateChannel(...)
1069//
1070// This function performs channel estimation. NLMS and decision on channel storage.
1071//
1072//
1073// @param  aecm         [i/o]   Handle of the AECM instance.
1074// @param  far_spectrum [in]    Absolute value of the farend signal in Q(far_q)
1075// @param  far_q        [in]    Q-domain of the farend signal
1076// @param  dfa          [in]    Absolute value of the nearend signal (Q[aecm->dfaQDomain])
1077// @param  mu           [in]    NLMS step size.
1078// @param  echoEst      [i/o]   Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
1079//
1080void WebRtcAecm_UpdateChannel(AecmCore_t * aecm,
1081                              const WebRtc_UWord16* far_spectrum,
1082                              const WebRtc_Word16 far_q,
1083                              const WebRtc_UWord16 * const dfa,
1084                              const WebRtc_Word16 mu,
1085                              WebRtc_Word32 * echoEst)
1086{
1087
1088    WebRtc_UWord32 tmpU32no1, tmpU32no2;
1089    WebRtc_Word32 tmp32no1, tmp32no2;
1090    WebRtc_Word32 mseStored;
1091    WebRtc_Word32 mseAdapt;
1092
1093    int i;
1094
1095    WebRtc_Word16 zerosFar, zerosNum, zerosCh, zerosDfa;
1096    WebRtc_Word16 shiftChFar, shiftNum, shift2ResChan;
1097    WebRtc_Word16 tmp16no1;
1098    WebRtc_Word16 xfaQ, dfaQ;
1099
1100    // This is the channel estimation algorithm. It is base on NLMS but has a variable step
1101    // length, which was calculated above.
1102    if (mu)
1103    {
1104        for (i = 0; i < PART_LEN1; i++)
1105        {
1106            // Determine norm of channel and farend to make sure we don't get overflow in
1107            // multiplication
1108            zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
1109            zerosFar = WebRtcSpl_NormU32((WebRtc_UWord32)far_spectrum[i]);
1110            if (zerosCh + zerosFar > 31)
1111            {
1112                // Multiplication is safe
1113                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
1114                        far_spectrum[i]);
1115                shiftChFar = 0;
1116            } else
1117            {
1118                // We need to shift down before multiplication
1119                shiftChFar = 32 - zerosCh - zerosFar;
1120                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(
1121                    WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], shiftChFar),
1122                    far_spectrum[i]);
1123            }
1124            // Determine Q-domain of numerator
1125            zerosNum = WebRtcSpl_NormU32(tmpU32no1);
1126            if (dfa[i])
1127            {
1128                zerosDfa = WebRtcSpl_NormU32((WebRtc_UWord32)dfa[i]);
1129            } else
1130            {
1131                zerosDfa = 32;
1132            }
1133            tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
1134                RESOLUTION_CHANNEL32 - far_q + shiftChFar;
1135            if (zerosNum > tmp16no1 + 1)
1136            {
1137                xfaQ = tmp16no1;
1138                dfaQ = zerosDfa - 2;
1139            } else
1140            {
1141                xfaQ = zerosNum - 2;
1142                dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
1143                    shiftChFar + xfaQ;
1144            }
1145            // Add in the same Q-domain
1146            tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
1147            tmpU32no2 = WEBRTC_SPL_SHIFT_W32((WebRtc_UWord32)dfa[i], dfaQ);
1148            tmp32no1 = (WebRtc_Word32)tmpU32no2 - (WebRtc_Word32)tmpU32no1;
1149            zerosNum = WebRtcSpl_NormW32(tmp32no1);
1150            if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
1151            {
1152                //
1153                // Update is needed
1154                //
1155                // This is what we would like to compute
1156                //
1157                // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
1158                // tmp32norm = (i + 1)
1159                // aecm->channelAdapt[i] += (2^mu) * tmp32no1
1160                //                        / (tmp32norm * far_spectrum[i])
1161                //
1162
1163                // Make sure we don't get overflow in multiplication.
1164                if (zerosNum + zerosFar > 31)
1165                {
1166                    if (tmp32no1 > 0)
1167                    {
1168                        tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmp32no1,
1169                                                                        far_spectrum[i]);
1170                    } else
1171                    {
1172                        tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
1173                                                                         far_spectrum[i]);
1174                    }
1175                    shiftNum = 0;
1176                } else
1177                {
1178                    shiftNum = 32 - (zerosNum + zerosFar);
1179                    if (tmp32no1 > 0)
1180                    {
1181                        tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(
1182                                WEBRTC_SPL_RSHIFT_W32(tmp32no1, shiftNum),
1183                                far_spectrum[i]);
1184                    } else
1185                    {
1186                        tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(
1187                                WEBRTC_SPL_RSHIFT_W32(-tmp32no1, shiftNum),
1188                                far_spectrum[i]);
1189                    }
1190                }
1191                // Normalize with respect to frequency bin
1192                tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
1193                // Make sure we are in the right Q-domain
1194                shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
1195                if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
1196                {
1197                    tmp32no2 = WEBRTC_SPL_WORD32_MAX;
1198                } else
1199                {
1200                    tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
1201                }
1202                aecm->channelAdapt32[i] = WEBRTC_SPL_ADD_SAT_W32(aecm->channelAdapt32[i],
1203                        tmp32no2);
1204                if (aecm->channelAdapt32[i] < 0)
1205                {
1206                    // We can never have negative channel gain
1207                    aecm->channelAdapt32[i] = 0;
1208                }
1209                aecm->channelAdapt16[i]
1210                        = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], 16);
1211            }
1212        }
1213    }
1214    // END: Adaptive channel update
1215
1216    // Determine if we should store or restore the channel
1217    if ((aecm->startupState == 0) & (aecm->currentVADValue))
1218    {
1219        // During startup we store the channel every block,
1220        // and we recalculate echo estimate
1221        WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1222    } else
1223    {
1224        if (aecm->farLogEnergy < aecm->farEnergyMSE)
1225        {
1226            aecm->mseChannelCount = 0;
1227        } else
1228        {
1229            aecm->mseChannelCount++;
1230        }
1231        // Enough data for validation. Store channel if we can.
1232        if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
1233        {
1234            // We have enough data.
1235            // Calculate MSE of "Adapt" and "Stored" versions.
1236            // It is actually not MSE, but average absolute error.
1237            mseStored = 0;
1238            mseAdapt = 0;
1239            for (i = 0; i < MIN_MSE_COUNT; i++)
1240            {
1241                tmp32no1 = ((WebRtc_Word32)aecm->echoStoredLogEnergy[i]
1242                        - (WebRtc_Word32)aecm->nearLogEnergy[i]);
1243                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1244                mseStored += tmp32no2;
1245
1246                tmp32no1 = ((WebRtc_Word32)aecm->echoAdaptLogEnergy[i]
1247                        - (WebRtc_Word32)aecm->nearLogEnergy[i]);
1248                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1249                mseAdapt += tmp32no2;
1250            }
1251            if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
1252                    & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
1253                            * aecm->mseAdaptOld)))
1254            {
1255                // The stored channel has a significantly lower MSE than the adaptive one for
1256                // two consecutive calculations. Reset the adaptive channel.
1257                WebRtcAecm_ResetAdaptiveChannel(aecm);
1258            } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
1259                    < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
1260            {
1261                // The adaptive channel has a significantly lower MSE than the stored one.
1262                // The MSE for the adaptive channel has also been low for two consecutive
1263                // calculations. Store the adaptive channel.
1264                WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1265
1266                // Update threshold
1267                if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
1268                {
1269                    aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
1270                } else
1271                {
1272                    aecm->mseThreshold += WEBRTC_SPL_MUL_16_16_RSFT(mseAdapt
1273                            - WEBRTC_SPL_MUL_16_16_RSFT(aecm->mseThreshold, 5, 3), 205, 8);
1274                }
1275
1276            }
1277
1278            // Reset counter
1279            aecm->mseChannelCount = 0;
1280
1281            // Store the MSE values.
1282            aecm->mseStoredOld = mseStored;
1283            aecm->mseAdaptOld = mseAdapt;
1284        }
1285    }
1286    // END: Determine if we should store or reset channel estimate.
1287}
1288
1289// CalcSuppressionGain(...)
1290//
1291// This function calculates the suppression gain that is used in the Wiener filter.
1292//
1293//
1294// @param  aecm     [i/n]   Handle of the AECM instance.
1295// @param  supGain  [out]   (Return value) Suppression gain with which to scale the noise
1296//                          level (Q14).
1297//
1298//
1299static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm)
1300{
1301    WebRtc_Word32 tmp32no1;
1302
1303    WebRtc_Word16 supGain = SUPGAIN_DEFAULT;
1304    WebRtc_Word16 tmp16no1;
1305    WebRtc_Word16 dE = 0;
1306
1307    // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
1308    // end energy and echo estimation error.
1309    // Adjust for the far end signal level. A low signal level indicates no far end signal,
1310    // hence we set the suppression gain to 0
1311    if (!aecm->currentVADValue)
1312    {
1313        supGain = 0;
1314    } else
1315    {
1316        // Adjust for possible double talk. If we have large variations in estimation error we
1317        // likely have double talk (or poor channel).
1318        tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
1319        dE = WEBRTC_SPL_ABS_W16(tmp16no1);
1320
1321        if (dE < ENERGY_DEV_TOL)
1322        {
1323            // Likely no double talk. The better estimation, the more we can suppress signal.
1324            // Update counters
1325            if (dE < SUPGAIN_EPC_DT)
1326            {
1327                tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffAB, dE);
1328                tmp32no1 += (SUPGAIN_EPC_DT >> 1);
1329                tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
1330                supGain = aecm->supGainErrParamA - tmp16no1;
1331            } else
1332            {
1333                tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffBD,
1334                                                (ENERGY_DEV_TOL - dE));
1335                tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
1336                tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
1337                        - SUPGAIN_EPC_DT));
1338                supGain = aecm->supGainErrParamD + tmp16no1;
1339            }
1340        } else
1341        {
1342            // Likely in double talk. Use default value
1343            supGain = aecm->supGainErrParamD;
1344        }
1345    }
1346
1347    if (supGain > aecm->supGainOld)
1348    {
1349        tmp16no1 = supGain;
1350    } else
1351    {
1352        tmp16no1 = aecm->supGainOld;
1353    }
1354    aecm->supGainOld = supGain;
1355    if (tmp16no1 < aecm->supGain)
1356    {
1357        aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4);
1358    } else
1359    {
1360        aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4);
1361    }
1362
1363    // END: Update suppression gain
1364
1365    return aecm->supGain;
1366}
1367
1368// Transforms a time domain signal into the frequency domain, outputting the
1369// complex valued signal, absolute value and sum of absolute values.
1370//
1371// time_signal          [in]    Pointer to time domain signal
1372// freq_signal_real     [out]   Pointer to real part of frequency domain array
1373// freq_signal_imag     [out]   Pointer to imaginary part of frequency domain
1374//                              array
1375// freq_signal_abs      [out]   Pointer to absolute value of frequency domain
1376//                              array
1377// freq_signal_sum_abs  [out]   Pointer to the sum of all absolute values in
1378//                              the frequency domain array
1379// return value                 The Q-domain of current frequency values
1380//
1381static int TimeToFrequencyDomain(const WebRtc_Word16* time_signal,
1382                                 complex16_t* freq_signal,
1383                                 WebRtc_UWord16* freq_signal_abs,
1384                                 WebRtc_UWord32* freq_signal_sum_abs)
1385{
1386    int i = 0;
1387    int time_signal_scaling = 0;
1388
1389    WebRtc_Word32 tmp32no1;
1390    WebRtc_Word32 tmp32no2;
1391
1392    // In fft_buf, +16 for 32-byte alignment.
1393    WebRtc_Word16 fft_buf[PART_LEN4 + 16];
1394    WebRtc_Word16 *fft = (WebRtc_Word16 *) (((uintptr_t) fft_buf + 31) & ~31);
1395
1396    WebRtc_Word16 tmp16no1;
1397    WebRtc_Word16 tmp16no2;
1398#ifdef AECM_WITH_ABS_APPROX
1399    WebRtc_Word16 max_value = 0;
1400    WebRtc_Word16 min_value = 0;
1401    WebRtc_UWord16 alpha = 0;
1402    WebRtc_UWord16 beta = 0;
1403#endif
1404
1405#ifdef AECM_DYNAMIC_Q
1406    tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2);
1407    time_signal_scaling = WebRtcSpl_NormW16(tmp16no1);
1408#endif
1409
1410    WebRtcAecm_WindowAndFFT(fft, time_signal, freq_signal, time_signal_scaling);
1411
1412    // Extract imaginary and real part, calculate the magnitude for all frequency bins
1413    freq_signal[0].imag = 0;
1414    freq_signal[PART_LEN].imag = 0;
1415    freq_signal[PART_LEN].real = fft[PART_LEN2];
1416    freq_signal_abs[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1417        freq_signal[0].real);
1418    freq_signal_abs[PART_LEN] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1419        freq_signal[PART_LEN].real);
1420    (*freq_signal_sum_abs) = (WebRtc_UWord32)(freq_signal_abs[0]) +
1421        (WebRtc_UWord32)(freq_signal_abs[PART_LEN]);
1422
1423    for (i = 1; i < PART_LEN; i++)
1424    {
1425        if (freq_signal[i].real == 0)
1426        {
1427            freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1428                freq_signal[i].imag);
1429        }
1430        else if (freq_signal[i].imag == 0)
1431        {
1432            freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1433                freq_signal[i].real);
1434        }
1435        else
1436        {
1437            // Approximation for magnitude of complex fft output
1438            // magn = sqrt(real^2 + imag^2)
1439            // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
1440            //
1441            // The parameters alpha and beta are stored in Q15
1442
1443#ifdef AECM_WITH_ABS_APPROX
1444            tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
1445            tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
1446
1447            if(tmp16no1 > tmp16no2)
1448            {
1449                max_value = tmp16no1;
1450                min_value = tmp16no2;
1451            } else
1452            {
1453                max_value = tmp16no2;
1454                min_value = tmp16no1;
1455            }
1456
1457            // Magnitude in Q(-6)
1458            if ((max_value >> 2) > min_value)
1459            {
1460                alpha = kAlpha1;
1461                beta = kBeta1;
1462            } else if ((max_value >> 1) > min_value)
1463            {
1464                alpha = kAlpha2;
1465                beta = kBeta2;
1466            } else
1467            {
1468                alpha = kAlpha3;
1469                beta = kBeta3;
1470            }
1471            tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(max_value,
1472                                                                alpha,
1473                                                                15);
1474            tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(min_value,
1475                                                                beta,
1476                                                                15);
1477            freq_signal_abs[i] = (WebRtc_UWord16)tmp16no1 +
1478                (WebRtc_UWord16)tmp16no2;
1479#else
1480#ifdef WEBRTC_ARCH_ARM_V7A
1481           __asm__("smulbb %0, %1, %2" : "=r"(tmp32no1) : "r"(freq_signal[i].real),
1482                                                "r"(freq_signal[i].real));
1483           __asm__("smlabb %0, %1, %2, %3" :: "r"(tmp32no2), "r"(freq_signal[i].imag),
1484                                                "r"(freq_signal[i].imag), "r"(tmp32no1));
1485#else
1486            tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
1487            tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
1488            tmp32no1 = WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1);
1489            tmp32no2 = WEBRTC_SPL_MUL_16_16(tmp16no2, tmp16no2);
1490            tmp32no2 = WEBRTC_SPL_ADD_SAT_W32(tmp32no1, tmp32no2);
1491#endif // WEBRTC_ARCH_ARM_V7A
1492            tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
1493
1494            freq_signal_abs[i] = (WebRtc_UWord16)tmp32no1;
1495#endif // AECM_WITH_ABS_APPROX
1496        }
1497        (*freq_signal_sum_abs) += (WebRtc_UWord32)freq_signal_abs[i];
1498    }
1499
1500    return time_signal_scaling;
1501}
1502
1503int WebRtcAecm_ProcessBlock(AecmCore_t * aecm,
1504                            const WebRtc_Word16 * farend,
1505                            const WebRtc_Word16 * nearendNoisy,
1506                            const WebRtc_Word16 * nearendClean,
1507                            WebRtc_Word16 * output)
1508{
1509    int i;
1510
1511    WebRtc_UWord32 xfaSum;
1512    WebRtc_UWord32 dfaNoisySum;
1513    WebRtc_UWord32 dfaCleanSum;
1514    WebRtc_UWord32 echoEst32Gained;
1515    WebRtc_UWord32 tmpU32;
1516
1517    WebRtc_Word32 tmp32no1;
1518
1519    WebRtc_UWord16 xfa[PART_LEN1];
1520    WebRtc_UWord16 dfaNoisy[PART_LEN1];
1521    WebRtc_UWord16 dfaClean[PART_LEN1];
1522    WebRtc_UWord16* ptrDfaClean = dfaClean;
1523    const WebRtc_UWord16* far_spectrum_ptr = NULL;
1524
1525    // 32 byte aligned buffers (with +8 or +16).
1526    // TODO (kma): define fft with complex16_t.
1527    WebRtc_Word16 fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
1528    WebRtc_Word32 echoEst32_buf[PART_LEN1 + 8];
1529    WebRtc_Word32 dfw_buf[PART_LEN1 + 8];
1530    WebRtc_Word32 efw_buf[PART_LEN1 + 8];
1531
1532    WebRtc_Word16* fft = (WebRtc_Word16*) (((uintptr_t) fft_buf + 31) & ~ 31);
1533    WebRtc_Word32* echoEst32 = (WebRtc_Word32*) (((uintptr_t) echoEst32_buf + 31) & ~ 31);
1534    complex16_t* dfw = (complex16_t*) (((uintptr_t) dfw_buf + 31) & ~ 31);
1535    complex16_t* efw = (complex16_t*) (((uintptr_t) efw_buf + 31) & ~ 31);
1536
1537    WebRtc_Word16 hnl[PART_LEN1];
1538    WebRtc_Word16 numPosCoef = 0;
1539    WebRtc_Word16 nlpGain = ONE_Q14;
1540    int delay;
1541    WebRtc_Word16 tmp16no1;
1542    WebRtc_Word16 tmp16no2;
1543    WebRtc_Word16 mu;
1544    WebRtc_Word16 supGain;
1545    WebRtc_Word16 zeros32, zeros16;
1546    WebRtc_Word16 zerosDBufNoisy, zerosDBufClean, zerosXBuf;
1547    int far_q;
1548    WebRtc_Word16 resolutionDiff, qDomainDiff;
1549
1550    const int kMinPrefBand = 4;
1551    const int kMaxPrefBand = 24;
1552    WebRtc_Word32 avgHnl32 = 0;
1553
1554#ifdef ARM_WINM_LOG_
1555    DWORD temp;
1556    static int flag0 = 0;
1557    __int64 freq, start, end, diff__;
1558    unsigned int milliseconds;
1559#endif
1560
1561    // Determine startup state. There are three states:
1562    // (0) the first CONV_LEN blocks
1563    // (1) another CONV_LEN blocks
1564    // (2) the rest
1565
1566    if (aecm->startupState < 2)
1567    {
1568        aecm->startupState = (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2);
1569    }
1570    // END: Determine startup state
1571
1572    // Buffer near and far end signals
1573    memcpy(aecm->xBuf + PART_LEN, farend, sizeof(WebRtc_Word16) * PART_LEN);
1574    memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(WebRtc_Word16) * PART_LEN);
1575    if (nearendClean != NULL)
1576    {
1577        memcpy(aecm->dBufClean + PART_LEN, nearendClean, sizeof(WebRtc_Word16) * PART_LEN);
1578    }
1579
1580#ifdef ARM_WINM_LOG_
1581    // measure tick start
1582    QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
1583    QueryPerformanceCounter((LARGE_INTEGER*)&start);
1584#endif
1585
1586    // Transform far end signal from time domain to frequency domain.
1587    far_q = TimeToFrequencyDomain(aecm->xBuf,
1588                                  dfw,
1589                                  xfa,
1590                                  &xfaSum);
1591
1592    // Transform noisy near end signal from time domain to frequency domain.
1593    zerosDBufNoisy = TimeToFrequencyDomain(aecm->dBufNoisy,
1594                                           dfw,
1595                                           dfaNoisy,
1596                                           &dfaNoisySum);
1597    aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
1598    aecm->dfaNoisyQDomain = (WebRtc_Word16)zerosDBufNoisy;
1599
1600
1601    if (nearendClean == NULL)
1602    {
1603        ptrDfaClean = dfaNoisy;
1604        aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
1605        aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
1606        dfaCleanSum = dfaNoisySum;
1607    } else
1608    {
1609        // Transform clean near end signal from time domain to frequency domain.
1610        zerosDBufClean = TimeToFrequencyDomain(aecm->dBufClean,
1611                                               dfw,
1612                                               dfaClean,
1613                                               &dfaCleanSum);
1614        aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
1615        aecm->dfaCleanQDomain = (WebRtc_Word16)zerosDBufClean;
1616    }
1617
1618#ifdef ARM_WINM_LOG_
1619    // measure tick end
1620    QueryPerformanceCounter((LARGE_INTEGER*)&end);
1621    diff__ = ((end - start) * 1000) / (freq/1000);
1622    milliseconds = (unsigned int)(diff__ & 0xffffffff);
1623    WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1624    // measure tick start
1625    QueryPerformanceCounter((LARGE_INTEGER*)&start);
1626#endif
1627
1628    // Get the delay
1629    // Save far-end history and estimate delay
1630    UpdateFarHistory(aecm, xfa, far_q);
1631    delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
1632                                            xfa,
1633                                            dfaNoisy,
1634                                            PART_LEN1,
1635                                            far_q,
1636                                            zerosDBufNoisy);
1637    if (delay == -1)
1638    {
1639        return -1;
1640    }
1641    else if (delay == -2)
1642    {
1643        // If the delay is unknown, we assume zero.
1644        // NOTE: this will have to be adjusted if we ever add lookahead.
1645        delay = 0;
1646    }
1647
1648    if (aecm->fixedDelay >= 0)
1649    {
1650        // Use fixed delay
1651        delay = aecm->fixedDelay;
1652    }
1653
1654#ifdef ARM_WINM_LOG_
1655    // measure tick end
1656    QueryPerformanceCounter((LARGE_INTEGER*)&end);
1657    diff__ = ((end - start) * 1000) / (freq/1000);
1658    milliseconds = (unsigned int)(diff__ & 0xffffffff);
1659    WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1660    // measure tick start
1661    QueryPerformanceCounter((LARGE_INTEGER*)&start);
1662#endif
1663    // Get aligned far end spectrum
1664    far_spectrum_ptr = AlignedFarend(aecm, &far_q, delay);
1665    zerosXBuf = (WebRtc_Word16) far_q;
1666    if (far_spectrum_ptr == NULL)
1667    {
1668        return -1;
1669    }
1670
1671    // Calculate log(energy) and update energy threshold levels
1672    WebRtcAecm_CalcEnergies(aecm,
1673                            far_spectrum_ptr,
1674                            zerosXBuf,
1675                            dfaNoisySum,
1676                            echoEst32);
1677
1678    // Calculate stepsize
1679    mu = WebRtcAecm_CalcStepSize(aecm);
1680
1681    // Update counters
1682    aecm->totCount++;
1683
1684    // This is the channel estimation algorithm.
1685    // It is base on NLMS but has a variable step length, which was calculated above.
1686    WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, echoEst32);
1687    supGain = CalcSuppressionGain(aecm);
1688
1689#ifdef ARM_WINM_LOG_
1690    // measure tick end
1691    QueryPerformanceCounter((LARGE_INTEGER*)&end);
1692    diff__ = ((end - start) * 1000) / (freq/1000);
1693    milliseconds = (unsigned int)(diff__ & 0xffffffff);
1694    WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1695    // measure tick start
1696    QueryPerformanceCounter((LARGE_INTEGER*)&start);
1697#endif
1698
1699    // Calculate Wiener filter hnl[]
1700    for (i = 0; i < PART_LEN1; i++)
1701    {
1702        // Far end signal through channel estimate in Q8
1703        // How much can we shift right to preserve resolution
1704        tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
1705        aecm->echoFilt[i] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32no1, 50), 8);
1706
1707        zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
1708        zeros16 = WebRtcSpl_NormW16(supGain) + 1;
1709        if (zeros32 + zeros16 > 16)
1710        {
1711            // Multiplication is safe
1712            // Result in Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff])
1713            echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i],
1714                                                    (WebRtc_UWord16)supGain);
1715            resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
1716            resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
1717        } else
1718        {
1719            tmp16no1 = 17 - zeros32 - zeros16;
1720            resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
1721            resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
1722            if (zeros32 > tmp16no1)
1723            {
1724                echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i],
1725                        (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W16(supGain,
1726                                tmp16no1)); // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
1727            } else
1728            {
1729                // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
1730                echoEst32Gained = WEBRTC_SPL_UMUL_32_16(
1731                        (WebRtc_UWord32)WEBRTC_SPL_RSHIFT_W32(aecm->echoFilt[i], tmp16no1),
1732                        (WebRtc_UWord16)supGain);
1733            }
1734        }
1735
1736        zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
1737        if ((zeros16 < (aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld))
1738                & (aecm->nearFilt[i]))
1739        {
1740            tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], zeros16);
1741            qDomainDiff = zeros16 - aecm->dfaCleanQDomain + aecm->dfaCleanQDomainOld;
1742        } else
1743        {
1744            tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i],
1745                                            aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld);
1746            qDomainDiff = 0;
1747        }
1748        tmp16no2 = WEBRTC_SPL_SHIFT_W16(ptrDfaClean[i], qDomainDiff);
1749        tmp32no1 = (WebRtc_Word32)(tmp16no2 - tmp16no1);
1750        tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 4);
1751        tmp16no2 += tmp16no1;
1752        zeros16 = WebRtcSpl_NormW16(tmp16no2);
1753        if ((tmp16no2) & (-qDomainDiff > zeros16))
1754        {
1755            aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
1756        } else
1757        {
1758            aecm->nearFilt[i] = WEBRTC_SPL_SHIFT_W16(tmp16no2, -qDomainDiff);
1759        }
1760
1761        // Wiener filter coefficients, resulting hnl in Q14
1762        if (echoEst32Gained == 0)
1763        {
1764            hnl[i] = ONE_Q14;
1765        } else if (aecm->nearFilt[i] == 0)
1766        {
1767            hnl[i] = 0;
1768        } else
1769        {
1770            // Multiply the suppression gain
1771            // Rounding
1772            echoEst32Gained += (WebRtc_UWord32)(aecm->nearFilt[i] >> 1);
1773            tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (WebRtc_UWord16)aecm->nearFilt[i]);
1774
1775            // Current resolution is
1776            // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN - max(0, 17 - zeros16 - zeros32))
1777            // Make sure we are in Q14
1778            tmp32no1 = (WebRtc_Word32)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
1779            if (tmp32no1 > ONE_Q14)
1780            {
1781                hnl[i] = 0;
1782            } else if (tmp32no1 < 0)
1783            {
1784                hnl[i] = ONE_Q14;
1785            } else
1786            {
1787                // 1-echoEst/dfa
1788                hnl[i] = ONE_Q14 - (WebRtc_Word16)tmp32no1;
1789                if (hnl[i] < 0)
1790                {
1791                    hnl[i] = 0;
1792                }
1793            }
1794        }
1795        if (hnl[i])
1796        {
1797            numPosCoef++;
1798        }
1799    }
1800    // Only in wideband. Prevent the gain in upper band from being larger than
1801    // in lower band.
1802    if (aecm->mult == 2)
1803    {
1804        // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
1805        //               speech distortion in double-talk.
1806        for (i = 0; i < PART_LEN1; i++)
1807        {
1808            hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], hnl[i], 14);
1809        }
1810
1811        for (i = kMinPrefBand; i <= kMaxPrefBand; i++)
1812        {
1813            avgHnl32 += (WebRtc_Word32)hnl[i];
1814        }
1815        assert(kMaxPrefBand - kMinPrefBand + 1 > 0);
1816        avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
1817
1818        for (i = kMaxPrefBand; i < PART_LEN1; i++)
1819        {
1820            if (hnl[i] > (WebRtc_Word16)avgHnl32)
1821            {
1822                hnl[i] = (WebRtc_Word16)avgHnl32;
1823            }
1824        }
1825    }
1826
1827#ifdef ARM_WINM_LOG_
1828    // measure tick end
1829    QueryPerformanceCounter((LARGE_INTEGER*)&end);
1830    diff__ = ((end - start) * 1000) / (freq/1000);
1831    milliseconds = (unsigned int)(diff__ & 0xffffffff);
1832    WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1833    // measure tick start
1834    QueryPerformanceCounter((LARGE_INTEGER*)&start);
1835#endif
1836
1837    // Calculate NLP gain, result is in Q14
1838    if (aecm->nlpFlag)
1839    {
1840        for (i = 0; i < PART_LEN1; i++)
1841        {
1842            // Truncate values close to zero and one.
1843            if (hnl[i] > NLP_COMP_HIGH)
1844            {
1845                hnl[i] = ONE_Q14;
1846            } else if (hnl[i] < NLP_COMP_LOW)
1847            {
1848                hnl[i] = 0;
1849            }
1850
1851            // Remove outliers
1852            if (numPosCoef < 3)
1853            {
1854                nlpGain = 0;
1855            } else
1856            {
1857                nlpGain = ONE_Q14;
1858            }
1859
1860            // NLP
1861            if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14))
1862            {
1863                hnl[i] = ONE_Q14;
1864            } else
1865            {
1866                hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], nlpGain, 14);
1867            }
1868
1869            // multiply with Wiener coefficients
1870            efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
1871                                                                            hnl[i], 14));
1872            efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
1873                                                                            hnl[i], 14));
1874        }
1875    }
1876    else
1877    {
1878        // multiply with Wiener coefficients
1879        for (i = 0; i < PART_LEN1; i++)
1880        {
1881            efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
1882                                                                           hnl[i], 14));
1883            efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
1884                                                                           hnl[i], 14));
1885        }
1886    }
1887
1888    if (aecm->cngMode == AecmTrue)
1889    {
1890        ComfortNoise(aecm, ptrDfaClean, efw, hnl);
1891    }
1892
1893#ifdef ARM_WINM_LOG_
1894    // measure tick end
1895    QueryPerformanceCounter((LARGE_INTEGER*)&end);
1896    diff__ = ((end - start) * 1000) / (freq/1000);
1897    milliseconds = (unsigned int)(diff__ & 0xffffffff);
1898    WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1899    // measure tick start
1900    QueryPerformanceCounter((LARGE_INTEGER*)&start);
1901#endif
1902
1903    WebRtcAecm_InverseFFTAndWindow(aecm, fft, efw, output, nearendClean);
1904
1905    return 0;
1906}
1907
1908
1909// Generate comfort noise and add to output signal.
1910//
1911// \param[in]     aecm     Handle of the AECM instance.
1912// \param[in]     dfa     Absolute value of the nearend signal (Q[aecm->dfaQDomain]).
1913// \param[in,out] outReal Real part of the output signal (Q[aecm->dfaQDomain]).
1914// \param[in,out] outImag Imaginary part of the output signal (Q[aecm->dfaQDomain]).
1915// \param[in]     lambda  Suppression gain with which to scale the noise level (Q14).
1916//
1917static void ComfortNoise(AecmCore_t* aecm,
1918                         const WebRtc_UWord16* dfa,
1919                         complex16_t* out,
1920                         const WebRtc_Word16* lambda)
1921{
1922    WebRtc_Word16 i;
1923    WebRtc_Word16 tmp16;
1924    WebRtc_Word32 tmp32;
1925
1926    WebRtc_Word16 randW16[PART_LEN];
1927    WebRtc_Word16 uReal[PART_LEN1];
1928    WebRtc_Word16 uImag[PART_LEN1];
1929    WebRtc_Word32 outLShift32;
1930    WebRtc_Word16 noiseRShift16[PART_LEN1];
1931
1932    WebRtc_Word16 shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
1933    WebRtc_Word16 minTrackShift;
1934
1935    assert(shiftFromNearToNoise >= 0);
1936    assert(shiftFromNearToNoise < 16);
1937
1938    if (aecm->noiseEstCtr < 100)
1939    {
1940        // Track the minimum more quickly initially.
1941        aecm->noiseEstCtr++;
1942        minTrackShift = 6;
1943    } else
1944    {
1945        minTrackShift = 9;
1946    }
1947
1948    // Estimate noise power.
1949    for (i = 0; i < PART_LEN1; i++)
1950    {
1951
1952        // Shift to the noise domain.
1953        tmp32 = (WebRtc_Word32)dfa[i];
1954        outLShift32 = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise);
1955
1956        if (outLShift32 < aecm->noiseEst[i])
1957        {
1958            // Reset "too low" counter
1959            aecm->noiseEstTooLowCtr[i] = 0;
1960            // Track the minimum.
1961            if (aecm->noiseEst[i] < (1 << minTrackShift))
1962            {
1963                // For small values, decrease noiseEst[i] every
1964                // |kNoiseEstIncCount| block. The regular approach below can not
1965                // go further down due to truncation.
1966                aecm->noiseEstTooHighCtr[i]++;
1967                if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount)
1968                {
1969                    aecm->noiseEst[i]--;
1970                    aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
1971                }
1972            }
1973            else
1974            {
1975                aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32) >> minTrackShift);
1976            }
1977        } else
1978        {
1979            // Reset "too high" counter
1980            aecm->noiseEstTooHighCtr[i] = 0;
1981            // Ramp slowly upwards until we hit the minimum again.
1982            if ((aecm->noiseEst[i] >> 19) > 0)
1983            {
1984                // Avoid overflow.
1985                // Multiplication with 2049 will cause wrap around. Scale
1986                // down first and then multiply
1987                aecm->noiseEst[i] >>= 11;
1988                aecm->noiseEst[i] *= 2049;
1989            }
1990            else if ((aecm->noiseEst[i] >> 11) > 0)
1991            {
1992                // Large enough for relative increase
1993                aecm->noiseEst[i] *= 2049;
1994                aecm->noiseEst[i] >>= 11;
1995            }
1996            else
1997            {
1998                // Make incremental increases based on size every
1999                // |kNoiseEstIncCount| block
2000                aecm->noiseEstTooLowCtr[i]++;
2001                if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount)
2002                {
2003                    aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
2004                    aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
2005                }
2006            }
2007        }
2008    }
2009
2010    for (i = 0; i < PART_LEN1; i++)
2011    {
2012        tmp32 = WEBRTC_SPL_RSHIFT_W32(aecm->noiseEst[i], shiftFromNearToNoise);
2013        if (tmp32 > 32767)
2014        {
2015            tmp32 = 32767;
2016            aecm->noiseEst[i] = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise);
2017        }
2018        noiseRShift16[i] = (WebRtc_Word16)tmp32;
2019
2020        tmp16 = ONE_Q14 - lambda[i];
2021        noiseRShift16[i]
2022                = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, noiseRShift16[i], 14);
2023    }
2024
2025    // Generate a uniform random array on [0 2^15-1].
2026    WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
2027
2028    // Generate noise according to estimated energy.
2029    uReal[0] = 0; // Reject LF noise.
2030    uImag[0] = 0;
2031    for (i = 1; i < PART_LEN1; i++)
2032    {
2033        // Get a random index for the cos and sin tables over [0 359].
2034        tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(359, randW16[i - 1], 15);
2035
2036        // Tables are in Q13.
2037        uReal[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(noiseRShift16[i],
2038                kCosTable[tmp16], 13);
2039        uImag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(-noiseRShift16[i],
2040                kSinTable[tmp16], 13);
2041    }
2042    uImag[PART_LEN] = 0;
2043
2044#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
2045    for (i = 0; i < PART_LEN1; i++)
2046    {
2047        out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2048        out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2049    }
2050#else
2051    for (i = 0; i < PART_LEN1 -1; )
2052    {
2053        out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2054        out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2055        i++;
2056
2057        out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2058        out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2059        i++;
2060    }
2061    out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2062    out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2063#endif
2064}
2065
2066void WebRtcAecm_BufferFarFrame(AecmCore_t* const aecm,
2067                               const WebRtc_Word16* const farend,
2068                               const int farLen)
2069{
2070    int writeLen = farLen, writePos = 0;
2071
2072    // Check if the write position must be wrapped
2073    while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
2074    {
2075        // Write to remaining buffer space before wrapping
2076        writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
2077        memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
2078               sizeof(WebRtc_Word16) * writeLen);
2079        aecm->farBufWritePos = 0;
2080        writePos = writeLen;
2081        writeLen = farLen - writeLen;
2082    }
2083
2084    memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
2085           sizeof(WebRtc_Word16) * writeLen);
2086    aecm->farBufWritePos += writeLen;
2087}
2088
2089void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend,
2090                              const int farLen, const int knownDelay)
2091{
2092    int readLen = farLen;
2093    int readPos = 0;
2094    int delayChange = knownDelay - aecm->lastKnownDelay;
2095
2096    aecm->farBufReadPos -= delayChange;
2097
2098    // Check if delay forces a read position wrap
2099    while (aecm->farBufReadPos < 0)
2100    {
2101        aecm->farBufReadPos += FAR_BUF_LEN;
2102    }
2103    while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
2104    {
2105        aecm->farBufReadPos -= FAR_BUF_LEN;
2106    }
2107
2108    aecm->lastKnownDelay = knownDelay;
2109
2110    // Check if read position must be wrapped
2111    while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
2112    {
2113
2114        // Read from remaining buffer space before wrapping
2115        readLen = FAR_BUF_LEN - aecm->farBufReadPos;
2116        memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
2117               sizeof(WebRtc_Word16) * readLen);
2118        aecm->farBufReadPos = 0;
2119        readPos = readLen;
2120        readLen = farLen - readLen;
2121    }
2122    memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
2123           sizeof(WebRtc_Word16) * readLen);
2124    aecm->farBufReadPos += readLen;
2125}
2126
2127