Index: webrtc/modules/audio_processing/aec/aec_core.c |
diff --git a/webrtc/modules/audio_processing/aec/aec_core.c b/webrtc/modules/audio_processing/aec/aec_core.c |
index f8eed323720f6593f9513db667465253c19b49e1..a6b9db03da3dafa21536fe686ef773d410534139 100644 |
--- a/webrtc/modules/audio_processing/aec/aec_core.c |
+++ b/webrtc/modules/audio_processing/aec/aec_core.c |
@@ -175,16 +175,20 @@ static void FilterFar(AecCore* aec, float yf[2][PART_LEN1]) { |
} |
} |
-static void ScaleErrorSignal(AecCore* aec, float ef[2][PART_LEN1]) { |
- const float mu = aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu; |
- const float error_threshold = aec->extended_filter_enabled |
+static void ScaleErrorSignal(int extended_filter_enabled, |
+ float normal_mu, |
+ float normal_error_threshold, |
+ float *x_pow, |
+ float ef[2][PART_LEN1]) { |
+ const float mu = extended_filter_enabled ? kExtendedMu : normal_mu; |
+ const float error_threshold = extended_filter_enabled |
? kExtendedErrorThreshold |
- : aec->normal_error_threshold; |
+ : normal_error_threshold; |
int i; |
float abs_ef; |
for (i = 0; i < (PART_LEN1); i++) { |
- ef[0][i] /= (aec->xPow[i] + 1e-10f); |
- ef[1][i] /= (aec->xPow[i] + 1e-10f); |
+ ef[0][i] /= (x_pow[i] + 1e-10f); |
+ ef[1][i] /= (x_pow[i] + 1e-10f); |
abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]); |
if (abs_ef > error_threshold) { |
@@ -837,6 +841,19 @@ static void UpdateDelayMetrics(AecCore* self) { |
return; |
} |
+static void FrequencyToTime(float freq_data[2][PART_LEN1], |
+ float time_data[PART_LEN2]) { |
+ int i; |
+ time_data[0] = freq_data[0][0]; |
+ time_data[1] = freq_data[0][PART_LEN]; |
+ for (i = 1; i < PART_LEN; i++) { |
+ time_data[2 * i] = freq_data[0][i]; |
+ time_data[2 * i + 1] = freq_data[1][i]; |
+ } |
+ aec_rdft_inverse_128(time_data); |
+} |
+ |
+ |
static void TimeToFrequency(float time_data[PART_LEN2], |
float freq_data[2][PART_LEN1], |
int window) { |
@@ -942,9 +959,63 @@ static int SignalBasedDelayCorrection(AecCore* self) { |
return delay_correction; |
} |
-static void NonLinearProcessing(AecCore* aec, |
- float* output, |
- float* const* outputH) { |
+static void EchoSubtraction(AecCore* aec, |
+ float* nearend_ptr) { |
+ float yf[2][PART_LEN1]; |
+ float fft[PART_LEN2]; |
+ float y[PART_LEN]; |
+ float e[PART_LEN]; |
+ float ef[2][PART_LEN1]; |
+ float scale; |
+ int i; |
+ memset(yf, 0, sizeof(yf)); |
+ |
+ // Produce frequency domain echo estimate. |
+ WebRtcAec_FilterFar(aec, yf); |
+ |
+ // Inverse fft to obtain echo estimate and error. |
+ FrequencyToTime(yf, fft); |
+ |
+ // Extract the output signal and compute the time-domain error. |
+ scale = 2.0f / PART_LEN2; |
+ for (i = 0; i < PART_LEN; ++i) { |
+ y[i] = fft[PART_LEN + i] * scale; // fft scaling. |
+ e[i] = nearend_ptr[i] - y[i]; |
+ } |
+ |
+ // Error fft |
+ memcpy(aec->eBuf + PART_LEN, e, sizeof(float) * PART_LEN); |
+ memset(fft, 0, sizeof(float) * PART_LEN); |
+ memcpy(fft + PART_LEN, e, sizeof(float) * PART_LEN); |
+ TimeToFrequency(fft, ef, 0); |
+ |
+ RTC_AEC_DEBUG_RAW_WRITE(aec->e_fft_file, |
+ &ef[0][0], |
+ sizeof(ef[0][0]) * PART_LEN1 * 2); |
+ |
+ if (aec->metricsMode == 1) { |
+ // Note that the first PART_LEN samples in fft (before transformation) are |
+ // zero. Hence, the scaling by two in UpdateLevel() should not be |
+ // performed. That scaling is taken care of in UpdateMetrics() instead. |
+ UpdateLevel(&aec->linoutlevel, ef); |
+ } |
+ |
+ // Scale error signal inversely with far power. |
+ WebRtcAec_ScaleErrorSignal(aec->extended_filter_enabled, |
+ aec->normal_mu, |
+ aec->normal_error_threshold, |
+ aec->xPow, |
+ ef); |
+ WebRtcAec_FilterAdaptation(aec, fft, ef); |
+ |
+ |
+ RTC_AEC_DEBUG_WAV_WRITE(aec->outLinearFile, e, PART_LEN); |
+} |
+ |
+ |
+static void EchoSuppression(AecCore* aec, |
+ float* output, |
+ float* const* outputH) { |
float efw[2][PART_LEN1], xfw[2][PART_LEN1]; |
complex_t comfortNoiseHband[PART_LEN1]; |
float fft[PART_LEN2]; |
@@ -1177,11 +1248,9 @@ static void NonLinearProcessing(AecCore* aec, |
static void ProcessBlock(AecCore* aec) { |
size_t i; |
- float y[PART_LEN], e[PART_LEN]; |
- float scale; |
float fft[PART_LEN2]; |
- float xf[2][PART_LEN1], yf[2][PART_LEN1], ef[2][PART_LEN1]; |
+ float xf[2][PART_LEN1]; |
float df[2][PART_LEN1]; |
float far_spectrum = 0.0f; |
float near_spectrum = 0.0f; |
@@ -1201,12 +1270,12 @@ static void ProcessBlock(AecCore* aec) { |
float output[PART_LEN]; |
float outputH[NUM_HIGH_BANDS_MAX][PART_LEN]; |
float* outputH_ptr[NUM_HIGH_BANDS_MAX]; |
+ float* xf_ptr = NULL; |
+ |
for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
outputH_ptr[i] = outputH[i]; |
} |
- float* xf_ptr = NULL; |
- |
// Concatenate old and new nearend blocks. |
for (i = 0; i < aec->num_bands - 1; ++i) { |
WebRtc_ReadBuffer(aec->nearFrBufH[i], |
@@ -1314,60 +1383,11 @@ static void ProcessBlock(AecCore* aec) { |
&xf_ptr[PART_LEN1], |
sizeof(float) * PART_LEN1); |
- memset(yf, 0, sizeof(yf)); |
- |
- // Filter far |
- WebRtcAec_FilterFar(aec, yf); |
- |
- // Inverse fft to obtain echo estimate and error. |
- fft[0] = yf[0][0]; |
- fft[1] = yf[0][PART_LEN]; |
- for (i = 1; i < PART_LEN; i++) { |
- fft[2 * i] = yf[0][i]; |
- fft[2 * i + 1] = yf[1][i]; |
- } |
- aec_rdft_inverse_128(fft); |
- |
- scale = 2.0f / PART_LEN2; |
- for (i = 0; i < PART_LEN; i++) { |
- y[i] = fft[PART_LEN + i] * scale; // fft scaling |
- } |
- |
- for (i = 0; i < PART_LEN; i++) { |
- e[i] = nearend_ptr[i] - y[i]; |
- } |
- |
- // Error fft |
- memcpy(aec->eBuf + PART_LEN, e, sizeof(float) * PART_LEN); |
- memset(fft, 0, sizeof(float) * PART_LEN); |
- memcpy(fft + PART_LEN, e, sizeof(float) * PART_LEN); |
- // TODO(bjornv): Change to use TimeToFrequency(). |
- aec_rdft_forward_128(fft); |
- |
- ef[1][0] = 0; |
- ef[1][PART_LEN] = 0; |
- ef[0][0] = fft[0]; |
- ef[0][PART_LEN] = fft[1]; |
- for (i = 1; i < PART_LEN; i++) { |
- ef[0][i] = fft[2 * i]; |
- ef[1][i] = fft[2 * i + 1]; |
- } |
- |
- RTC_AEC_DEBUG_RAW_WRITE(aec->e_fft_file, |
- &ef[0][0], |
- sizeof(ef[0][0]) * PART_LEN1 * 2); |
+ // Perform echo subtraction. |
+ EchoSubtraction(aec, nearend_ptr); |
- if (aec->metricsMode == 1) { |
- // Note that the first PART_LEN samples in fft (before transformation) are |
- // zero. Hence, the scaling by two in UpdateLevel() should not be |
- // performed. That scaling is taken care of in UpdateMetrics() instead. |
- UpdateLevel(&aec->linoutlevel, ef); |
- } |
- |
- // Scale error signal inversely with far power. |
- WebRtcAec_ScaleErrorSignal(aec, ef); |
- WebRtcAec_FilterAdaptation(aec, fft, ef); |
- NonLinearProcessing(aec, output, outputH_ptr); |
+ // Perform echo suppression. |
+ EchoSuppression(aec, output, outputH_ptr); |
if (aec->metricsMode == 1) { |
// Update power levels and echo metrics |
@@ -1383,7 +1403,6 @@ static void ProcessBlock(AecCore* aec) { |
WebRtc_WriteBuffer(aec->outFrBufH[i], outputH[i], PART_LEN); |
} |
- RTC_AEC_DEBUG_WAV_WRITE(aec->outLinearFile, e, PART_LEN); |
RTC_AEC_DEBUG_WAV_WRITE(aec->outFile, output, PART_LEN); |
} |