Home | History | Annotate | Download | only in aec
      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 "echo_cancellation.h"
     15 
     16 #include <math.h>
     17 #ifdef WEBRTC_AEC_DEBUG_DUMP
     18 #include <stdio.h>
     19 #endif
     20 #include <stdlib.h>
     21 #include <string.h>
     22 
     23 #include "aec_core.h"
     24 #include "aec_resampler.h"
     25 #include "ring_buffer.h"
     26 #include "typedefs.h"
     27 
     28 // Maximum length of resampled signal. Must be an integer multiple of frames
     29 // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
     30 // The factor of 2 handles wb, and the + 1 is as a safety margin
     31 // TODO(bjornv): Replace with kResamplerBufferSize
     32 #define MAX_RESAMP_LEN (5 * FRAME_LEN)
     33 
     34 static const int kMaxBufSizeStart = 62;  // In partitions
     35 static const int sampMsNb = 8; // samples per ms in nb
     36 // Target suppression levels for nlp modes
     37 // log{0.001, 0.00001, 0.00000001}
     38 static const float targetSupp[3] = {-6.9f, -11.5f, -18.4f};
     39 static const float minOverDrive[3] = {1.0f, 2.0f, 5.0f};
     40 static const int initCheck = 42;
     41 
     42 #ifdef WEBRTC_AEC_DEBUG_DUMP
     43 static int instance_count = 0;
     44 #endif
     45 
     46 typedef struct {
     47     int delayCtr;
     48     int sampFreq;
     49     int splitSampFreq;
     50     int scSampFreq;
     51     float sampFactor; // scSampRate / sampFreq
     52     short nlpMode;
     53     short autoOnOff;
     54     short activity;
     55     short skewMode;
     56     int bufSizeStart;
     57     //short bufResetCtr;  // counts number of noncausal frames
     58     int knownDelay;
     59 
     60     short initFlag; // indicates if AEC has been initialized
     61 
     62     // Variables used for averaging far end buffer size
     63     short counter;
     64     int sum;
     65     short firstVal;
     66     short checkBufSizeCtr;
     67 
     68     // Variables used for delay shifts
     69     short msInSndCardBuf;
     70     short filtDelay;  // Filtered delay estimate.
     71     int timeForDelayChange;
     72     int ECstartup;
     73     int checkBuffSize;
     74     short lastDelayDiff;
     75 
     76 #ifdef WEBRTC_AEC_DEBUG_DUMP
     77     void* far_pre_buf_s16;  // Time domain far-end pre-buffer in int16_t.
     78     FILE *bufFile;
     79     FILE *delayFile;
     80     FILE *skewFile;
     81 #endif
     82 
     83     // Structures
     84     void *resampler;
     85 
     86     int skewFrCtr;
     87     int resample; // if the skew is small enough we don't resample
     88     int highSkewCtr;
     89     float skew;
     90 
     91     void* far_pre_buf;  // Time domain far-end pre-buffer.
     92 
     93     int lastError;
     94 
     95     aec_t *aec;
     96 } aecpc_t;
     97 
     98 // Estimates delay to set the position of the far-end buffer read pointer
     99 // (controlled by knownDelay)
    100 static int EstBufDelay(aecpc_t *aecInst);
    101 
    102 WebRtc_Word32 WebRtcAec_Create(void **aecInst)
    103 {
    104     aecpc_t *aecpc;
    105     if (aecInst == NULL) {
    106         return -1;
    107     }
    108 
    109     aecpc = malloc(sizeof(aecpc_t));
    110     *aecInst = aecpc;
    111     if (aecpc == NULL) {
    112         return -1;
    113     }
    114 
    115     if (WebRtcAec_CreateAec(&aecpc->aec) == -1) {
    116         WebRtcAec_Free(aecpc);
    117         aecpc = NULL;
    118         return -1;
    119     }
    120 
    121     if (WebRtcAec_CreateResampler(&aecpc->resampler) == -1) {
    122         WebRtcAec_Free(aecpc);
    123         aecpc = NULL;
    124         return -1;
    125     }
    126     // Create far-end pre-buffer. The buffer size has to be large enough for
    127     // largest possible drift compensation (kResamplerBufferSize) + "almost" an
    128     // FFT buffer (PART_LEN2 - 1).
    129     if (WebRtc_CreateBuffer(&aecpc->far_pre_buf,
    130                             PART_LEN2 + kResamplerBufferSize,
    131                             sizeof(float)) == -1) {
    132         WebRtcAec_Free(aecpc);
    133         aecpc = NULL;
    134         return -1;
    135     }
    136 
    137     aecpc->initFlag = 0;
    138     aecpc->lastError = 0;
    139 
    140 #ifdef WEBRTC_AEC_DEBUG_DUMP
    141     if (WebRtc_CreateBuffer(&aecpc->far_pre_buf_s16,
    142                             PART_LEN2 + kResamplerBufferSize,
    143                             sizeof(int16_t)) == -1) {
    144         WebRtcAec_Free(aecpc);
    145         aecpc = NULL;
    146         return -1;
    147     }
    148     {
    149       char filename[64];
    150       sprintf(filename, "aec_far%d.pcm", instance_count);
    151       aecpc->aec->farFile = fopen(filename, "wb");
    152       sprintf(filename, "aec_near%d.pcm", instance_count);
    153       aecpc->aec->nearFile = fopen(filename, "wb");
    154       sprintf(filename, "aec_out%d.pcm", instance_count);
    155       aecpc->aec->outFile = fopen(filename, "wb");
    156       sprintf(filename, "aec_out_linear%d.pcm", instance_count);
    157       aecpc->aec->outLinearFile = fopen(filename, "wb");
    158       sprintf(filename, "aec_buf%d.dat", instance_count);
    159       aecpc->bufFile = fopen(filename, "wb");
    160       sprintf(filename, "aec_skew%d.dat", instance_count);
    161       aecpc->skewFile = fopen(filename, "wb");
    162       sprintf(filename, "aec_delay%d.dat", instance_count);
    163       aecpc->delayFile = fopen(filename, "wb");
    164       instance_count++;
    165     }
    166 #endif
    167 
    168     return 0;
    169 }
    170 
    171 WebRtc_Word32 WebRtcAec_Free(void *aecInst)
    172 {
    173     aecpc_t *aecpc = aecInst;
    174 
    175     if (aecpc == NULL) {
    176         return -1;
    177     }
    178 
    179     WebRtc_FreeBuffer(aecpc->far_pre_buf);
    180 
    181 #ifdef WEBRTC_AEC_DEBUG_DUMP
    182     WebRtc_FreeBuffer(aecpc->far_pre_buf_s16);
    183     fclose(aecpc->aec->farFile);
    184     fclose(aecpc->aec->nearFile);
    185     fclose(aecpc->aec->outFile);
    186     fclose(aecpc->aec->outLinearFile);
    187     fclose(aecpc->bufFile);
    188     fclose(aecpc->skewFile);
    189     fclose(aecpc->delayFile);
    190 #endif
    191 
    192     WebRtcAec_FreeAec(aecpc->aec);
    193     WebRtcAec_FreeResampler(aecpc->resampler);
    194     free(aecpc);
    195 
    196     return 0;
    197 }
    198 
    199 WebRtc_Word32 WebRtcAec_Init(void *aecInst, WebRtc_Word32 sampFreq, WebRtc_Word32 scSampFreq)
    200 {
    201     aecpc_t *aecpc = aecInst;
    202     AecConfig aecConfig;
    203 
    204     if (aecpc == NULL) {
    205         return -1;
    206     }
    207 
    208     if (sampFreq != 8000 && sampFreq != 16000  && sampFreq != 32000) {
    209         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    210         return -1;
    211     }
    212     aecpc->sampFreq = sampFreq;
    213 
    214     if (scSampFreq < 1 || scSampFreq > 96000) {
    215         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    216         return -1;
    217     }
    218     aecpc->scSampFreq = scSampFreq;
    219 
    220     // Initialize echo canceller core
    221     if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
    222         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    223         return -1;
    224     }
    225 
    226     if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
    227         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    228         return -1;
    229     }
    230 
    231     if (WebRtc_InitBuffer(aecpc->far_pre_buf) == -1) {
    232         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    233         return -1;
    234     }
    235     WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);  // Start overlap.
    236 
    237     aecpc->initFlag = initCheck;  // indicates that initialization has been done
    238 
    239     if (aecpc->sampFreq == 32000) {
    240         aecpc->splitSampFreq = 16000;
    241     }
    242     else {
    243         aecpc->splitSampFreq = sampFreq;
    244     }
    245 
    246     aecpc->skewFrCtr = 0;
    247     aecpc->activity = 0;
    248 
    249     aecpc->delayCtr = 0;
    250 
    251     aecpc->sum = 0;
    252     aecpc->counter = 0;
    253     aecpc->checkBuffSize = 1;
    254     aecpc->firstVal = 0;
    255 
    256     aecpc->ECstartup = 1;
    257     aecpc->bufSizeStart = 0;
    258     aecpc->checkBufSizeCtr = 0;
    259     aecpc->filtDelay = 0;
    260     aecpc->timeForDelayChange = 0;
    261     aecpc->knownDelay = 0;
    262     aecpc->lastDelayDiff = 0;
    263 
    264     aecpc->skew = 0;
    265     aecpc->resample = kAecFalse;
    266     aecpc->highSkewCtr = 0;
    267     aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
    268 
    269     // Default settings.
    270     aecConfig.nlpMode = kAecNlpModerate;
    271     aecConfig.skewMode = kAecFalse;
    272     aecConfig.metricsMode = kAecFalse;
    273     aecConfig.delay_logging = kAecFalse;
    274 
    275     if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
    276         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    277         return -1;
    278     }
    279 
    280 #ifdef WEBRTC_AEC_DEBUG_DUMP
    281     if (WebRtc_InitBuffer(aecpc->far_pre_buf_s16) == -1) {
    282         aecpc->lastError = AEC_UNSPECIFIED_ERROR;
    283         return -1;
    284     }
    285     WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);  // Start overlap.
    286 #endif
    287 
    288     return 0;
    289 }
    290 
    291 // only buffer L band for farend
    292 WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst, const WebRtc_Word16 *farend,
    293     WebRtc_Word16 nrOfSamples)
    294 {
    295     aecpc_t *aecpc = aecInst;
    296     WebRtc_Word32 retVal = 0;
    297     int newNrOfSamples = (int) nrOfSamples;
    298     short newFarend[MAX_RESAMP_LEN];
    299     const int16_t* farend_ptr = farend;
    300     float tmp_farend[MAX_RESAMP_LEN];
    301     const float* farend_float = tmp_farend;
    302     float skew;
    303     int i = 0;
    304 
    305     if (aecpc == NULL) {
    306         return -1;
    307     }
    308 
    309     if (farend == NULL) {
    310         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    311         return -1;
    312     }
    313 
    314     if (aecpc->initFlag != initCheck) {
    315         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    316         return -1;
    317     }
    318 
    319     // number of samples == 160 for SWB input
    320     if (nrOfSamples != 80 && nrOfSamples != 160) {
    321         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    322         return -1;
    323     }
    324 
    325     skew = aecpc->skew;
    326 
    327     if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
    328         // Resample and get a new number of samples
    329         newNrOfSamples = WebRtcAec_ResampleLinear(aecpc->resampler,
    330                                                   farend,
    331                                                   nrOfSamples,
    332                                                   skew,
    333                                                   newFarend);
    334         farend_ptr = (const int16_t*) newFarend;
    335     }
    336 
    337     aecpc->aec->system_delay += newNrOfSamples;
    338 
    339 #ifdef WEBRTC_AEC_DEBUG_DUMP
    340     WebRtc_WriteBuffer(aecpc->far_pre_buf_s16, farend_ptr,
    341                        (size_t) newNrOfSamples);
    342 #endif
    343     // Cast to float and write the time-domain data to |far_pre_buf|.
    344     for (i = 0; i < newNrOfSamples; i++) {
    345       tmp_farend[i] = (float) farend_ptr[i];
    346     }
    347     WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_float,
    348                        (size_t) newNrOfSamples);
    349 
    350     // Transform to frequency domain if we have enough data.
    351     while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
    352       // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
    353       WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**) &farend_float, tmp_farend,
    354                         PART_LEN2);
    355 
    356       WebRtcAec_BufferFarendPartition(aecpc->aec, farend_float);
    357 
    358       // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
    359       WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
    360 #ifdef WEBRTC_AEC_DEBUG_DUMP
    361       WebRtc_ReadBuffer(aecpc->far_pre_buf_s16, (void**) &farend_ptr, newFarend,
    362                         PART_LEN2);
    363       WebRtc_WriteBuffer(aecpc->aec->far_time_buf, &farend_ptr[PART_LEN], 1);
    364       WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);
    365 #endif
    366     }
    367 
    368     return retVal;
    369 }
    370 
    371 WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend,
    372     const WebRtc_Word16 *nearendH, WebRtc_Word16 *out, WebRtc_Word16 *outH,
    373     WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf, WebRtc_Word32 skew)
    374 {
    375     aecpc_t *aecpc = aecInst;
    376     WebRtc_Word32 retVal = 0;
    377     short i;
    378     short nBlocks10ms;
    379     short nFrames;
    380     // Limit resampling to doubling/halving of signal
    381     const float minSkewEst = -0.5f;
    382     const float maxSkewEst = 1.0f;
    383 
    384     if (aecpc == NULL) {
    385         return -1;
    386     }
    387 
    388     if (nearend == NULL) {
    389         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    390         return -1;
    391     }
    392 
    393     if (out == NULL) {
    394         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    395         return -1;
    396     }
    397 
    398     if (aecpc->initFlag != initCheck) {
    399         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    400         return -1;
    401     }
    402 
    403     // number of samples == 160 for SWB input
    404     if (nrOfSamples != 80 && nrOfSamples != 160) {
    405         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    406         return -1;
    407     }
    408 
    409     // Check for valid pointers based on sampling rate
    410     if (aecpc->sampFreq == 32000 && nearendH == NULL) {
    411        aecpc->lastError = AEC_NULL_POINTER_ERROR;
    412        return -1;
    413     }
    414 
    415     if (msInSndCardBuf < 0) {
    416         msInSndCardBuf = 0;
    417         aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
    418         retVal = -1;
    419     }
    420     else if (msInSndCardBuf > 500) {
    421         msInSndCardBuf = 500;
    422         aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
    423         retVal = -1;
    424     }
    425     // TODO(andrew): we need to investigate if this +10 is really wanted.
    426     msInSndCardBuf += 10;
    427     aecpc->msInSndCardBuf = msInSndCardBuf;
    428 
    429     if (aecpc->skewMode == kAecTrue) {
    430         if (aecpc->skewFrCtr < 25) {
    431             aecpc->skewFrCtr++;
    432         }
    433         else {
    434             retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
    435             if (retVal == -1) {
    436                 aecpc->skew = 0;
    437                 aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
    438             }
    439 
    440             aecpc->skew /= aecpc->sampFactor*nrOfSamples;
    441 
    442             if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
    443                 aecpc->resample = kAecFalse;
    444             }
    445             else {
    446                 aecpc->resample = kAecTrue;
    447             }
    448 
    449             if (aecpc->skew < minSkewEst) {
    450                 aecpc->skew = minSkewEst;
    451             }
    452             else if (aecpc->skew > maxSkewEst) {
    453                 aecpc->skew = maxSkewEst;
    454             }
    455 
    456 #ifdef WEBRTC_AEC_DEBUG_DUMP
    457             fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
    458 #endif
    459         }
    460     }
    461 
    462     nFrames = nrOfSamples / FRAME_LEN;
    463     nBlocks10ms = nFrames / aecpc->aec->mult;
    464 
    465     if (aecpc->ECstartup) {
    466         if (nearend != out) {
    467             // Only needed if they don't already point to the same place.
    468             memcpy(out, nearend, sizeof(short) * nrOfSamples);
    469         }
    470 
    471         // The AEC is in the start up mode
    472         // AEC is disabled until the system delay is OK
    473 
    474         // Mechanism to ensure that the system delay is reasonably stable.
    475         if (aecpc->checkBuffSize) {
    476             aecpc->checkBufSizeCtr++;
    477             // Before we fill up the far-end buffer we require the system delay
    478             // to be stable (+/-8 ms) compared to the first value. This
    479             // comparison is made during the following 6 consecutive 10 ms
    480             // blocks. If it seems to be stable then we start to fill up the
    481             // far-end buffer.
    482             if (aecpc->counter == 0) {
    483                 aecpc->firstVal = aecpc->msInSndCardBuf;
    484                 aecpc->sum = 0;
    485             }
    486 
    487             if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) <
    488                 WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) {
    489                 aecpc->sum += aecpc->msInSndCardBuf;
    490                 aecpc->counter++;
    491             }
    492             else {
    493                 aecpc->counter = 0;
    494             }
    495 
    496             if (aecpc->counter * nBlocks10ms >= 6) {
    497                 // The far-end buffer size is determined in partitions of
    498                 // PART_LEN samples. Use 75% of the average value of the system
    499                 // delay as buffer size to start with.
    500                 aecpc->bufSizeStart = WEBRTC_SPL_MIN((3 * aecpc->sum *
    501                   aecpc->aec->mult * 8) / (4 * aecpc->counter * PART_LEN),
    502                   kMaxBufSizeStart);
    503                 // Buffer size has now been determined.
    504                 aecpc->checkBuffSize = 0;
    505             }
    506 
    507             if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) {
    508                 // For really bad systems, don't disable the echo canceller for
    509                 // more than 0.5 sec.
    510                 aecpc->bufSizeStart = WEBRTC_SPL_MIN((aecpc->msInSndCardBuf *
    511                     aecpc->aec->mult * 3) / 40, kMaxBufSizeStart);
    512                 aecpc->checkBuffSize = 0;
    513             }
    514         }
    515 
    516         // If |checkBuffSize| changed in the if-statement above.
    517         if (!aecpc->checkBuffSize) {
    518             // The system delay is now reasonably stable (or has been unstable
    519             // for too long). When the far-end buffer is filled with
    520             // approximately the same amount of data as reported by the system
    521             // we end the startup phase.
    522             int overhead_elements = aecpc->aec->system_delay / PART_LEN -
    523                 aecpc->bufSizeStart;
    524             if (overhead_elements == 0) {
    525                 // Enable the AEC
    526                 aecpc->ECstartup = 0;
    527             } else if (overhead_elements > 0) {
    528                 WebRtc_MoveReadPtr(aecpc->aec->far_buf_windowed,
    529                                    overhead_elements);
    530                 WebRtc_MoveReadPtr(aecpc->aec->far_buf, overhead_elements);
    531 #ifdef WEBRTC_AEC_DEBUG_DUMP
    532                 WebRtc_MoveReadPtr(aecpc->aec->far_time_buf, overhead_elements);
    533 #endif
    534                 // TODO(bjornv): Do we need a check on how much we actually
    535                 // moved the read pointer? It should always be possible to move
    536                 // the pointer |overhead_elements| since we have only added data
    537                 // to the buffer and no delay compensation nor AEC processing
    538                 // has been done.
    539                 aecpc->aec->system_delay -= overhead_elements * PART_LEN;
    540 
    541                 // Enable the AEC
    542                 aecpc->ECstartup = 0;
    543             }
    544         }
    545     } else {
    546         // AEC is enabled.
    547 
    548         int out_elements = 0;
    549 
    550         EstBufDelay(aecpc);
    551 
    552         // Note that 1 frame is supported for NB and 2 frames for WB.
    553         for (i = 0; i < nFrames; i++) {
    554             int16_t* out_ptr = NULL;
    555             int16_t out_tmp[FRAME_LEN];
    556 
    557             // Call the AEC.
    558             WebRtcAec_ProcessFrame(aecpc->aec,
    559                                    &nearend[FRAME_LEN * i],
    560                                    &nearendH[FRAME_LEN * i],
    561                                    aecpc->knownDelay);
    562             // TODO(bjornv): Re-structure such that we don't have to pass
    563             // |aecpc->knownDelay| as input. Change name to something like
    564             // |system_buffer_diff|.
    565 
    566             // Stuff the out buffer if we have less than a frame to output.
    567             // This should only happen for the first frame.
    568             out_elements = (int) WebRtc_available_read(aecpc->aec->outFrBuf);
    569             if (out_elements < FRAME_LEN) {
    570                 WebRtc_MoveReadPtr(aecpc->aec->outFrBuf,
    571                                    out_elements - FRAME_LEN);
    572                 if (aecpc->sampFreq == 32000) {
    573                     WebRtc_MoveReadPtr(aecpc->aec->outFrBufH,
    574                                        out_elements - FRAME_LEN);
    575                 }
    576             }
    577 
    578             // Obtain an output frame.
    579             WebRtc_ReadBuffer(aecpc->aec->outFrBuf, (void**) &out_ptr,
    580                               out_tmp, FRAME_LEN);
    581             memcpy(&out[FRAME_LEN * i], out_ptr, sizeof(int16_t) * FRAME_LEN);
    582             // For H band
    583             if (aecpc->sampFreq == 32000) {
    584                 WebRtc_ReadBuffer(aecpc->aec->outFrBufH, (void**) &out_ptr,
    585                                   out_tmp, FRAME_LEN);
    586                 memcpy(&outH[FRAME_LEN * i], out_ptr,
    587                        sizeof(int16_t) * FRAME_LEN);
    588             }
    589         }
    590     }
    591 
    592 #ifdef WEBRTC_AEC_DEBUG_DUMP
    593     {
    594         int16_t far_buf_size_ms = (int16_t) (aecpc->aec->system_delay /
    595             (sampMsNb * aecpc->aec->mult));
    596         fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile);
    597         fwrite(&(aecpc->knownDelay), sizeof(aecpc->knownDelay), 1, aecpc->delayFile);
    598     }
    599 #endif
    600 
    601     return retVal;
    602 }
    603 
    604 WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config)
    605 {
    606     aecpc_t *aecpc = aecInst;
    607 
    608     if (aecpc == NULL) {
    609         return -1;
    610     }
    611 
    612     if (aecpc->initFlag != initCheck) {
    613         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    614         return -1;
    615     }
    616 
    617     if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
    618         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    619         return -1;
    620     }
    621     aecpc->skewMode = config.skewMode;
    622 
    623     if (config.nlpMode != kAecNlpConservative && config.nlpMode !=
    624             kAecNlpModerate && config.nlpMode != kAecNlpAggressive) {
    625         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    626         return -1;
    627     }
    628     aecpc->nlpMode = config.nlpMode;
    629     aecpc->aec->targetSupp = targetSupp[aecpc->nlpMode];
    630     aecpc->aec->minOverDrive = minOverDrive[aecpc->nlpMode];
    631 
    632     if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
    633         aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    634         return -1;
    635     }
    636     aecpc->aec->metricsMode = config.metricsMode;
    637     if (aecpc->aec->metricsMode == kAecTrue) {
    638         WebRtcAec_InitMetrics(aecpc->aec);
    639     }
    640 
    641   if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) {
    642     aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    643     return -1;
    644   }
    645   aecpc->aec->delay_logging_enabled = config.delay_logging;
    646   if (aecpc->aec->delay_logging_enabled == kAecTrue) {
    647     memset(aecpc->aec->delay_histogram, 0, sizeof(aecpc->aec->delay_histogram));
    648   }
    649 
    650     return 0;
    651 }
    652 
    653 WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config)
    654 {
    655     aecpc_t *aecpc = aecInst;
    656 
    657     if (aecpc == NULL) {
    658         return -1;
    659     }
    660 
    661     if (config == NULL) {
    662         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    663         return -1;
    664     }
    665 
    666     if (aecpc->initFlag != initCheck) {
    667         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    668         return -1;
    669     }
    670 
    671     config->nlpMode = aecpc->nlpMode;
    672     config->skewMode = aecpc->skewMode;
    673     config->metricsMode = aecpc->aec->metricsMode;
    674     config->delay_logging = aecpc->aec->delay_logging_enabled;
    675 
    676     return 0;
    677 }
    678 
    679 WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status)
    680 {
    681     aecpc_t *aecpc = aecInst;
    682 
    683     if (aecpc == NULL) {
    684         return -1;
    685     }
    686 
    687     if (status == NULL) {
    688         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    689         return -1;
    690     }
    691 
    692     if (aecpc->initFlag != initCheck) {
    693         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    694         return -1;
    695     }
    696 
    697     *status = aecpc->aec->echoState;
    698 
    699     return 0;
    700 }
    701 
    702 WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics)
    703 {
    704     const float upweight = 0.7f;
    705     float dtmp;
    706     short stmp;
    707     aecpc_t *aecpc = aecInst;
    708 
    709     if (aecpc == NULL) {
    710         return -1;
    711     }
    712 
    713     if (metrics == NULL) {
    714         aecpc->lastError = AEC_NULL_POINTER_ERROR;
    715         return -1;
    716     }
    717 
    718     if (aecpc->initFlag != initCheck) {
    719         aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    720         return -1;
    721     }
    722 
    723     // ERL
    724     metrics->erl.instant = (short) aecpc->aec->erl.instant;
    725 
    726     if ((aecpc->aec->erl.himean > offsetLevel) && (aecpc->aec->erl.average > offsetLevel)) {
    727     // Use a mix between regular average and upper part average
    728         dtmp = upweight * aecpc->aec->erl.himean + (1 - upweight) * aecpc->aec->erl.average;
    729         metrics->erl.average = (short) dtmp;
    730     }
    731     else {
    732         metrics->erl.average = offsetLevel;
    733     }
    734 
    735     metrics->erl.max = (short) aecpc->aec->erl.max;
    736 
    737     if (aecpc->aec->erl.min < (offsetLevel * (-1))) {
    738         metrics->erl.min = (short) aecpc->aec->erl.min;
    739     }
    740     else {
    741         metrics->erl.min = offsetLevel;
    742     }
    743 
    744     // ERLE
    745     metrics->erle.instant = (short) aecpc->aec->erle.instant;
    746 
    747     if ((aecpc->aec->erle.himean > offsetLevel) && (aecpc->aec->erle.average > offsetLevel)) {
    748         // Use a mix between regular average and upper part average
    749         dtmp =  upweight * aecpc->aec->erle.himean + (1 - upweight) * aecpc->aec->erle.average;
    750         metrics->erle.average = (short) dtmp;
    751     }
    752     else {
    753         metrics->erle.average = offsetLevel;
    754     }
    755 
    756     metrics->erle.max = (short) aecpc->aec->erle.max;
    757 
    758     if (aecpc->aec->erle.min < (offsetLevel * (-1))) {
    759         metrics->erle.min = (short) aecpc->aec->erle.min;
    760     } else {
    761         metrics->erle.min = offsetLevel;
    762     }
    763 
    764     // RERL
    765     if ((metrics->erl.average > offsetLevel) && (metrics->erle.average > offsetLevel)) {
    766         stmp = metrics->erl.average + metrics->erle.average;
    767     }
    768     else {
    769         stmp = offsetLevel;
    770     }
    771     metrics->rerl.average = stmp;
    772 
    773     // No other statistics needed, but returned for completeness
    774     metrics->rerl.instant = stmp;
    775     metrics->rerl.max = stmp;
    776     metrics->rerl.min = stmp;
    777 
    778     // A_NLP
    779     metrics->aNlp.instant = (short) aecpc->aec->aNlp.instant;
    780 
    781     if ((aecpc->aec->aNlp.himean > offsetLevel) && (aecpc->aec->aNlp.average > offsetLevel)) {
    782         // Use a mix between regular average and upper part average
    783         dtmp =  upweight * aecpc->aec->aNlp.himean + (1 - upweight) * aecpc->aec->aNlp.average;
    784         metrics->aNlp.average = (short) dtmp;
    785     }
    786     else {
    787         metrics->aNlp.average = offsetLevel;
    788     }
    789 
    790     metrics->aNlp.max = (short) aecpc->aec->aNlp.max;
    791 
    792     if (aecpc->aec->aNlp.min < (offsetLevel * (-1))) {
    793         metrics->aNlp.min = (short) aecpc->aec->aNlp.min;
    794     }
    795     else {
    796         metrics->aNlp.min = offsetLevel;
    797     }
    798 
    799     return 0;
    800 }
    801 
    802 int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std) {
    803   aecpc_t* self = handle;
    804   int i = 0;
    805   int delay_values = 0;
    806   int num_delay_values = 0;
    807   int my_median = 0;
    808   const int kMsPerBlock = (PART_LEN * 1000) / self->splitSampFreq;
    809   float l1_norm = 0;
    810 
    811   if (self == NULL) {
    812     return -1;
    813   }
    814   if (median == NULL) {
    815     self->lastError = AEC_NULL_POINTER_ERROR;
    816     return -1;
    817   }
    818   if (std == NULL) {
    819     self->lastError = AEC_NULL_POINTER_ERROR;
    820     return -1;
    821   }
    822   if (self->initFlag != initCheck) {
    823     self->lastError = AEC_UNINITIALIZED_ERROR;
    824     return -1;
    825   }
    826   if (self->aec->delay_logging_enabled == 0) {
    827     // Logging disabled
    828     self->lastError = AEC_UNSUPPORTED_FUNCTION_ERROR;
    829     return -1;
    830   }
    831 
    832   // Get number of delay values since last update
    833   for (i = 0; i < kHistorySizeBlocks; i++) {
    834     num_delay_values += self->aec->delay_histogram[i];
    835   }
    836   if (num_delay_values == 0) {
    837     // We have no new delay value data. Even though -1 is a valid estimate, it
    838     // will practically never be used since multiples of |kMsPerBlock| will
    839     // always be returned.
    840     *median = -1;
    841     *std = -1;
    842     return 0;
    843   }
    844 
    845   delay_values = num_delay_values >> 1; // Start value for median count down
    846   // Get median of delay values since last update
    847   for (i = 0; i < kHistorySizeBlocks; i++) {
    848     delay_values -= self->aec->delay_histogram[i];
    849     if (delay_values < 0) {
    850       my_median = i;
    851       break;
    852     }
    853   }
    854   // Account for lookahead.
    855   *median = (my_median - kLookaheadBlocks) * kMsPerBlock;
    856 
    857   // Calculate the L1 norm, with median value as central moment
    858   for (i = 0; i < kHistorySizeBlocks; i++) {
    859     l1_norm += (float) (fabs(i - my_median) * self->aec->delay_histogram[i]);
    860   }
    861   *std = (int) (l1_norm / (float) num_delay_values + 0.5f) * kMsPerBlock;
    862 
    863   // Reset histogram
    864   memset(self->aec->delay_histogram, 0, sizeof(self->aec->delay_histogram));
    865 
    866   return 0;
    867 }
    868 
    869 WebRtc_Word32 WebRtcAec_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len)
    870 {
    871     const char version[] = "AEC 2.5.0";
    872     const short versionLen = (short)strlen(version) + 1; // +1 for null-termination
    873 
    874     if (versionStr == NULL) {
    875         return -1;
    876     }
    877 
    878     if (versionLen > len) {
    879         return -1;
    880     }
    881 
    882     strncpy(versionStr, version, versionLen);
    883     return 0;
    884 }
    885 
    886 WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst)
    887 {
    888     aecpc_t *aecpc = aecInst;
    889 
    890     if (aecpc == NULL) {
    891         return -1;
    892     }
    893 
    894     return aecpc->lastError;
    895 }
    896 
    897 static int EstBufDelay(aecpc_t* aecpc) {
    898   int nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->aec->mult;
    899   int current_delay = nSampSndCard - aecpc->aec->system_delay;
    900   int delay_difference = 0;
    901 
    902   // Before we proceed with the delay estimate filtering we:
    903   // 1) Compensate for the frame that will be read.
    904   // 2) Compensate for drift resampling.
    905 
    906   // 1) Compensating for the frame(s) that will be read/processed.
    907   current_delay += FRAME_LEN * aecpc->aec->mult;
    908 
    909   // 2) Account for resampling frame delay.
    910   if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
    911     current_delay -= kResamplingDelay;
    912   }
    913 
    914   aecpc->filtDelay = WEBRTC_SPL_MAX(0, (short) (0.8 * aecpc->filtDelay +
    915           0.2 * current_delay));
    916 
    917   delay_difference = aecpc->filtDelay - aecpc->knownDelay;
    918   if (delay_difference > 224) {
    919     if (aecpc->lastDelayDiff < 96) {
    920       aecpc->timeForDelayChange = 0;
    921     } else {
    922       aecpc->timeForDelayChange++;
    923     }
    924   } else if (delay_difference < 96 && aecpc->knownDelay > 0) {
    925     if (aecpc->lastDelayDiff > 224) {
    926       aecpc->timeForDelayChange = 0;
    927     } else {
    928       aecpc->timeForDelayChange++;
    929     }
    930   } else {
    931     aecpc->timeForDelayChange = 0;
    932   }
    933   aecpc->lastDelayDiff = delay_difference;
    934 
    935   if (aecpc->timeForDelayChange > 25) {
    936     aecpc->knownDelay = WEBRTC_SPL_MAX((int) aecpc->filtDelay - 160, 0);
    937   }
    938 
    939   return 0;
    940 }
    941