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/include/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/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" 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 int lastError; 72 73 AecmCore_t *aecmCore; 74 } aecmob_t; 75 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); 79 80 // Stuffs the farend buffer if the estimated delay is too large 81 static int WebRtcAecm_DelayComp(aecmob_t *aecmInst); 82 83 int32_t WebRtcAecm_Create(void **aecmInst) 84 { 85 aecmob_t *aecm; 86 if (aecmInst == NULL) 87 { 88 return -1; 89 } 90 91 aecm = malloc(sizeof(aecmob_t)); 92 *aecmInst = aecm; 93 if (aecm == NULL) 94 { 95 return -1; 96 } 97 98 WebRtcSpl_Init(); 99 100 if (WebRtcAecm_CreateCore(&aecm->aecmCore) == -1) 101 { 102 WebRtcAecm_Free(aecm); 103 aecm = NULL; 104 return -1; 105 } 106 107 aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp, 108 sizeof(int16_t)); 109 if (!aecm->farendBuf) 110 { 111 WebRtcAecm_Free(aecm); 112 aecm = NULL; 113 return -1; 114 } 115 116 aecm->initFlag = 0; 117 aecm->lastError = 0; 118 119 #ifdef AEC_DEBUG 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"); 124 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"); 129 #endif // AEC_DEBUG 130 return 0; 131 } 132 133 int32_t WebRtcAecm_Free(void *aecmInst) 134 { 135 aecmob_t *aecm = aecmInst; 136 137 if (aecm == NULL) 138 { 139 return -1; 140 } 141 142 #ifdef AEC_DEBUG 143 fclose(aecm->aecmCore->farFile); 144 fclose(aecm->aecmCore->nearFile); 145 fclose(aecm->aecmCore->outFile); 146 //fclose(aecm->aecmCore->outLpFile); 147 148 fclose(aecm->bufFile); 149 fclose(aecm->delayFile); 150 fclose(aecm->preCompFile); 151 fclose(aecm->postCompFile); 152 #endif // AEC_DEBUG 153 WebRtcAecm_FreeCore(aecm->aecmCore); 154 WebRtc_FreeBuffer(aecm->farendBuf); 155 free(aecm); 156 157 return 0; 158 } 159 160 int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq) 161 { 162 aecmob_t *aecm = aecmInst; 163 AecmConfig aecConfig; 164 165 if (aecm == NULL) 166 { 167 return -1; 168 } 169 170 if (sampFreq != 8000 && sampFreq != 16000) 171 { 172 aecm->lastError = AECM_BAD_PARAMETER_ERROR; 173 return -1; 174 } 175 aecm->sampFreq = sampFreq; 176 177 // Initialize AECM core 178 if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) 179 { 180 aecm->lastError = AECM_UNSPECIFIED_ERROR; 181 return -1; 182 } 183 184 // Initialize farend buffer 185 if (WebRtc_InitBuffer(aecm->farendBuf) == -1) 186 { 187 aecm->lastError = AECM_UNSPECIFIED_ERROR; 188 return -1; 189 } 190 191 aecm->initFlag = kInitCheck; // indicates that initialization has been done 192 193 aecm->delayChange = 1; 194 195 aecm->sum = 0; 196 aecm->counter = 0; 197 aecm->checkBuffSize = 1; 198 aecm->firstVal = 0; 199 200 aecm->ECstartup = 1; 201 aecm->bufSizeStart = 0; 202 aecm->checkBufSizeCtr = 0; 203 aecm->filtDelay = 0; 204 aecm->timeForDelayChange = 0; 205 aecm->knownDelay = 0; 206 aecm->lastDelayDiff = 0; 207 208 memset(&aecm->farendOld[0][0], 0, 160); 209 210 // Default settings. 211 aecConfig.cngMode = AecmTrue; 212 aecConfig.echoMode = 3; 213 214 if (WebRtcAecm_set_config(aecm, aecConfig) == -1) 215 { 216 aecm->lastError = AECM_UNSPECIFIED_ERROR; 217 return -1; 218 } 219 220 return 0; 221 } 222 223 int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend, 224 int16_t nrOfSamples) 225 { 226 aecmob_t *aecm = aecmInst; 227 int32_t retVal = 0; 228 229 if (aecm == NULL) 230 { 231 return -1; 232 } 233 234 if (farend == NULL) 235 { 236 aecm->lastError = AECM_NULL_POINTER_ERROR; 237 return -1; 238 } 239 240 if (aecm->initFlag != kInitCheck) 241 { 242 aecm->lastError = AECM_UNINITIALIZED_ERROR; 243 return -1; 244 } 245 246 if (nrOfSamples != 80 && nrOfSamples != 160) 247 { 248 aecm->lastError = AECM_BAD_PARAMETER_ERROR; 249 return -1; 250 } 251 252 // TODO: Is this really a good idea? 253 if (!aecm->ECstartup) 254 { 255 WebRtcAecm_DelayComp(aecm); 256 } 257 258 WebRtc_WriteBuffer(aecm->farendBuf, farend, (size_t) nrOfSamples); 259 260 return retVal; 261 } 262 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) 266 { 267 aecmob_t *aecm = aecmInst; 268 int32_t retVal = 0; 269 short i; 270 short nmbrOfFilledBuffers; 271 short nBlocks10ms; 272 short nFrames; 273 #ifdef AEC_DEBUG 274 short msInAECBuf; 275 #endif 276 277 if (aecm == NULL) 278 { 279 return -1; 280 } 281 282 if (nearendNoisy == NULL) 283 { 284 aecm->lastError = AECM_NULL_POINTER_ERROR; 285 return -1; 286 } 287 288 if (out == NULL) 289 { 290 aecm->lastError = AECM_NULL_POINTER_ERROR; 291 return -1; 292 } 293 294 if (aecm->initFlag != kInitCheck) 295 { 296 aecm->lastError = AECM_UNINITIALIZED_ERROR; 297 return -1; 298 } 299 300 if (nrOfSamples != 80 && nrOfSamples != 160) 301 { 302 aecm->lastError = AECM_BAD_PARAMETER_ERROR; 303 return -1; 304 } 305 306 if (msInSndCardBuf < 0) 307 { 308 msInSndCardBuf = 0; 309 aecm->lastError = AECM_BAD_PARAMETER_WARNING; 310 retVal = -1; 311 } else if (msInSndCardBuf > 500) 312 { 313 msInSndCardBuf = 500; 314 aecm->lastError = AECM_BAD_PARAMETER_WARNING; 315 retVal = -1; 316 } 317 msInSndCardBuf += 10; 318 aecm->msInSndCardBuf = msInSndCardBuf; 319 320 nFrames = nrOfSamples / FRAME_LEN; 321 nBlocks10ms = nFrames / aecm->aecmCore->mult; 322 323 if (aecm->ECstartup) 324 { 325 if (nearendClean == NULL) 326 { 327 if (out != nearendNoisy) 328 { 329 memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples); 330 } 331 } else if (out != nearendClean) 332 { 333 memcpy(out, nearendClean, sizeof(short) * nrOfSamples); 334 } 335 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 340 341 // Mechanism to ensure that the soundcard buffer is reasonably stable. 342 if (aecm->checkBuffSize) 343 { 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. 349 350 if (aecm->counter == 0) 351 { 352 aecm->firstVal = aecm->msInSndCardBuf; 353 aecm->sum = 0; 354 } 355 356 if (abs(aecm->firstVal - aecm->msInSndCardBuf) 357 < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) 358 { 359 aecm->sum += aecm->msInSndCardBuf; 360 aecm->counter++; 361 } else 362 { 363 aecm->counter = 0; 364 } 365 366 if (aecm->counter * nBlocks10ms >= 6) 367 { 368 // The farend buffer size is determined in blocks of 80 samples 369 // Use 75% of the average value of the soundcard buffer 370 aecm->bufSizeStart 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; 375 } 376 377 if (aecm->checkBufSizeCtr * nBlocks10ms > 50) 378 { 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; 383 } 384 } 385 386 // if checkBuffSize changed in the if-statement above 387 if (!aecm->checkBuffSize) 388 { 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 392 // to cancel echoes. 393 394 if (nmbrOfFilledBuffers == aecm->bufSizeStart) 395 { 396 aecm->ECstartup = 0; // Enable the AECM 397 } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) 398 { 399 WebRtc_MoveReadPtr(aecm->farendBuf, 400 (int) WebRtc_available_read(aecm->farendBuf) 401 - (int) aecm->bufSizeStart * FRAME_LEN); 402 aecm->ECstartup = 0; 403 } 404 } 405 406 } else 407 { 408 // AECM is enabled 409 410 // Note only 1 block supported for nb and 2 blocks for wb 411 for (i = 0; i < nFrames; i++) 412 { 413 int16_t farend[FRAME_LEN]; 414 const int16_t* farend_ptr = NULL; 415 416 nmbrOfFilledBuffers = 417 (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN; 418 419 // Check that there is data in the far end buffer 420 if (nmbrOfFilledBuffers > 0) 421 { 422 // Get the next 80 samples from the farend buffer 423 WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend, 424 FRAME_LEN); 425 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)); 429 } else 430 { 431 // We have no data so we use the last played frame 432 memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short)); 433 farend_ptr = farend; 434 } 435 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)) 439 { 440 WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf); 441 } 442 443 // Call the AECM 444 /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i], 445 &out[FRAME_LEN * i], aecm->knownDelay);*/ 446 if (WebRtcAecm_ProcessFrame(aecm->aecmCore, 447 farend_ptr, 448 &nearendNoisy[FRAME_LEN * i], 449 (nearendClean 450 ? &nearendClean[FRAME_LEN * i] 451 : NULL), 452 &out[FRAME_LEN * i]) == -1) 453 return -1; 454 } 455 } 456 457 #ifdef AEC_DEBUG 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); 462 #endif 463 464 return retVal; 465 } 466 467 int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config) 468 { 469 aecmob_t *aecm = aecmInst; 470 471 if (aecm == NULL) 472 { 473 return -1; 474 } 475 476 if (aecm->initFlag != kInitCheck) 477 { 478 aecm->lastError = AECM_UNINITIALIZED_ERROR; 479 return -1; 480 } 481 482 if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) 483 { 484 aecm->lastError = AECM_BAD_PARAMETER_ERROR; 485 return -1; 486 } 487 aecm->aecmCore->cngMode = config.cngMode; 488 489 if (config.echoMode < 0 || config.echoMode > 4) 490 { 491 aecm->lastError = AECM_BAD_PARAMETER_ERROR; 492 return -1; 493 } 494 aecm->echoMode = config.echoMode; 495 496 if (aecm->echoMode == 0) 497 { 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) 507 { 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) 517 { 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) 527 { 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) 535 { 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); 544 } 545 546 return 0; 547 } 548 549 int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config) 550 { 551 aecmob_t *aecm = aecmInst; 552 553 if (aecm == NULL) 554 { 555 return -1; 556 } 557 558 if (config == NULL) 559 { 560 aecm->lastError = AECM_NULL_POINTER_ERROR; 561 return -1; 562 } 563 564 if (aecm->initFlag != kInitCheck) 565 { 566 aecm->lastError = AECM_UNINITIALIZED_ERROR; 567 return -1; 568 } 569 570 config->cngMode = aecm->aecmCore->cngMode; 571 config->echoMode = aecm->echoMode; 572 573 return 0; 574 } 575 576 int32_t WebRtcAecm_InitEchoPath(void* aecmInst, 577 const void* echo_path, 578 size_t size_bytes) 579 { 580 aecmob_t *aecm = aecmInst; 581 const int16_t* echo_path_ptr = echo_path; 582 583 if (aecmInst == NULL) { 584 return -1; 585 } 586 if (echo_path == NULL) { 587 aecm->lastError = AECM_NULL_POINTER_ERROR; 588 return -1; 589 } 590 if (size_bytes != WebRtcAecm_echo_path_size_bytes()) 591 { 592 // Input channel size does not match the size of AECM 593 aecm->lastError = AECM_BAD_PARAMETER_ERROR; 594 return -1; 595 } 596 if (aecm->initFlag != kInitCheck) 597 { 598 aecm->lastError = AECM_UNINITIALIZED_ERROR; 599 return -1; 600 } 601 602 WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr); 603 604 return 0; 605 } 606 607 int32_t WebRtcAecm_GetEchoPath(void* aecmInst, 608 void* echo_path, 609 size_t size_bytes) 610 { 611 aecmob_t *aecm = aecmInst; 612 int16_t* echo_path_ptr = echo_path; 613 614 if (aecmInst == NULL) { 615 return -1; 616 } 617 if (echo_path == NULL) { 618 aecm->lastError = AECM_NULL_POINTER_ERROR; 619 return -1; 620 } 621 if (size_bytes != WebRtcAecm_echo_path_size_bytes()) 622 { 623 // Input channel size does not match the size of AECM 624 aecm->lastError = AECM_BAD_PARAMETER_ERROR; 625 return -1; 626 } 627 if (aecm->initFlag != kInitCheck) 628 { 629 aecm->lastError = AECM_UNINITIALIZED_ERROR; 630 return -1; 631 } 632 633 memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes); 634 return 0; 635 } 636 637 size_t WebRtcAecm_echo_path_size_bytes() 638 { 639 return (PART_LEN1 * sizeof(int16_t)); 640 } 641 642 int32_t WebRtcAecm_get_error_code(void *aecmInst) 643 { 644 aecmob_t *aecm = aecmInst; 645 646 if (aecm == NULL) 647 { 648 return -1; 649 } 650 651 return aecm->lastError; 652 } 653 654 static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf) 655 { 656 short delayNew, nSampSndCard; 657 short nSampFar = (short) WebRtc_available_read(aecm->farendBuf); 658 short diff; 659 660 nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; 661 662 delayNew = nSampSndCard - nSampFar; 663 664 if (delayNew < FRAME_LEN) 665 { 666 WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN); 667 delayNew += FRAME_LEN; 668 } 669 670 aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10); 671 672 diff = aecm->filtDelay - aecm->knownDelay; 673 if (diff > 224) 674 { 675 if (aecm->lastDelayDiff < 96) 676 { 677 aecm->timeForDelayChange = 0; 678 } else 679 { 680 aecm->timeForDelayChange++; 681 } 682 } else if (diff < 96 && aecm->knownDelay > 0) 683 { 684 if (aecm->lastDelayDiff > 224) 685 { 686 aecm->timeForDelayChange = 0; 687 } else 688 { 689 aecm->timeForDelayChange++; 690 } 691 } else 692 { 693 aecm->timeForDelayChange = 0; 694 } 695 aecm->lastDelayDiff = diff; 696 697 if (aecm->timeForDelayChange > 25) 698 { 699 aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0); 700 } 701 return 0; 702 } 703 704 static int WebRtcAecm_DelayComp(aecmob_t *aecm) 705 { 706 int nSampFar = (int) WebRtc_available_read(aecm->farendBuf); 707 int nSampSndCard, delayNew, nSampAdd; 708 const int maxStuffSamp = 10 * FRAME_LEN; 709 710 nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; 711 delayNew = nSampSndCard - nSampFar; 712 713 if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) 714 { 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), 718 FRAME_LEN)); 719 nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp); 720 721 WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd); 722 aecm->delayChange = 1; // the delay needs to be updated 723 } 724 725 return 0; 726 } 727