• 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 "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 
WebRtcAec_Create(void ** aecInst)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 
WebRtcAec_Free(void * aecInst)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 
WebRtcAec_Init(void * aecInst,WebRtc_Word32 sampFreq,WebRtc_Word32 scSampFreq)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
WebRtcAec_BufferFarend(void * aecInst,const WebRtc_Word16 * farend,WebRtc_Word16 nrOfSamples)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 
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)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 
WebRtcAec_set_config(void * aecInst,AecConfig config)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 
WebRtcAec_get_config(void * aecInst,AecConfig * config)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 
WebRtcAec_get_echo_status(void * aecInst,WebRtc_Word16 * status)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 
WebRtcAec_GetMetrics(void * aecInst,AecMetrics * metrics)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 
WebRtcAec_GetDelayMetrics(void * handle,int * median,int * std)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 
WebRtcAec_get_version(WebRtc_Word8 * versionStr,WebRtc_Word16 len)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 
WebRtcAec_get_error_code(void * aecInst)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 
EstBufDelay(aecpc_t * aecpc)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