Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 /*
     12  * Contains the API functions for the AEC.
     13  */
     14 #include <stdlib.h>
     15 #include <string.h>
     16 
     17 #include "echo_cancellation.h"
     18 #include "aec_core.h"
     19 #include "ring_buffer.h"
     20 #include "resampler.h"
     21 #ifdef AEC_DEBUG
     22     #include <stdio.h>
     23 #endif
     24 
     25 #define BUF_SIZE_FRAMES 50 // buffer size (frames)
     26 // Maximum length of resampled signal. Must be an integer multiple of frames
     27 // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
     28 // The factor of 2 handles wb, and the + 1 is as a safety margin
     29 #define MAX_RESAMP_LEN (5 * FRAME_LEN)
     30 
     31 static const int bufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
     32 static const int sampMsNb = 8; // samples per ms in nb
     33 // Target suppression levels for nlp modes
     34 // log{0.001, 0.00001, 0.00000001}
     35 static const float targetSupp[3] = {-6.9f, -11.5f, -18.4f};
     36 static const float minOverDrive[3] = {1.0f, 2.0f, 5.0f};
     37 static const int initCheck = 42;
     38 
     39 typedef struct {
     40     int delayCtr;
     41     int sampFreq;
     42     int splitSampFreq;
     43     int scSampFreq;
     44     float sampFactor; // scSampRate / sampFreq
     45     short nlpMode;
     46     short autoOnOff;
     47     short activity;
     48     short skewMode;
     49     short bufSizeStart;
     50     //short bufResetCtr;  // counts number of noncausal frames
     51     int knownDelay;
     52 
     53     // Stores the last frame added to the farend buffer
     54     short farendOld[2][FRAME_LEN];
     55     short initFlag; // indicates if AEC has been initialized
     56 
     57     // Variables used for averaging far end buffer size
     58     short counter;
     59     short sum;
     60     short firstVal;
     61     short checkBufSizeCtr;
     62 
     63     // Variables used for delay shifts
     64     short msInSndCardBuf;
     65     short filtDelay;
     66     int timeForDelayChange;
     67     int ECstartup;
     68     int checkBuffSize;
     69     int delayChange;
     70     short lastDelayDiff;
     71 
     72 #ifdef AEC_DEBUG
     73     FILE *bufFile;
     74     FILE *delayFile;
     75     FILE *skewFile;
     76     FILE *preCompFile;
     77     FILE *postCompFile;
     78 #endif // AEC_DEBUG
     79 
     80     // Structures
     81     void *farendBuf;
     82     void *resampler;
     83 
     84     int skewFrCtr;
     85     int resample; // if the skew is small enough we don't resample
     86     int highSkewCtr;
     87     float skew;
     88 
     89     int lastError;
     90 
     91     aec_t *aec;
     92 } aecpc_t;
     93 
     94 // Estimates delay to set the position of the farend buffer read pointer
     95 // (controlled by knownDelay)
     96 static int EstBufDelay(aecpc_t *aecInst, short msInSndCardBuf);
     97 
     98 // Stuffs the farend buffer if the estimated delay is too large
     99 static int DelayComp(aecpc_t *aecInst);
    100 
    101 WebRtc_Word32 WebRtcAec_Create(void **aecInst)
    102 {
    103     aecpc_t *aecpc;
    104     if (aecInst == NULL) {
    105         return -1;
    106     }
    107 
    108     aecpc = malloc(sizeof(aecpc_t));
    109     *aecInst = aecpc;
    110     if (aecpc == NULL) {
    111         return -1;
    112     }
    113 
    114     if (WebRtcAec_CreateAec(&aecpc->aec) == -1) {
    115         WebRtcAec_Free(aecpc);
    116         aecpc = NULL;
    117         return -1;
    118     }
    119 
    120     if (WebRtcApm_CreateBuffer(&aecpc->farendBuf, bufSizeSamp) == -1) {
    121         WebRtcAec_Free(aecpc);
    122         aecpc = NULL;
    123         return -1;
    124     }
    125 
    126     if (WebRtcAec_CreateResampler(&aecpc->resampler) == -1) {
    127         WebRtcAec_Free(aecpc);
    128         aecpc = NULL;
    129         return -1;
    130     }
    131 
    132     aecpc->initFlag = 0;
    133     aecpc->lastError = 0;
    134 
    135 #ifdef AEC_DEBUG
    136     aecpc->aec->farFile = fopen("aecFar.pcm","wb");
    137     aecpc->aec->nearFile = fopen("aecNear.pcm","wb");
    138     aecpc->aec->outFile = fopen("aecOut.pcm","wb");
    139     aecpc->aec->outLpFile = fopen("aecOutLp.pcm","wb");
    140 
    141     aecpc->bufFile = fopen("aecBuf.dat", "wb");
    142     aecpc->skewFile = fopen("aecSkew.dat", "wb");
    143     aecpc->delayFile = fopen("aecDelay.dat", "wb");
    144     aecpc->preCompFile = fopen("preComp.pcm", "wb");
    145     aecpc->postCompFile = fopen("postComp.pcm", "wb");
    146 #endif // AEC_DEBUG
    147 
    148     return 0;
    149 }
    150 
    151 WebRtc_Word32 WebRtcAec_Free(void *aecInst)
    152 {
    153     aecpc_t *aecpc = aecInst;
    154 
    155     if (aecpc == NULL) {
    156         return -1;
    157     }
    158 
    159 #ifdef AEC_DEBUG
    160     fclose(aecpc->aec->farFile);
    161     fclose(aecpc->aec->nearFile);
    162     fclose(aecpc->aec->outFile);
    163     fclose(aecpc->aec->outLpFile);
    164 
    165     fclose(aecpc->bufFile);
    166     fclose(aecpc->skewFile);
    167     fclose(aecpc->delayFile);
    168     fclose(aecpc->preCompFile);
    169     fclose(aecpc->postCompFile);
    170 #endif // AEC_DEBUG
    171 
    172     WebRtcAec_FreeAec(aecpc->aec);
    173     WebRtcApm_FreeBuffer(aecpc->farendBuf);
    174     WebRtcAec_FreeResampler(aecpc->resampler);
    175     free(aecpc);
    176 
    177     return 0;
    178 }
    179 
    180 WebRtc_Word32 WebRtcAec_Init(void *aecInst, WebRtc_Word32 sampFreq, WebRtc_Word32 scSampFreq)
    181 {
    182     aecpc_t *aecpc = aecInst;
    183     AecConfig aecConfig;
    184 
    185     if (aecpc == NULL) {
    186         return -1;
    187     }
    188 
    189     if (sampFreq != 8000 && sampFreq != 16000  && sampFreq != 32000) {
    190         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    191         return -1;
    192     }
    193     aecpc->sampFreq = sampFreq;
    194 
    195     if (scSampFreq < 1 || scSampFreq > 96000) {
    196         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    197         return -1;
    198     }
    199     aecpc->scSampFreq = scSampFreq;
    200 
    201     // Initialize echo canceller core
    202     if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
    203         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    204         return -1;
    205     }
    206 
    207     // Initialize farend buffer
    208     if (WebRtcApm_InitBuffer(aecpc->farendBuf) == -1) {
    209         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    210         return -1;
    211     }
    212 
    213     if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
    214         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    215         return -1;
    216     }
    217 
    218     aecpc->initFlag = initCheck;  // indicates that initilisation has been done
    219 
    220     if (aecpc->sampFreq == 32000) {
    221         aecpc->splitSampFreq = 16000;
    222     }
    223     else {
    224         aecpc->splitSampFreq = sampFreq;
    225     }
    226 
    227     aecpc->skewFrCtr = 0;
    228     aecpc->activity = 0;
    229 
    230     aecpc->delayChange = 1;
    231     aecpc->delayCtr = 0;
    232 
    233     aecpc->sum = 0;
    234     aecpc->counter = 0;
    235     aecpc->checkBuffSize = 1;
    236     aecpc->firstVal = 0;
    237 
    238     aecpc->ECstartup = 1;
    239     aecpc->bufSizeStart = 0;
    240     aecpc->checkBufSizeCtr = 0;
    241     aecpc->filtDelay = 0;
    242     aecpc->timeForDelayChange =0;
    243     aecpc->knownDelay = 0;
    244     aecpc->lastDelayDiff = 0;
    245 
    246     aecpc->skew = 0;
    247     aecpc->resample = kAecFalse;
    248     aecpc->highSkewCtr = 0;
    249     aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
    250 
    251     memset(&aecpc->farendOld[0][0], 0, 160);
    252 
    253     // Default settings.
    254     aecConfig.nlpMode = kAecNlpModerate;
    255     aecConfig.skewMode = kAecFalse;
    256     aecConfig.metricsMode = kAecFalse;
    257 
    258     if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
    259         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    260         return -1;
    261     }
    262 
    263     return 0;
    264 }
    265 
    266 // only buffer L band for farend
    267 WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst, const WebRtc_Word16 *farend,
    268     WebRtc_Word16 nrOfSamples)
    269 {
    270     aecpc_t *aecpc = aecInst;
    271     WebRtc_Word32 retVal = 0;
    272     short newNrOfSamples;
    273     short newFarend[MAX_RESAMP_LEN];
    274     float skew;
    275 
    276     if (aecpc == NULL) {
    277         return -1;
    278     }
    279 
    280     if (farend == NULL) {
    281         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    282         return -1;
    283     }
    284 
    285     if (aecpc->initFlag != initCheck) {
    286         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    287         return -1;
    288     }
    289 
    290     // number of samples == 160 for SWB input
    291     if (nrOfSamples != 80 && nrOfSamples != 160) {
    292         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    293         return -1;
    294     }
    295 
    296     skew = aecpc->skew;
    297 
    298     // TODO: Is this really a good idea?
    299     if (!aecpc->ECstartup) {
    300         DelayComp(aecpc);
    301     }
    302 
    303     if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
    304         // Resample and get a new number of samples
    305         newNrOfSamples = WebRtcAec_ResampleLinear(aecpc->resampler,
    306                                                   farend,
    307                                                   nrOfSamples,
    308                                                   skew,
    309                                                   newFarend);
    310         WebRtcApm_WriteBuffer(aecpc->farendBuf, newFarend, newNrOfSamples);
    311 
    312 #ifdef AEC_DEBUG
    313         fwrite(farend, 2, nrOfSamples, aecpc->preCompFile);
    314         fwrite(newFarend, 2, newNrOfSamples, aecpc->postCompFile);
    315 #endif
    316     }
    317     else {
    318         WebRtcApm_WriteBuffer(aecpc->farendBuf, farend, nrOfSamples);
    319     }
    320 
    321     return retVal;
    322 }
    323 
    324 WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend,
    325     const WebRtc_Word16 *nearendH, WebRtc_Word16 *out, WebRtc_Word16 *outH,
    326     WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf, WebRtc_Word32 skew)
    327 {
    328     aecpc_t *aecpc = aecInst;
    329     WebRtc_Word32 retVal = 0;
    330     short i;
    331     short farend[FRAME_LEN];
    332     short nmbrOfFilledBuffers;
    333     short nBlocks10ms;
    334     short nFrames;
    335 #ifdef AEC_DEBUG
    336     short msInAECBuf;
    337 #endif
    338     // Limit resampling to doubling/halving of signal
    339     const float minSkewEst = -0.5f;
    340     const float maxSkewEst = 1.0f;
    341 
    342     if (aecpc == NULL) {
    343         return -1;
    344     }
    345 
    346     if (nearend == NULL) {
    347         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    348         return -1;
    349     }
    350 
    351     if (out == NULL) {
    352         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    353         return -1;
    354     }
    355 
    356     if (aecpc->initFlag != initCheck) {
    357         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    358         return -1;
    359     }
    360 
    361     // number of samples == 160 for SWB input
    362     if (nrOfSamples != 80 && nrOfSamples != 160) {
    363         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    364         return -1;
    365     }
    366 
    367     // Check for valid pointers based on sampling rate
    368     if (aecpc->sampFreq == 32000 && nearendH == NULL) {
    369        aecpc->lastError = AEC_NULL_POINTER_ERROR;
    370        return -1;
    371     }
    372 
    373     if (msInSndCardBuf < 0) {
    374         msInSndCardBuf = 0;
    375         aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
    376         retVal = -1;
    377     }
    378     else if (msInSndCardBuf > 500) {
    379         msInSndCardBuf = 500;
    380         aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
    381         retVal = -1;
    382     }
    383     msInSndCardBuf += 10;
    384     aecpc->msInSndCardBuf = msInSndCardBuf;
    385 
    386     if (aecpc->skewMode == kAecTrue) {
    387         if (aecpc->skewFrCtr < 25) {
    388             aecpc->skewFrCtr++;
    389         }
    390         else {
    391             retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
    392             if (retVal == -1) {
    393                 aecpc->skew = 0;
    394                 aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
    395             }
    396 
    397             aecpc->skew /= aecpc->sampFactor*nrOfSamples;
    398 
    399             if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
    400                 aecpc->resample = kAecFalse;
    401             }
    402             else {
    403                 aecpc->resample = kAecTrue;
    404             }
    405 
    406             if (aecpc->skew < minSkewEst) {
    407                 aecpc->skew = minSkewEst;
    408             }
    409             else if (aecpc->skew > maxSkewEst) {
    410                 aecpc->skew = maxSkewEst;
    411             }
    412 
    413 #ifdef AEC_DEBUG
    414             fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
    415 #endif
    416         }
    417     }
    418 
    419     nFrames = nrOfSamples / FRAME_LEN;
    420     nBlocks10ms = nFrames / aecpc->aec->mult;
    421 
    422     if (aecpc->ECstartup) {
    423         memcpy(out, nearend, sizeof(short) * nrOfSamples);
    424         nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecpc->farendBuf) / FRAME_LEN;
    425 
    426         // The AEC is in the start up mode
    427         // AEC is disabled until the soundcard buffer and farend buffers are OK
    428 
    429         // Mechanism to ensure that the soundcard buffer is reasonably stable.
    430         if (aecpc->checkBuffSize) {
    431 
    432             aecpc->checkBufSizeCtr++;
    433             // Before we fill up the far end buffer we require the amount of data on the
    434             // sound card to be stable (+/-8 ms) compared to the first value. This
    435             // comparison is made during the following 4 consecutive frames. If it seems
    436             // to be stable then we start to fill up the far end buffer.
    437 
    438             if (aecpc->counter == 0) {
    439                 aecpc->firstVal = aecpc->msInSndCardBuf;
    440                 aecpc->sum = 0;
    441             }
    442 
    443             if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) <
    444                 WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) {
    445                 aecpc->sum += aecpc->msInSndCardBuf;
    446                 aecpc->counter++;
    447             }
    448             else {
    449                 aecpc->counter = 0;
    450             }
    451 
    452             if (aecpc->counter*nBlocks10ms >= 6) {
    453                 // The farend buffer size is determined in blocks of 80 samples
    454                 // Use 75% of the average value of the soundcard buffer
    455                 aecpc->bufSizeStart = WEBRTC_SPL_MIN((int) (0.75 * (aecpc->sum *
    456                     aecpc->aec->mult) / (aecpc->counter * 10)), BUF_SIZE_FRAMES);
    457                 // buffersize has now been determined
    458                 aecpc->checkBuffSize = 0;
    459             }
    460 
    461             if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) {
    462                 // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
    463                 aecpc->bufSizeStart = WEBRTC_SPL_MIN((int) (0.75 * (aecpc->msInSndCardBuf *
    464                     aecpc->aec->mult) / 10), BUF_SIZE_FRAMES);
    465                 aecpc->checkBuffSize = 0;
    466             }
    467         }
    468 
    469         // if checkBuffSize changed in the if-statement above
    470         if (!aecpc->checkBuffSize) {
    471             // soundcard buffer is now reasonably stable
    472             // When the far end buffer is filled with approximately the same amount of
    473             // data as the amount on the sound card we end the start up phase and start
    474             // to cancel echoes.
    475 
    476             if (nmbrOfFilledBuffers == aecpc->bufSizeStart) {
    477                 aecpc->ECstartup = 0;  // Enable the AEC
    478             }
    479             else if (nmbrOfFilledBuffers > aecpc->bufSizeStart) {
    480                 WebRtcApm_FlushBuffer(aecpc->farendBuf, WebRtcApm_get_buffer_size(aecpc->farendBuf) -
    481                     aecpc->bufSizeStart * FRAME_LEN);
    482                 aecpc->ECstartup = 0;
    483             }
    484         }
    485 
    486     }
    487     else {
    488         // AEC is enabled
    489 
    490         // Note only 1 block supported for nb and 2 blocks for wb
    491         for (i = 0; i < nFrames; i++) {
    492             nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecpc->farendBuf) / FRAME_LEN;
    493 
    494             // Check that there is data in the far end buffer
    495             if (nmbrOfFilledBuffers > 0) {
    496                 // Get the next 80 samples from the farend buffer
    497                 WebRtcApm_ReadBuffer(aecpc->farendBuf, farend, FRAME_LEN);
    498 
    499                 // Always store the last frame for use when we run out of data
    500                 memcpy(&(aecpc->farendOld[i][0]), farend, FRAME_LEN * sizeof(short));
    501             }
    502             else {
    503                 // We have no data so we use the last played frame
    504                 memcpy(farend, &(aecpc->farendOld[i][0]), FRAME_LEN * sizeof(short));
    505             }
    506 
    507             // Call buffer delay estimator when all data is extracted,
    508             // i.e. i = 0 for NB and i = 1 for WB or SWB
    509             if ((i == 0 && aecpc->splitSampFreq == 8000) ||
    510                     (i == 1 && (aecpc->splitSampFreq == 16000))) {
    511                 EstBufDelay(aecpc, aecpc->msInSndCardBuf);
    512             }
    513 
    514             // Call the AEC
    515            WebRtcAec_ProcessFrame(aecpc->aec, farend, &nearend[FRAME_LEN * i], &nearendH[FRAME_LEN * i],
    516                &out[FRAME_LEN * i], &outH[FRAME_LEN * i], aecpc->knownDelay);
    517         }
    518     }
    519 
    520 #ifdef AEC_DEBUG
    521     msInAECBuf = WebRtcApm_get_buffer_size(aecpc->farendBuf) / (sampMsNb*aecpc->aec->mult);
    522     fwrite(&msInAECBuf, 2, 1, aecpc->bufFile);
    523     fwrite(&(aecpc->knownDelay), sizeof(aecpc->knownDelay), 1, aecpc->delayFile);
    524 #endif
    525 
    526     return retVal;
    527 }
    528 
    529 WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config)
    530 {
    531     aecpc_t *aecpc = aecInst;
    532 
    533     if (aecpc == NULL) {
    534         return -1;
    535     }
    536 
    537     if (aecpc->initFlag != initCheck) {
    538         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    539         return -1;
    540     }
    541 
    542     if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
    543         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    544         return -1;
    545     }
    546     aecpc->skewMode = config.skewMode;
    547 
    548     if (config.nlpMode != kAecNlpConservative && config.nlpMode !=
    549             kAecNlpModerate && config.nlpMode != kAecNlpAggressive) {
    550         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    551         return -1;
    552     }
    553     aecpc->nlpMode = config.nlpMode;
    554     aecpc->aec->targetSupp = targetSupp[aecpc->nlpMode];
    555     aecpc->aec->minOverDrive = minOverDrive[aecpc->nlpMode];
    556 
    557     if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
    558         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    559         return -1;
    560     }
    561     aecpc->aec->metricsMode = config.metricsMode;
    562     if (aecpc->aec->metricsMode == kAecTrue) {
    563         WebRtcAec_InitMetrics(aecpc->aec);
    564     }
    565 
    566     return 0;
    567 }
    568 
    569 WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config)
    570 {
    571     aecpc_t *aecpc = aecInst;
    572 
    573     if (aecpc == NULL) {
    574         return -1;
    575     }
    576 
    577     if (config == NULL) {
    578         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    579         return -1;
    580     }
    581 
    582     if (aecpc->initFlag != initCheck) {
    583         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    584         return -1;
    585     }
    586 
    587     config->nlpMode = aecpc->nlpMode;
    588     config->skewMode = aecpc->skewMode;
    589     config->metricsMode = aecpc->aec->metricsMode;
    590 
    591     return 0;
    592 }
    593 
    594 WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status)
    595 {
    596     aecpc_t *aecpc = aecInst;
    597 
    598     if (aecpc == NULL) {
    599         return -1;
    600     }
    601 
    602     if (status == NULL) {
    603         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    604         return -1;
    605     }
    606 
    607     if (aecpc->initFlag != initCheck) {
    608         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    609         return -1;
    610     }
    611 
    612     *status = aecpc->aec->echoState;
    613 
    614     return 0;
    615 }
    616 
    617 WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics)
    618 {
    619     const float upweight = 0.7f;
    620     float dtmp;
    621     short stmp;
    622     aecpc_t *aecpc = aecInst;
    623 
    624     if (aecpc == NULL) {
    625         return -1;
    626     }
    627 
    628     if (metrics == NULL) {
    629         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    630         return -1;
    631     }
    632 
    633     if (aecpc->initFlag != initCheck) {
    634         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    635         return -1;
    636     }
    637 
    638     // ERL
    639     metrics->erl.instant = (short) aecpc->aec->erl.instant;
    640 
    641     if ((aecpc->aec->erl.himean > offsetLevel) && (aecpc->aec->erl.average > offsetLevel)) {
    642     // Use a mix between regular average and upper part average
    643         dtmp = upweight * aecpc->aec->erl.himean + (1 - upweight) * aecpc->aec->erl.average;
    644         metrics->erl.average = (short) dtmp;
    645     }
    646     else {
    647         metrics->erl.average = offsetLevel;
    648     }
    649 
    650     metrics->erl.max = (short) aecpc->aec->erl.max;
    651 
    652     if (aecpc->aec->erl.min < (offsetLevel * (-1))) {
    653         metrics->erl.min = (short) aecpc->aec->erl.min;
    654     }
    655     else {
    656         metrics->erl.min = offsetLevel;
    657     }
    658 
    659     // ERLE
    660     metrics->erle.instant = (short) aecpc->aec->erle.instant;
    661 
    662     if ((aecpc->aec->erle.himean > offsetLevel) && (aecpc->aec->erle.average > offsetLevel)) {
    663         // Use a mix between regular average and upper part average
    664         dtmp =  upweight * aecpc->aec->erle.himean + (1 - upweight) * aecpc->aec->erle.average;
    665         metrics->erle.average = (short) dtmp;
    666     }
    667     else {
    668         metrics->erle.average = offsetLevel;
    669     }
    670 
    671     metrics->erle.max = (short) aecpc->aec->erle.max;
    672 
    673     if (aecpc->aec->erle.min < (offsetLevel * (-1))) {
    674         metrics->erle.min = (short) aecpc->aec->erle.min;
    675     } else {
    676         metrics->erle.min = offsetLevel;
    677     }
    678 
    679     // RERL
    680     if ((metrics->erl.average > offsetLevel) && (metrics->erle.average > offsetLevel)) {
    681         stmp = metrics->erl.average + metrics->erle.average;
    682     }
    683     else {
    684         stmp = offsetLevel;
    685     }
    686     metrics->rerl.average = stmp;
    687 
    688     // No other statistics needed, but returned for completeness
    689     metrics->rerl.instant = stmp;
    690     metrics->rerl.max = stmp;
    691     metrics->rerl.min = stmp;
    692 
    693     // A_NLP
    694     metrics->aNlp.instant = (short) aecpc->aec->aNlp.instant;
    695 
    696     if ((aecpc->aec->aNlp.himean > offsetLevel) && (aecpc->aec->aNlp.average > offsetLevel)) {
    697         // Use a mix between regular average and upper part average
    698         dtmp =  upweight * aecpc->aec->aNlp.himean + (1 - upweight) * aecpc->aec->aNlp.average;
    699         metrics->aNlp.average = (short) dtmp;
    700     }
    701     else {
    702         metrics->aNlp.average = offsetLevel;
    703     }
    704 
    705     metrics->aNlp.max = (short) aecpc->aec->aNlp.max;
    706 
    707     if (aecpc->aec->aNlp.min < (offsetLevel * (-1))) {
    708         metrics->aNlp.min = (short) aecpc->aec->aNlp.min;
    709     }
    710     else {
    711         metrics->aNlp.min = offsetLevel;
    712     }
    713 
    714     return 0;
    715 }
    716 
    717 WebRtc_Word32 WebRtcAec_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len)
    718 {
    719     const char version[] = "AEC 2.5.0";
    720     const short versionLen = (short)strlen(version) + 1; // +1 for null-termination
    721 
    722     if (versionStr == NULL) {
    723         return -1;
    724     }
    725 
    726     if (versionLen > len) {
    727         return -1;
    728     }
    729 
    730     strncpy(versionStr, version, versionLen);
    731     return 0;
    732 }
    733 
    734 WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst)
    735 {
    736     aecpc_t *aecpc = aecInst;
    737 
    738     if (aecpc == NULL) {
    739         return -1;
    740     }
    741 
    742     return aecpc->lastError;
    743 }
    744 
    745 static int EstBufDelay(aecpc_t *aecpc, short msInSndCardBuf)
    746 {
    747     short delayNew, nSampFar, nSampSndCard;
    748     short diff;
    749 
    750     nSampFar = WebRtcApm_get_buffer_size(aecpc->farendBuf);
    751     nSampSndCard = msInSndCardBuf * sampMsNb * aecpc->aec->mult;
    752 
    753     delayNew = nSampSndCard - nSampFar;
    754 
    755     // Account for resampling frame delay
    756     if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
    757         delayNew -= kResamplingDelay;
    758     }
    759 
    760     if (delayNew < FRAME_LEN) {
    761         WebRtcApm_FlushBuffer(aecpc->farendBuf, FRAME_LEN);
    762         delayNew += FRAME_LEN;
    763     }
    764 
    765     aecpc->filtDelay = WEBRTC_SPL_MAX(0, (short)(0.8*aecpc->filtDelay + 0.2*delayNew));
    766 
    767     diff = aecpc->filtDelay - aecpc->knownDelay;
    768     if (diff > 224) {
    769         if (aecpc->lastDelayDiff < 96) {
    770             aecpc->timeForDelayChange = 0;
    771         }
    772         else {
    773             aecpc->timeForDelayChange++;
    774         }
    775     }
    776     else if (diff < 96 && aecpc->knownDelay > 0) {
    777         if (aecpc->lastDelayDiff > 224) {
    778             aecpc->timeForDelayChange = 0;
    779         }
    780         else {
    781             aecpc->timeForDelayChange++;
    782         }
    783     }
    784     else {
    785         aecpc->timeForDelayChange = 0;
    786     }
    787     aecpc->lastDelayDiff = diff;
    788 
    789     if (aecpc->timeForDelayChange > 25) {
    790         aecpc->knownDelay = WEBRTC_SPL_MAX((int)aecpc->filtDelay - 160, 0);
    791     }
    792     return 0;
    793 }
    794 
    795 static int DelayComp(aecpc_t *aecpc)
    796 {
    797     int nSampFar, nSampSndCard, delayNew, nSampAdd;
    798     const int maxStuffSamp = 10 * FRAME_LEN;
    799 
    800     nSampFar = WebRtcApm_get_buffer_size(aecpc->farendBuf);
    801     nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->aec->mult;
    802     delayNew = nSampSndCard - nSampFar;
    803 
    804     // Account for resampling frame delay
    805     if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
    806         delayNew -= kResamplingDelay;
    807     }
    808 
    809     if (delayNew > FAR_BUF_LEN - FRAME_LEN*aecpc->aec->mult) {
    810         // The difference of the buffersizes is larger than the maximum
    811         // allowed known delay. Compensate by stuffing the buffer.
    812         nSampAdd = (int)(WEBRTC_SPL_MAX((int)(0.5 * nSampSndCard - nSampFar),
    813                     FRAME_LEN));
    814         nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
    815 
    816         WebRtcApm_StuffBuffer(aecpc->farendBuf, nSampAdd);
    817         aecpc->delayChange = 1; // the delay needs to be updated
    818     }
    819 
    820     return 0;
    821 }
    822