| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 /* | 11 /* |
| 12 * The core AEC algorithm, which is presented with time-aligned signals. | 12 * The core AEC algorithm, which is presented with time-aligned signals. |
| 13 */ | 13 */ |
| 14 | 14 |
| 15 #include "webrtc/modules/audio_processing/aec/aec_core.h" | 15 #include "webrtc/modules/audio_processing/aec/aec_core.h" |
| 16 | 16 |
| 17 #ifdef WEBRTC_AEC_DEBUG_DUMP | 17 #ifdef WEBRTC_AEC_DEBUG_DUMP |
| 18 #include <stdio.h> | 18 #include <stdio.h> |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 #include <assert.h> | 21 #include <assert.h> |
| 22 #include <math.h> | 22 #include <math.h> |
| 23 #include <stddef.h> // size_t | 23 #include <stddef.h> // size_t |
| 24 #include <stdlib.h> | 24 #include <stdlib.h> |
| 25 #include <string.h> | 25 #include <string.h> |
| 26 | 26 |
| 27 extern "C" { |
| 27 #include "webrtc/common_audio/ring_buffer.h" | 28 #include "webrtc/common_audio/ring_buffer.h" |
| 29 } |
| 28 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar
y.h" | 30 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar
y.h" |
| 29 #include "webrtc/modules/audio_processing/aec/aec_common.h" | 31 #include "webrtc/modules/audio_processing/aec/aec_common.h" |
| 30 #include "webrtc/modules/audio_processing/aec/aec_core_internal.h" | 32 #include "webrtc/modules/audio_processing/aec/aec_core_internal.h" |
| 33 extern "C" { |
| 31 #include "webrtc/modules/audio_processing/aec/aec_rdft.h" | 34 #include "webrtc/modules/audio_processing/aec/aec_rdft.h" |
| 35 } |
| 32 #include "webrtc/modules/audio_processing/logging/aec_logging.h" | 36 #include "webrtc/modules/audio_processing/logging/aec_logging.h" |
| 37 extern "C" { |
| 33 #include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h" | 38 #include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h" |
| 39 } |
| 34 #include "webrtc/system_wrappers/include/cpu_features_wrapper.h" | 40 #include "webrtc/system_wrappers/include/cpu_features_wrapper.h" |
| 35 #include "webrtc/typedefs.h" | 41 #include "webrtc/typedefs.h" |
| 36 | 42 |
| 37 // Buffer size (samples) | 43 // Buffer size (samples) |
| 38 static const size_t kBufSizePartitions = 250; // 1 second of audio in 16 kHz. | 44 static const size_t kBufSizePartitions = 250; // 1 second of audio in 16 kHz. |
| 39 | 45 |
| 40 // Metrics | 46 // Metrics |
| 41 static const int subCountLen = 4; | 47 static const int subCountLen = 4; |
| 42 static const int countLen = 50; | 48 static const int countLen = 50; |
| 43 static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz. | 49 static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz. |
| 44 | 50 |
| 45 // Quantities to control H band scaling for SWB input | 51 // Quantities to control H band scaling for SWB input |
| 46 static const float cnScaleHband = | 52 static const float cnScaleHband = 0.4f; // scale for comfort noise in H band. |
| 47 (float)0.4; // scale for comfort noise in H band | |
| 48 // Initial bin for averaging nlp gain in low band | 53 // Initial bin for averaging nlp gain in low band |
| 49 static const int freqAvgIc = PART_LEN / 2; | 54 static const int freqAvgIc = PART_LEN / 2; |
| 50 | 55 |
| 51 // Matlab code to produce table: | 56 // Matlab code to produce table: |
| 52 // win = sqrt(hanning(63)); win = [0 ; win(1:32)]; | 57 // win = sqrt(hanning(63)); win = [0 ; win(1:32)]; |
| 53 // fprintf(1, '\t%.14f, %.14f, %.14f,\n', win); | 58 // fprintf(1, '\t%.14f, %.14f, %.14f,\n', win); |
| 54 ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = { | 59 ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = { |
| 55 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, | 60 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, |
| 56 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f, | 61 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f, |
| 57 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, | 62 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 (aec->sd[i] * aec->se[i] + 1e-10f); | 414 (aec->sd[i] * aec->se[i] + 1e-10f); |
| 410 cohxd[i] = | 415 cohxd[i] = |
| 411 (aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) / | 416 (aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) / |
| 412 (aec->sx[i] * aec->sd[i] + 1e-10f); | 417 (aec->sx[i] * aec->sd[i] + 1e-10f); |
| 413 } | 418 } |
| 414 } | 419 } |
| 415 | 420 |
| 416 static void GetHighbandGain(const float* lambda, float* nlpGainHband) { | 421 static void GetHighbandGain(const float* lambda, float* nlpGainHband) { |
| 417 int i; | 422 int i; |
| 418 | 423 |
| 419 *nlpGainHband = (float)0.0; | 424 *nlpGainHband = 0.0f; |
| 420 for (i = freqAvgIc; i < PART_LEN1 - 1; i++) { | 425 for (i = freqAvgIc; i < PART_LEN1 - 1; i++) { |
| 421 *nlpGainHband += lambda[i]; | 426 *nlpGainHband += lambda[i]; |
| 422 } | 427 } |
| 423 *nlpGainHband /= (float)(PART_LEN1 - 1 - freqAvgIc); | 428 *nlpGainHband /= static_cast<float>(PART_LEN1 - 1 - freqAvgIc); |
| 424 } | 429 } |
| 425 | 430 |
| 426 static void ComfortNoise(AecCore* aec, | 431 static void ComfortNoise(AecCore* aec, |
| 427 float efw[2][PART_LEN1], | 432 float efw[2][PART_LEN1], |
| 428 float comfortNoiseHband[2][PART_LEN1], | 433 float comfortNoiseHband[2][PART_LEN1], |
| 429 const float* noisePow, | 434 const float* noisePow, |
| 430 const float* lambda) { | 435 const float* lambda) { |
| 431 int i, num; | 436 int i, num; |
| 432 float rand[PART_LEN]; | 437 float rand[PART_LEN]; |
| 433 float noise, noiseAvg, tmp, tmpAvg; | 438 float noise, noiseAvg, tmp, tmpAvg; |
| 434 int16_t randW16[PART_LEN]; | 439 int16_t randW16[PART_LEN]; |
| 435 float u[2][PART_LEN1]; | 440 float u[2][PART_LEN1]; |
| 436 | 441 |
| 437 const float pi2 = 6.28318530717959f; | 442 const float pi2 = 6.28318530717959f; |
| 438 | 443 |
| 439 // Generate a uniform random array on [0 1] | 444 // Generate a uniform random array on [0 1] |
| 440 WebRtcSpl_RandUArray(randW16, PART_LEN, &aec->seed); | 445 WebRtcSpl_RandUArray(randW16, PART_LEN, &aec->seed); |
| 441 for (i = 0; i < PART_LEN; i++) { | 446 for (i = 0; i < PART_LEN; i++) { |
| 442 rand[i] = ((float)randW16[i]) / 32768; | 447 rand[i] = static_cast<float>(randW16[i]) / 32768; |
| 443 } | 448 } |
| 444 | 449 |
| 445 // Reject LF noise | 450 // Reject LF noise |
| 446 u[0][0] = 0; | 451 u[0][0] = 0; |
| 447 u[1][0] = 0; | 452 u[1][0] = 0; |
| 448 for (i = 1; i < PART_LEN1; i++) { | 453 for (i = 1; i < PART_LEN1; i++) { |
| 449 tmp = pi2 * rand[i - 1]; | 454 tmp = pi2 * rand[i - 1]; |
| 450 | 455 |
| 451 noise = sqrtf(noisePow[i]); | 456 noise = sqrtf(noisePow[i]); |
| 452 u[0][i] = noise * cosf(tmp); | 457 u[0][i] = noise * cosf(tmp); |
| 453 u[1][i] = -noise * sinf(tmp); | 458 u[1][i] = -noise * sinf(tmp); |
| 454 } | 459 } |
| 455 u[1][PART_LEN] = 0; | 460 u[1][PART_LEN] = 0; |
| 456 | 461 |
| 457 for (i = 0; i < PART_LEN1; i++) { | 462 for (i = 0; i < PART_LEN1; i++) { |
| 458 // This is the proper weighting to match the background noise power | 463 // This is the proper weighting to match the background noise power |
| 459 tmp = sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0)); | 464 tmp = sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0)); |
| 460 // tmp = 1 - lambda[i]; | 465 // tmp = 1 - lambda[i]; |
| 461 efw[0][i] += tmp * u[0][i]; | 466 efw[0][i] += tmp * u[0][i]; |
| 462 efw[1][i] += tmp * u[1][i]; | 467 efw[1][i] += tmp * u[1][i]; |
| 463 } | 468 } |
| 464 | 469 |
| 465 // For H band comfort noise | 470 // For H band comfort noise |
| 466 // TODO: don't compute noise and "tmp" twice. Use the previous results. | 471 // TODO(peah): don't compute noise and "tmp" twice. Use the previous results. |
| 467 noiseAvg = 0.0; | 472 noiseAvg = 0.0; |
| 468 tmpAvg = 0.0; | 473 tmpAvg = 0.0; |
| 469 num = 0; | 474 num = 0; |
| 470 if (aec->num_bands > 1) { | 475 if (aec->num_bands > 1) { |
| 471 // average noise scale | 476 // average noise scale |
| 472 // average over second half of freq spectrum (i.e., 4->8khz) | 477 // average over second half of freq spectrum (i.e., 4->8khz) |
| 473 // TODO: we shouldn't need num. We know how many elements we're summing. | 478 // TODO(peah): we shouldn't need num. We know how many elements we're |
| 479 // summing. |
| 474 for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) { | 480 for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) { |
| 475 num++; | 481 num++; |
| 476 noiseAvg += sqrtf(noisePow[i]); | 482 noiseAvg += sqrtf(noisePow[i]); |
| 477 } | 483 } |
| 478 noiseAvg /= (float)num; | 484 noiseAvg /= static_cast<float>(num); |
| 479 | 485 |
| 480 // average nlp scale | 486 // average nlp scale |
| 481 // average over second half of freq spectrum (i.e., 4->8khz) | 487 // average over second half of freq spectrum (i.e., 4->8khz) |
| 482 // TODO: we shouldn't need num. We know how many elements we're summing. | 488 // TODO(peah): we shouldn't need num. We know how many elements |
| 489 // we're summing. |
| 483 num = 0; | 490 num = 0; |
| 484 for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) { | 491 for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) { |
| 485 num++; | 492 num++; |
| 486 tmpAvg += sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0)); | 493 tmpAvg += sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0)); |
| 487 } | 494 } |
| 488 tmpAvg /= (float)num; | 495 tmpAvg /= static_cast<float>(num); |
| 489 | 496 |
| 490 // Use average noise for H band | 497 // Use average noise for H band |
| 491 // TODO: we should probably have a new random vector here. | 498 // TODO(peah): we should probably have a new random vector here. |
| 492 // Reject LF noise | 499 // Reject LF noise |
| 493 u[0][0] = 0; | 500 u[0][0] = 0; |
| 494 u[1][0] = 0; | 501 u[1][0] = 0; |
| 495 for (i = 1; i < PART_LEN1; i++) { | 502 for (i = 1; i < PART_LEN1; i++) { |
| 496 tmp = pi2 * rand[i - 1]; | 503 tmp = pi2 * rand[i - 1]; |
| 497 | 504 |
| 498 // Use average noise for H band | 505 // Use average noise for H band |
| 499 u[0][i] = noiseAvg * (float)cos(tmp); | 506 u[0][i] = noiseAvg * static_cast<float>(cos(tmp)); |
| 500 u[1][i] = -noiseAvg * (float)sin(tmp); | 507 u[1][i] = -noiseAvg * static_cast<float>(sin(tmp)); |
| 501 } | 508 } |
| 502 u[1][PART_LEN] = 0; | 509 u[1][PART_LEN] = 0; |
| 503 | 510 |
| 504 for (i = 0; i < PART_LEN1; i++) { | 511 for (i = 0; i < PART_LEN1; i++) { |
| 505 // Use average NLP weight for H band | 512 // Use average NLP weight for H band |
| 506 comfortNoiseHband[0][i] = tmpAvg * u[0][i]; | 513 comfortNoiseHband[0][i] = tmpAvg * u[0][i]; |
| 507 comfortNoiseHband[1][i] = tmpAvg * u[1][i]; | 514 comfortNoiseHband[1][i] = tmpAvg * u[1][i]; |
| 508 } | 515 } |
| 509 } else { | 516 } else { |
| 510 memset(comfortNoiseHband, 0, | 517 memset(comfortNoiseHband, 0, |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 if ((aec->stateCounter > (0.5f * countLen * subCountLen)) && | 621 if ((aec->stateCounter > (0.5f * countLen * subCountLen)) && |
| 615 (aec->farlevel.sfrcounter == 0) | 622 (aec->farlevel.sfrcounter == 0) |
| 616 | 623 |
| 617 // Estimate in active far-end segments only | 624 // Estimate in active far-end segments only |
| 618 && (aec->farlevel.averagelevel > | 625 && (aec->farlevel.averagelevel > |
| 619 (actThreshold * aec->farlevel.minlevel))) { | 626 (actThreshold * aec->farlevel.minlevel))) { |
| 620 // Subtract noise power | 627 // Subtract noise power |
| 621 echo = aec->nearlevel.averagelevel - safety * aec->nearlevel.minlevel; | 628 echo = aec->nearlevel.averagelevel - safety * aec->nearlevel.minlevel; |
| 622 | 629 |
| 623 // ERL | 630 // ERL |
| 624 dtmp = 10 * (float)log10(aec->farlevel.averagelevel / | 631 dtmp = 10 * static_cast<float>(log10(aec->farlevel.averagelevel / |
| 625 aec->nearlevel.averagelevel + | 632 aec->nearlevel.averagelevel + |
| 626 1e-10f); | 633 1e-10f)); |
| 627 dtmp2 = 10 * (float)log10(aec->farlevel.averagelevel / echo + 1e-10f); | 634 dtmp2 = 10 * static_cast<float>(log10(aec->farlevel.averagelevel / |
| 635 echo + |
| 636 1e-10f)); |
| 628 | 637 |
| 629 aec->erl.instant = dtmp; | 638 aec->erl.instant = dtmp; |
| 630 if (dtmp > aec->erl.max) { | 639 if (dtmp > aec->erl.max) { |
| 631 aec->erl.max = dtmp; | 640 aec->erl.max = dtmp; |
| 632 } | 641 } |
| 633 | 642 |
| 634 if (dtmp < aec->erl.min) { | 643 if (dtmp < aec->erl.min) { |
| 635 aec->erl.min = dtmp; | 644 aec->erl.min = dtmp; |
| 636 } | 645 } |
| 637 | 646 |
| 638 aec->erl.counter++; | 647 aec->erl.counter++; |
| 639 aec->erl.sum += dtmp; | 648 aec->erl.sum += dtmp; |
| 640 aec->erl.average = aec->erl.sum / aec->erl.counter; | 649 aec->erl.average = aec->erl.sum / aec->erl.counter; |
| 641 | 650 |
| 642 // Upper mean | 651 // Upper mean |
| 643 if (dtmp > aec->erl.average) { | 652 if (dtmp > aec->erl.average) { |
| 644 aec->erl.hicounter++; | 653 aec->erl.hicounter++; |
| 645 aec->erl.hisum += dtmp; | 654 aec->erl.hisum += dtmp; |
| 646 aec->erl.himean = aec->erl.hisum / aec->erl.hicounter; | 655 aec->erl.himean = aec->erl.hisum / aec->erl.hicounter; |
| 647 } | 656 } |
| 648 | 657 |
| 649 // A_NLP | 658 // A_NLP |
| 650 dtmp = 10 * (float)log10(aec->nearlevel.averagelevel / | 659 dtmp = 10 * static_cast<float>(log10(aec->nearlevel.averagelevel / |
| 651 aec->linoutlevel.averagelevel + 1e-10f); | 660 aec->linoutlevel.averagelevel + |
| 661 1e-10f)); |
| 652 | 662 |
| 653 // subtract noise power | 663 // subtract noise power |
| 654 suppressedEcho = aec->linoutlevel.averagelevel - | 664 suppressedEcho = aec->linoutlevel.averagelevel - |
| 655 safety * aec->linoutlevel.minlevel; | 665 safety * aec->linoutlevel.minlevel; |
| 656 | 666 |
| 657 dtmp2 = 10 * (float)log10(echo / suppressedEcho + 1e-10f); | 667 dtmp2 = 10 * static_cast<float>(log10(echo / suppressedEcho + 1e-10f)); |
| 658 | 668 |
| 659 aec->aNlp.instant = dtmp2; | 669 aec->aNlp.instant = dtmp2; |
| 660 if (dtmp > aec->aNlp.max) { | 670 if (dtmp > aec->aNlp.max) { |
| 661 aec->aNlp.max = dtmp; | 671 aec->aNlp.max = dtmp; |
| 662 } | 672 } |
| 663 | 673 |
| 664 if (dtmp < aec->aNlp.min) { | 674 if (dtmp < aec->aNlp.min) { |
| 665 aec->aNlp.min = dtmp; | 675 aec->aNlp.min = dtmp; |
| 666 } | 676 } |
| 667 | 677 |
| 668 aec->aNlp.counter++; | 678 aec->aNlp.counter++; |
| 669 aec->aNlp.sum += dtmp; | 679 aec->aNlp.sum += dtmp; |
| 670 aec->aNlp.average = aec->aNlp.sum / aec->aNlp.counter; | 680 aec->aNlp.average = aec->aNlp.sum / aec->aNlp.counter; |
| 671 | 681 |
| 672 // Upper mean | 682 // Upper mean |
| 673 if (dtmp > aec->aNlp.average) { | 683 if (dtmp > aec->aNlp.average) { |
| 674 aec->aNlp.hicounter++; | 684 aec->aNlp.hicounter++; |
| 675 aec->aNlp.hisum += dtmp; | 685 aec->aNlp.hisum += dtmp; |
| 676 aec->aNlp.himean = aec->aNlp.hisum / aec->aNlp.hicounter; | 686 aec->aNlp.himean = aec->aNlp.hisum / aec->aNlp.hicounter; |
| 677 } | 687 } |
| 678 | 688 |
| 679 // ERLE | 689 // ERLE |
| 680 | 690 |
| 681 // subtract noise power | 691 // subtract noise power |
| 682 suppressedEcho = 2 * (aec->nlpoutlevel.averagelevel - | 692 suppressedEcho = 2 * (aec->nlpoutlevel.averagelevel - |
| 683 safety * aec->nlpoutlevel.minlevel); | 693 safety * aec->nlpoutlevel.minlevel); |
| 684 | 694 |
| 685 dtmp = 10 * (float)log10(aec->nearlevel.averagelevel / | 695 dtmp = 10 * static_cast<float>(log10(aec->nearlevel.averagelevel / |
| 686 (2 * aec->nlpoutlevel.averagelevel) + | 696 (2 * aec->nlpoutlevel.averagelevel) + |
| 687 1e-10f); | 697 1e-10f)); |
| 688 dtmp2 = 10 * (float)log10(echo / suppressedEcho + 1e-10f); | 698 dtmp2 = 10 * static_cast<float>(log10(echo / suppressedEcho + 1e-10f)); |
| 689 | 699 |
| 690 dtmp = dtmp2; | 700 dtmp = dtmp2; |
| 691 aec->erle.instant = dtmp; | 701 aec->erle.instant = dtmp; |
| 692 if (dtmp > aec->erle.max) { | 702 if (dtmp > aec->erle.max) { |
| 693 aec->erle.max = dtmp; | 703 aec->erle.max = dtmp; |
| 694 } | 704 } |
| 695 | 705 |
| 696 if (dtmp < aec->erle.min) { | 706 if (dtmp < aec->erle.min) { |
| 697 aec->erle.min = dtmp; | 707 aec->erle.min = dtmp; |
| 698 } | 708 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 744 } | 754 } |
| 745 } | 755 } |
| 746 // Account for lookahead. | 756 // Account for lookahead. |
| 747 self->delay_median = (median - lookahead) * kMsPerBlock; | 757 self->delay_median = (median - lookahead) * kMsPerBlock; |
| 748 | 758 |
| 749 // Calculate the L1 norm, with median value as central moment. | 759 // Calculate the L1 norm, with median value as central moment. |
| 750 for (i = 0; i < kHistorySizeBlocks; i++) { | 760 for (i = 0; i < kHistorySizeBlocks; i++) { |
| 751 l1_norm += abs(i - median) * self->delay_histogram[i]; | 761 l1_norm += abs(i - median) * self->delay_histogram[i]; |
| 752 } | 762 } |
| 753 self->delay_std = | 763 self->delay_std = |
| 754 (int)((l1_norm + self->num_delay_values / 2) / self->num_delay_values) * | 764 static_cast<int>((l1_norm + self->num_delay_values / 2) / |
| 755 kMsPerBlock; | 765 self->num_delay_values) * kMsPerBlock; |
| 756 | 766 |
| 757 // Determine fraction of delays that are out of bounds, that is, either | 767 // Determine fraction of delays that are out of bounds, that is, either |
| 758 // negative (anti-causal system) or larger than the AEC filter length. | 768 // negative (anti-causal system) or larger than the AEC filter length. |
| 759 { | 769 { |
| 760 int num_delays_out_of_bounds = self->num_delay_values; | 770 int num_delays_out_of_bounds = self->num_delay_values; |
| 761 const int histogram_length = | 771 const int histogram_length = |
| 762 sizeof(self->delay_histogram) / sizeof(self->delay_histogram[0]); | 772 sizeof(self->delay_histogram) / sizeof(self->delay_histogram[0]); |
| 763 for (i = lookahead; i < lookahead + self->num_partitions; ++i) { | 773 for (i = lookahead; i < lookahead + self->num_partitions; ++i) { |
| 764 if (i < histogram_length) | 774 if (i < histogram_length) |
| 765 num_delays_out_of_bounds -= self->delay_histogram[i]; | 775 num_delays_out_of_bounds -= self->delay_histogram[i]; |
| 766 } | 776 } |
| 767 self->fraction_poor_delays = | 777 self->fraction_poor_delays = |
| 768 (float)num_delays_out_of_bounds / self->num_delay_values; | 778 static_cast<float>(num_delays_out_of_bounds) / self->num_delay_values; |
| 769 } | 779 } |
| 770 | 780 |
| 771 // Reset histogram. | 781 // Reset histogram. |
| 772 memset(self->delay_histogram, 0, sizeof(self->delay_histogram)); | 782 memset(self->delay_histogram, 0, sizeof(self->delay_histogram)); |
| 773 self->num_delay_values = 0; | 783 self->num_delay_values = 0; |
| 774 | 784 |
| 775 return; | 785 return; |
| 776 } | 786 } |
| 777 | 787 |
| 778 static void ScaledInverseFft(float freq_data[2][PART_LEN1], | 788 static void ScaledInverseFft(float freq_data[2][PART_LEN1], |
| 779 float time_data[PART_LEN2], | 789 float time_data[PART_LEN2], |
| 780 float scale, | 790 float scale, |
| 781 int conjugate) { | 791 int conjugate) { |
| 782 int i; | 792 int i; |
| 783 const float normalization = scale / ((float)PART_LEN2); | 793 const float normalization = scale / static_cast<float>(PART_LEN2); |
| 784 const float sign = (conjugate ? -1 : 1); | 794 const float sign = (conjugate ? -1 : 1); |
| 785 time_data[0] = freq_data[0][0] * normalization; | 795 time_data[0] = freq_data[0][0] * normalization; |
| 786 time_data[1] = freq_data[0][PART_LEN] * normalization; | 796 time_data[1] = freq_data[0][PART_LEN] * normalization; |
| 787 for (i = 1; i < PART_LEN; i++) { | 797 for (i = 1; i < PART_LEN; i++) { |
| 788 time_data[2 * i] = freq_data[0][i] * normalization; | 798 time_data[2 * i] = freq_data[0][i] * normalization; |
| 789 time_data[2 * i + 1] = sign * freq_data[1][i] * normalization; | 799 time_data[2 * i + 1] = sign * freq_data[1][i] * normalization; |
| 790 } | 800 } |
| 791 aec_rdft_inverse_128(time_data); | 801 aec_rdft_inverse_128(time_data); |
| 792 } | 802 } |
| 793 | 803 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 self->delay_quality_threshold)) { | 847 self->delay_quality_threshold)) { |
| 838 int delay = last_delay - WebRtc_lookahead(self->delay_estimator); | 848 int delay = last_delay - WebRtc_lookahead(self->delay_estimator); |
| 839 // Allow for a slack in the actual delay, defined by a |lower_bound| and an | 849 // Allow for a slack in the actual delay, defined by a |lower_bound| and an |
| 840 // |upper_bound|. The adaptive echo cancellation filter is currently | 850 // |upper_bound|. The adaptive echo cancellation filter is currently |
| 841 // |num_partitions| (of 64 samples) long. If the delay estimate is negative | 851 // |num_partitions| (of 64 samples) long. If the delay estimate is negative |
| 842 // or at least 3/4 of the filter length we open up for correction. | 852 // or at least 3/4 of the filter length we open up for correction. |
| 843 const int lower_bound = 0; | 853 const int lower_bound = 0; |
| 844 const int upper_bound = self->num_partitions * 3 / 4; | 854 const int upper_bound = self->num_partitions * 3 / 4; |
| 845 const int do_correction = delay <= lower_bound || delay > upper_bound; | 855 const int do_correction = delay <= lower_bound || delay > upper_bound; |
| 846 if (do_correction == 1) { | 856 if (do_correction == 1) { |
| 847 int available_read = (int)WebRtc_available_read(self->far_time_buf); | 857 int available_read = |
| 858 static_cast<int>(WebRtc_available_read(self->far_time_buf)); |
| 848 // With |shift_offset| we gradually rely on the delay estimates. For | 859 // With |shift_offset| we gradually rely on the delay estimates. For |
| 849 // positive delays we reduce the correction by |shift_offset| to lower the | 860 // positive delays we reduce the correction by |shift_offset| to lower the |
| 850 // risk of pushing the AEC into a non causal state. For negative delays | 861 // risk of pushing the AEC into a non causal state. For negative delays |
| 851 // we rely on the values up to a rounding error, hence compensate by 1 | 862 // we rely on the values up to a rounding error, hence compensate by 1 |
| 852 // element to make sure to push the delay into the causal region. | 863 // element to make sure to push the delay into the causal region. |
| 853 delay_correction = -delay; | 864 delay_correction = -delay; |
| 854 delay_correction += delay > self->shift_offset ? self->shift_offset : 1; | 865 delay_correction += delay > self->shift_offset ? self->shift_offset : 1; |
| 855 self->shift_offset--; | 866 self->shift_offset--; |
| 856 self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset); | 867 self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset); |
| 857 if (delay_correction > available_read - self->mult - 1) { | 868 if (delay_correction > available_read - self->mult - 1) { |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1072 memcpy(hNl, cohde, sizeof(hNl)); | 1083 memcpy(hNl, cohde, sizeof(hNl)); |
| 1073 hNlFb = hNlDeAvg; | 1084 hNlFb = hNlDeAvg; |
| 1074 hNlFbLow = hNlDeAvg; | 1085 hNlFbLow = hNlDeAvg; |
| 1075 } else { | 1086 } else { |
| 1076 aec->echoState = 1; | 1087 aec->echoState = 1; |
| 1077 for (i = 0; i < PART_LEN1; i++) { | 1088 for (i = 0; i < PART_LEN1; i++) { |
| 1078 hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]); | 1089 hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]); |
| 1079 } | 1090 } |
| 1080 | 1091 |
| 1081 // Select an order statistic from the preferred bands. | 1092 // Select an order statistic from the preferred bands. |
| 1082 // TODO: Using quicksort now, but a selection algorithm may be preferred. | 1093 // TODO(peah): Using quicksort now, but a selection algorithm may be |
| 1094 // preferred. |
| 1083 memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize); | 1095 memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize); |
| 1084 qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat); | 1096 qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat); |
| 1085 hNlFb = hNlPref[(int)floor(prefBandQuant * (prefBandSize - 1))]; | 1097 hNlFb = hNlPref[static_cast<int>(floor(prefBandQuant * |
| 1086 hNlFbLow = hNlPref[(int)floor(prefBandQuantLow * (prefBandSize - 1))]; | 1098 (prefBandSize - 1)))]; |
| 1099 hNlFbLow = hNlPref[static_cast<int>(floor(prefBandQuantLow * |
| 1100 (prefBandSize - 1)))]; |
| 1087 } | 1101 } |
| 1088 } | 1102 } |
| 1089 | 1103 |
| 1090 // Track the local filter minimum to determine suppression overdrive. | 1104 // Track the local filter minimum to determine suppression overdrive. |
| 1091 if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) { | 1105 if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) { |
| 1092 aec->hNlFbLocalMin = hNlFbLow; | 1106 aec->hNlFbLocalMin = hNlFbLow; |
| 1093 aec->hNlFbMin = hNlFbLow; | 1107 aec->hNlFbMin = hNlFbLow; |
| 1094 aec->hNlNewMin = 1; | 1108 aec->hNlNewMin = 1; |
| 1095 aec->hNlMinCtr = 0; | 1109 aec->hNlMinCtr = 0; |
| 1096 } | 1110 } |
| 1097 aec->hNlFbLocalMin = | 1111 aec->hNlFbLocalMin = |
| 1098 WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1); | 1112 WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1); |
| 1099 aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1); | 1113 aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1); |
| 1100 | 1114 |
| 1101 if (aec->hNlNewMin == 1) { | 1115 if (aec->hNlNewMin == 1) { |
| 1102 aec->hNlMinCtr++; | 1116 aec->hNlMinCtr++; |
| 1103 } | 1117 } |
| 1104 if (aec->hNlMinCtr == 2) { | 1118 if (aec->hNlMinCtr == 2) { |
| 1105 aec->hNlNewMin = 0; | 1119 aec->hNlNewMin = 0; |
| 1106 aec->hNlMinCtr = 0; | 1120 aec->hNlMinCtr = 0; |
| 1107 aec->overDrive = | 1121 aec->overDrive = |
| 1108 WEBRTC_SPL_MAX(kTargetSupp[aec->nlp_mode] / | 1122 WEBRTC_SPL_MAX(kTargetSupp[aec->nlp_mode] / |
| 1109 ((float)log(aec->hNlFbMin + 1e-10f) + 1e-10f), | 1123 static_cast<float>(log(aec->hNlFbMin + 1e-10f) + 1e-10f), |
| 1110 min_overdrive[aec->nlp_mode]); | 1124 min_overdrive[aec->nlp_mode]); |
| 1111 } | 1125 } |
| 1112 | 1126 |
| 1113 // Smooth the overdrive. | 1127 // Smooth the overdrive. |
| 1114 if (aec->overDrive < aec->overDriveSm) { | 1128 if (aec->overDrive < aec->overDriveSm) { |
| 1115 aec->overDriveSm = 0.99f * aec->overDriveSm + 0.01f * aec->overDrive; | 1129 aec->overDriveSm = 0.99f * aec->overDriveSm + 0.01f * aec->overDrive; |
| 1116 } else { | 1130 } else { |
| 1117 aec->overDriveSm = 0.9f * aec->overDriveSm + 0.1f * aec->overDrive; | 1131 aec->overDriveSm = 0.9f * aec->overDriveSm + 0.1f * aec->overDrive; |
| 1118 } | 1132 } |
| 1119 | 1133 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1218 float outputH[NUM_HIGH_BANDS_MAX][PART_LEN]; | 1232 float outputH[NUM_HIGH_BANDS_MAX][PART_LEN]; |
| 1219 float* outputH_ptr[NUM_HIGH_BANDS_MAX]; | 1233 float* outputH_ptr[NUM_HIGH_BANDS_MAX]; |
| 1220 float* x_fft_ptr = NULL; | 1234 float* x_fft_ptr = NULL; |
| 1221 | 1235 |
| 1222 for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { | 1236 for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
| 1223 outputH_ptr[i] = outputH[i]; | 1237 outputH_ptr[i] = outputH[i]; |
| 1224 } | 1238 } |
| 1225 | 1239 |
| 1226 // Concatenate old and new nearend blocks. | 1240 // Concatenate old and new nearend blocks. |
| 1227 for (i = 0; i < aec->num_bands - 1; ++i) { | 1241 for (i = 0; i < aec->num_bands - 1; ++i) { |
| 1228 WebRtc_ReadBuffer(aec->nearFrBufH[i], (void**)&nearend_ptr, nearend, | 1242 WebRtc_ReadBuffer(aec->nearFrBufH[i], |
| 1229 PART_LEN); | 1243 reinterpret_cast<void**>(&nearend_ptr), |
| 1244 nearend, PART_LEN); |
| 1230 memcpy(aec->dBufH[i] + PART_LEN, nearend_ptr, sizeof(nearend)); | 1245 memcpy(aec->dBufH[i] + PART_LEN, nearend_ptr, sizeof(nearend)); |
| 1231 } | 1246 } |
| 1232 WebRtc_ReadBuffer(aec->nearFrBuf, (void**)&nearend_ptr, nearend, PART_LEN); | 1247 WebRtc_ReadBuffer(aec->nearFrBuf, reinterpret_cast<void**>(&nearend_ptr), |
| 1248 nearend, PART_LEN); |
| 1233 memcpy(aec->dBuf + PART_LEN, nearend_ptr, sizeof(nearend)); | 1249 memcpy(aec->dBuf + PART_LEN, nearend_ptr, sizeof(nearend)); |
| 1234 | 1250 |
| 1235 // We should always have at least one element stored in |far_buf|. | 1251 // We should always have at least one element stored in |far_buf|. |
| 1236 assert(WebRtc_available_read(aec->far_time_buf) > 0); | 1252 assert(WebRtc_available_read(aec->far_time_buf) > 0); |
| 1237 WebRtc_ReadBuffer(aec->far_time_buf, (void**)&farend_ptr, farend, 1); | 1253 WebRtc_ReadBuffer(aec->far_time_buf, reinterpret_cast<void**>(&farend_ptr), |
| 1254 farend, 1); |
| 1238 | 1255 |
| 1239 #ifdef WEBRTC_AEC_DEBUG_DUMP | 1256 #ifdef WEBRTC_AEC_DEBUG_DUMP |
| 1240 { | 1257 { |
| 1241 // TODO(minyue): |farend_ptr| starts from buffered samples. This will be | 1258 // TODO(minyue): |farend_ptr| starts from buffered samples. This will be |
| 1242 // modified when |aec->far_time_buf| is revised. | 1259 // modified when |aec->far_time_buf| is revised. |
| 1243 RTC_AEC_DEBUG_WAV_WRITE(aec->farFile, &farend_ptr[PART_LEN], PART_LEN); | 1260 RTC_AEC_DEBUG_WAV_WRITE(aec->farFile, &farend_ptr[PART_LEN], PART_LEN); |
| 1244 | 1261 |
| 1245 RTC_AEC_DEBUG_WAV_WRITE(aec->nearFile, nearend_ptr, PART_LEN); | 1262 RTC_AEC_DEBUG_WAV_WRITE(aec->nearFile, nearend_ptr, PART_LEN); |
| 1246 } | 1263 } |
| 1247 #endif | 1264 #endif |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1349 // For high bands | 1366 // For high bands |
| 1350 for (i = 0; i < aec->num_bands - 1; ++i) { | 1367 for (i = 0; i < aec->num_bands - 1; ++i) { |
| 1351 WebRtc_WriteBuffer(aec->outFrBufH[i], outputH[i], PART_LEN); | 1368 WebRtc_WriteBuffer(aec->outFrBufH[i], outputH[i], PART_LEN); |
| 1352 } | 1369 } |
| 1353 | 1370 |
| 1354 RTC_AEC_DEBUG_WAV_WRITE(aec->outFile, output, PART_LEN); | 1371 RTC_AEC_DEBUG_WAV_WRITE(aec->outFile, output, PART_LEN); |
| 1355 } | 1372 } |
| 1356 | 1373 |
| 1357 AecCore* WebRtcAec_CreateAec() { | 1374 AecCore* WebRtcAec_CreateAec() { |
| 1358 int i; | 1375 int i; |
| 1359 AecCore* aec = malloc(sizeof(AecCore)); | 1376 AecCore* aec = reinterpret_cast<AecCore*>(malloc(sizeof(AecCore))); |
| 1360 if (!aec) { | 1377 if (!aec) { |
| 1361 return NULL; | 1378 return NULL; |
| 1362 } | 1379 } |
| 1363 | 1380 |
| 1364 aec->nearFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); | 1381 aec->nearFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); |
| 1365 if (!aec->nearFrBuf) { | 1382 if (!aec->nearFrBuf) { |
| 1366 WebRtcAec_FreeAec(aec); | 1383 WebRtcAec_FreeAec(aec); |
| 1367 return NULL; | 1384 return NULL; |
| 1368 } | 1385 } |
| 1369 | 1386 |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1578 | 1595 |
| 1579 // Default target suppression mode. | 1596 // Default target suppression mode. |
| 1580 aec->nlp_mode = 1; | 1597 aec->nlp_mode = 1; |
| 1581 | 1598 |
| 1582 // Sampling frequency multiplier w.r.t. 8 kHz. | 1599 // Sampling frequency multiplier w.r.t. 8 kHz. |
| 1583 // In case of multiple bands we process the lower band in 16 kHz, hence the | 1600 // In case of multiple bands we process the lower band in 16 kHz, hence the |
| 1584 // multiplier is always 2. | 1601 // multiplier is always 2. |
| 1585 if (aec->num_bands > 1) { | 1602 if (aec->num_bands > 1) { |
| 1586 aec->mult = 2; | 1603 aec->mult = 2; |
| 1587 } else { | 1604 } else { |
| 1588 aec->mult = (short)aec->sampFreq / 8000; | 1605 aec->mult = static_cast<int16_t>(aec->sampFreq) / 8000; |
| 1589 } | 1606 } |
| 1590 | 1607 |
| 1591 aec->farBufWritePos = 0; | 1608 aec->farBufWritePos = 0; |
| 1592 aec->farBufReadPos = 0; | 1609 aec->farBufReadPos = 0; |
| 1593 | 1610 |
| 1594 aec->inSamples = 0; | 1611 aec->inSamples = 0; |
| 1595 aec->outSamples = 0; | 1612 aec->outSamples = 0; |
| 1596 aec->knownDelay = 0; | 1613 aec->knownDelay = 0; |
| 1597 | 1614 |
| 1598 // Initialize buffers | 1615 // Initialize buffers |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1609 aec->noisePow = aec->dInitMinPow; | 1626 aec->noisePow = aec->dInitMinPow; |
| 1610 aec->noiseEstCtr = 0; | 1627 aec->noiseEstCtr = 0; |
| 1611 | 1628 |
| 1612 // Initial comfort noise power | 1629 // Initial comfort noise power |
| 1613 for (i = 0; i < PART_LEN1; i++) { | 1630 for (i = 0; i < PART_LEN1; i++) { |
| 1614 aec->dMinPow[i] = 1.0e6f; | 1631 aec->dMinPow[i] = 1.0e6f; |
| 1615 } | 1632 } |
| 1616 | 1633 |
| 1617 // Holds the last block written to | 1634 // Holds the last block written to |
| 1618 aec->xfBufBlockPos = 0; | 1635 aec->xfBufBlockPos = 0; |
| 1619 // TODO: Investigate need for these initializations. Deleting them doesn't | 1636 // TODO(peah): Investigate need for these initializations. Deleting them |
| 1620 // change the output at all and yields 0.4% overall speedup. | 1637 // doesn't change the output at all and yields 0.4% overall speedup. |
| 1621 memset(aec->xfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1); | 1638 memset(aec->xfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1); |
| 1622 memset(aec->wfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1); | 1639 memset(aec->wfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1); |
| 1623 memset(aec->sde, 0, sizeof(complex_t) * PART_LEN1); | 1640 memset(aec->sde, 0, sizeof(complex_t) * PART_LEN1); |
| 1624 memset(aec->sxd, 0, sizeof(complex_t) * PART_LEN1); | 1641 memset(aec->sxd, 0, sizeof(complex_t) * PART_LEN1); |
| 1625 memset(aec->xfwBuf, 0, | 1642 memset(aec->xfwBuf, 0, |
| 1626 sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1); | 1643 sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1); |
| 1627 memset(aec->se, 0, sizeof(float) * PART_LEN1); | 1644 memset(aec->se, 0, sizeof(float) * PART_LEN1); |
| 1628 | 1645 |
| 1629 // To prevent numerical instability in the first block. | 1646 // To prevent numerical instability in the first block. |
| 1630 for (i = 0; i < PART_LEN1; i++) { | 1647 for (i = 0; i < PART_LEN1; i++) { |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1775 while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) { | 1792 while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) { |
| 1776 ProcessBlock(aec); | 1793 ProcessBlock(aec); |
| 1777 } | 1794 } |
| 1778 | 1795 |
| 1779 // 5) Update system delay with respect to the entire frame. | 1796 // 5) Update system delay with respect to the entire frame. |
| 1780 aec->system_delay -= FRAME_LEN; | 1797 aec->system_delay -= FRAME_LEN; |
| 1781 | 1798 |
| 1782 // 6) Update output frame. | 1799 // 6) Update output frame. |
| 1783 // Stuff the out buffer if we have less than a frame to output. | 1800 // Stuff the out buffer if we have less than a frame to output. |
| 1784 // This should only happen for the first frame. | 1801 // This should only happen for the first frame. |
| 1785 out_elements = (int)WebRtc_available_read(aec->outFrBuf); | 1802 out_elements = static_cast<int>(WebRtc_available_read(aec->outFrBuf)); |
| 1786 if (out_elements < FRAME_LEN) { | 1803 if (out_elements < FRAME_LEN) { |
| 1787 WebRtc_MoveReadPtr(aec->outFrBuf, out_elements - FRAME_LEN); | 1804 WebRtc_MoveReadPtr(aec->outFrBuf, out_elements - FRAME_LEN); |
| 1788 for (i = 0; i < num_bands - 1; ++i) { | 1805 for (i = 0; i < num_bands - 1; ++i) { |
| 1789 WebRtc_MoveReadPtr(aec->outFrBufH[i], out_elements - FRAME_LEN); | 1806 WebRtc_MoveReadPtr(aec->outFrBufH[i], out_elements - FRAME_LEN); |
| 1790 } | 1807 } |
| 1791 } | 1808 } |
| 1792 // Obtain an output frame. | 1809 // Obtain an output frame. |
| 1793 WebRtc_ReadBuffer(aec->outFrBuf, NULL, &out[0][j], FRAME_LEN); | 1810 WebRtc_ReadBuffer(aec->outFrBuf, NULL, &out[0][j], FRAME_LEN); |
| 1794 // For H bands. | 1811 // For H bands. |
| 1795 for (i = 1; i < num_bands; ++i) { | 1812 for (i = 1; i < num_bands; ++i) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1887 } | 1904 } |
| 1888 | 1905 |
| 1889 int WebRtcAec_system_delay(AecCore* self) { | 1906 int WebRtcAec_system_delay(AecCore* self) { |
| 1890 return self->system_delay; | 1907 return self->system_delay; |
| 1891 } | 1908 } |
| 1892 | 1909 |
| 1893 void WebRtcAec_SetSystemDelay(AecCore* self, int delay) { | 1910 void WebRtcAec_SetSystemDelay(AecCore* self, int delay) { |
| 1894 assert(delay >= 0); | 1911 assert(delay >= 0); |
| 1895 self->system_delay = delay; | 1912 self->system_delay = delay; |
| 1896 } | 1913 } |
| OLD | NEW |