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