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 7cadcbb49863c6dfe7a4e2f5968fbcb0769e737f..fcc6ab3057e7de1e2b4bdcc70a6756e53d7a8cdf 100644 |
--- a/webrtc/modules/audio_processing/aec/aec_core.cc |
+++ b/webrtc/modules/audio_processing/aec/aec_core.cc |
@@ -1108,8 +1108,7 @@ static void EchoSuppression(AecCore* aec, |
float* nearend_extended_block_lowest_band, |
float farend[PART_LEN2], |
float* echo_subtractor_output, |
- float* output, |
- float* const* outputH) { |
+ float output[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) { |
float efw[2][PART_LEN1]; |
float xfw[2][PART_LEN1]; |
float dfw[2][PART_LEN1]; |
@@ -1193,12 +1192,12 @@ static void EchoSuppression(AecCore* aec, |
// Overlap and add to obtain output. |
for (i = 0; i < PART_LEN; i++) { |
- output[i] = (fft[i] * WebRtcAec_sqrtHanning[i] + |
- aec->outBuf[i] * WebRtcAec_sqrtHanning[PART_LEN - i]); |
+ output[0][i] = (fft[i] * WebRtcAec_sqrtHanning[i] + |
+ aec->outBuf[i] * WebRtcAec_sqrtHanning[PART_LEN - i]); |
// Saturate output to keep it in the allowed range. |
- output[i] = |
- WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[i], WEBRTC_SPL_WORD16_MIN); |
+ output[0][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[0][i], |
+ WEBRTC_SPL_WORD16_MIN); |
} |
memcpy(aec->outBuf, &fft[PART_LEN], PART_LEN * sizeof(aec->outBuf[0])); |
@@ -1213,22 +1212,22 @@ static void EchoSuppression(AecCore* aec, |
ScaledInverseFft(comfortNoiseHband, fft, 2.0f, 0); |
// compute gain factor |
- for (j = 0; j < aec->num_bands - 1; ++j) { |
+ for (j = 1; j < aec->num_bands; ++j) { |
for (i = 0; i < PART_LEN; i++) { |
- outputH[j][i] = aec->previous_nearend_block[j + 1][i] * nlpGainHband; |
+ output[j][i] = aec->previous_nearend_block[j][i] * nlpGainHband; |
} |
} |
// Add some comfort noise where Hband is attenuated. |
for (i = 0; i < PART_LEN; i++) { |
- outputH[0][i] += cnScaleHband * fft[i]; |
+ output[1][i] += cnScaleHband * fft[i]; |
} |
// Saturate output to keep it in the allowed range. |
- for (j = 0; j < aec->num_bands - 1; ++j) { |
+ for (j = 1; j < aec->num_bands; ++j) { |
for (i = 0; i < PART_LEN; i++) { |
- outputH[j][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, outputH[j][i], |
- WEBRTC_SPL_WORD16_MIN); |
+ output[j][i] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, output[j][i], |
+ WEBRTC_SPL_WORD16_MIN); |
} |
} |
} |
@@ -1241,8 +1240,8 @@ static void EchoSuppression(AecCore* aec, |
} |
static void ProcessBlock(AecCore* aec, |
- float nearend_block[NUM_HIGH_BANDS_MAX + 1] |
- [PART_LEN]) { |
+ float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN], |
+ float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) { |
size_t i; |
float fft[PART_LEN2]; |
@@ -1265,15 +1264,8 @@ static void ProcessBlock(AecCore* aec, |
float farend[PART_LEN2]; |
float* farend_ptr = NULL; |
float echo_subtractor_output[PART_LEN]; |
- float output[PART_LEN]; |
- float outputH[NUM_HIGH_BANDS_MAX][PART_LEN]; |
- float* outputH_ptr[NUM_HIGH_BANDS_MAX]; |
float* x_fft_ptr = NULL; |
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
- outputH_ptr[i] = outputH[i]; |
- } |
- |
// We should always have at least one element stored in |far_buf|. |
assert(WebRtc_available_read(aec->far_time_buf) > 0); |
WebRtc_ReadBuffer(aec->far_time_buf, reinterpret_cast<void**>(&farend_ptr), |
@@ -1403,10 +1395,11 @@ static void ProcessBlock(AecCore* aec, |
// Perform echo suppression. |
EchoSuppression(aec, nearend_extended_block_lowest_band, farend_ptr, |
- echo_subtractor_output, output, outputH_ptr); |
+ echo_subtractor_output, output_block); |
if (aec->metricsMode == 1) { |
- UpdateLevel(&aec->nlpoutlevel, CalculatePower(output, PART_LEN)); |
+ UpdateLevel(&aec->nlpoutlevel, |
+ CalculatePower(&output_block[0][0], PART_LEN)); |
UpdateMetrics(aec); |
} |
@@ -1416,19 +1409,11 @@ static void ProcessBlock(AecCore* aec, |
sizeof(float) * PART_LEN); |
} |
- // Store the output block. |
- WebRtc_WriteBuffer(aec->outFrBuf, output, PART_LEN); |
- // For high bands |
- for (i = 0; i < aec->num_bands - 1; ++i) { |
- WebRtc_WriteBuffer(aec->outFrBufH[i], outputH[i], PART_LEN); |
- } |
- |
- aec->data_dumper->DumpWav("aec_out", PART_LEN, output, |
+ aec->data_dumper->DumpWav("aec_out", PART_LEN, &output_block[0][0], |
std::min(aec->sampFreq, 16000), 1); |
} |
AecCore* WebRtcAec_CreateAec(int instance_count) { |
- int i; |
AecCore* aec = new AecCore(instance_count); |
if (!aec) { |
@@ -1436,21 +1421,10 @@ AecCore* WebRtcAec_CreateAec(int instance_count) { |
} |
aec->nearend_buffer_size = 0; |
memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer)); |
- |
- aec->outFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); |
- if (!aec->outFrBuf) { |
- WebRtcAec_FreeAec(aec); |
- return NULL; |
- } |
- |
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
- aec->outFrBufH[i] = |
- WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); |
- if (!aec->outFrBufH[i]) { |
- WebRtcAec_FreeAec(aec); |
- return NULL; |
- } |
- } |
+ // Start the output buffer with zeros to be able to produce |
+ // a full output frame in the first frame. |
+ aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN); |
+ memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer)); |
// Create far-end buffers. |
// For bit exactness with legacy code, each element in |far_time_buf| is |
@@ -1523,17 +1497,10 @@ AecCore* WebRtcAec_CreateAec(int instance_count) { |
} |
void WebRtcAec_FreeAec(AecCore* aec) { |
- int i; |
if (aec == NULL) { |
return; |
} |
- WebRtc_FreeBuffer(aec->outFrBuf); |
- |
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
- WebRtc_FreeBuffer(aec->outFrBufH[i]); |
- } |
- |
WebRtc_FreeBuffer(aec->far_time_buf); |
WebRtc_FreeDelayEstimator(aec->delay_estimator); |
@@ -1593,14 +1560,13 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { |
aec->num_bands = (size_t)(sampFreq / 16000); |
} |
+ // Start the output buffer with zeros to be able to produce |
+ // a full output frame in the first frame. |
+ aec->output_buffer_size = PART_LEN - (FRAME_LEN - PART_LEN); |
+ memset(&aec->output_buffer[0], 0, sizeof(aec->output_buffer)); |
aec->nearend_buffer_size = 0; |
memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer)); |
- WebRtc_InitBuffer(aec->outFrBuf); |
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
- WebRtc_InitBuffer(aec->outFrBufH[i]); |
- } |
- |
// Initialize far-end buffers. |
WebRtc_InitBuffer(aec->far_time_buf); |
@@ -1740,14 +1706,87 @@ int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements) { |
return elements_moved; |
} |
+void FormNearendBlock( |
+ size_t nearend_start_index, |
+ size_t num_bands, |
+ const float* const* nearend_frame, |
+ size_t num_samples_from_nearend_frame, |
+ const float nearend_buffer[NUM_HIGH_BANDS_MAX + 1] |
+ [PART_LEN - (FRAME_LEN - PART_LEN)], |
+ float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) { |
+ RTC_DCHECK_LE(num_samples_from_nearend_frame, static_cast<size_t>(PART_LEN)); |
+ const int num_samples_from_buffer = PART_LEN - num_samples_from_nearend_frame; |
+ |
+ if (num_samples_from_buffer > 0) { |
+ for (size_t i = 0; i < num_bands; ++i) { |
+ memcpy(&nearend_block[i][0], &nearend_buffer[i][0], |
+ num_samples_from_buffer * sizeof(float)); |
+ } |
+ } |
+ |
+ for (size_t i = 0; i < num_bands; ++i) { |
+ memcpy(&nearend_block[i][num_samples_from_buffer], |
+ &nearend_frame[i][nearend_start_index], |
+ num_samples_from_nearend_frame * sizeof(float)); |
+ } |
+} |
+ |
+void BufferNearendFrame( |
+ size_t nearend_start_index, |
+ size_t num_bands, |
+ const float* const* nearend_frame, |
+ size_t num_samples_to_buffer, |
+ float nearend_buffer[NUM_HIGH_BANDS_MAX + 1] |
+ [PART_LEN - (FRAME_LEN - PART_LEN)]) { |
+ for (size_t i = 0; i < num_bands; ++i) { |
+ memcpy( |
+ &nearend_buffer[i][0], |
+ &nearend_frame[i] |
+ [nearend_start_index + FRAME_LEN - num_samples_to_buffer], |
+ num_samples_to_buffer * sizeof(float)); |
+ } |
+} |
+ |
+void BufferOutputBlock(size_t num_bands, |
+ const float output_block[NUM_HIGH_BANDS_MAX + 1] |
+ [PART_LEN], |
+ size_t* output_buffer_size, |
+ float output_buffer[NUM_HIGH_BANDS_MAX + 1] |
+ [2 * PART_LEN]) { |
+ for (size_t i = 0; i < num_bands; ++i) { |
+ memcpy(&output_buffer[i][*output_buffer_size], &output_block[i][0], |
+ PART_LEN * sizeof(float)); |
+ } |
+ (*output_buffer_size) += PART_LEN; |
+} |
+ |
+void FormOutputFrame(size_t output_start_index, |
+ size_t num_bands, |
+ size_t* output_buffer_size, |
+ float output_buffer[NUM_HIGH_BANDS_MAX + 1][2 * PART_LEN], |
+ float* const* output_frame) { |
+ RTC_DCHECK_LE(static_cast<size_t>(FRAME_LEN), *output_buffer_size); |
+ for (size_t i = 0; i < num_bands; ++i) { |
+ memcpy(&output_frame[i][output_start_index], &output_buffer[i][0], |
+ FRAME_LEN * sizeof(float)); |
+ } |
+ (*output_buffer_size) -= FRAME_LEN; |
+ if (*output_buffer_size > 0) { |
+ RTC_DCHECK_GE(static_cast<size_t>(2 * PART_LEN - FRAME_LEN), |
+ (*output_buffer_size)); |
+ for (size_t i = 0; i < num_bands; ++i) { |
+ memcpy(&output_buffer[i][0], &output_buffer[i][FRAME_LEN], |
+ (*output_buffer_size) * sizeof(float)); |
+ } |
+ } |
+} |
+ |
void WebRtcAec_ProcessFrames(AecCore* aec, |
const float* const* nearend, |
size_t num_bands, |
size_t num_samples, |
int knownDelay, |
float* const* out) { |
- int out_elements = 0; |
- |
RTC_DCHECK(num_samples == 80 || num_samples == 160); |
aec->frame_count++; |
@@ -1827,56 +1866,45 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
} |
} |
- // Form a process a block of samples. |
- RTC_DCHECK_EQ(16, FRAME_LEN - PART_LEN); |
+ static_assert( |
+ 16 == (FRAME_LEN - PART_LEN), |
+ "These constants need to be properly related for this code to work"); |
+ float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]; |
float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]; |
- const int num_samples_to_block = PART_LEN - aec->nearend_buffer_size; |
- const int num_samples_to_buffer = FRAME_LEN - num_samples_to_block; |
- for (size_t i = 0; i < num_bands; ++i) { |
- memcpy(&nearend_block[i][0], &aec->nearend_buffer[i][0], |
- aec->nearend_buffer_size * sizeof(float)); |
- memcpy(&nearend_block[i][aec->nearend_buffer_size], &nearend[i][j], |
- num_samples_to_block * sizeof(float)); |
- } |
- ProcessBlock(aec, nearend_block); |
- if (num_samples_to_buffer == PART_LEN) { |
- // If possible form and process a second block of samples. |
- for (size_t i = 0; i < num_bands; ++i) { |
- memcpy(&nearend_block[i][0], &nearend[i][j + num_samples_to_block], |
- num_samples_to_buffer * sizeof(float)); |
- } |
- ProcessBlock(aec, nearend_block); |
+ // Form and process a block of nearend samples, buffer the output block of |
+ // samples. |
+ FormNearendBlock(j, num_bands, nearend, PART_LEN - aec->nearend_buffer_size, |
+ aec->nearend_buffer, nearend_block); |
+ ProcessBlock(aec, nearend_block, output_block); |
+ BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size, |
+ aec->output_buffer); |
+ |
+ if ((FRAME_LEN - PART_LEN + aec->nearend_buffer_size) == PART_LEN) { |
+ // When possible (every fourth frame) form and process a second block of |
+ // nearend samples, buffer the output block of samples. |
+ FormNearendBlock(j + FRAME_LEN - PART_LEN, num_bands, nearend, PART_LEN, |
+ aec->nearend_buffer, nearend_block); |
+ ProcessBlock(aec, nearend_block, output_block); |
+ BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size, |
+ aec->output_buffer); |
+ |
+ // Reset the buffer size as there are no samples left in the nearend input |
+ // to buffer. |
aec->nearend_buffer_size = 0; |
} else { |
- // Buffer the remaining samples in the frame. |
- for (size_t i = 0; i < num_bands; ++i) { |
- memcpy(&aec->nearend_buffer[i][0], |
- &nearend[i][j + num_samples_to_block], |
- num_samples_to_buffer * sizeof(float)); |
- } |
- aec->nearend_buffer_size = num_samples_to_buffer; |
+ // Buffer the remaining samples in the nearend input. |
+ aec->nearend_buffer_size += FRAME_LEN - PART_LEN; |
+ BufferNearendFrame(j, num_bands, nearend, aec->nearend_buffer_size, |
+ aec->nearend_buffer); |
} |
// 5) Update system delay with respect to the entire frame. |
aec->system_delay -= FRAME_LEN; |
- // 6) Update output frame. |
- // Stuff the out buffer if we have less than a frame to output. |
- // This should only happen for the first frame. |
- out_elements = static_cast<int>(WebRtc_available_read(aec->outFrBuf)); |
- if (out_elements < FRAME_LEN) { |
- WebRtc_MoveReadPtr(aec->outFrBuf, out_elements - FRAME_LEN); |
- for (size_t i = 0; i < num_bands - 1; ++i) { |
- WebRtc_MoveReadPtr(aec->outFrBufH[i], out_elements - FRAME_LEN); |
- } |
- } |
- // Obtain an output frame. |
- WebRtc_ReadBuffer(aec->outFrBuf, NULL, &out[0][j], FRAME_LEN); |
- // For H bands. |
- for (size_t i = 1; i < num_bands; ++i) { |
- WebRtc_ReadBuffer(aec->outFrBufH[i - 1], NULL, &out[i][j], FRAME_LEN); |
- } |
+ // 6) Form the output frame. |
+ FormOutputFrame(j, num_bands, &aec->output_buffer_size, aec->output_buffer, |
+ out); |
} |
} |