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 fcc6ab3057e7de1e2b4bdcc70a6756e53d7a8cdf..acdd8a9cad698f8eb1e61978252917dbbf91234c 100644 |
--- a/webrtc/modules/audio_processing/aec/aec_core.cc |
+++ b/webrtc/modules/audio_processing/aec/aec_core.cc |
@@ -66,7 +66,7 @@ void MaybeLogDelayAdjustment(int moved_ms, DelaySource source) { |
} // namespace |
// Buffer size (samples) |
-static const size_t kBufSizePartitions = 250; // 1 second of audio in 16 kHz. |
+static const size_t kBufferSizeBlocks = 250; // 1 second of audio in 16 kHz. |
// Metrics |
static const size_t kSubCountLen = 4; |
@@ -184,6 +184,56 @@ PowerLevel::PowerLevel() |
averagelevel(kCountLen + 1) { |
} |
+BlockBuffer::BlockBuffer() { |
+ buffer_ = WebRtc_CreateBuffer(kBufferSizeBlocks, sizeof(float) * PART_LEN); |
+ RTC_CHECK(buffer_); |
+ ReInit(); |
+} |
+ |
+BlockBuffer::~BlockBuffer() { |
+ WebRtc_FreeBuffer(buffer_); |
+} |
+ |
+void BlockBuffer::ReInit() { |
+ WebRtc_InitBuffer(buffer_); |
+} |
+ |
+void BlockBuffer::Insert(const float block[PART_LEN]) { |
+ WebRtc_WriteBuffer(buffer_, block, 1); |
+} |
+ |
+void BlockBuffer::ExtractExtendedBlock(float extended_block[PART_LEN2]) { |
+ float* block_ptr = NULL; |
+ RTC_DCHECK_LT(0u, AvaliableSpace()); |
+ |
+ // Extract the previous block. |
+ WebRtc_MoveReadPtr(buffer_, -1); |
+ WebRtc_ReadBuffer(buffer_, reinterpret_cast<void**>(&block_ptr), |
+ &extended_block[0], 1); |
+ if (block_ptr != &extended_block[0]) { |
+ memcpy(&extended_block[0], block_ptr, PART_LEN * sizeof(float)); |
+ } |
+ |
+ // Extract the current block. |
+ WebRtc_ReadBuffer(buffer_, reinterpret_cast<void**>(&block_ptr), |
+ &extended_block[PART_LEN], 1); |
+ if (block_ptr != &extended_block[PART_LEN]) { |
+ memcpy(&extended_block[PART_LEN], block_ptr, PART_LEN * sizeof(float)); |
+ } |
+} |
+ |
+int BlockBuffer::AdjustSize(int buffer_size_decrease) { |
+ return WebRtc_MoveReadPtr(buffer_, buffer_size_decrease); |
+} |
+ |
+size_t BlockBuffer::Size() { |
+ return static_cast<int>(WebRtc_available_read(buffer_)); |
+} |
+ |
+size_t BlockBuffer::AvaliableSpace() { |
+ return WebRtc_available_write(buffer_); |
+} |
+ |
DivergentFilterFraction::DivergentFilterFraction() |
: count_(0), |
occurrence_(0), |
@@ -857,8 +907,7 @@ static int SignalBasedDelayCorrection(AecCore* self) { |
const int upper_bound = self->num_partitions * 3 / 4; |
const int do_correction = delay <= lower_bound || delay > upper_bound; |
if (do_correction == 1) { |
- int available_read = |
- static_cast<int>(WebRtc_available_read(self->far_time_buf)); |
+ int available_read = self->farend_block_buffer_.Size(); |
// With |shift_offset| we gradually rely on the delay estimates. For |
// positive delays we reduce the correction by |shift_offset| to lower the |
// risk of pushing the AEC into a non causal state. For negative delays |
@@ -1106,7 +1155,7 @@ static void FormSuppressionGain(AecCore* aec, |
static void EchoSuppression(AecCore* aec, |
float* nearend_extended_block_lowest_band, |
- float farend[PART_LEN2], |
+ float farend_extended_block[PART_LEN2], |
float* echo_subtractor_output, |
float output[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) { |
float efw[2][PART_LEN1]; |
@@ -1145,7 +1194,7 @@ static void EchoSuppression(AecCore* aec, |
// NLP |
// Convert far-end partition to the frequency domain with windowing. |
- WindowData(fft, farend); |
+ WindowData(fft, farend_extended_block); |
Fft(fft, xfw); |
xfw_ptr = &xfw[0][0]; |
@@ -1239,15 +1288,17 @@ static void EchoSuppression(AecCore* aec, |
sizeof(aec->xfwBuf) - sizeof(complex_t) * PART_LEN1); |
} |
-static void ProcessBlock(AecCore* aec, |
- float nearend_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN], |
- float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN]) { |
+static void ProcessNearendBlock( |
+ AecCore* aec, |
+ float farend_extended_block_lowest_band[PART_LEN2], |
+ 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]; |
float nearend_extended_block_lowest_band[PART_LEN2]; |
- float x_fft[2][PART_LEN1]; |
- float df[2][PART_LEN1]; |
+ float farend_fft[2][PART_LEN1]; |
+ float nearend_fft[2][PART_LEN1]; |
float far_spectrum = 0.0f; |
float near_spectrum = 0.0f; |
float abs_far_spectrum[PART_LEN1]; |
@@ -1261,33 +1312,26 @@ static void ProcessBlock(AecCore* aec, |
const float ramp = 1.0002f; |
const float gInitNoise[2] = {0.999f, 0.001f}; |
- float farend[PART_LEN2]; |
- float* farend_ptr = NULL; |
float echo_subtractor_output[PART_LEN]; |
- float* x_fft_ptr = NULL; |
- |
- // 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), |
- farend, 1); |
- aec->data_dumper->DumpWav("aec_far", PART_LEN, &farend_ptr[PART_LEN], |
+ aec->data_dumper->DumpWav("aec_far", PART_LEN, |
+ &farend_extended_block_lowest_band[PART_LEN], |
std::min(aec->sampFreq, 16000), 1); |
aec->data_dumper->DumpWav("aec_near", PART_LEN, &nearend_block[0][0], |
std::min(aec->sampFreq, 16000), 1); |
if (aec->metricsMode == 1) { |
// Update power levels |
- UpdateLevel(&aec->farlevel, |
- CalculatePower(&farend_ptr[PART_LEN], PART_LEN)); |
+ UpdateLevel( |
+ &aec->farlevel, |
+ CalculatePower(&farend_extended_block_lowest_band[PART_LEN], PART_LEN)); |
UpdateLevel(&aec->nearlevel, |
CalculatePower(&nearend_block[0][0], PART_LEN)); |
} |
// Convert far-end signal to the frequency domain. |
- memcpy(fft, farend_ptr, sizeof(float) * PART_LEN2); |
- Fft(fft, x_fft); |
- x_fft_ptr = &x_fft[0][0]; |
+ memcpy(fft, farend_extended_block_lowest_band, sizeof(float) * PART_LEN2); |
+ Fft(fft, farend_fft); |
// Form extended nearend frame. |
memcpy(&nearend_extended_block_lowest_band[0], |
@@ -1295,15 +1339,15 @@ static void ProcessBlock(AecCore* aec, |
memcpy(&nearend_extended_block_lowest_band[PART_LEN], &nearend_block[0][0], |
sizeof(float) * PART_LEN); |
- // Near fft |
+ // Convert near-end signal to the frequency domain. |
memcpy(fft, nearend_extended_block_lowest_band, sizeof(float) * PART_LEN2); |
- Fft(fft, df); |
+ Fft(fft, nearend_fft); |
// 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]); |
+ far_spectrum = farend_fft[0][i] * farend_fft[0][i] + |
+ farend_fft[1][i] * farend_fft[1][i]; |
// Calculate the magnitude spectrum. |
abs_far_spectrum[i] = sqrtf(far_spectrum); |
} |
@@ -1311,8 +1355,8 @@ static void ProcessBlock(AecCore* aec, |
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]); |
+ far_spectrum = farend_fft[0][i] * farend_fft[0][i] + |
+ farend_fft[1][i] * farend_fft[1][i]; |
aec->xPow[i] = |
gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum; |
// Calculate the magnitude spectrum. |
@@ -1321,7 +1365,8 @@ static void ProcessBlock(AecCore* aec, |
} |
for (i = 0; i < PART_LEN1; ++i) { |
- near_spectrum = df[0][i] * df[0][i] + df[1][i] * df[1][i]; |
+ near_spectrum = nearend_fft[0][i] * nearend_fft[0][i] + |
+ nearend_fft[1][i] * nearend_fft[1][i]; |
aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum; |
// Calculate the magnitude spectrum. |
abs_near_spectrum[i] = sqrtf(near_spectrum); |
@@ -1377,7 +1422,7 @@ static void ProcessBlock(AecCore* aec, |
// Perform echo subtraction. |
EchoSubtraction(aec->num_partitions, aec->extended_filter_enabled, |
&aec->extreme_filter_divergence, aec->filter_step_size, |
- aec->error_threshold, &x_fft[0][0], &aec->xfBufBlockPos, |
+ aec->error_threshold, &farend_fft[0][0], &aec->xfBufBlockPos, |
aec->xfBuf, &nearend_block[0][0], aec->xPow, aec->wfBuf, |
echo_subtractor_output); |
aec->data_dumper->DumpRaw("aec_h_fft", PART_LEN1 * aec->num_partitions, |
@@ -1394,8 +1439,9 @@ static void ProcessBlock(AecCore* aec, |
} |
// Perform echo suppression. |
- EchoSuppression(aec, nearend_extended_block_lowest_band, farend_ptr, |
- echo_subtractor_output, output_block); |
+ EchoSuppression(aec, nearend_extended_block_lowest_band, |
+ farend_extended_block_lowest_band, echo_subtractor_output, |
+ output_block); |
if (aec->metricsMode == 1) { |
UpdateLevel(&aec->nlpoutlevel, |
@@ -1426,18 +1472,6 @@ AecCore* WebRtcAec_CreateAec(int instance_count) { |
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 |
- // supposed to contain |PART_LEN2| samples with an overlap of |PART_LEN| |
- // samples from the last frame. |
- // TODO(minyue): reduce |far_time_buf| to non-overlapped |PART_LEN| samples. |
- aec->far_time_buf = |
- WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * PART_LEN2); |
- if (!aec->far_time_buf) { |
- WebRtcAec_FreeAec(aec); |
- return NULL; |
- } |
- |
aec->delay_estimator_farend = |
WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks); |
if (aec->delay_estimator_farend == NULL) { |
@@ -1501,8 +1535,6 @@ void WebRtcAec_FreeAec(AecCore* aec) { |
return; |
} |
- WebRtc_FreeBuffer(aec->far_time_buf); |
- |
WebRtc_FreeDelayEstimator(aec->delay_estimator); |
WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend); |
@@ -1567,8 +1599,8 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { |
aec->nearend_buffer_size = 0; |
memset(&aec->nearend_buffer[0], 0, sizeof(aec->nearend_buffer)); |
- // Initialize far-end buffers. |
- WebRtc_InitBuffer(aec->far_time_buf); |
+ // Initialize far-end buffer. |
+ aec->farend_block_buffer_.ReInit(); |
aec->system_delay = 0; |
@@ -1687,23 +1719,20 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { |
return 0; |
} |
-// For bit exactness with a legacy code, |farend| is supposed to contain |
-// |PART_LEN2| samples with an overlap of |PART_LEN| samples from the last |
-// frame. |
-// TODO(minyue): reduce |farend| to non-overlapped |PART_LEN| samples. |
-void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend) { |
+void WebRtcAec_BufferFarendBlock(AecCore* aec, const float* farend) { |
// Check if the buffer is full, and in that case flush the oldest data. |
- if (WebRtc_available_write(aec->far_time_buf) < 1) { |
- WebRtcAec_MoveFarReadPtr(aec, 1); |
+ if (aec->farend_block_buffer_.AvaliableSpace() < 1) { |
+ aec->farend_block_buffer_.AdjustSize(1); |
} |
- |
- WebRtc_WriteBuffer(aec->far_time_buf, farend, 1); |
+ aec->farend_block_buffer_.Insert(farend); |
} |
-int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements) { |
- int elements_moved = WebRtc_MoveReadPtr(aec->far_time_buf, elements); |
- aec->system_delay -= elements_moved * PART_LEN; |
- return elements_moved; |
+int WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(AecCore* aec, |
+ int buffer_size_decrease) { |
+ int achieved_buffer_size_decrease = |
+ aec->farend_block_buffer_.AdjustSize(buffer_size_decrease); |
+ aec->system_delay -= achieved_buffer_size_decrease * PART_LEN; |
+ return achieved_buffer_size_decrease; |
} |
void FormNearendBlock( |
@@ -1825,7 +1854,7 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
// |system_delay| indicates others. |
if (aec->system_delay < FRAME_LEN) { |
// We don't have enough data so we rewind 10 ms. |
- WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1)); |
+ WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec, -(aec->mult + 1)); |
} |
if (!aec->delay_agnostic_enabled) { |
@@ -1839,18 +1868,18 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
// which should be investigated. Maybe, allow for a non-symmetric |
// rounding, like -16. |
int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN; |
- int moved_elements = WebRtc_MoveReadPtr(aec->far_time_buf, move_elements); |
+ int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements); |
MaybeLogDelayAdjustment(moved_elements * (aec->sampFreq == 8000 ? 8 : 4), |
DelaySource::kSystemDelay); |
aec->knownDelay -= moved_elements * PART_LEN; |
} else { |
// 2 b) Apply signal based delay correction. |
int move_elements = SignalBasedDelayCorrection(aec); |
- int moved_elements = WebRtc_MoveReadPtr(aec->far_time_buf, move_elements); |
+ int moved_elements = aec->farend_block_buffer_.AdjustSize(move_elements); |
MaybeLogDelayAdjustment(moved_elements * (aec->sampFreq == 8000 ? 8 : 4), |
DelaySource::kDelayAgnostic); |
int far_near_buffer_diff = |
- WebRtc_available_read(aec->far_time_buf) - |
+ aec->farend_block_buffer_.Size() - |
(aec->nearend_buffer_size + FRAME_LEN) / PART_LEN; |
WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements); |
WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend, |
@@ -1862,7 +1891,8 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
// buffer underruns since the delay estimation can be wrong. We therefore |
// stuff the buffer with enough elements if needed. |
if (far_near_buffer_diff < 0) { |
- WebRtcAec_MoveFarReadPtr(aec, far_near_buffer_diff); |
+ WebRtcAec_AdjustFarendBufferSizeAndSystemDelay(aec, |
+ far_near_buffer_diff); |
} |
} |
@@ -1871,21 +1901,28 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
"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]; |
+ float farend_extended_block_lowest_band[PART_LEN2]; |
// Form and process a block of nearend samples, buffer the output block of |
// samples. |
+ aec->farend_block_buffer_.ExtractExtendedBlock( |
+ farend_extended_block_lowest_band); |
FormNearendBlock(j, num_bands, nearend, PART_LEN - aec->nearend_buffer_size, |
aec->nearend_buffer, nearend_block); |
- ProcessBlock(aec, nearend_block, output_block); |
+ ProcessNearendBlock(aec, farend_extended_block_lowest_band, 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. |
+ aec->farend_block_buffer_.ExtractExtendedBlock( |
+ farend_extended_block_lowest_band); |
FormNearendBlock(j + FRAME_LEN - PART_LEN, num_bands, nearend, PART_LEN, |
aec->nearend_buffer, nearend_block); |
- ProcessBlock(aec, nearend_block, output_block); |
+ ProcessNearendBlock(aec, farend_extended_block_lowest_band, nearend_block, |
+ output_block); |
BufferOutputBlock(num_bands, output_block, &aec->output_buffer_size, |
aec->output_buffer); |