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