LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_processing/aecm - aecm_core.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 442 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13