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