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