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
34static const int kMaxBufSizeStart = 62;  // In partitions
35static const int sampMsNb = 8; // samples per ms in nb
36// Target suppression levels for nlp modes
37// log{0.001, 0.00001, 0.00000001}
38static const float targetSupp[3] = {-6.9f, -11.5f, -18.4f};
39static const float minOverDrive[3] = {1.0f, 2.0f, 5.0f};
40static const int initCheck = 42;
41
42#ifdef WEBRTC_AEC_DEBUG_DUMP
43static int instance_count = 0;
44#endif
45
46typedef 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)
100static int EstBufDelay(aecpc_t *aecInst);
101
102WebRtc_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
171WebRtc_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
199WebRtc_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
292WebRtc_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
371WebRtc_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
604WebRtc_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
653WebRtc_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
679WebRtc_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
702WebRtc_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
802int 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
869WebRtc_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
886WebRtc_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
897static 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