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