Chromium Code Reviews| 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 08079b8a3f67ff7e7aed9f730de02b04b2cfd7e8..42cd69ca7b8c049f420d5bc81b1c45ff70e95ccd 100644 |
| --- a/webrtc/modules/audio_processing/aec/aec_core.cc |
| +++ b/webrtc/modules/audio_processing/aec/aec_core.cc |
| @@ -1105,6 +1105,7 @@ static void FormSuppressionGain(AecCore* aec, |
| } |
| static void EchoSuppression(AecCore* aec, |
| + float* nearend_extended_block_lowest_band, |
| float farend[PART_LEN2], |
| float* echo_subtractor_output, |
| float* output, |
| @@ -1133,7 +1134,7 @@ static void EchoSuppression(AecCore* aec, |
| // Analysis filter banks for the echo suppressor. |
| // Windowed near-end ffts. |
| - WindowData(fft, aec->dBuf); |
| + WindowData(fft, nearend_extended_block_lowest_band); |
| aec_rdft_forward_128(fft); |
| StoreAsComplex(fft, dfw); |
| @@ -1214,7 +1215,7 @@ static void EchoSuppression(AecCore* aec, |
| // compute gain factor |
| for (j = 0; j < aec->num_bands - 1; ++j) { |
| for (i = 0; i < PART_LEN; i++) { |
| - outputH[j][i] = aec->dBufH[j][i] * nlpGainHband; |
| + outputH[j][i] = aec->previous_nearend_block[j + 1][i] * nlpGainHband; |
| } |
| } |
| @@ -1233,22 +1234,19 @@ static void EchoSuppression(AecCore* aec, |
| } |
| // Copy the current block to the old position. |
| - memcpy(aec->dBuf, aec->dBuf + PART_LEN, sizeof(float) * PART_LEN); |
| memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN); |
| - // Copy the current block to the old position for H band |
| - for (j = 0; j < aec->num_bands - 1; ++j) { |
| - memcpy(aec->dBufH[j], aec->dBufH[j] + PART_LEN, sizeof(float) * PART_LEN); |
| - } |
| - |
| memmove(aec->xfwBuf + PART_LEN1, aec->xfwBuf, |
| sizeof(aec->xfwBuf) - sizeof(complex_t) * PART_LEN1); |
| } |
| -static void ProcessBlock(AecCore* aec) { |
| +static void ProcessBlock(AecCore* aec, |
| + float nearend_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 far_spectrum = 0.0f; |
| @@ -1264,8 +1262,6 @@ static void ProcessBlock(AecCore* aec) { |
| const float ramp = 1.0002f; |
| const float gInitNoise[2] = {0.999f, 0.001f}; |
| - float nearend[PART_LEN]; |
| - float* nearend_ptr = NULL; |
| float farend[PART_LEN2]; |
| float* farend_ptr = NULL; |
| float echo_subtractor_output[PART_LEN]; |
| @@ -1278,17 +1274,6 @@ static void ProcessBlock(AecCore* aec) { |
| outputH_ptr[i] = outputH[i]; |
| } |
| - // Concatenate old and new nearend blocks. |
| - for (i = 0; i < aec->num_bands - 1; ++i) { |
| - WebRtc_ReadBuffer(aec->nearFrBufH[i], |
| - reinterpret_cast<void**>(&nearend_ptr), |
| - nearend, PART_LEN); |
| - memcpy(aec->dBufH[i] + PART_LEN, nearend_ptr, sizeof(nearend)); |
| - } |
| - WebRtc_ReadBuffer(aec->nearFrBuf, reinterpret_cast<void**>(&nearend_ptr), |
| - nearend, PART_LEN); |
| - memcpy(aec->dBuf + PART_LEN, nearend_ptr, sizeof(nearend)); |
| - |
| // 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), |
| @@ -1296,14 +1281,15 @@ static void ProcessBlock(AecCore* aec) { |
| aec->data_dumper->DumpWav("aec_far", PART_LEN, &farend_ptr[PART_LEN], |
| std::min(aec->sampFreq, 16000), 1); |
| - aec->data_dumper->DumpWav("aec_near", PART_LEN, nearend_ptr, |
| + 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->nearlevel, CalculatePower(nearend_ptr, PART_LEN)); |
| + UpdateLevel(&aec->nearlevel, |
| + CalculatePower(&nearend_block[0][0], PART_LEN)); |
| } |
| // Convert far-end signal to the frequency domain. |
| @@ -1311,8 +1297,14 @@ static void ProcessBlock(AecCore* aec) { |
| Fft(fft, x_fft); |
| x_fft_ptr = &x_fft[0][0]; |
| + // Form extended nearend frame. |
| + memcpy(&nearend_extended_block_lowest_band[0], |
| + &aec->previous_nearend_block[0][0], sizeof(float) * PART_LEN); |
| + memcpy(&nearend_extended_block_lowest_band[PART_LEN], &nearend_block[0][0], |
| + sizeof(float) * PART_LEN); |
| + |
| // Near fft |
| - memcpy(fft, aec->dBuf, sizeof(float) * PART_LEN2); |
| + memcpy(fft, nearend_extended_block_lowest_band, sizeof(float) * PART_LEN2); |
| Fft(fft, df); |
| // Power smoothing. |
| @@ -1394,7 +1386,7 @@ static void ProcessBlock(AecCore* aec) { |
| 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->xfBuf, nearend_ptr, aec->xPow, aec->wfBuf, |
| + 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, |
| &aec->wfBuf[0][0]); |
| @@ -1410,13 +1402,20 @@ static void ProcessBlock(AecCore* aec) { |
| } |
| // Perform echo suppression. |
| - EchoSuppression(aec, farend_ptr, echo_subtractor_output, output, outputH_ptr); |
| + EchoSuppression(aec, nearend_extended_block_lowest_band, farend_ptr, |
| + echo_subtractor_output, output, outputH_ptr); |
| if (aec->metricsMode == 1) { |
| UpdateLevel(&aec->nlpoutlevel, CalculatePower(output, PART_LEN)); |
| UpdateMetrics(aec); |
| } |
| + // Store the nearend signal until the next frame. |
| + for (i = 0; i < aec->num_bands; ++i) { |
| + memcpy(&aec->previous_nearend_block[i][0], &nearend_block[i][0], |
| + sizeof(float) * PART_LEN); |
| + } |
| + |
| // Store the output block. |
| WebRtc_WriteBuffer(aec->outFrBuf, output, PART_LEN); |
| // For high bands |
| @@ -1435,12 +1434,8 @@ AecCore* WebRtcAec_CreateAec(int instance_count) { |
| if (!aec) { |
| return NULL; |
| } |
| - |
| - aec->nearFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); |
| - if (!aec->nearFrBuf) { |
| - WebRtcAec_FreeAec(aec); |
| - return NULL; |
| - } |
| + 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) { |
| @@ -1449,12 +1444,6 @@ AecCore* WebRtcAec_CreateAec(int instance_count) { |
| } |
| for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
| - aec->nearFrBufH[i] = |
| - WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); |
| - if (!aec->nearFrBufH[i]) { |
| - WebRtcAec_FreeAec(aec); |
| - return NULL; |
| - } |
| aec->outFrBufH[i] = |
| WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); |
| if (!aec->outFrBufH[i]) { |
| @@ -1539,11 +1528,9 @@ void WebRtcAec_FreeAec(AecCore* aec) { |
| return; |
| } |
| - WebRtc_FreeBuffer(aec->nearFrBuf); |
| WebRtc_FreeBuffer(aec->outFrBuf); |
| for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
| - WebRtc_FreeBuffer(aec->nearFrBufH[i]); |
| WebRtc_FreeBuffer(aec->outFrBufH[i]); |
| } |
| @@ -1606,10 +1593,11 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { |
| aec->num_bands = (size_t)(sampFreq / 16000); |
| } |
| - WebRtc_InitBuffer(aec->nearFrBuf); |
| + 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->nearFrBufH[i]); |
| WebRtc_InitBuffer(aec->outFrBufH[i]); |
| } |
| @@ -1672,12 +1660,8 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { |
| aec->knownDelay = 0; |
| // Initialize buffers |
| - memset(aec->dBuf, 0, sizeof(aec->dBuf)); |
| + memset(aec->previous_nearend_block, 0, sizeof(aec->previous_nearend_block)); |
| memset(aec->eBuf, 0, sizeof(aec->eBuf)); |
| - // For H bands |
| - for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { |
| - memset(aec->dBufH[i], 0, sizeof(aec->dBufH[i])); |
| - } |
| memset(aec->xPow, 0, sizeof(aec->xPow)); |
| memset(aec->dPow, 0, sizeof(aec->dPow)); |
| @@ -1762,9 +1746,10 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
| size_t num_samples, |
| int knownDelay, |
| float* const* out) { |
| - size_t i, j; |
| int out_elements = 0; |
| + RTC_DCHECK(num_samples == 80 || num_samples == 160); |
| + |
| aec->frame_count++; |
| // For each frame the process is as follows: |
| // 1) If the system_delay indicates on being too small for processing a |
| @@ -1795,16 +1780,7 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
| assert(aec->num_bands == num_bands); |
| - for (j = 0; j < num_samples; j += FRAME_LEN) { |
| - // TODO(bjornv): Change the near-end buffer handling to be the same as for |
| - // far-end, that is, with a near_pre_buf. |
| - // Buffer the near-end frame. |
| - WebRtc_WriteBuffer(aec->nearFrBuf, &nearend[0][j], FRAME_LEN); |
| - // For H band |
| - for (i = 1; i < num_bands; ++i) { |
| - WebRtc_WriteBuffer(aec->nearFrBufH[i - 1], &nearend[i][j], FRAME_LEN); |
| - } |
| - |
| + for (size_t j = 0; j < num_samples; j += FRAME_LEN) { |
| // 1) At most we process |aec->mult|+1 partitions in 10 ms. Make sure we |
| // have enough far-end data for that by stuffing the buffer if the |
| // |system_delay| indicates others. |
| @@ -1836,7 +1812,7 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
| DelaySource::kDelayAgnostic); |
| int far_near_buffer_diff = |
| WebRtc_available_read(aec->far_time_buf) - |
| - WebRtc_available_read(aec->nearFrBuf) / PART_LEN; |
| + (aec->nearend_buffer_size + FRAME_LEN) / PART_LEN; |
| WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements); |
| WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend, |
| moved_elements); |
| @@ -1851,9 +1827,35 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
| } |
| } |
| - // 4) Process as many blocks as possible. |
| - while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) { |
| - ProcessBlock(aec); |
| + // Form an process a block of samples. |
|
hlundin-webrtc
2016/09/07 21:28:46
Typo: an -> a
|
| + RTC_DCHECK_EQ(16, FRAME_LEN - 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); |
| + 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; |
| } |
| // 5) Update system delay with respect to the entire frame. |
| @@ -1865,14 +1867,14 @@ void WebRtcAec_ProcessFrames(AecCore* aec, |
| out_elements = static_cast<int>(WebRtc_available_read(aec->outFrBuf)); |
| if (out_elements < FRAME_LEN) { |
| WebRtc_MoveReadPtr(aec->outFrBuf, out_elements - FRAME_LEN); |
| - for (i = 0; i < num_bands - 1; ++i) { |
| + 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 (i = 1; i < num_bands; ++i) { |
| + for (size_t i = 1; i < num_bands; ++i) { |
| WebRtc_ReadBuffer(aec->outFrBufH[i - 1], NULL, &out[i][j], FRAME_LEN); |
| } |
| } |