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