Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1591)

Unified Diff: webrtc/modules/audio_processing/aec/aec_core.cc

Issue 2321483002: Refactoring of the buffering of the output signal done inside the AEC (Closed)
Patch Set: New testvectors Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/modules/audio_processing/aec/aec_core.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
}
« no previous file with comments | « webrtc/modules/audio_processing/aec/aec_core.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698