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