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 /* 12 * Contains the API functions for the AEC. 13 */ 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include "echo_cancellation.h" 18 #include "aec_core.h" 19 #include "ring_buffer.h" 20 #include "resampler.h" 21 #ifdef AEC_DEBUG 22 #include <stdio.h> 23 #endif 24 25 #define BUF_SIZE_FRAMES 50 // buffer size (frames) 26 // Maximum length of resampled signal. Must be an integer multiple of frames 27 // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN 28 // The factor of 2 handles wb, and the + 1 is as a safety margin 29 #define MAX_RESAMP_LEN (5 * FRAME_LEN) 30 31 static const int bufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples) 32 static const int sampMsNb = 8; // samples per ms in nb 33 // Target suppression levels for nlp modes 34 // log{0.001, 0.00001, 0.00000001} 35 static const float targetSupp[3] = {-6.9f, -11.5f, -18.4f}; 36 static const float minOverDrive[3] = {1.0f, 2.0f, 5.0f}; 37 static const int initCheck = 42; 38 39 typedef struct { 40 int delayCtr; 41 int sampFreq; 42 int splitSampFreq; 43 int scSampFreq; 44 float sampFactor; // scSampRate / sampFreq 45 short nlpMode; 46 short autoOnOff; 47 short activity; 48 short skewMode; 49 short bufSizeStart; 50 //short bufResetCtr; // counts number of noncausal frames 51 int knownDelay; 52 53 // Stores the last frame added to the farend buffer 54 short farendOld[2][FRAME_LEN]; 55 short initFlag; // indicates if AEC has been initialized 56 57 // Variables used for averaging far end buffer size 58 short counter; 59 short sum; 60 short firstVal; 61 short checkBufSizeCtr; 62 63 // Variables used for delay shifts 64 short msInSndCardBuf; 65 short filtDelay; 66 int timeForDelayChange; 67 int ECstartup; 68 int checkBuffSize; 69 int delayChange; 70 short lastDelayDiff; 71 72 #ifdef AEC_DEBUG 73 FILE *bufFile; 74 FILE *delayFile; 75 FILE *skewFile; 76 FILE *preCompFile; 77 FILE *postCompFile; 78 #endif // AEC_DEBUG 79 80 // Structures 81 void *farendBuf; 82 void *resampler; 83 84 int skewFrCtr; 85 int resample; // if the skew is small enough we don't resample 86 int highSkewCtr; 87 float skew; 88 89 int lastError; 90 91 aec_t *aec; 92 } aecpc_t; 93 94 // Estimates delay to set the position of the farend buffer read pointer 95 // (controlled by knownDelay) 96 static int EstBufDelay(aecpc_t *aecInst, short msInSndCardBuf); 97 98 // Stuffs the farend buffer if the estimated delay is too large 99 static int DelayComp(aecpc_t *aecInst); 100 101 WebRtc_Word32 WebRtcAec_Create(void **aecInst) 102 { 103 aecpc_t *aecpc; 104 if (aecInst == NULL) { 105 return -1; 106 } 107 108 aecpc = malloc(sizeof(aecpc_t)); 109 *aecInst = aecpc; 110 if (aecpc == NULL) { 111 return -1; 112 } 113 114 if (WebRtcAec_CreateAec(&aecpc->aec) == -1) { 115 WebRtcAec_Free(aecpc); 116 aecpc = NULL; 117 return -1; 118 } 119 120 if (WebRtcApm_CreateBuffer(&aecpc->farendBuf, bufSizeSamp) == -1) { 121 WebRtcAec_Free(aecpc); 122 aecpc = NULL; 123 return -1; 124 } 125 126 if (WebRtcAec_CreateResampler(&aecpc->resampler) == -1) { 127 WebRtcAec_Free(aecpc); 128 aecpc = NULL; 129 return -1; 130 } 131 132 aecpc->initFlag = 0; 133 aecpc->lastError = 0; 134 135 #ifdef AEC_DEBUG 136 aecpc->aec->farFile = fopen("aecFar.pcm","wb"); 137 aecpc->aec->nearFile = fopen("aecNear.pcm","wb"); 138 aecpc->aec->outFile = fopen("aecOut.pcm","wb"); 139 aecpc->aec->outLpFile = fopen("aecOutLp.pcm","wb"); 140 141 aecpc->bufFile = fopen("aecBuf.dat", "wb"); 142 aecpc->skewFile = fopen("aecSkew.dat", "wb"); 143 aecpc->delayFile = fopen("aecDelay.dat", "wb"); 144 aecpc->preCompFile = fopen("preComp.pcm", "wb"); 145 aecpc->postCompFile = fopen("postComp.pcm", "wb"); 146 #endif // AEC_DEBUG 147 148 return 0; 149 } 150 151 WebRtc_Word32 WebRtcAec_Free(void *aecInst) 152 { 153 aecpc_t *aecpc = aecInst; 154 155 if (aecpc == NULL) { 156 return -1; 157 } 158 159 #ifdef AEC_DEBUG 160 fclose(aecpc->aec->farFile); 161 fclose(aecpc->aec->nearFile); 162 fclose(aecpc->aec->outFile); 163 fclose(aecpc->aec->outLpFile); 164 165 fclose(aecpc->bufFile); 166 fclose(aecpc->skewFile); 167 fclose(aecpc->delayFile); 168 fclose(aecpc->preCompFile); 169 fclose(aecpc->postCompFile); 170 #endif // AEC_DEBUG 171 172 WebRtcAec_FreeAec(aecpc->aec); 173 WebRtcApm_FreeBuffer(aecpc->farendBuf); 174 WebRtcAec_FreeResampler(aecpc->resampler); 175 free(aecpc); 176 177 return 0; 178 } 179 180 WebRtc_Word32 WebRtcAec_Init(void *aecInst, WebRtc_Word32 sampFreq, WebRtc_Word32 scSampFreq) 181 { 182 aecpc_t *aecpc = aecInst; 183 AecConfig aecConfig; 184 185 if (aecpc == NULL) { 186 return -1; 187 } 188 189 if (sampFreq != 8000 && sampFreq != 16000 && sampFreq != 32000) { 190 aecpc->lastError = AEC_BAD_PARAMETER_ERROR; 191 return -1; 192 } 193 aecpc->sampFreq = sampFreq; 194 195 if (scSampFreq < 1 || scSampFreq > 96000) { 196 aecpc->lastError = AEC_BAD_PARAMETER_ERROR; 197 return -1; 198 } 199 aecpc->scSampFreq = scSampFreq; 200 201 // Initialize echo canceller core 202 if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) { 203 aecpc->lastError = AEC_UNSPECIFIED_ERROR; 204 return -1; 205 } 206 207 // Initialize farend buffer 208 if (WebRtcApm_InitBuffer(aecpc->farendBuf) == -1) { 209 aecpc->lastError = AEC_UNSPECIFIED_ERROR; 210 return -1; 211 } 212 213 if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) { 214 aecpc->lastError = AEC_UNSPECIFIED_ERROR; 215 return -1; 216 } 217 218 aecpc->initFlag = initCheck; // indicates that initilisation has been done 219 220 if (aecpc->sampFreq == 32000) { 221 aecpc->splitSampFreq = 16000; 222 } 223 else { 224 aecpc->splitSampFreq = sampFreq; 225 } 226 227 aecpc->skewFrCtr = 0; 228 aecpc->activity = 0; 229 230 aecpc->delayChange = 1; 231 aecpc->delayCtr = 0; 232 233 aecpc->sum = 0; 234 aecpc->counter = 0; 235 aecpc->checkBuffSize = 1; 236 aecpc->firstVal = 0; 237 238 aecpc->ECstartup = 1; 239 aecpc->bufSizeStart = 0; 240 aecpc->checkBufSizeCtr = 0; 241 aecpc->filtDelay = 0; 242 aecpc->timeForDelayChange =0; 243 aecpc->knownDelay = 0; 244 aecpc->lastDelayDiff = 0; 245 246 aecpc->skew = 0; 247 aecpc->resample = kAecFalse; 248 aecpc->highSkewCtr = 0; 249 aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq; 250 251 memset(&aecpc->farendOld[0][0], 0, 160); 252 253 // Default settings. 254 aecConfig.nlpMode = kAecNlpModerate; 255 aecConfig.skewMode = kAecFalse; 256 aecConfig.metricsMode = kAecFalse; 257 258 if (WebRtcAec_set_config(aecpc, aecConfig) == -1) { 259 aecpc->lastError = AEC_UNSPECIFIED_ERROR; 260 return -1; 261 } 262 263 return 0; 264 } 265 266 // only buffer L band for farend 267 WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst, const WebRtc_Word16 *farend, 268 WebRtc_Word16 nrOfSamples) 269 { 270 aecpc_t *aecpc = aecInst; 271 WebRtc_Word32 retVal = 0; 272 short newNrOfSamples; 273 short newFarend[MAX_RESAMP_LEN]; 274 float skew; 275 276 if (aecpc == NULL) { 277 return -1; 278 } 279 280 if (farend == NULL) { 281 aecpc->lastError = AEC_NULL_POINTER_ERROR; 282 return -1; 283 } 284 285 if (aecpc->initFlag != initCheck) { 286 aecpc->lastError = AEC_UNINITIALIZED_ERROR; 287 return -1; 288 } 289 290 // number of samples == 160 for SWB input 291 if (nrOfSamples != 80 && nrOfSamples != 160) { 292 aecpc->lastError = AEC_BAD_PARAMETER_ERROR; 293 return -1; 294 } 295 296 skew = aecpc->skew; 297 298 // TODO: Is this really a good idea? 299 if (!aecpc->ECstartup) { 300 DelayComp(aecpc); 301 } 302 303 if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) { 304 // Resample and get a new number of samples 305 newNrOfSamples = WebRtcAec_ResampleLinear(aecpc->resampler, 306 farend, 307 nrOfSamples, 308 skew, 309 newFarend); 310 WebRtcApm_WriteBuffer(aecpc->farendBuf, newFarend, newNrOfSamples); 311 312 #ifdef AEC_DEBUG 313 fwrite(farend, 2, nrOfSamples, aecpc->preCompFile); 314 fwrite(newFarend, 2, newNrOfSamples, aecpc->postCompFile); 315 #endif 316 } 317 else { 318 WebRtcApm_WriteBuffer(aecpc->farendBuf, farend, nrOfSamples); 319 } 320 321 return retVal; 322 } 323 324 WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend, 325 const WebRtc_Word16 *nearendH, WebRtc_Word16 *out, WebRtc_Word16 *outH, 326 WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf, WebRtc_Word32 skew) 327 { 328 aecpc_t *aecpc = aecInst; 329 WebRtc_Word32 retVal = 0; 330 short i; 331 short farend[FRAME_LEN]; 332 short nmbrOfFilledBuffers; 333 short nBlocks10ms; 334 short nFrames; 335 #ifdef AEC_DEBUG 336 short msInAECBuf; 337 #endif 338 // Limit resampling to doubling/halving of signal 339 const float minSkewEst = -0.5f; 340 const float maxSkewEst = 1.0f; 341 342 if (aecpc == NULL) { 343 return -1; 344 } 345 346 if (nearend == NULL) { 347 aecpc->lastError = AEC_NULL_POINTER_ERROR; 348 return -1; 349 } 350 351 if (out == NULL) { 352 aecpc->lastError = AEC_NULL_POINTER_ERROR; 353 return -1; 354 } 355 356 if (aecpc->initFlag != initCheck) { 357 aecpc->lastError = AEC_UNINITIALIZED_ERROR; 358 return -1; 359 } 360 361 // number of samples == 160 for SWB input 362 if (nrOfSamples != 80 && nrOfSamples != 160) { 363 aecpc->lastError = AEC_BAD_PARAMETER_ERROR; 364 return -1; 365 } 366 367 // Check for valid pointers based on sampling rate 368 if (aecpc->sampFreq == 32000 && nearendH == NULL) { 369 aecpc->lastError = AEC_NULL_POINTER_ERROR; 370 return -1; 371 } 372 373 if (msInSndCardBuf < 0) { 374 msInSndCardBuf = 0; 375 aecpc->lastError = AEC_BAD_PARAMETER_WARNING; 376 retVal = -1; 377 } 378 else if (msInSndCardBuf > 500) { 379 msInSndCardBuf = 500; 380 aecpc->lastError = AEC_BAD_PARAMETER_WARNING; 381 retVal = -1; 382 } 383 msInSndCardBuf += 10; 384 aecpc->msInSndCardBuf = msInSndCardBuf; 385 386 if (aecpc->skewMode == kAecTrue) { 387 if (aecpc->skewFrCtr < 25) { 388 aecpc->skewFrCtr++; 389 } 390 else { 391 retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew); 392 if (retVal == -1) { 393 aecpc->skew = 0; 394 aecpc->lastError = AEC_BAD_PARAMETER_WARNING; 395 } 396 397 aecpc->skew /= aecpc->sampFactor*nrOfSamples; 398 399 if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) { 400 aecpc->resample = kAecFalse; 401 } 402 else { 403 aecpc->resample = kAecTrue; 404 } 405 406 if (aecpc->skew < minSkewEst) { 407 aecpc->skew = minSkewEst; 408 } 409 else if (aecpc->skew > maxSkewEst) { 410 aecpc->skew = maxSkewEst; 411 } 412 413 #ifdef AEC_DEBUG 414 fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile); 415 #endif 416 } 417 } 418 419 nFrames = nrOfSamples / FRAME_LEN; 420 nBlocks10ms = nFrames / aecpc->aec->mult; 421 422 if (aecpc->ECstartup) { 423 memcpy(out, nearend, sizeof(short) * nrOfSamples); 424 nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecpc->farendBuf) / FRAME_LEN; 425 426 // The AEC is in the start up mode 427 // AEC is disabled until the soundcard buffer and farend buffers are OK 428 429 // Mechanism to ensure that the soundcard buffer is reasonably stable. 430 if (aecpc->checkBuffSize) { 431 432 aecpc->checkBufSizeCtr++; 433 // Before we fill up the far end buffer we require the amount of data on the 434 // sound card to be stable (+/-8 ms) compared to the first value. This 435 // comparison is made during the following 4 consecutive frames. If it seems 436 // to be stable then we start to fill up the far end buffer. 437 438 if (aecpc->counter == 0) { 439 aecpc->firstVal = aecpc->msInSndCardBuf; 440 aecpc->sum = 0; 441 } 442 443 if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) < 444 WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) { 445 aecpc->sum += aecpc->msInSndCardBuf; 446 aecpc->counter++; 447 } 448 else { 449 aecpc->counter = 0; 450 } 451 452 if (aecpc->counter*nBlocks10ms >= 6) { 453 // The farend buffer size is determined in blocks of 80 samples 454 // Use 75% of the average value of the soundcard buffer 455 aecpc->bufSizeStart = WEBRTC_SPL_MIN((int) (0.75 * (aecpc->sum * 456 aecpc->aec->mult) / (aecpc->counter * 10)), BUF_SIZE_FRAMES); 457 // buffersize has now been determined 458 aecpc->checkBuffSize = 0; 459 } 460 461 if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) { 462 // for really bad sound cards, don't disable echocanceller for more than 0.5 sec 463 aecpc->bufSizeStart = WEBRTC_SPL_MIN((int) (0.75 * (aecpc->msInSndCardBuf * 464 aecpc->aec->mult) / 10), BUF_SIZE_FRAMES); 465 aecpc->checkBuffSize = 0; 466 } 467 } 468 469 // if checkBuffSize changed in the if-statement above 470 if (!aecpc->checkBuffSize) { 471 // soundcard buffer is now reasonably stable 472 // When the far end buffer is filled with approximately the same amount of 473 // data as the amount on the sound card we end the start up phase and start 474 // to cancel echoes. 475 476 if (nmbrOfFilledBuffers == aecpc->bufSizeStart) { 477 aecpc->ECstartup = 0; // Enable the AEC 478 } 479 else if (nmbrOfFilledBuffers > aecpc->bufSizeStart) { 480 WebRtcApm_FlushBuffer(aecpc->farendBuf, WebRtcApm_get_buffer_size(aecpc->farendBuf) - 481 aecpc->bufSizeStart * FRAME_LEN); 482 aecpc->ECstartup = 0; 483 } 484 } 485 486 } 487 else { 488 // AEC is enabled 489 490 // Note only 1 block supported for nb and 2 blocks for wb 491 for (i = 0; i < nFrames; i++) { 492 nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecpc->farendBuf) / FRAME_LEN; 493 494 // Check that there is data in the far end buffer 495 if (nmbrOfFilledBuffers > 0) { 496 // Get the next 80 samples from the farend buffer 497 WebRtcApm_ReadBuffer(aecpc->farendBuf, farend, FRAME_LEN); 498 499 // Always store the last frame for use when we run out of data 500 memcpy(&(aecpc->farendOld[i][0]), farend, FRAME_LEN * sizeof(short)); 501 } 502 else { 503 // We have no data so we use the last played frame 504 memcpy(farend, &(aecpc->farendOld[i][0]), FRAME_LEN * sizeof(short)); 505 } 506 507 // Call buffer delay estimator when all data is extracted, 508 // i.e. i = 0 for NB and i = 1 for WB or SWB 509 if ((i == 0 && aecpc->splitSampFreq == 8000) || 510 (i == 1 && (aecpc->splitSampFreq == 16000))) { 511 EstBufDelay(aecpc, aecpc->msInSndCardBuf); 512 } 513 514 // Call the AEC 515 WebRtcAec_ProcessFrame(aecpc->aec, farend, &nearend[FRAME_LEN * i], &nearendH[FRAME_LEN * i], 516 &out[FRAME_LEN * i], &outH[FRAME_LEN * i], aecpc->knownDelay); 517 } 518 } 519 520 #ifdef AEC_DEBUG 521 msInAECBuf = WebRtcApm_get_buffer_size(aecpc->farendBuf) / (sampMsNb*aecpc->aec->mult); 522 fwrite(&msInAECBuf, 2, 1, aecpc->bufFile); 523 fwrite(&(aecpc->knownDelay), sizeof(aecpc->knownDelay), 1, aecpc->delayFile); 524 #endif 525 526 return retVal; 527 } 528 529 WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config) 530 { 531 aecpc_t *aecpc = aecInst; 532 533 if (aecpc == NULL) { 534 return -1; 535 } 536 537 if (aecpc->initFlag != initCheck) { 538 aecpc->lastError = AEC_UNINITIALIZED_ERROR; 539 return -1; 540 } 541 542 if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) { 543 aecpc->lastError = AEC_BAD_PARAMETER_ERROR; 544 return -1; 545 } 546 aecpc->skewMode = config.skewMode; 547 548 if (config.nlpMode != kAecNlpConservative && config.nlpMode != 549 kAecNlpModerate && config.nlpMode != kAecNlpAggressive) { 550 aecpc->lastError = AEC_BAD_PARAMETER_ERROR; 551 return -1; 552 } 553 aecpc->nlpMode = config.nlpMode; 554 aecpc->aec->targetSupp = targetSupp[aecpc->nlpMode]; 555 aecpc->aec->minOverDrive = minOverDrive[aecpc->nlpMode]; 556 557 if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) { 558 aecpc->lastError = AEC_BAD_PARAMETER_ERROR; 559 return -1; 560 } 561 aecpc->aec->metricsMode = config.metricsMode; 562 if (aecpc->aec->metricsMode == kAecTrue) { 563 WebRtcAec_InitMetrics(aecpc->aec); 564 } 565 566 return 0; 567 } 568 569 WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config) 570 { 571 aecpc_t *aecpc = aecInst; 572 573 if (aecpc == NULL) { 574 return -1; 575 } 576 577 if (config == NULL) { 578 aecpc->lastError = AEC_NULL_POINTER_ERROR; 579 return -1; 580 } 581 582 if (aecpc->initFlag != initCheck) { 583 aecpc->lastError = AEC_UNINITIALIZED_ERROR; 584 return -1; 585 } 586 587 config->nlpMode = aecpc->nlpMode; 588 config->skewMode = aecpc->skewMode; 589 config->metricsMode = aecpc->aec->metricsMode; 590 591 return 0; 592 } 593 594 WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status) 595 { 596 aecpc_t *aecpc = aecInst; 597 598 if (aecpc == NULL) { 599 return -1; 600 } 601 602 if (status == NULL) { 603 aecpc->lastError = AEC_NULL_POINTER_ERROR; 604 return -1; 605 } 606 607 if (aecpc->initFlag != initCheck) { 608 aecpc->lastError = AEC_UNINITIALIZED_ERROR; 609 return -1; 610 } 611 612 *status = aecpc->aec->echoState; 613 614 return 0; 615 } 616 617 WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics) 618 { 619 const float upweight = 0.7f; 620 float dtmp; 621 short stmp; 622 aecpc_t *aecpc = aecInst; 623 624 if (aecpc == NULL) { 625 return -1; 626 } 627 628 if (metrics == NULL) { 629 aecpc->lastError = AEC_NULL_POINTER_ERROR; 630 return -1; 631 } 632 633 if (aecpc->initFlag != initCheck) { 634 aecpc->lastError = AEC_UNINITIALIZED_ERROR; 635 return -1; 636 } 637 638 // ERL 639 metrics->erl.instant = (short) aecpc->aec->erl.instant; 640 641 if ((aecpc->aec->erl.himean > offsetLevel) && (aecpc->aec->erl.average > offsetLevel)) { 642 // Use a mix between regular average and upper part average 643 dtmp = upweight * aecpc->aec->erl.himean + (1 - upweight) * aecpc->aec->erl.average; 644 metrics->erl.average = (short) dtmp; 645 } 646 else { 647 metrics->erl.average = offsetLevel; 648 } 649 650 metrics->erl.max = (short) aecpc->aec->erl.max; 651 652 if (aecpc->aec->erl.min < (offsetLevel * (-1))) { 653 metrics->erl.min = (short) aecpc->aec->erl.min; 654 } 655 else { 656 metrics->erl.min = offsetLevel; 657 } 658 659 // ERLE 660 metrics->erle.instant = (short) aecpc->aec->erle.instant; 661 662 if ((aecpc->aec->erle.himean > offsetLevel) && (aecpc->aec->erle.average > offsetLevel)) { 663 // Use a mix between regular average and upper part average 664 dtmp = upweight * aecpc->aec->erle.himean + (1 - upweight) * aecpc->aec->erle.average; 665 metrics->erle.average = (short) dtmp; 666 } 667 else { 668 metrics->erle.average = offsetLevel; 669 } 670 671 metrics->erle.max = (short) aecpc->aec->erle.max; 672 673 if (aecpc->aec->erle.min < (offsetLevel * (-1))) { 674 metrics->erle.min = (short) aecpc->aec->erle.min; 675 } else { 676 metrics->erle.min = offsetLevel; 677 } 678 679 // RERL 680 if ((metrics->erl.average > offsetLevel) && (metrics->erle.average > offsetLevel)) { 681 stmp = metrics->erl.average + metrics->erle.average; 682 } 683 else { 684 stmp = offsetLevel; 685 } 686 metrics->rerl.average = stmp; 687 688 // No other statistics needed, but returned for completeness 689 metrics->rerl.instant = stmp; 690 metrics->rerl.max = stmp; 691 metrics->rerl.min = stmp; 692 693 // A_NLP 694 metrics->aNlp.instant = (short) aecpc->aec->aNlp.instant; 695 696 if ((aecpc->aec->aNlp.himean > offsetLevel) && (aecpc->aec->aNlp.average > offsetLevel)) { 697 // Use a mix between regular average and upper part average 698 dtmp = upweight * aecpc->aec->aNlp.himean + (1 - upweight) * aecpc->aec->aNlp.average; 699 metrics->aNlp.average = (short) dtmp; 700 } 701 else { 702 metrics->aNlp.average = offsetLevel; 703 } 704 705 metrics->aNlp.max = (short) aecpc->aec->aNlp.max; 706 707 if (aecpc->aec->aNlp.min < (offsetLevel * (-1))) { 708 metrics->aNlp.min = (short) aecpc->aec->aNlp.min; 709 } 710 else { 711 metrics->aNlp.min = offsetLevel; 712 } 713 714 return 0; 715 } 716 717 WebRtc_Word32 WebRtcAec_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len) 718 { 719 const char version[] = "AEC 2.5.0"; 720 const short versionLen = (short)strlen(version) + 1; // +1 for null-termination 721 722 if (versionStr == NULL) { 723 return -1; 724 } 725 726 if (versionLen > len) { 727 return -1; 728 } 729 730 strncpy(versionStr, version, versionLen); 731 return 0; 732 } 733 734 WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst) 735 { 736 aecpc_t *aecpc = aecInst; 737 738 if (aecpc == NULL) { 739 return -1; 740 } 741 742 return aecpc->lastError; 743 } 744 745 static int EstBufDelay(aecpc_t *aecpc, short msInSndCardBuf) 746 { 747 short delayNew, nSampFar, nSampSndCard; 748 short diff; 749 750 nSampFar = WebRtcApm_get_buffer_size(aecpc->farendBuf); 751 nSampSndCard = msInSndCardBuf * sampMsNb * aecpc->aec->mult; 752 753 delayNew = nSampSndCard - nSampFar; 754 755 // Account for resampling frame delay 756 if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) { 757 delayNew -= kResamplingDelay; 758 } 759 760 if (delayNew < FRAME_LEN) { 761 WebRtcApm_FlushBuffer(aecpc->farendBuf, FRAME_LEN); 762 delayNew += FRAME_LEN; 763 } 764 765 aecpc->filtDelay = WEBRTC_SPL_MAX(0, (short)(0.8*aecpc->filtDelay + 0.2*delayNew)); 766 767 diff = aecpc->filtDelay - aecpc->knownDelay; 768 if (diff > 224) { 769 if (aecpc->lastDelayDiff < 96) { 770 aecpc->timeForDelayChange = 0; 771 } 772 else { 773 aecpc->timeForDelayChange++; 774 } 775 } 776 else if (diff < 96 && aecpc->knownDelay > 0) { 777 if (aecpc->lastDelayDiff > 224) { 778 aecpc->timeForDelayChange = 0; 779 } 780 else { 781 aecpc->timeForDelayChange++; 782 } 783 } 784 else { 785 aecpc->timeForDelayChange = 0; 786 } 787 aecpc->lastDelayDiff = diff; 788 789 if (aecpc->timeForDelayChange > 25) { 790 aecpc->knownDelay = WEBRTC_SPL_MAX((int)aecpc->filtDelay - 160, 0); 791 } 792 return 0; 793 } 794 795 static int DelayComp(aecpc_t *aecpc) 796 { 797 int nSampFar, nSampSndCard, delayNew, nSampAdd; 798 const int maxStuffSamp = 10 * FRAME_LEN; 799 800 nSampFar = WebRtcApm_get_buffer_size(aecpc->farendBuf); 801 nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->aec->mult; 802 delayNew = nSampSndCard - nSampFar; 803 804 // Account for resampling frame delay 805 if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) { 806 delayNew -= kResamplingDelay; 807 } 808 809 if (delayNew > FAR_BUF_LEN - FRAME_LEN*aecpc->aec->mult) { 810 // The difference of the buffersizes is larger than the maximum 811 // allowed known delay. Compensate by stuffing the buffer. 812 nSampAdd = (int)(WEBRTC_SPL_MAX((int)(0.5 * nSampSndCard - nSampFar), 813 FRAME_LEN)); 814 nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp); 815 816 WebRtcApm_StuffBuffer(aecpc->farendBuf, nSampAdd); 817 aecpc->delayChange = 1; // the delay needs to be updated 818 } 819 820 return 0; 821 } 822