2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
18 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
19 #include "webrtc/modules/audio_processing/aecm/aecm_core.h"
20 #include "webrtc/modules/audio_processing/utility/ring_buffer.h"
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)
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;
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
45 // Variables used for averaging far end buffer size
49 short checkBufSizeCtr;
51 // Variables used for delay shifts
54 int timeForDelayChange;
69 RingBuffer *farendBuf;
76 // Estimates delay to set the position of the farend buffer read pointer
77 // (controlled by knownDelay)
78 static int WebRtcAecm_EstBufDelay(aecmob_t *aecmInst, short msInSndCardBuf);
80 // Stuffs the farend buffer if the estimated delay is too large
81 static int WebRtcAecm_DelayComp(aecmob_t *aecmInst);
83 int32_t WebRtcAecm_Create(void **aecmInst)
91 aecm = malloc(sizeof(aecmob_t));
100 if (WebRtcAecm_CreateCore(&aecm->aecmCore) == -1)
102 WebRtcAecm_Free(aecm);
107 aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp,
109 if (!aecm->farendBuf)
111 WebRtcAecm_Free(aecm);
120 aecm->aecmCore->farFile = fopen("aecFar.pcm","wb");
121 aecm->aecmCore->nearFile = fopen("aecNear.pcm","wb");
122 aecm->aecmCore->outFile = fopen("aecOut.pcm","wb");
123 //aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
125 aecm->bufFile = fopen("aecBuf.dat", "wb");
126 aecm->delayFile = fopen("aecDelay.dat", "wb");
127 aecm->preCompFile = fopen("preComp.pcm", "wb");
128 aecm->postCompFile = fopen("postComp.pcm", "wb");
133 int32_t WebRtcAecm_Free(void *aecmInst)
135 aecmob_t *aecm = aecmInst;
143 fclose(aecm->aecmCore->farFile);
144 fclose(aecm->aecmCore->nearFile);
145 fclose(aecm->aecmCore->outFile);
146 //fclose(aecm->aecmCore->outLpFile);
148 fclose(aecm->bufFile);
149 fclose(aecm->delayFile);
150 fclose(aecm->preCompFile);
151 fclose(aecm->postCompFile);
153 WebRtcAecm_FreeCore(aecm->aecmCore);
154 WebRtc_FreeBuffer(aecm->farendBuf);
160 int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
162 aecmob_t *aecm = aecmInst;
163 AecmConfig aecConfig;
170 if (sampFreq != 8000 && sampFreq != 16000)
172 aecm->lastError = AECM_BAD_PARAMETER_ERROR;
175 aecm->sampFreq = sampFreq;
177 // Initialize AECM core
178 if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
180 aecm->lastError = AECM_UNSPECIFIED_ERROR;
184 // Initialize farend buffer
185 if (WebRtc_InitBuffer(aecm->farendBuf) == -1)
187 aecm->lastError = AECM_UNSPECIFIED_ERROR;
191 aecm->initFlag = kInitCheck; // indicates that initialization has been done
193 aecm->delayChange = 1;
197 aecm->checkBuffSize = 1;
201 aecm->bufSizeStart = 0;
202 aecm->checkBufSizeCtr = 0;
204 aecm->timeForDelayChange = 0;
205 aecm->knownDelay = 0;
206 aecm->lastDelayDiff = 0;
208 memset(&aecm->farendOld[0][0], 0, 160);
211 aecConfig.cngMode = AecmTrue;
212 aecConfig.echoMode = 3;
214 if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
216 aecm->lastError = AECM_UNSPECIFIED_ERROR;
223 int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend,
226 aecmob_t *aecm = aecmInst;
236 aecm->lastError = AECM_NULL_POINTER_ERROR;
240 if (aecm->initFlag != kInitCheck)
242 aecm->lastError = AECM_UNINITIALIZED_ERROR;
246 if (nrOfSamples != 80 && nrOfSamples != 160)
248 aecm->lastError = AECM_BAD_PARAMETER_ERROR;
252 // TODO: Is this really a good idea?
253 if (!aecm->ECstartup)
255 WebRtcAecm_DelayComp(aecm);
258 WebRtc_WriteBuffer(aecm->farendBuf, farend, (size_t) nrOfSamples);
263 int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
264 const int16_t *nearendClean, int16_t *out,
265 int16_t nrOfSamples, int16_t msInSndCardBuf)
267 aecmob_t *aecm = aecmInst;
270 short nmbrOfFilledBuffers;
282 if (nearendNoisy == NULL)
284 aecm->lastError = AECM_NULL_POINTER_ERROR;
290 aecm->lastError = AECM_NULL_POINTER_ERROR;
294 if (aecm->initFlag != kInitCheck)
296 aecm->lastError = AECM_UNINITIALIZED_ERROR;
300 if (nrOfSamples != 80 && nrOfSamples != 160)
302 aecm->lastError = AECM_BAD_PARAMETER_ERROR;
306 if (msInSndCardBuf < 0)
309 aecm->lastError = AECM_BAD_PARAMETER_WARNING;
311 } else if (msInSndCardBuf > 500)
313 msInSndCardBuf = 500;
314 aecm->lastError = AECM_BAD_PARAMETER_WARNING;
317 msInSndCardBuf += 10;
318 aecm->msInSndCardBuf = msInSndCardBuf;
320 nFrames = nrOfSamples / FRAME_LEN;
321 nBlocks10ms = nFrames / aecm->aecmCore->mult;
325 if (nearendClean == NULL)
327 if (out != nearendNoisy)
329 memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
331 } else if (out != nearendClean)
333 memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
336 nmbrOfFilledBuffers =
337 (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
338 // The AECM is in the start up mode
339 // AECM is disabled until the soundcard buffer and farend buffers are OK
341 // Mechanism to ensure that the soundcard buffer is reasonably stable.
342 if (aecm->checkBuffSize)
344 aecm->checkBufSizeCtr++;
345 // Before we fill up the far end buffer we require the amount of data on the
346 // sound card to be stable (+/-8 ms) compared to the first value. This
347 // comparison is made during the following 4 consecutive frames. If it seems
348 // to be stable then we start to fill up the far end buffer.
350 if (aecm->counter == 0)
352 aecm->firstVal = aecm->msInSndCardBuf;
356 if (abs(aecm->firstVal - aecm->msInSndCardBuf)
357 < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb))
359 aecm->sum += aecm->msInSndCardBuf;
366 if (aecm->counter * nBlocks10ms >= 6)
368 // The farend buffer size is determined in blocks of 80 samples
369 // Use 75% of the average value of the soundcard buffer
371 = WEBRTC_SPL_MIN((3 * aecm->sum
372 * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES);
373 // buffersize has now been determined
374 aecm->checkBuffSize = 0;
377 if (aecm->checkBufSizeCtr * nBlocks10ms > 50)
379 // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
380 aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf
381 * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES);
382 aecm->checkBuffSize = 0;
386 // if checkBuffSize changed in the if-statement above
387 if (!aecm->checkBuffSize)
389 // soundcard buffer is now reasonably stable
390 // When the far end buffer is filled with approximately the same amount of
391 // data as the amount on the sound card we end the start up phase and start
394 if (nmbrOfFilledBuffers == aecm->bufSizeStart)
396 aecm->ECstartup = 0; // Enable the AECM
397 } else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
399 WebRtc_MoveReadPtr(aecm->farendBuf,
400 (int) WebRtc_available_read(aecm->farendBuf)
401 - (int) aecm->bufSizeStart * FRAME_LEN);
410 // Note only 1 block supported for nb and 2 blocks for wb
411 for (i = 0; i < nFrames; i++)
413 int16_t farend[FRAME_LEN];
414 const int16_t* farend_ptr = NULL;
416 nmbrOfFilledBuffers =
417 (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
419 // Check that there is data in the far end buffer
420 if (nmbrOfFilledBuffers > 0)
422 // Get the next 80 samples from the farend buffer
423 WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend,
426 // Always store the last frame for use when we run out of data
427 memcpy(&(aecm->farendOld[i][0]), farend_ptr,
428 FRAME_LEN * sizeof(short));
431 // We have no data so we use the last played frame
432 memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
436 // Call buffer delay estimator when all data is extracted,
437 // i,e. i = 0 for NB and i = 1 for WB
438 if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000))
440 WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
444 /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
445 &out[FRAME_LEN * i], aecm->knownDelay);*/
446 if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
448 &nearendNoisy[FRAME_LEN * i],
450 ? &nearendClean[FRAME_LEN * i]
452 &out[FRAME_LEN * i]) == -1)
458 msInAECBuf = (short) WebRtc_available_read(aecm->farendBuf) /
459 (kSampMsNb * aecm->aecmCore->mult);
460 fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
461 fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
467 int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
469 aecmob_t *aecm = aecmInst;
476 if (aecm->initFlag != kInitCheck)
478 aecm->lastError = AECM_UNINITIALIZED_ERROR;
482 if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
484 aecm->lastError = AECM_BAD_PARAMETER_ERROR;
487 aecm->aecmCore->cngMode = config.cngMode;
489 if (config.echoMode < 0 || config.echoMode > 4)
491 aecm->lastError = AECM_BAD_PARAMETER_ERROR;
494 aecm->echoMode = config.echoMode;
496 if (aecm->echoMode == 0)
498 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
499 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
500 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
501 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
502 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3)
503 - (SUPGAIN_ERROR_PARAM_B >> 3);
504 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3)
505 - (SUPGAIN_ERROR_PARAM_D >> 3);
506 } else if (aecm->echoMode == 1)
508 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
509 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
510 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
511 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
512 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2)
513 - (SUPGAIN_ERROR_PARAM_B >> 2);
514 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2)
515 - (SUPGAIN_ERROR_PARAM_D >> 2);
516 } else if (aecm->echoMode == 2)
518 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
519 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
520 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
521 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
522 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1)
523 - (SUPGAIN_ERROR_PARAM_B >> 1);
524 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1)
525 - (SUPGAIN_ERROR_PARAM_D >> 1);
526 } else if (aecm->echoMode == 3)
528 aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
529 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
530 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
531 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
532 aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
533 aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
534 } else if (aecm->echoMode == 4)
536 aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
537 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
538 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
539 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
540 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1)
541 - (SUPGAIN_ERROR_PARAM_B << 1);
542 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1)
543 - (SUPGAIN_ERROR_PARAM_D << 1);
549 int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
551 aecmob_t *aecm = aecmInst;
560 aecm->lastError = AECM_NULL_POINTER_ERROR;
564 if (aecm->initFlag != kInitCheck)
566 aecm->lastError = AECM_UNINITIALIZED_ERROR;
570 config->cngMode = aecm->aecmCore->cngMode;
571 config->echoMode = aecm->echoMode;
576 int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
577 const void* echo_path,
580 aecmob_t *aecm = aecmInst;
581 const int16_t* echo_path_ptr = echo_path;
583 if (aecmInst == NULL) {
586 if (echo_path == NULL) {
587 aecm->lastError = AECM_NULL_POINTER_ERROR;
590 if (size_bytes != WebRtcAecm_echo_path_size_bytes())
592 // Input channel size does not match the size of AECM
593 aecm->lastError = AECM_BAD_PARAMETER_ERROR;
596 if (aecm->initFlag != kInitCheck)
598 aecm->lastError = AECM_UNINITIALIZED_ERROR;
602 WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
607 int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
611 aecmob_t *aecm = aecmInst;
612 int16_t* echo_path_ptr = echo_path;
614 if (aecmInst == NULL) {
617 if (echo_path == NULL) {
618 aecm->lastError = AECM_NULL_POINTER_ERROR;
621 if (size_bytes != WebRtcAecm_echo_path_size_bytes())
623 // Input channel size does not match the size of AECM
624 aecm->lastError = AECM_BAD_PARAMETER_ERROR;
627 if (aecm->initFlag != kInitCheck)
629 aecm->lastError = AECM_UNINITIALIZED_ERROR;
633 memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
637 size_t WebRtcAecm_echo_path_size_bytes()
639 return (PART_LEN1 * sizeof(int16_t));
642 int32_t WebRtcAecm_get_error_code(void *aecmInst)
644 aecmob_t *aecm = aecmInst;
651 return aecm->lastError;
654 static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf)
656 short delayNew, nSampSndCard;
657 short nSampFar = (short) WebRtc_available_read(aecm->farendBuf);
660 nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
662 delayNew = nSampSndCard - nSampFar;
664 if (delayNew < FRAME_LEN)
666 WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
667 delayNew += FRAME_LEN;
670 aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
672 diff = aecm->filtDelay - aecm->knownDelay;
675 if (aecm->lastDelayDiff < 96)
677 aecm->timeForDelayChange = 0;
680 aecm->timeForDelayChange++;
682 } else if (diff < 96 && aecm->knownDelay > 0)
684 if (aecm->lastDelayDiff > 224)
686 aecm->timeForDelayChange = 0;
689 aecm->timeForDelayChange++;
693 aecm->timeForDelayChange = 0;
695 aecm->lastDelayDiff = diff;
697 if (aecm->timeForDelayChange > 25)
699 aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
704 static int WebRtcAecm_DelayComp(aecmob_t *aecm)
706 int nSampFar = (int) WebRtc_available_read(aecm->farendBuf);
707 int nSampSndCard, delayNew, nSampAdd;
708 const int maxStuffSamp = 10 * FRAME_LEN;
710 nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
711 delayNew = nSampSndCard - nSampFar;
713 if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult)
715 // The difference of the buffer sizes is larger than the maximum
716 // allowed known delay. Compensate by stuffing the buffer.
717 nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar),
719 nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
721 WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
722 aecm->delayChange = 1; // the delay needs to be updated