| Index: webrtc/modules/audio_processing/aec/aec_core.cc
|
| diff --git a/webrtc/modules/audio_processing/aec/aec_core.cc b/webrtc/modules/audio_processing/aec/aec_core.cc
|
| index 4b5abedd5aa7694172fe773438fcc0822dc08ee9..f13cf94c2bc1cbe66f0e0ec84a79ca2a10434661 100644
|
| --- a/webrtc/modules/audio_processing/aec/aec_core.cc
|
| +++ b/webrtc/modules/audio_processing/aec/aec_core.cc
|
| @@ -25,6 +25,7 @@
|
| #include <stdlib.h>
|
| #include <string.h>
|
|
|
| +#include "webrtc/base/checks.h"
|
| extern "C" {
|
| #include "webrtc/common_audio/ring_buffer.h"
|
| }
|
| @@ -238,15 +239,10 @@ static void FilterFar(int num_partitions,
|
| }
|
| }
|
|
|
| -static void ScaleErrorSignal(int extended_filter_enabled,
|
| - float normal_mu,
|
| - float normal_error_threshold,
|
| +static void ScaleErrorSignal(float mu,
|
| + float error_threshold,
|
| float x_pow[PART_LEN1],
|
| float ef[2][PART_LEN1]) {
|
| - const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
|
| - const float error_threshold = extended_filter_enabled
|
| - ? kExtendedErrorThreshold
|
| - : normal_error_threshold;
|
| int i;
|
| float abs_ef;
|
| for (i = 0; i < (PART_LEN1); i++) {
|
| @@ -936,11 +932,38 @@ static int SignalBasedDelayCorrection(AecCore* self) {
|
| return delay_correction;
|
| }
|
|
|
| +static void RegressorPower(int num_partitions,
|
| + int latest_added_partition,
|
| + float x_fft_buf[2]
|
| + [kExtendedNumPartitions * PART_LEN1],
|
| + float x_pow[PART_LEN1]) {
|
| + RTC_DCHECK_LT(latest_added_partition, num_partitions);
|
| + memset(x_pow, 0, PART_LEN1 * sizeof(x_pow[0]));
|
| +
|
| + int partition = latest_added_partition;
|
| + int x_fft_buf_position = partition * PART_LEN1;
|
| + for (int i = 0; i < num_partitions; ++i) {
|
| + for (int bin = 0; bin < PART_LEN1; ++bin) {
|
| + float re = x_fft_buf[0][x_fft_buf_position];
|
| + float im = x_fft_buf[1][x_fft_buf_position];
|
| + x_pow[bin] += re * re + im * im;
|
| + ++x_fft_buf_position;
|
| + }
|
| +
|
| + ++partition;
|
| + if (partition == num_partitions) {
|
| + partition = 0;
|
| + RTC_DCHECK_EQ(num_partitions * PART_LEN1, x_fft_buf_position);
|
| + x_fft_buf_position = 0;
|
| + }
|
| + }
|
| +}
|
| +
|
| static void EchoSubtraction(AecCore* aec,
|
| int num_partitions,
|
| int extended_filter_enabled,
|
| - float normal_mu,
|
| - float normal_error_threshold,
|
| + float filter_step_size,
|
| + float error_threshold,
|
| float* x_fft,
|
| int* x_fft_buf_block_pos,
|
| float x_fft_buf[2]
|
| @@ -1001,8 +1024,7 @@ static void EchoSubtraction(AecCore* aec,
|
| sizeof(e_fft[0][0]) * PART_LEN1 * 2);
|
|
|
| // Scale error signal inversely with far power.
|
| - WebRtcAec_ScaleErrorSignal(extended_filter_enabled, normal_mu,
|
| - normal_error_threshold, x_pow, e_fft);
|
| + WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft);
|
| WebRtcAec_FilterAdaptation(num_partitions, *x_fft_buf_block_pos, x_fft_buf,
|
| e_fft, h_fft_buf);
|
| memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN);
|
| @@ -1315,18 +1337,31 @@ static void ProcessBlock(AecCore* aec) {
|
| memcpy(fft, aec->dBuf, sizeof(float) * PART_LEN2);
|
| Fft(fft, df);
|
|
|
| - // Power smoothing
|
| - for (i = 0; i < PART_LEN1; i++) {
|
| - far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
|
| - (x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]);
|
| - aec->xPow[i] =
|
| - gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
|
| - // Calculate absolute spectra
|
| - abs_far_spectrum[i] = sqrtf(far_spectrum);
|
| + // Power smoothing.
|
| + if (aec->refined_adaptive_filter_enabled) {
|
| + for (i = 0; i < PART_LEN1; ++i) {
|
| + far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
|
| + (x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]);
|
| + // Calculate the magnitude spectrum.
|
| + abs_far_spectrum[i] = sqrtf(far_spectrum);
|
| + }
|
| + RegressorPower(aec->num_partitions, aec->xfBufBlockPos, aec->xfBuf,
|
| + aec->xPow);
|
| + } else {
|
| + for (i = 0; i < PART_LEN1; ++i) {
|
| + far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
|
| + (x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]);
|
| + aec->xPow[i] =
|
| + gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
|
| + // Calculate the magnitude spectrum.
|
| + abs_far_spectrum[i] = sqrtf(far_spectrum);
|
| + }
|
| + }
|
|
|
| + for (i = 0; i < PART_LEN1; ++i) {
|
| near_spectrum = df[0][i] * df[0][i] + df[1][i] * df[1][i];
|
| aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum;
|
| - // Calculate absolute spectra
|
| + // Calculate the magnitude spectrum.
|
| abs_near_spectrum[i] = sqrtf(near_spectrum);
|
| }
|
|
|
| @@ -1379,7 +1414,7 @@ static void ProcessBlock(AecCore* aec) {
|
|
|
| // Perform echo subtraction.
|
| EchoSubtraction(aec, aec->num_partitions, aec->extended_filter_enabled,
|
| - aec->normal_mu, aec->normal_error_threshold, &x_fft[0][0],
|
| + aec->filter_step_size, aec->error_threshold, &x_fft[0][0],
|
| &aec->xfBufBlockPos, aec->xfBuf, nearend_ptr, aec->xPow,
|
| aec->wfBuf, echo_subtractor_output);
|
|
|
| @@ -1485,6 +1520,7 @@ AecCore* WebRtcAec_CreateAec() {
|
| #endif
|
| aec->extended_filter_enabled = 0;
|
| aec->aec3_enabled = 0;
|
| + aec->refined_adaptive_filter_enabled = false;
|
|
|
| // Assembly optimization
|
| WebRtcAec_FilterFar = FilterFar;
|
| @@ -1548,18 +1584,53 @@ void WebRtcAec_FreeAec(AecCore* aec) {
|
| delete aec;
|
| }
|
|
|
| +static void SetAdaptiveFilterStepSize(AecCore* aec) {
|
| + // Extended filter adaptation parameter.
|
| + // TODO(ajm): No narrowband tuning yet.
|
| + const float kExtendedMu = 0.4f;
|
| +
|
| + if (aec->refined_adaptive_filter_enabled) {
|
| + aec->filter_step_size = 0.05f;
|
| + } else {
|
| + if (aec->extended_filter_enabled) {
|
| + aec->filter_step_size = kExtendedMu;
|
| + } else {
|
| + if (aec->sampFreq == 8000) {
|
| + aec->filter_step_size = 0.6f;
|
| + } else {
|
| + aec->filter_step_size = 0.5f;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +static void SetErrorThreshold(AecCore* aec) {
|
| + // Extended filter adaptation parameter.
|
| + // TODO(ajm): No narrowband tuning yet.
|
| + static const float kExtendedErrorThreshold = 1.0e-6f;
|
| +
|
| + if (aec->extended_filter_enabled) {
|
| + aec->error_threshold = kExtendedErrorThreshold;
|
| + } else {
|
| + if (aec->sampFreq == 8000) {
|
| + aec->error_threshold = 2e-6f;
|
| + } else {
|
| + aec->error_threshold = 1.5e-6f;
|
| + }
|
| + }
|
| +}
|
| +
|
| int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
| int i;
|
|
|
| aec->sampFreq = sampFreq;
|
|
|
| + SetAdaptiveFilterStepSize(aec);
|
| + SetErrorThreshold(aec);
|
| +
|
| if (sampFreq == 8000) {
|
| - aec->normal_mu = 0.6f;
|
| - aec->normal_error_threshold = 2e-6f;
|
| aec->num_bands = 1;
|
| } else {
|
| - aec->normal_mu = 0.5f;
|
| - aec->normal_error_threshold = 1.5e-6f;
|
| aec->num_bands = (size_t)(sampFreq / 16000);
|
| }
|
|
|
| @@ -1930,9 +2001,20 @@ int WebRtcAec_aec3_enabled(AecCore* self) {
|
| return self->aec3_enabled;
|
| }
|
|
|
| +void WebRtcAec_enable_refined_adaptive_filter(AecCore* self, bool enable) {
|
| + self->refined_adaptive_filter_enabled = enable;
|
| + SetAdaptiveFilterStepSize(self);
|
| + SetErrorThreshold(self);
|
| +}
|
| +
|
| +bool WebRtcAec_refined_adaptive_filter_enabled(const AecCore* self) {
|
| + return self->refined_adaptive_filter_enabled;
|
| +}
|
|
|
| void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
|
| self->extended_filter_enabled = enable;
|
| + SetAdaptiveFilterStepSize(self);
|
| + SetErrorThreshold(self);
|
| self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
|
| // Update the delay estimator with filter length. See InitAEC() for details.
|
| WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);
|
|
|