Home | History | Annotate | Download | only in aecm
      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 #include "webrtc/modules/audio_processing/aecm/aecm_core.h"
     12 
     13 #include <assert.h>
     14 #include <stddef.h>
     15 #include <stdlib.h>
     16 
     17 #include "webrtc/common_audio/ring_buffer.h"
     18 #include "webrtc/common_audio/signal_processing/include/real_fft.h"
     19 #include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h"
     20 #include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
     21 #include "webrtc/system_wrappers/include/compile_assert_c.h"
     22 #include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
     23 #include "webrtc/typedefs.h"
     24 
     25 #ifdef AEC_DEBUG
     26 FILE *dfile;
     27 FILE *testfile;
     28 #endif
     29 
     30 const int16_t WebRtcAecm_kCosTable[] = {
     31     8192,  8190,  8187,  8180,  8172,  8160,  8147,  8130,  8112,
     32     8091,  8067,  8041,  8012,  7982,  7948,  7912,  7874,  7834,
     33     7791,  7745,  7697,  7647,  7595,  7540,  7483,  7424,  7362,
     34     7299,  7233,  7164,  7094,  7021,  6947,  6870,  6791,  6710,
     35     6627,  6542,  6455,  6366,  6275,  6182,  6087,  5991,  5892,
     36     5792,  5690,  5586,  5481,  5374,  5265,  5155,  5043,  4930,
     37     4815,  4698,  4580,  4461,  4341,  4219,  4096,  3971,  3845,
     38     3719,  3591,  3462,  3331,  3200,  3068,  2935,  2801,  2667,
     39     2531,  2395,  2258,  2120,  1981,  1842,  1703,  1563,  1422,
     40     1281,  1140,   998,   856,   713,   571,   428,   285,   142,
     41        0,  -142,  -285,  -428,  -571,  -713,  -856,  -998, -1140,
     42    -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
     43    -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591,
     44    -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
     45    -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690,
     46    -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542,
     47    -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233,
     48    -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745,
     49    -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067,
     50    -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190,
     51    -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112,
     52    -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
     53    -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
     54    -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710,
     55    -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892,
     56    -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930,
     57    -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845,
     58    -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667,
     59    -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422,
     60    -1281, -1140,  -998,  -856,  -713,  -571,  -428,  -285,  -142,
     61        0,   142,   285,   428,   571,   713,   856,   998,  1140,
     62     1281,  1422,  1563,  1703,  1842,  1981,  2120,  2258,  2395,
     63     2531,  2667,  2801,  2935,  3068,  3200,  3331,  3462,  3591,
     64     3719,  3845,  3971,  4095,  4219,  4341,  4461,  4580,  4698,
     65     4815,  4930,  5043,  5155,  5265,  5374,  5481,  5586,  5690,
     66     5792,  5892,  5991,  6087,  6182,  6275,  6366,  6455,  6542,
     67     6627,  6710,  6791,  6870,  6947,  7021,  7094,  7164,  7233,
     68     7299,  7362,  7424,  7483,  7540,  7595,  7647,  7697,  7745,
     69     7791,  7834,  7874,  7912,  7948,  7982,  8012,  8041,  8067,
     70     8091,  8112,  8130,  8147,  8160,  8172,  8180,  8187,  8190
     71 };
     72 
     73 const int16_t WebRtcAecm_kSinTable[] = {
     74        0,    142,    285,    428,    571,    713,    856,    998,
     75     1140,   1281,   1422,   1563,   1703,   1842,   1981,   2120,
     76     2258,   2395,   2531,   2667,   2801,   2935,   3068,   3200,
     77     3331,   3462,   3591,   3719,   3845,   3971,   4095,   4219,
     78     4341,   4461,   4580,   4698,   4815,   4930,   5043,   5155,
     79     5265,   5374,   5481,   5586,   5690,   5792,   5892,   5991,
     80     6087,   6182,   6275,   6366,   6455,   6542,   6627,   6710,
     81     6791,   6870,   6947,   7021,   7094,   7164,   7233,   7299,
     82     7362,   7424,   7483,   7540,   7595,   7647,   7697,   7745,
     83     7791,   7834,   7874,   7912,   7948,   7982,   8012,   8041,
     84     8067,   8091,   8112,   8130,   8147,   8160,   8172,   8180,
     85     8187,   8190,   8191,   8190,   8187,   8180,   8172,   8160,
     86     8147,   8130,   8112,   8091,   8067,   8041,   8012,   7982,
     87     7948,   7912,   7874,   7834,   7791,   7745,   7697,   7647,
     88     7595,   7540,   7483,   7424,   7362,   7299,   7233,   7164,
     89     7094,   7021,   6947,   6870,   6791,   6710,   6627,   6542,
     90     6455,   6366,   6275,   6182,   6087,   5991,   5892,   5792,
     91     5690,   5586,   5481,   5374,   5265,   5155,   5043,   4930,
     92     4815,   4698,   4580,   4461,   4341,   4219,   4096,   3971,
     93     3845,   3719,   3591,   3462,   3331,   3200,   3068,   2935,
     94     2801,   2667,   2531,   2395,   2258,   2120,   1981,   1842,
     95     1703,   1563,   1422,   1281,   1140,    998,    856,    713,
     96      571,    428,    285,    142,      0,   -142,   -285,   -428,
     97     -571,   -713,   -856,   -998,  -1140,  -1281,  -1422,  -1563,
     98    -1703,  -1842,  -1981,  -2120,  -2258,  -2395,  -2531,  -2667,
     99    -2801,  -2935,  -3068,  -3200,  -3331,  -3462,  -3591,  -3719,
    100    -3845,  -3971,  -4095,  -4219,  -4341,  -4461,  -4580,  -4698,
    101    -4815,  -4930,  -5043,  -5155,  -5265,  -5374,  -5481,  -5586,
    102    -5690,  -5792,  -5892,  -5991,  -6087,  -6182,  -6275,  -6366,
    103    -6455,  -6542,  -6627,  -6710,  -6791,  -6870,  -6947,  -7021,
    104    -7094,  -7164,  -7233,  -7299,  -7362,  -7424,  -7483,  -7540,
    105    -7595,  -7647,  -7697,  -7745,  -7791,  -7834,  -7874,  -7912,
    106    -7948,  -7982,  -8012,  -8041,  -8067,  -8091,  -8112,  -8130,
    107    -8147,  -8160,  -8172,  -8180,  -8187,  -8190,  -8191,  -8190,
    108    -8187,  -8180,  -8172,  -8160,  -8147,  -8130,  -8112,  -8091,
    109    -8067,  -8041,  -8012,  -7982,  -7948,  -7912,  -7874,  -7834,
    110    -7791,  -7745,  -7697,  -7647,  -7595,  -7540,  -7483,  -7424,
    111    -7362,  -7299,  -7233,  -7164,  -7094,  -7021,  -6947,  -6870,
    112    -6791,  -6710,  -6627,  -6542,  -6455,  -6366,  -6275,  -6182,
    113    -6087,  -5991,  -5892,  -5792,  -5690,  -5586,  -5481,  -5374,
    114    -5265,  -5155,  -5043,  -4930,  -4815,  -4698,  -4580,  -4461,
    115    -4341,  -4219,  -4096,  -3971,  -3845,  -3719,  -3591,  -3462,
    116    -3331,  -3200,  -3068,  -2935,  -2801,  -2667,  -2531,  -2395,
    117    -2258,  -2120,  -1981,  -1842,  -1703,  -1563,  -1422,  -1281,
    118    -1140,   -998,   -856,   -713,   -571,   -428,   -285,   -142
    119 };
    120 
    121 // Initialization table for echo channel in 8 kHz
    122 static const int16_t kChannelStored8kHz[PART_LEN1] = {
    123     2040,   1815,   1590,   1498,   1405,   1395,   1385,   1418,
    124     1451,   1506,   1562,   1644,   1726,   1804,   1882,   1918,
    125     1953,   1982,   2010,   2025,   2040,   2034,   2027,   2021,
    126     2014,   1997,   1980,   1925,   1869,   1800,   1732,   1683,
    127     1635,   1604,   1572,   1545,   1517,   1481,   1444,   1405,
    128     1367,   1331,   1294,   1270,   1245,   1239,   1233,   1247,
    129     1260,   1282,   1303,   1338,   1373,   1407,   1441,   1470,
    130     1499,   1524,   1549,   1565,   1582,   1601,   1621,   1649,
    131     1676
    132 };
    133 
    134 // Initialization table for echo channel in 16 kHz
    135 static const int16_t kChannelStored16kHz[PART_LEN1] = {
    136     2040,   1590,   1405,   1385,   1451,   1562,   1726,   1882,
    137     1953,   2010,   2040,   2027,   2014,   1980,   1869,   1732,
    138     1635,   1572,   1517,   1444,   1367,   1294,   1245,   1233,
    139     1260,   1303,   1373,   1441,   1499,   1549,   1582,   1621,
    140     1676,   1741,   1802,   1861,   1921,   1983,   2040,   2102,
    141     2170,   2265,   2375,   2515,   2651,   2781,   2922,   3075,
    142     3253,   3471,   3738,   3976,   4151,   4258,   4308,   4288,
    143     4270,   4253,   4237,   4179,   4086,   3947,   3757,   3484,
    144     3153
    145 };
    146 
    147 // Moves the pointer to the next entry and inserts |far_spectrum| and
    148 // corresponding Q-domain in its buffer.
    149 //
    150 // Inputs:
    151 //      - self          : Pointer to the delay estimation instance
    152 //      - far_spectrum  : Pointer to the far end spectrum
    153 //      - far_q         : Q-domain of far end spectrum
    154 //
    155 void WebRtcAecm_UpdateFarHistory(AecmCore* self,
    156                                  uint16_t* far_spectrum,
    157                                  int far_q) {
    158   // Get new buffer position
    159   self->far_history_pos++;
    160   if (self->far_history_pos >= MAX_DELAY) {
    161     self->far_history_pos = 0;
    162   }
    163   // Update Q-domain buffer
    164   self->far_q_domains[self->far_history_pos] = far_q;
    165   // Update far end spectrum buffer
    166   memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]),
    167          far_spectrum,
    168          sizeof(uint16_t) * PART_LEN1);
    169 }
    170 
    171 // Returns a pointer to the far end spectrum aligned to current near end
    172 // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
    173 // called before AlignedFarend(...). Otherwise, you get the pointer to the
    174 // previous frame. The memory is only valid until the next call of
    175 // WebRtc_DelayEstimatorProcessFix(...).
    176 //
    177 // Inputs:
    178 //      - self              : Pointer to the AECM instance.
    179 //      - delay             : Current delay estimate.
    180 //
    181 // Output:
    182 //      - far_q             : The Q-domain of the aligned far end spectrum
    183 //
    184 // Return value:
    185 //      - far_spectrum      : Pointer to the aligned far end spectrum
    186 //                            NULL - Error
    187 //
    188 const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self,
    189                                          int* far_q,
    190                                          int delay) {
    191   int buffer_position = 0;
    192   assert(self != NULL);
    193   buffer_position = self->far_history_pos - delay;
    194 
    195   // Check buffer position
    196   if (buffer_position < 0) {
    197     buffer_position += MAX_DELAY;
    198   }
    199   // Get Q-domain
    200   *far_q = self->far_q_domains[buffer_position];
    201   // Return far end spectrum
    202   return &(self->far_history[buffer_position * PART_LEN1]);
    203 }
    204 
    205 // Declare function pointers.
    206 CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
    207 StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
    208 ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
    209 
    210 AecmCore* WebRtcAecm_CreateCore() {
    211     AecmCore* aecm = malloc(sizeof(AecmCore));
    212 
    213     aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
    214                                             sizeof(int16_t));
    215     if (!aecm->farFrameBuf)
    216     {
    217         WebRtcAecm_FreeCore(aecm);
    218         return NULL;
    219     }
    220 
    221     aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
    222                                                   sizeof(int16_t));
    223     if (!aecm->nearNoisyFrameBuf)
    224     {
    225         WebRtcAecm_FreeCore(aecm);
    226         return NULL;
    227     }
    228 
    229     aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
    230                                                   sizeof(int16_t));
    231     if (!aecm->nearCleanFrameBuf)
    232     {
    233         WebRtcAecm_FreeCore(aecm);
    234         return NULL;
    235     }
    236 
    237     aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
    238                                             sizeof(int16_t));
    239     if (!aecm->outFrameBuf)
    240     {
    241         WebRtcAecm_FreeCore(aecm);
    242         return NULL;
    243     }
    244 
    245     aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1,
    246                                                                      MAX_DELAY);
    247     if (aecm->delay_estimator_farend == NULL) {
    248       WebRtcAecm_FreeCore(aecm);
    249       return NULL;
    250     }
    251     aecm->delay_estimator =
    252         WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
    253     if (aecm->delay_estimator == NULL) {
    254       WebRtcAecm_FreeCore(aecm);
    255       return NULL;
    256     }
    257     // TODO(bjornv): Explicitly disable robust delay validation until no
    258     // performance regression has been established.  Then remove the line.
    259     WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
    260 
    261     aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
    262     if (aecm->real_fft == NULL) {
    263       WebRtcAecm_FreeCore(aecm);
    264       return NULL;
    265     }
    266 
    267     // Init some aecm pointers. 16 and 32 byte alignment is only necessary
    268     // for Neon code currently.
    269     aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
    270     aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
    271     aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
    272     aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
    273     aecm->channelStored = (int16_t*) (((uintptr_t)
    274                                              aecm->channelStored_buf + 15) & ~ 15);
    275     aecm->channelAdapt16 = (int16_t*) (((uintptr_t)
    276                                               aecm->channelAdapt16_buf + 15) & ~ 15);
    277     aecm->channelAdapt32 = (int32_t*) (((uintptr_t)
    278                                               aecm->channelAdapt32_buf + 31) & ~ 31);
    279 
    280     return aecm;
    281 }
    282 
    283 void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) {
    284     int i = 0;
    285 
    286     // Reset the stored channel
    287     memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
    288     // Reset the adapted channels
    289     memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
    290     for (i = 0; i < PART_LEN1; i++)
    291     {
    292         aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16;
    293     }
    294 
    295     // Reset channel storing variables
    296     aecm->mseAdaptOld = 1000;
    297     aecm->mseStoredOld = 1000;
    298     aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
    299     aecm->mseChannelCount = 0;
    300 }
    301 
    302 static void CalcLinearEnergiesC(AecmCore* aecm,
    303                                 const uint16_t* far_spectrum,
    304                                 int32_t* echo_est,
    305                                 uint32_t* far_energy,
    306                                 uint32_t* echo_energy_adapt,
    307                                 uint32_t* echo_energy_stored) {
    308     int i;
    309 
    310     // Get energy for the delayed far end signal and estimated
    311     // echo using both stored and adapted channels.
    312     for (i = 0; i < PART_LEN1; i++)
    313     {
    314         echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
    315                                            far_spectrum[i]);
    316         (*far_energy) += (uint32_t)(far_spectrum[i]);
    317         *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
    318         (*echo_energy_stored) += (uint32_t)echo_est[i];
    319     }
    320 }
    321 
    322 static void StoreAdaptiveChannelC(AecmCore* aecm,
    323                                   const uint16_t* far_spectrum,
    324                                   int32_t* echo_est) {
    325     int i;
    326 
    327     // During startup we store the channel every block.
    328     memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1);
    329     // Recalculate echo estimate
    330     for (i = 0; i < PART_LEN; i += 4)
    331     {
    332         echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
    333                                            far_spectrum[i]);
    334         echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
    335                                            far_spectrum[i + 1]);
    336         echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
    337                                            far_spectrum[i + 2]);
    338         echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
    339                                            far_spectrum[i + 3]);
    340     }
    341     echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
    342                                        far_spectrum[i]);
    343 }
    344 
    345 static void ResetAdaptiveChannelC(AecmCore* aecm) {
    346     int i;
    347 
    348     // The stored channel has a significantly lower MSE than the adaptive one for
    349     // two consecutive calculations. Reset the adaptive channel.
    350     memcpy(aecm->channelAdapt16, aecm->channelStored,
    351            sizeof(int16_t) * PART_LEN1);
    352     // Restore the W32 channel
    353     for (i = 0; i < PART_LEN; i += 4)
    354     {
    355         aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
    356         aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16;
    357         aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16;
    358         aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16;
    359     }
    360     aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
    361 }
    362 
    363 // Initialize function pointers for ARM Neon platform.
    364 #if (defined WEBRTC_DETECT_NEON || defined WEBRTC_HAS_NEON)
    365 static void WebRtcAecm_InitNeon(void)
    366 {
    367   WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
    368   WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
    369   WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
    370 }
    371 #endif
    372 
    373 // Initialize function pointers for MIPS platform.
    374 #if defined(MIPS32_LE)
    375 static void WebRtcAecm_InitMips(void)
    376 {
    377 #if defined(MIPS_DSP_R1_LE)
    378   WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
    379   WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
    380 #endif
    381   WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips;
    382 }
    383 #endif
    384 
    385 // WebRtcAecm_InitCore(...)
    386 //
    387 // This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
    388 // Input:
    389 //      - aecm            : Pointer to the Echo Suppression instance
    390 //      - samplingFreq   : Sampling Frequency
    391 //
    392 // Output:
    393 //      - aecm            : Initialized instance
    394 //
    395 // Return value         :  0 - Ok
    396 //                        -1 - Error
    397 //
    398 int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq) {
    399     int i = 0;
    400     int32_t tmp32 = PART_LEN1 * PART_LEN1;
    401     int16_t tmp16 = PART_LEN1;
    402 
    403     if (samplingFreq != 8000 && samplingFreq != 16000)
    404     {
    405         samplingFreq = 8000;
    406         return -1;
    407     }
    408     // sanity check of sampling frequency
    409     aecm->mult = (int16_t)samplingFreq / 8000;
    410 
    411     aecm->farBufWritePos = 0;
    412     aecm->farBufReadPos = 0;
    413     aecm->knownDelay = 0;
    414     aecm->lastKnownDelay = 0;
    415 
    416     WebRtc_InitBuffer(aecm->farFrameBuf);
    417     WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
    418     WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
    419     WebRtc_InitBuffer(aecm->outFrameBuf);
    420 
    421     memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
    422     memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
    423     memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
    424     memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
    425 
    426     aecm->seed = 666;
    427     aecm->totCount = 0;
    428 
    429     if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
    430       return -1;
    431     }
    432     if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
    433       return -1;
    434     }
    435     // Set far end histories to zero
    436     memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
    437     memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
    438     aecm->far_history_pos = MAX_DELAY;
    439 
    440     aecm->nlpFlag = 1;
    441     aecm->fixedDelay = -1;
    442 
    443     aecm->dfaCleanQDomain = 0;
    444     aecm->dfaCleanQDomainOld = 0;
    445     aecm->dfaNoisyQDomain = 0;
    446     aecm->dfaNoisyQDomainOld = 0;
    447 
    448     memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
    449     aecm->farLogEnergy = 0;
    450     memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
    451     memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
    452 
    453     // Initialize the echo channels with a stored shape.
    454     if (samplingFreq == 8000)
    455     {
    456         WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
    457     }
    458     else
    459     {
    460         WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
    461     }
    462 
    463     memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
    464     memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
    465     aecm->noiseEstCtr = 0;
    466 
    467     aecm->cngMode = AecmTrue;
    468 
    469     memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
    470     memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
    471     // Shape the initial noise level to an approximate pink noise.
    472     for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
    473     {
    474         aecm->noiseEst[i] = (tmp32 << 8);
    475         tmp16--;
    476         tmp32 -= (int32_t)((tmp16 << 1) + 1);
    477     }
    478     for (; i < PART_LEN1; i++)
    479     {
    480         aecm->noiseEst[i] = (tmp32 << 8);
    481     }
    482 
    483     aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
    484     aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
    485     aecm->farEnergyMaxMin = 0;
    486     aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
    487                                          // beginning.
    488     aecm->farEnergyMSE = 0;
    489     aecm->currentVADValue = 0;
    490     aecm->vadUpdateCount = 0;
    491     aecm->firstVAD = 1;
    492 
    493     aecm->startupState = 0;
    494     aecm->supGain = SUPGAIN_DEFAULT;
    495     aecm->supGainOld = SUPGAIN_DEFAULT;
    496 
    497     aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
    498     aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
    499     aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
    500     aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
    501 
    502     // Assert a preprocessor definition at compile-time. It's an assumption
    503     // used in assembly code, so check the assembly files before any change.
    504     COMPILE_ASSERT(PART_LEN % 16 == 0);
    505 
    506     // Initialize function pointers.
    507     WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
    508     WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
    509     WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
    510 
    511 #ifdef WEBRTC_DETECT_NEON
    512     uint64_t features = WebRtc_GetCPUFeaturesARM();
    513     if ((features & kCPUFeatureNEON) != 0)
    514     {
    515       WebRtcAecm_InitNeon();
    516     }
    517 #elif defined(WEBRTC_HAS_NEON)
    518     WebRtcAecm_InitNeon();
    519 #endif
    520 
    521 #if defined(MIPS32_LE)
    522     WebRtcAecm_InitMips();
    523 #endif
    524     return 0;
    525 }
    526 
    527 // TODO(bjornv): This function is currently not used. Add support for these
    528 // parameters from a higher level
    529 int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) {
    530     aecm->nlpFlag = nlpFlag;
    531     aecm->fixedDelay = delay;
    532 
    533     return 0;
    534 }
    535 
    536 void WebRtcAecm_FreeCore(AecmCore* aecm) {
    537     if (aecm == NULL) {
    538       return;
    539     }
    540 
    541     WebRtc_FreeBuffer(aecm->farFrameBuf);
    542     WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
    543     WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
    544     WebRtc_FreeBuffer(aecm->outFrameBuf);
    545 
    546     WebRtc_FreeDelayEstimator(aecm->delay_estimator);
    547     WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
    548     WebRtcSpl_FreeRealFFT(aecm->real_fft);
    549 
    550     free(aecm);
    551 }
    552 
    553 int WebRtcAecm_ProcessFrame(AecmCore* aecm,
    554                             const int16_t* farend,
    555                             const int16_t* nearendNoisy,
    556                             const int16_t* nearendClean,
    557                             int16_t* out) {
    558     int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
    559     int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
    560 
    561     int16_t farFrame[FRAME_LEN];
    562     const int16_t* out_ptr = NULL;
    563     int size = 0;
    564 
    565     // Buffer the current frame.
    566     // Fetch an older one corresponding to the delay.
    567     WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
    568     WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
    569 
    570     // Buffer the synchronized far and near frames,
    571     // to pass the smaller blocks individually.
    572     WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
    573     WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
    574     if (nearendClean != NULL)
    575     {
    576         WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
    577     }
    578 
    579     // Process as many blocks as possible.
    580     while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
    581     {
    582         int16_t far_block[PART_LEN];
    583         const int16_t* far_block_ptr = NULL;
    584         int16_t near_noisy_block[PART_LEN];
    585         const int16_t* near_noisy_block_ptr = NULL;
    586 
    587         WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
    588                           PART_LEN);
    589         WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
    590                           (void**) &near_noisy_block_ptr,
    591                           near_noisy_block,
    592                           PART_LEN);
    593         if (nearendClean != NULL)
    594         {
    595             int16_t near_clean_block[PART_LEN];
    596             const int16_t* near_clean_block_ptr = NULL;
    597 
    598             WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
    599                               (void**) &near_clean_block_ptr,
    600                               near_clean_block,
    601                               PART_LEN);
    602             if (WebRtcAecm_ProcessBlock(aecm,
    603                                         far_block_ptr,
    604                                         near_noisy_block_ptr,
    605                                         near_clean_block_ptr,
    606                                         outBlock) == -1)
    607             {
    608                 return -1;
    609             }
    610         } else
    611         {
    612             if (WebRtcAecm_ProcessBlock(aecm,
    613                                         far_block_ptr,
    614                                         near_noisy_block_ptr,
    615                                         NULL,
    616                                         outBlock) == -1)
    617             {
    618                 return -1;
    619             }
    620         }
    621 
    622         WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
    623     }
    624 
    625     // Stuff the out buffer if we have less than a frame to output.
    626     // This should only happen for the first frame.
    627     size = (int) WebRtc_available_read(aecm->outFrameBuf);
    628     if (size < FRAME_LEN)
    629     {
    630         WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
    631     }
    632 
    633     // Obtain an output frame.
    634     WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
    635     if (out_ptr != out) {
    636       // ReadBuffer() hasn't copied to |out| in this case.
    637       memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
    638     }
    639 
    640     return 0;
    641 }
    642 
    643 // WebRtcAecm_AsymFilt(...)
    644 //
    645 // Performs asymmetric filtering.
    646 //
    647 // Inputs:
    648 //      - filtOld       : Previous filtered value.
    649 //      - inVal         : New input value.
    650 //      - stepSizePos   : Step size when we have a positive contribution.
    651 //      - stepSizeNeg   : Step size when we have a negative contribution.
    652 //
    653 // Output:
    654 //
    655 // Return: - Filtered value.
    656 //
    657 int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal,
    658                             const int16_t stepSizePos,
    659                             const int16_t stepSizeNeg)
    660 {
    661     int16_t retVal;
    662 
    663     if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
    664     {
    665         return inVal;
    666     }
    667     retVal = filtOld;
    668     if (filtOld > inVal)
    669     {
    670         retVal -= (filtOld - inVal) >> stepSizeNeg;
    671     } else
    672     {
    673         retVal += (inVal - filtOld) >> stepSizePos;
    674     }
    675 
    676     return retVal;
    677 }
    678 
    679 // ExtractFractionPart(a, zeros)
    680 //
    681 // returns the fraction part of |a|, with |zeros| number of leading zeros, as an
    682 // int16_t scaled to Q8. There is no sanity check of |a| in the sense that the
    683 // number of zeros match.
    684 static int16_t ExtractFractionPart(uint32_t a, int zeros) {
    685   return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23);
    686 }
    687 
    688 // Calculates and returns the log of |energy| in Q8. The input |energy| is
    689 // supposed to be in Q(|q_domain|).
    690 static int16_t LogOfEnergyInQ8(uint32_t energy, int q_domain) {
    691   static const int16_t kLogLowValue = PART_LEN_SHIFT << 7;
    692   int16_t log_energy_q8 = kLogLowValue;
    693   if (energy > 0) {
    694     int zeros = WebRtcSpl_NormU32(energy);
    695     int16_t frac = ExtractFractionPart(energy, zeros);
    696     // log2 of |energy| in Q8.
    697     log_energy_q8 += ((31 - zeros) << 8) + frac - (q_domain << 8);
    698   }
    699   return log_energy_q8;
    700 }
    701 
    702 // WebRtcAecm_CalcEnergies(...)
    703 //
    704 // This function calculates the log of energies for nearend, farend and estimated
    705 // echoes. There is also an update of energy decision levels, i.e. internal VAD.
    706 //
    707 //
    708 // @param  aecm         [i/o]   Handle of the AECM instance.
    709 // @param  far_spectrum [in]    Pointer to farend spectrum.
    710 // @param  far_q        [in]    Q-domain of farend spectrum.
    711 // @param  nearEner     [in]    Near end energy for current block in
    712 //                              Q(aecm->dfaQDomain).
    713 // @param  echoEst      [out]   Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
    714 //
    715 void WebRtcAecm_CalcEnergies(AecmCore* aecm,
    716                              const uint16_t* far_spectrum,
    717                              const int16_t far_q,
    718                              const uint32_t nearEner,
    719                              int32_t* echoEst) {
    720     // Local variables
    721     uint32_t tmpAdapt = 0;
    722     uint32_t tmpStored = 0;
    723     uint32_t tmpFar = 0;
    724 
    725     int i;
    726 
    727     int16_t tmp16;
    728     int16_t increase_max_shifts = 4;
    729     int16_t decrease_max_shifts = 11;
    730     int16_t increase_min_shifts = 11;
    731     int16_t decrease_min_shifts = 3;
    732 
    733     // Get log of near end energy and store in buffer
    734 
    735     // Shift buffer
    736     memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
    737             sizeof(int16_t) * (MAX_BUF_LEN - 1));
    738 
    739     // Logarithm of integrated magnitude spectrum (nearEner)
    740     aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain);
    741 
    742     WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
    743 
    744     // Shift buffers
    745     memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
    746             sizeof(int16_t) * (MAX_BUF_LEN - 1));
    747     memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
    748             sizeof(int16_t) * (MAX_BUF_LEN - 1));
    749 
    750     // Logarithm of delayed far end energy
    751     aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q);
    752 
    753     // Logarithm of estimated echo energy through adapted channel
    754     aecm->echoAdaptLogEnergy[0] = LogOfEnergyInQ8(tmpAdapt,
    755                                                   RESOLUTION_CHANNEL16 + far_q);
    756 
    757     // Logarithm of estimated echo energy through stored channel
    758     aecm->echoStoredLogEnergy[0] =
    759         LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q);
    760 
    761     // Update farend energy levels (min, max, vad, mse)
    762     if (aecm->farLogEnergy > FAR_ENERGY_MIN)
    763     {
    764         if (aecm->startupState == 0)
    765         {
    766             increase_max_shifts = 2;
    767             decrease_min_shifts = 2;
    768             increase_min_shifts = 8;
    769         }
    770 
    771         aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
    772                                                  increase_min_shifts, decrease_min_shifts);
    773         aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
    774                                                  increase_max_shifts, decrease_max_shifts);
    775         aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
    776 
    777         // Dynamic VAD region size
    778         tmp16 = 2560 - aecm->farEnergyMin;
    779         if (tmp16 > 0)
    780         {
    781           tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9);
    782         } else
    783         {
    784             tmp16 = 0;
    785         }
    786         tmp16 += FAR_ENERGY_VAD_REGION;
    787 
    788         if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
    789         {
    790             // In startup phase or VAD update halted
    791             aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
    792         } else
    793         {
    794             if (aecm->farEnergyVAD > aecm->farLogEnergy)
    795             {
    796                 aecm->farEnergyVAD +=
    797                     (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6;
    798                 aecm->vadUpdateCount = 0;
    799             } else
    800             {
    801                 aecm->vadUpdateCount++;
    802             }
    803         }
    804         // Put MSE threshold higher than VAD
    805         aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
    806     }
    807 
    808     // Update VAD variables
    809     if (aecm->farLogEnergy > aecm->farEnergyVAD)
    810     {
    811         if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
    812         {
    813             // We are in startup or have significant dynamics in input speech level
    814             aecm->currentVADValue = 1;
    815         }
    816     } else
    817     {
    818         aecm->currentVADValue = 0;
    819     }
    820     if ((aecm->currentVADValue) && (aecm->firstVAD))
    821     {
    822         aecm->firstVAD = 0;
    823         if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
    824         {
    825             // The estimated echo has higher energy than the near end signal.
    826             // This means that the initialization was too aggressive. Scale
    827             // down by a factor 8
    828             for (i = 0; i < PART_LEN1; i++)
    829             {
    830                 aecm->channelAdapt16[i] >>= 3;
    831             }
    832             // Compensate the adapted echo energy level accordingly.
    833             aecm->echoAdaptLogEnergy[0] -= (3 << 8);
    834             aecm->firstVAD = 1;
    835         }
    836     }
    837 }
    838 
    839 // WebRtcAecm_CalcStepSize(...)
    840 //
    841 // This function calculates the step size used in channel estimation
    842 //
    843 //
    844 // @param  aecm  [in]    Handle of the AECM instance.
    845 // @param  mu    [out]   (Return value) Stepsize in log2(), i.e. number of shifts.
    846 //
    847 //
    848 int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) {
    849     int32_t tmp32;
    850     int16_t tmp16;
    851     int16_t mu = MU_MAX;
    852 
    853     // Here we calculate the step size mu used in the
    854     // following NLMS based Channel estimation algorithm
    855     if (!aecm->currentVADValue)
    856     {
    857         // Far end energy level too low, no channel update
    858         mu = 0;
    859     } else if (aecm->startupState > 0)
    860     {
    861         if (aecm->farEnergyMin >= aecm->farEnergyMax)
    862         {
    863             mu = MU_MIN;
    864         } else
    865         {
    866             tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
    867             tmp32 = tmp16 * MU_DIFF;
    868             tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
    869             mu = MU_MIN - 1 - (int16_t)(tmp32);
    870             // The -1 is an alternative to rounding. This way we get a larger
    871             // stepsize, so we in some sense compensate for truncation in NLMS
    872         }
    873         if (mu < MU_MAX)
    874         {
    875             mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
    876         }
    877     }
    878 
    879     return mu;
    880 }
    881 
    882 // WebRtcAecm_UpdateChannel(...)
    883 //
    884 // This function performs channel estimation. NLMS and decision on channel storage.
    885 //
    886 //
    887 // @param  aecm         [i/o]   Handle of the AECM instance.
    888 // @param  far_spectrum [in]    Absolute value of the farend signal in Q(far_q)
    889 // @param  far_q        [in]    Q-domain of the farend signal
    890 // @param  dfa          [in]    Absolute value of the nearend signal (Q[aecm->dfaQDomain])
    891 // @param  mu           [in]    NLMS step size.
    892 // @param  echoEst      [i/o]   Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
    893 //
    894 void WebRtcAecm_UpdateChannel(AecmCore* aecm,
    895                               const uint16_t* far_spectrum,
    896                               const int16_t far_q,
    897                               const uint16_t* const dfa,
    898                               const int16_t mu,
    899                               int32_t* echoEst) {
    900     uint32_t tmpU32no1, tmpU32no2;
    901     int32_t tmp32no1, tmp32no2;
    902     int32_t mseStored;
    903     int32_t mseAdapt;
    904 
    905     int i;
    906 
    907     int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
    908     int16_t shiftChFar, shiftNum, shift2ResChan;
    909     int16_t tmp16no1;
    910     int16_t xfaQ, dfaQ;
    911 
    912     // This is the channel estimation algorithm. It is base on NLMS but has a variable step
    913     // length, which was calculated above.
    914     if (mu)
    915     {
    916         for (i = 0; i < PART_LEN1; i++)
    917         {
    918             // Determine norm of channel and farend to make sure we don't get overflow in
    919             // multiplication
    920             zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
    921             zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
    922             if (zerosCh + zerosFar > 31)
    923             {
    924                 // Multiplication is safe
    925                 tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
    926                         far_spectrum[i]);
    927                 shiftChFar = 0;
    928             } else
    929             {
    930                 // We need to shift down before multiplication
    931                 shiftChFar = 32 - zerosCh - zerosFar;
    932                 tmpU32no1 = (aecm->channelAdapt32[i] >> shiftChFar) *
    933                     far_spectrum[i];
    934             }
    935             // Determine Q-domain of numerator
    936             zerosNum = WebRtcSpl_NormU32(tmpU32no1);
    937             if (dfa[i])
    938             {
    939                 zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
    940             } else
    941             {
    942                 zerosDfa = 32;
    943             }
    944             tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
    945                 RESOLUTION_CHANNEL32 - far_q + shiftChFar;
    946             if (zerosNum > tmp16no1 + 1)
    947             {
    948                 xfaQ = tmp16no1;
    949                 dfaQ = zerosDfa - 2;
    950             } else
    951             {
    952                 xfaQ = zerosNum - 2;
    953                 dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
    954                     shiftChFar + xfaQ;
    955             }
    956             // Add in the same Q-domain
    957             tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
    958             tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
    959             tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
    960             zerosNum = WebRtcSpl_NormW32(tmp32no1);
    961             if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
    962             {
    963                 //
    964                 // Update is needed
    965                 //
    966                 // This is what we would like to compute
    967                 //
    968                 // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
    969                 // tmp32norm = (i + 1)
    970                 // aecm->channelAdapt[i] += (2^mu) * tmp32no1
    971                 //                        / (tmp32norm * far_spectrum[i])
    972                 //
    973 
    974                 // Make sure we don't get overflow in multiplication.
    975                 if (zerosNum + zerosFar > 31)
    976                 {
    977                     if (tmp32no1 > 0)
    978                     {
    979                         tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1,
    980                                                                         far_spectrum[i]);
    981                     } else
    982                     {
    983                         tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
    984                                                                          far_spectrum[i]);
    985                     }
    986                     shiftNum = 0;
    987                 } else
    988                 {
    989                     shiftNum = 32 - (zerosNum + zerosFar);
    990                     if (tmp32no1 > 0)
    991                     {
    992                         tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i];
    993                     } else
    994                     {
    995                         tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]);
    996                     }
    997                 }
    998                 // Normalize with respect to frequency bin
    999                 tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
   1000                 // Make sure we are in the right Q-domain
   1001                 shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
   1002                 if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
   1003                 {
   1004                     tmp32no2 = WEBRTC_SPL_WORD32_MAX;
   1005                 } else
   1006                 {
   1007                     tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
   1008                 }
   1009                 aecm->channelAdapt32[i] =
   1010                     WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
   1011                 if (aecm->channelAdapt32[i] < 0)
   1012                 {
   1013                     // We can never have negative channel gain
   1014                     aecm->channelAdapt32[i] = 0;
   1015                 }
   1016                 aecm->channelAdapt16[i] =
   1017                     (int16_t)(aecm->channelAdapt32[i] >> 16);
   1018             }
   1019         }
   1020     }
   1021     // END: Adaptive channel update
   1022 
   1023     // Determine if we should store or restore the channel
   1024     if ((aecm->startupState == 0) & (aecm->currentVADValue))
   1025     {
   1026         // During startup we store the channel every block,
   1027         // and we recalculate echo estimate
   1028         WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
   1029     } else
   1030     {
   1031         if (aecm->farLogEnergy < aecm->farEnergyMSE)
   1032         {
   1033             aecm->mseChannelCount = 0;
   1034         } else
   1035         {
   1036             aecm->mseChannelCount++;
   1037         }
   1038         // Enough data for validation. Store channel if we can.
   1039         if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
   1040         {
   1041             // We have enough data.
   1042             // Calculate MSE of "Adapt" and "Stored" versions.
   1043             // It is actually not MSE, but average absolute error.
   1044             mseStored = 0;
   1045             mseAdapt = 0;
   1046             for (i = 0; i < MIN_MSE_COUNT; i++)
   1047             {
   1048                 tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i]
   1049                         - (int32_t)aecm->nearLogEnergy[i]);
   1050                 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
   1051                 mseStored += tmp32no2;
   1052 
   1053                 tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i]
   1054                         - (int32_t)aecm->nearLogEnergy[i]);
   1055                 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
   1056                 mseAdapt += tmp32no2;
   1057             }
   1058             if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
   1059                     & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
   1060                             * aecm->mseAdaptOld)))
   1061             {
   1062                 // The stored channel has a significantly lower MSE than the adaptive one for
   1063                 // two consecutive calculations. Reset the adaptive channel.
   1064                 WebRtcAecm_ResetAdaptiveChannel(aecm);
   1065             } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
   1066                     < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
   1067             {
   1068                 // The adaptive channel has a significantly lower MSE than the stored one.
   1069                 // The MSE for the adaptive channel has also been low for two consecutive
   1070                 // calculations. Store the adaptive channel.
   1071                 WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
   1072 
   1073                 // Update threshold
   1074                 if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
   1075                 {
   1076                     aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
   1077                 } else
   1078                 {
   1079                   int scaled_threshold = aecm->mseThreshold * 5 / 8;
   1080                   aecm->mseThreshold +=
   1081                       ((mseAdapt - scaled_threshold) * 205) >> 8;
   1082                 }
   1083 
   1084             }
   1085 
   1086             // Reset counter
   1087             aecm->mseChannelCount = 0;
   1088 
   1089             // Store the MSE values.
   1090             aecm->mseStoredOld = mseStored;
   1091             aecm->mseAdaptOld = mseAdapt;
   1092         }
   1093     }
   1094     // END: Determine if we should store or reset channel estimate.
   1095 }
   1096 
   1097 // CalcSuppressionGain(...)
   1098 //
   1099 // This function calculates the suppression gain that is used in the Wiener filter.
   1100 //
   1101 //
   1102 // @param  aecm     [i/n]   Handle of the AECM instance.
   1103 // @param  supGain  [out]   (Return value) Suppression gain with which to scale the noise
   1104 //                          level (Q14).
   1105 //
   1106 //
   1107 int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) {
   1108     int32_t tmp32no1;
   1109 
   1110     int16_t supGain = SUPGAIN_DEFAULT;
   1111     int16_t tmp16no1;
   1112     int16_t dE = 0;
   1113 
   1114     // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
   1115     // end energy and echo estimation error.
   1116     // Adjust for the far end signal level. A low signal level indicates no far end signal,
   1117     // hence we set the suppression gain to 0
   1118     if (!aecm->currentVADValue)
   1119     {
   1120         supGain = 0;
   1121     } else
   1122     {
   1123         // Adjust for possible double talk. If we have large variations in estimation error we
   1124         // likely have double talk (or poor channel).
   1125         tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
   1126         dE = WEBRTC_SPL_ABS_W16(tmp16no1);
   1127 
   1128         if (dE < ENERGY_DEV_TOL)
   1129         {
   1130             // Likely no double talk. The better estimation, the more we can suppress signal.
   1131             // Update counters
   1132             if (dE < SUPGAIN_EPC_DT)
   1133             {
   1134                 tmp32no1 = aecm->supGainErrParamDiffAB * dE;
   1135                 tmp32no1 += (SUPGAIN_EPC_DT >> 1);
   1136                 tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
   1137                 supGain = aecm->supGainErrParamA - tmp16no1;
   1138             } else
   1139             {
   1140                 tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE);
   1141                 tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
   1142                 tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
   1143                         - SUPGAIN_EPC_DT));
   1144                 supGain = aecm->supGainErrParamD + tmp16no1;
   1145             }
   1146         } else
   1147         {
   1148             // Likely in double talk. Use default value
   1149             supGain = aecm->supGainErrParamD;
   1150         }
   1151     }
   1152 
   1153     if (supGain > aecm->supGainOld)
   1154     {
   1155         tmp16no1 = supGain;
   1156     } else
   1157     {
   1158         tmp16no1 = aecm->supGainOld;
   1159     }
   1160     aecm->supGainOld = supGain;
   1161     if (tmp16no1 < aecm->supGain)
   1162     {
   1163         aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
   1164     } else
   1165     {
   1166         aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
   1167     }
   1168 
   1169     // END: Update suppression gain
   1170 
   1171     return aecm->supGain;
   1172 }
   1173 
   1174 void WebRtcAecm_BufferFarFrame(AecmCore* const aecm,
   1175                                const int16_t* const farend,
   1176                                const int farLen) {
   1177     int writeLen = farLen, writePos = 0;
   1178 
   1179     // Check if the write position must be wrapped
   1180     while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
   1181     {
   1182         // Write to remaining buffer space before wrapping
   1183         writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
   1184         memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
   1185                sizeof(int16_t) * writeLen);
   1186         aecm->farBufWritePos = 0;
   1187         writePos = writeLen;
   1188         writeLen = farLen - writeLen;
   1189     }
   1190 
   1191     memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
   1192            sizeof(int16_t) * writeLen);
   1193     aecm->farBufWritePos += writeLen;
   1194 }
   1195 
   1196 void WebRtcAecm_FetchFarFrame(AecmCore* const aecm,
   1197                               int16_t* const farend,
   1198                               const int farLen,
   1199                               const int knownDelay) {
   1200     int readLen = farLen;
   1201     int readPos = 0;
   1202     int delayChange = knownDelay - aecm->lastKnownDelay;
   1203 
   1204     aecm->farBufReadPos -= delayChange;
   1205 
   1206     // Check if delay forces a read position wrap
   1207     while (aecm->farBufReadPos < 0)
   1208     {
   1209         aecm->farBufReadPos += FAR_BUF_LEN;
   1210     }
   1211     while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
   1212     {
   1213         aecm->farBufReadPos -= FAR_BUF_LEN;
   1214     }
   1215 
   1216     aecm->lastKnownDelay = knownDelay;
   1217 
   1218     // Check if read position must be wrapped
   1219     while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
   1220     {
   1221 
   1222         // Read from remaining buffer space before wrapping
   1223         readLen = FAR_BUF_LEN - aecm->farBufReadPos;
   1224         memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
   1225                sizeof(int16_t) * readLen);
   1226         aecm->farBufReadPos = 0;
   1227         readPos = readLen;
   1228         readLen = farLen - readLen;
   1229     }
   1230     memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
   1231            sizeof(int16_t) * readLen);
   1232     aecm->farBufReadPos += readLen;
   1233 }
   1234