LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_processing/aecm - echo_control_mobile.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 252 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 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/echo_control_mobile.h"
      12             : 
      13             : #ifdef AEC_DEBUG
      14             : #include <stdio.h>
      15             : #endif
      16             : #include <stdlib.h>
      17             : 
      18             : extern "C" {
      19             : #include "webrtc/common_audio/ring_buffer.h"
      20             : #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
      21             : }
      22             : #include "webrtc/modules/audio_processing/aecm/aecm_core.h"
      23             : 
      24             : #define BUF_SIZE_FRAMES 50 // buffer size (frames)
      25             : // Maximum length of resampled signal. Must be an integer multiple of frames
      26             : // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
      27             : // The factor of 2 handles wb, and the + 1 is as a safety margin
      28             : #define MAX_RESAMP_LEN (5 * FRAME_LEN)
      29             : 
      30             : static const size_t kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
      31             : static const int kSampMsNb = 8; // samples per ms in nb
      32             : // Target suppression levels for nlp modes
      33             : // log{0.001, 0.00001, 0.00000001}
      34             : static const int kInitCheck = 42;
      35             : 
      36             : typedef struct
      37             : {
      38             :     int sampFreq;
      39             :     int scSampFreq;
      40             :     short bufSizeStart;
      41             :     int knownDelay;
      42             : 
      43             :     // Stores the last frame added to the farend buffer
      44             :     short farendOld[2][FRAME_LEN];
      45             :     short initFlag; // indicates if AEC has been initialized
      46             : 
      47             :     // Variables used for averaging far end buffer size
      48             :     short counter;
      49             :     short sum;
      50             :     short firstVal;
      51             :     short checkBufSizeCtr;
      52             : 
      53             :     // Variables used for delay shifts
      54             :     short msInSndCardBuf;
      55             :     short filtDelay;
      56             :     int timeForDelayChange;
      57             :     int ECstartup;
      58             :     int checkBuffSize;
      59             :     int delayChange;
      60             :     short lastDelayDiff;
      61             : 
      62             :     int16_t echoMode;
      63             : 
      64             : #ifdef AEC_DEBUG
      65             :     FILE *bufFile;
      66             :     FILE *delayFile;
      67             :     FILE *preCompFile;
      68             :     FILE *postCompFile;
      69             : #endif // AEC_DEBUG
      70             :     // Structures
      71             :     RingBuffer *farendBuf;
      72             : 
      73             :     AecmCore* aecmCore;
      74             : } AecMobile;
      75             : 
      76             : // Estimates delay to set the position of the farend buffer read pointer
      77             : // (controlled by knownDelay)
      78             : static int WebRtcAecm_EstBufDelay(AecMobile* aecmInst, short msInSndCardBuf);
      79             : 
      80             : // Stuffs the farend buffer if the estimated delay is too large
      81             : static int WebRtcAecm_DelayComp(AecMobile* aecmInst);
      82             : 
      83           0 : void* WebRtcAecm_Create() {
      84           0 :     AecMobile* aecm = static_cast<AecMobile*>(malloc(sizeof(AecMobile)));
      85             : 
      86           0 :     WebRtcSpl_Init();
      87             : 
      88           0 :     aecm->aecmCore = WebRtcAecm_CreateCore();
      89           0 :     if (!aecm->aecmCore) {
      90           0 :         WebRtcAecm_Free(aecm);
      91           0 :         return NULL;
      92             :     }
      93             : 
      94           0 :     aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp,
      95             :                                           sizeof(int16_t));
      96           0 :     if (!aecm->farendBuf)
      97             :     {
      98           0 :         WebRtcAecm_Free(aecm);
      99           0 :         return NULL;
     100             :     }
     101             : 
     102           0 :     aecm->initFlag = 0;
     103             : 
     104             : #ifdef AEC_DEBUG
     105             :     aecm->aecmCore->farFile = fopen("aecFar.pcm","wb");
     106             :     aecm->aecmCore->nearFile = fopen("aecNear.pcm","wb");
     107             :     aecm->aecmCore->outFile = fopen("aecOut.pcm","wb");
     108             :     //aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
     109             : 
     110             :     aecm->bufFile = fopen("aecBuf.dat", "wb");
     111             :     aecm->delayFile = fopen("aecDelay.dat", "wb");
     112             :     aecm->preCompFile = fopen("preComp.pcm", "wb");
     113             :     aecm->postCompFile = fopen("postComp.pcm", "wb");
     114             : #endif // AEC_DEBUG
     115           0 :     return aecm;
     116             : }
     117             : 
     118           0 : void WebRtcAecm_Free(void* aecmInst) {
     119           0 :   AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     120             : 
     121           0 :     if (aecm == NULL) {
     122           0 :       return;
     123             :     }
     124             : 
     125             : #ifdef AEC_DEBUG
     126             :     fclose(aecm->aecmCore->farFile);
     127             :     fclose(aecm->aecmCore->nearFile);
     128             :     fclose(aecm->aecmCore->outFile);
     129             :     //fclose(aecm->aecmCore->outLpFile);
     130             : 
     131             :     fclose(aecm->bufFile);
     132             :     fclose(aecm->delayFile);
     133             :     fclose(aecm->preCompFile);
     134             :     fclose(aecm->postCompFile);
     135             : #endif // AEC_DEBUG
     136           0 :     WebRtcAecm_FreeCore(aecm->aecmCore);
     137           0 :     WebRtc_FreeBuffer(aecm->farendBuf);
     138           0 :     free(aecm);
     139             : }
     140             : 
     141           0 : int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
     142             : {
     143           0 :     AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     144             :     AecmConfig aecConfig;
     145             : 
     146           0 :     if (aecm == NULL)
     147             :     {
     148           0 :         return -1;
     149             :     }
     150             : 
     151           0 :     if (sampFreq != 8000 && sampFreq != 16000)
     152             :     {
     153           0 :         return AECM_BAD_PARAMETER_ERROR;
     154             :     }
     155           0 :     aecm->sampFreq = sampFreq;
     156             : 
     157             :     // Initialize AECM core
     158           0 :     if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
     159             :     {
     160           0 :         return AECM_UNSPECIFIED_ERROR;
     161             :     }
     162             : 
     163             :     // Initialize farend buffer
     164           0 :     WebRtc_InitBuffer(aecm->farendBuf);
     165             : 
     166           0 :     aecm->initFlag = kInitCheck; // indicates that initialization has been done
     167             : 
     168           0 :     aecm->delayChange = 1;
     169             : 
     170           0 :     aecm->sum = 0;
     171           0 :     aecm->counter = 0;
     172           0 :     aecm->checkBuffSize = 1;
     173           0 :     aecm->firstVal = 0;
     174             : 
     175           0 :     aecm->ECstartup = 1;
     176           0 :     aecm->bufSizeStart = 0;
     177           0 :     aecm->checkBufSizeCtr = 0;
     178           0 :     aecm->filtDelay = 0;
     179           0 :     aecm->timeForDelayChange = 0;
     180           0 :     aecm->knownDelay = 0;
     181           0 :     aecm->lastDelayDiff = 0;
     182             : 
     183           0 :     memset(&aecm->farendOld[0][0], 0, 160);
     184             : 
     185             :     // Default settings.
     186           0 :     aecConfig.cngMode = AecmTrue;
     187           0 :     aecConfig.echoMode = 3;
     188             : 
     189           0 :     if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
     190             :     {
     191           0 :         return AECM_UNSPECIFIED_ERROR;
     192             :     }
     193             : 
     194           0 :     return 0;
     195             : }
     196             : 
     197             : // Returns any error that is caused when buffering the
     198             : // farend signal.
     199           0 : int32_t WebRtcAecm_GetBufferFarendError(void *aecmInst, const int16_t *farend,
     200             :                                 size_t nrOfSamples) {
     201           0 :   AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     202             : 
     203           0 :   if (aecm == NULL)
     204           0 :     return -1;
     205             : 
     206           0 :   if (farend == NULL)
     207           0 :     return AECM_NULL_POINTER_ERROR;
     208             : 
     209           0 :   if (aecm->initFlag != kInitCheck)
     210           0 :     return AECM_UNINITIALIZED_ERROR;
     211             : 
     212           0 :   if (nrOfSamples != 80 && nrOfSamples != 160)
     213           0 :     return AECM_BAD_PARAMETER_ERROR;
     214             : 
     215           0 :   return 0;
     216             : }
     217             : 
     218             : 
     219           0 : int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend,
     220             :                                 size_t nrOfSamples) {
     221           0 :   AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     222             : 
     223             :   const int32_t err =
     224           0 :       WebRtcAecm_GetBufferFarendError(aecmInst, farend, nrOfSamples);
     225             : 
     226           0 :   if (err != 0)
     227           0 :     return err;
     228             : 
     229             :   // TODO(unknown): Is this really a good idea?
     230           0 :   if (!aecm->ECstartup)
     231             :   {
     232           0 :     WebRtcAecm_DelayComp(aecm);
     233             :   }
     234             : 
     235           0 :   WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
     236             : 
     237           0 :   return 0;
     238             : }
     239             : 
     240           0 : int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
     241             :                            const int16_t *nearendClean, int16_t *out,
     242             :                            size_t nrOfSamples, int16_t msInSndCardBuf)
     243             : {
     244           0 :     AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     245           0 :     int32_t retVal = 0;
     246             :     size_t i;
     247             :     short nmbrOfFilledBuffers;
     248             :     size_t nBlocks10ms;
     249             :     size_t nFrames;
     250             : #ifdef AEC_DEBUG
     251             :     short msInAECBuf;
     252             : #endif
     253             : 
     254           0 :     if (aecm == NULL)
     255             :     {
     256           0 :         return -1;
     257             :     }
     258             : 
     259           0 :     if (nearendNoisy == NULL)
     260             :     {
     261           0 :         return AECM_NULL_POINTER_ERROR;
     262             :     }
     263             : 
     264           0 :     if (out == NULL)
     265             :     {
     266           0 :         return AECM_NULL_POINTER_ERROR;
     267             :     }
     268             : 
     269           0 :     if (aecm->initFlag != kInitCheck)
     270             :     {
     271           0 :         return AECM_UNINITIALIZED_ERROR;
     272             :     }
     273             : 
     274           0 :     if (nrOfSamples != 80 && nrOfSamples != 160)
     275             :     {
     276           0 :         return AECM_BAD_PARAMETER_ERROR;
     277             :     }
     278             : 
     279           0 :     if (msInSndCardBuf < 0)
     280             :     {
     281           0 :         msInSndCardBuf = 0;
     282           0 :         retVal = AECM_BAD_PARAMETER_WARNING;
     283           0 :     } else if (msInSndCardBuf > 500)
     284             :     {
     285           0 :         msInSndCardBuf = 500;
     286           0 :         retVal = AECM_BAD_PARAMETER_WARNING;
     287             :     }
     288           0 :     msInSndCardBuf += 10;
     289           0 :     aecm->msInSndCardBuf = msInSndCardBuf;
     290             : 
     291           0 :     nFrames = nrOfSamples / FRAME_LEN;
     292           0 :     nBlocks10ms = nFrames / aecm->aecmCore->mult;
     293             : 
     294           0 :     if (aecm->ECstartup)
     295             :     {
     296           0 :         if (nearendClean == NULL)
     297             :         {
     298           0 :             if (out != nearendNoisy)
     299             :             {
     300           0 :                 memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
     301             :             }
     302           0 :         } else if (out != nearendClean)
     303             :         {
     304           0 :             memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
     305             :         }
     306             : 
     307           0 :         nmbrOfFilledBuffers =
     308           0 :             (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
     309             :         // The AECM is in the start up mode
     310             :         // AECM is disabled until the soundcard buffer and farend buffers are OK
     311             : 
     312             :         // Mechanism to ensure that the soundcard buffer is reasonably stable.
     313           0 :         if (aecm->checkBuffSize)
     314             :         {
     315           0 :             aecm->checkBufSizeCtr++;
     316             :             // Before we fill up the far end buffer we require the amount of data on the
     317             :             // sound card to be stable (+/-8 ms) compared to the first value. This
     318             :             // comparison is made during the following 4 consecutive frames. If it seems
     319             :             // to be stable then we start to fill up the far end buffer.
     320             : 
     321           0 :             if (aecm->counter == 0)
     322             :             {
     323           0 :                 aecm->firstVal = aecm->msInSndCardBuf;
     324           0 :                 aecm->sum = 0;
     325             :             }
     326             : 
     327           0 :             if (abs(aecm->firstVal - aecm->msInSndCardBuf)
     328           0 :                     < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb))
     329             :             {
     330           0 :                 aecm->sum += aecm->msInSndCardBuf;
     331           0 :                 aecm->counter++;
     332             :             } else
     333             :             {
     334           0 :                 aecm->counter = 0;
     335             :             }
     336             : 
     337           0 :             if (aecm->counter * nBlocks10ms >= 6)
     338             :             {
     339             :                 // The farend buffer size is determined in blocks of 80 samples
     340             :                 // Use 75% of the average value of the soundcard buffer
     341             :                 aecm->bufSizeStart
     342           0 :                         = WEBRTC_SPL_MIN((3 * aecm->sum
     343           0 :                                         * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES);
     344             :                 // buffersize has now been determined
     345           0 :                 aecm->checkBuffSize = 0;
     346             :             }
     347             : 
     348           0 :             if (aecm->checkBufSizeCtr * nBlocks10ms > 50)
     349             :             {
     350             :                 // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
     351           0 :                 aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf
     352           0 :                                 * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES);
     353           0 :                 aecm->checkBuffSize = 0;
     354             :             }
     355             :         }
     356             : 
     357             :         // if checkBuffSize changed in the if-statement above
     358           0 :         if (!aecm->checkBuffSize)
     359             :         {
     360             :             // soundcard buffer is now reasonably stable
     361             :             // When the far end buffer is filled with approximately the same amount of
     362             :             // data as the amount on the sound card we end the start up phase and start
     363             :             // to cancel echoes.
     364             : 
     365           0 :             if (nmbrOfFilledBuffers == aecm->bufSizeStart)
     366             :             {
     367           0 :                 aecm->ECstartup = 0; // Enable the AECM
     368           0 :             } else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
     369             :             {
     370           0 :                 WebRtc_MoveReadPtr(aecm->farendBuf,
     371           0 :                                    (int) WebRtc_available_read(aecm->farendBuf)
     372           0 :                                    - (int) aecm->bufSizeStart * FRAME_LEN);
     373           0 :                 aecm->ECstartup = 0;
     374             :             }
     375             :         }
     376             : 
     377             :     } else
     378             :     {
     379             :         // AECM is enabled
     380             : 
     381             :         // Note only 1 block supported for nb and 2 blocks for wb
     382           0 :         for (i = 0; i < nFrames; i++)
     383             :         {
     384             :             int16_t farend[FRAME_LEN];
     385           0 :             const int16_t* farend_ptr = NULL;
     386             : 
     387           0 :             nmbrOfFilledBuffers =
     388           0 :                 (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
     389             : 
     390             :             // Check that there is data in the far end buffer
     391           0 :             if (nmbrOfFilledBuffers > 0)
     392             :             {
     393             :                 // Get the next 80 samples from the farend buffer
     394           0 :                 WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend,
     395           0 :                                   FRAME_LEN);
     396             : 
     397             :                 // Always store the last frame for use when we run out of data
     398           0 :                 memcpy(&(aecm->farendOld[i][0]), farend_ptr,
     399           0 :                        FRAME_LEN * sizeof(short));
     400             :             } else
     401             :             {
     402             :                 // We have no data so we use the last played frame
     403           0 :                 memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
     404           0 :                 farend_ptr = farend;
     405             :             }
     406             : 
     407             :             // Call buffer delay estimator when all data is extracted,
     408             :             // i,e. i = 0 for NB and i = 1 for WB
     409           0 :             if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000))
     410             :             {
     411           0 :                 WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
     412             :             }
     413             : 
     414             :             // Call the AECM
     415             :             /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
     416             :              &out[FRAME_LEN * i], aecm->knownDelay);*/
     417           0 :             if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
     418             :                                         farend_ptr,
     419             :                                         &nearendNoisy[FRAME_LEN * i],
     420             :                                         (nearendClean
     421           0 :                                          ? &nearendClean[FRAME_LEN * i]
     422             :                                          : NULL),
     423             :                                         &out[FRAME_LEN * i]) == -1)
     424           0 :                 return -1;
     425             :         }
     426             :     }
     427             : 
     428             : #ifdef AEC_DEBUG
     429             :     msInAECBuf = (short) WebRtc_available_read(aecm->farendBuf) /
     430             :         (kSampMsNb * aecm->aecmCore->mult);
     431             :     fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
     432             :     fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
     433             : #endif
     434             : 
     435           0 :     return retVal;
     436             : }
     437             : 
     438           0 : int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
     439             : {
     440           0 :     AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     441             : 
     442           0 :     if (aecm == NULL)
     443             :     {
     444           0 :         return -1;
     445             :     }
     446             : 
     447           0 :     if (aecm->initFlag != kInitCheck)
     448             :     {
     449           0 :         return AECM_UNINITIALIZED_ERROR;
     450             :     }
     451             : 
     452           0 :     if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
     453             :     {
     454           0 :         return AECM_BAD_PARAMETER_ERROR;
     455             :     }
     456           0 :     aecm->aecmCore->cngMode = config.cngMode;
     457             : 
     458           0 :     if (config.echoMode < 0 || config.echoMode > 4)
     459             :     {
     460           0 :         return AECM_BAD_PARAMETER_ERROR;
     461             :     }
     462           0 :     aecm->echoMode = config.echoMode;
     463             : 
     464           0 :     if (aecm->echoMode == 0)
     465             :     {
     466           0 :         aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
     467           0 :         aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
     468           0 :         aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
     469           0 :         aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
     470           0 :         aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3)
     471             :                 - (SUPGAIN_ERROR_PARAM_B >> 3);
     472           0 :         aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3)
     473             :                 - (SUPGAIN_ERROR_PARAM_D >> 3);
     474           0 :     } else if (aecm->echoMode == 1)
     475             :     {
     476           0 :         aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
     477           0 :         aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
     478           0 :         aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
     479           0 :         aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
     480           0 :         aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2)
     481             :                 - (SUPGAIN_ERROR_PARAM_B >> 2);
     482           0 :         aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2)
     483             :                 - (SUPGAIN_ERROR_PARAM_D >> 2);
     484           0 :     } else if (aecm->echoMode == 2)
     485             :     {
     486           0 :         aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
     487           0 :         aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
     488           0 :         aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
     489           0 :         aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
     490           0 :         aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1)
     491             :                 - (SUPGAIN_ERROR_PARAM_B >> 1);
     492           0 :         aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1)
     493             :                 - (SUPGAIN_ERROR_PARAM_D >> 1);
     494           0 :     } else if (aecm->echoMode == 3)
     495             :     {
     496           0 :         aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
     497           0 :         aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
     498           0 :         aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
     499           0 :         aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
     500           0 :         aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
     501           0 :         aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
     502           0 :     } else if (aecm->echoMode == 4)
     503             :     {
     504           0 :         aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
     505           0 :         aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
     506           0 :         aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
     507           0 :         aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
     508           0 :         aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1)
     509             :                 - (SUPGAIN_ERROR_PARAM_B << 1);
     510           0 :         aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1)
     511             :                 - (SUPGAIN_ERROR_PARAM_D << 1);
     512             :     }
     513             : 
     514           0 :     return 0;
     515             : }
     516             : 
     517           0 : int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
     518             :                                 const void* echo_path,
     519             :                                 size_t size_bytes)
     520             : {
     521           0 :     AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     522           0 :     const int16_t* echo_path_ptr = static_cast<const int16_t*>(echo_path);
     523             : 
     524           0 :     if (aecmInst == NULL) {
     525           0 :       return -1;
     526             :     }
     527           0 :     if (echo_path == NULL) {
     528           0 :       return AECM_NULL_POINTER_ERROR;
     529             :     }
     530           0 :     if (size_bytes != WebRtcAecm_echo_path_size_bytes())
     531             :     {
     532             :         // Input channel size does not match the size of AECM
     533           0 :         return AECM_BAD_PARAMETER_ERROR;
     534             :     }
     535           0 :     if (aecm->initFlag != kInitCheck)
     536             :     {
     537           0 :         return AECM_UNINITIALIZED_ERROR;
     538             :     }
     539             : 
     540           0 :     WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
     541             : 
     542           0 :     return 0;
     543             : }
     544             : 
     545           0 : int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
     546             :                                void* echo_path,
     547             :                                size_t size_bytes)
     548             : {
     549           0 :     AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
     550           0 :     int16_t* echo_path_ptr = static_cast<int16_t*>(echo_path);
     551             : 
     552           0 :     if (aecmInst == NULL) {
     553           0 :       return -1;
     554             :     }
     555           0 :     if (echo_path == NULL) {
     556           0 :       return AECM_NULL_POINTER_ERROR;
     557             :     }
     558           0 :     if (size_bytes != WebRtcAecm_echo_path_size_bytes())
     559             :     {
     560             :         // Input channel size does not match the size of AECM
     561           0 :         return AECM_BAD_PARAMETER_ERROR;
     562             :     }
     563           0 :     if (aecm->initFlag != kInitCheck)
     564             :     {
     565           0 :         return AECM_UNINITIALIZED_ERROR;
     566             :     }
     567             : 
     568           0 :     memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
     569           0 :     return 0;
     570             : }
     571             : 
     572           0 : size_t WebRtcAecm_echo_path_size_bytes()
     573             : {
     574           0 :     return (PART_LEN1 * sizeof(int16_t));
     575             : }
     576             : 
     577             : 
     578           0 : static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
     579             :     short delayNew, nSampSndCard;
     580           0 :     short nSampFar = (short) WebRtc_available_read(aecm->farendBuf);
     581             :     short diff;
     582             : 
     583           0 :     nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
     584             : 
     585           0 :     delayNew = nSampSndCard - nSampFar;
     586             : 
     587           0 :     if (delayNew < FRAME_LEN)
     588             :     {
     589           0 :         WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
     590           0 :         delayNew += FRAME_LEN;
     591             :     }
     592             : 
     593           0 :     aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
     594             : 
     595           0 :     diff = aecm->filtDelay - aecm->knownDelay;
     596           0 :     if (diff > 224)
     597             :     {
     598           0 :         if (aecm->lastDelayDiff < 96)
     599             :         {
     600           0 :             aecm->timeForDelayChange = 0;
     601             :         } else
     602             :         {
     603           0 :             aecm->timeForDelayChange++;
     604             :         }
     605           0 :     } else if (diff < 96 && aecm->knownDelay > 0)
     606             :     {
     607           0 :         if (aecm->lastDelayDiff > 224)
     608             :         {
     609           0 :             aecm->timeForDelayChange = 0;
     610             :         } else
     611             :         {
     612           0 :             aecm->timeForDelayChange++;
     613             :         }
     614             :     } else
     615             :     {
     616           0 :         aecm->timeForDelayChange = 0;
     617             :     }
     618           0 :     aecm->lastDelayDiff = diff;
     619             : 
     620           0 :     if (aecm->timeForDelayChange > 25)
     621             :     {
     622           0 :         aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
     623             :     }
     624           0 :     return 0;
     625             : }
     626             : 
     627           0 : static int WebRtcAecm_DelayComp(AecMobile* aecm) {
     628           0 :     int nSampFar = (int) WebRtc_available_read(aecm->farendBuf);
     629             :     int nSampSndCard, delayNew, nSampAdd;
     630           0 :     const int maxStuffSamp = 10 * FRAME_LEN;
     631             : 
     632           0 :     nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
     633           0 :     delayNew = nSampSndCard - nSampFar;
     634             : 
     635           0 :     if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult)
     636             :     {
     637             :         // The difference of the buffer sizes is larger than the maximum
     638             :         // allowed known delay. Compensate by stuffing the buffer.
     639           0 :         nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar),
     640             :                 FRAME_LEN));
     641           0 :         nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
     642             : 
     643           0 :         WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
     644           0 :         aecm->delayChange = 1; // the delay needs to be updated
     645             :     }
     646             : 
     647           0 :     return 0;
     648             : }

Generated by: LCOV version 1.13