diff --git a/webrtc/modules/audio_processing/aec/aec_core.c b/webrtc/modules/audio_processing/aec/aec_core.c index ef04997cbc..e67273e3f7 100644 --- a/webrtc/modules/audio_processing/aec/aec_core.c +++ b/webrtc/modules/audio_processing/aec/aec_core.c @@ -502,7 +502,7 @@ static void ComfortNoise(AecCore* aec, noiseAvg = 0.0; tmpAvg = 0.0; num = 0; - if (aec->sampFreq == 32000 && flagHbandCn == 1) { + if (aec->num_bands > 1 && flagHbandCn == 1) { // average noise scale // average over second half of freq spectrum (i.e., 4->8khz) @@ -849,13 +849,15 @@ static int SignalBasedDelayCorrection(AecCore* self) { return delay_correction; } -static void NonLinearProcessing(AecCore* aec, float* output, float* outputH) { +static void NonLinearProcessing(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]; float scale, dtmp; float nlpGainHband; - int i; + int i, j; // Coherence and non-linear filter float cohde[PART_LEN1], cohxd[PART_LEN1]; @@ -1027,7 +1029,7 @@ static void NonLinearProcessing(AecCore* aec, float* output, float* outputH) { } // For H band - if (aec->sampFreq == 32000) { + if (aec->num_bands > 1) { // H band gain // average nlp over low band: average over second half of freq spectrum @@ -1047,19 +1049,21 @@ static void NonLinearProcessing(AecCore* aec, float* output, float* outputH) { } // compute gain factor - for (i = 0; i < PART_LEN; i++) { - dtmp = aec->dBufH[i]; - dtmp = dtmp * nlpGainHband; // for variable gain + for (j = 0; j < aec->num_bands - 1; ++j) { + for (i = 0; i < PART_LEN; i++) { + dtmp = aec->dBufH[j][i]; + dtmp = dtmp * nlpGainHband; // for variable gain - // add some comfort noise where Hband is attenuated - if (flagHbandCn == 1) { - fft[i] *= scale; // fft scaling - dtmp += cnScaleHband * fft[i]; + // add some comfort noise where Hband is attenuated + if (flagHbandCn == 1 && j == 0) { + fft[i] *= scale; // fft scaling + dtmp += cnScaleHband * fft[i]; + } + + // Saturate output to keep it in the allowed range. + outputH[j][i] = WEBRTC_SPL_SAT( + WEBRTC_SPL_WORD16_MAX, dtmp, WEBRTC_SPL_WORD16_MIN); } - - // Saturate output to keep it in the allowed range. - outputH[i] = WEBRTC_SPL_SAT( - WEBRTC_SPL_WORD16_MAX, dtmp, WEBRTC_SPL_WORD16_MIN); } } @@ -1068,8 +1072,8 @@ static void NonLinearProcessing(AecCore* aec, float* output, float* outputH) { memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN); // Copy the current block to the old position for H band - if (aec->sampFreq == 32000) { - memcpy(aec->dBufH, aec->dBufH + PART_LEN, sizeof(float) * PART_LEN); + for (i = 0; i < aec->num_bands - 1; ++i) { + memcpy(aec->dBufH[i], aec->dBufH[i] + PART_LEN, sizeof(float) * PART_LEN); } memmove(aec->xfwBuf + PART_LEN1, @@ -1101,14 +1105,21 @@ static void ProcessBlock(AecCore* aec) { float nearend[PART_LEN]; float* nearend_ptr = NULL; float output[PART_LEN]; - float outputH[PART_LEN]; + float outputH[NUM_HIGH_BANDS_MAX][PART_LEN]; + float* outputH_ptr[NUM_HIGH_BANDS_MAX]; + for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { + outputH_ptr[i] = outputH[i]; + } float* xf_ptr = NULL; // Concatenate old and new nearend blocks. - if (aec->sampFreq == 32000) { - WebRtc_ReadBuffer(aec->nearFrBufH, (void**)&nearend_ptr, nearend, PART_LEN); - memcpy(aec->dBufH + PART_LEN, nearend_ptr, sizeof(nearend)); + for (i = 0; i < aec->num_bands - 1; ++i) { + WebRtc_ReadBuffer(aec->nearFrBufH[i], + (void**)&nearend_ptr, + nearend, + PART_LEN); + memcpy(aec->dBufH[i] + PART_LEN, nearend_ptr, sizeof(nearend)); } WebRtc_ReadBuffer(aec->nearFrBuf, (void**)&nearend_ptr, nearend, PART_LEN); memcpy(aec->dBuf + PART_LEN, nearend_ptr, sizeof(nearend)); @@ -1254,7 +1265,7 @@ static void ProcessBlock(AecCore* aec) { // Scale error signal inversely with far power. WebRtcAec_ScaleErrorSignal(aec, ef); WebRtcAec_FilterAdaptation(aec, fft, ef); - NonLinearProcessing(aec, output, outputH); + NonLinearProcessing(aec, output, outputH_ptr); if (aec->metricsMode == 1) { // Update power levels and echo metrics @@ -1265,9 +1276,9 @@ static void ProcessBlock(AecCore* aec) { // Store the output block. WebRtc_WriteBuffer(aec->outFrBuf, output, PART_LEN); - // For H band - if (aec->sampFreq == 32000) { - WebRtc_WriteBuffer(aec->outFrBufH, outputH, PART_LEN); + // For high bands + for (i = 0; i < aec->num_bands - 1; ++i) { + WebRtc_WriteBuffer(aec->outFrBufH[i], outputH[i], PART_LEN); } #ifdef WEBRTC_AEC_DEBUG_DUMP @@ -1277,6 +1288,7 @@ static void ProcessBlock(AecCore* aec) { } int WebRtcAec_CreateAec(AecCore** aecInst) { + int i; AecCore* aec = malloc(sizeof(AecCore)); *aecInst = aec; if (aec == NULL) { @@ -1297,18 +1309,21 @@ int WebRtcAec_CreateAec(AecCore** aecInst) { return -1; } - aec->nearFrBufH = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); - if (!aec->nearFrBufH) { - WebRtcAec_FreeAec(aec); - aec = NULL; - return -1; - } - - aec->outFrBufH = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); - if (!aec->outFrBufH) { - WebRtcAec_FreeAec(aec); - aec = NULL; - return -1; + 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); + aec = NULL; + return -1; + } + aec->outFrBufH[i] = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, + sizeof(float)); + if (!aec->outFrBufH[i]) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } } // Create far-end buffers. @@ -1390,6 +1405,7 @@ int WebRtcAec_CreateAec(AecCore** aecInst) { } int WebRtcAec_FreeAec(AecCore* aec) { + int i; if (aec == NULL) { return -1; } @@ -1397,8 +1413,10 @@ int WebRtcAec_FreeAec(AecCore* aec) { WebRtc_FreeBuffer(aec->nearFrBuf); WebRtc_FreeBuffer(aec->outFrBuf); - WebRtc_FreeBuffer(aec->nearFrBufH); - WebRtc_FreeBuffer(aec->outFrBufH); + for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { + WebRtc_FreeBuffer(aec->nearFrBufH[i]); + WebRtc_FreeBuffer(aec->outFrBufH[i]); + } WebRtc_FreeBuffer(aec->far_buf); WebRtc_FreeBuffer(aec->far_buf_windowed); @@ -1447,15 +1465,19 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { if (sampFreq == 8000) { aec->normal_mu = 0.6f; aec->normal_error_threshold = 2e-6f; + aec->num_bands = 1; } else { aec->normal_mu = 0.5f; aec->normal_error_threshold = 1.5e-6f; + aec->num_bands = sampFreq / 16000; } WebRtc_InitBuffer(aec->nearFrBuf); WebRtc_InitBuffer(aec->outFrBuf); - WebRtc_InitBuffer(aec->nearFrBufH); - WebRtc_InitBuffer(aec->outFrBufH); + for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) { + WebRtc_InitBuffer(aec->nearFrBufH[i]); + WebRtc_InitBuffer(aec->outFrBufH[i]); + } // Initialize far-end buffers. WebRtc_InitBuffer(aec->far_buf); @@ -1516,7 +1538,7 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { // Sampling frequency multiplier // SWB is processed as 160 frame size - if (aec->sampFreq == 32000) { + if (aec->num_bands > 1) { aec->mult = (short)aec->sampFreq / 16000; } else { aec->mult = (short)aec->sampFreq / 8000; @@ -1532,8 +1554,10 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { // Initialize buffers memset(aec->dBuf, 0, sizeof(aec->dBuf)); memset(aec->eBuf, 0, sizeof(aec->eBuf)); - // For H band - memset(aec->dBufH, 0, sizeof(aec->dBufH)); + // 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)); @@ -1620,12 +1644,13 @@ int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements) { return elements_moved; } -void WebRtcAec_ProcessFrame(AecCore* aec, - const float* nearend, - const float* nearendH, - int knownDelay, - float* out, - float* outH) { +void WebRtcAec_ProcessFrames(AecCore* aec, + const float* const* nearend, + int num_bands, + int num_samples, + int knownDelay, + float* const* out) { + int i, j; int out_elements = 0; // For each frame the process is as follows: @@ -1655,94 +1680,100 @@ void WebRtcAec_ProcessFrame(AecCore* aec, // Note that the two algorithms operate independently. Currently, we only // allow one algorithm to be turned on. - // 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, FRAME_LEN); - // For H band - if (aec->sampFreq == 32000) { - WebRtc_WriteBuffer(aec->nearFrBufH, nearendH, FRAME_LEN); - } + assert(aec->num_bands == num_bands); - // 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. - if (aec->system_delay < FRAME_LEN) { - // We don't have enough data so we rewind 10 ms. - WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1)); - } + 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); + } - if (aec->reported_delay_enabled) { - // 2 a) Compensate for a possible change in the system delay. - - // TODO(bjornv): Investigate how we should round the delay difference; right - // now we know that incoming |knownDelay| is underestimated when it's less - // than |aec->knownDelay|. We therefore, round (-32) in that direction. In - // the other direction, we don't have this situation, but might flush one - // partition too little. This can cause non-causality, 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_buf, move_elements); - WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements); - aec->knownDelay -= moved_elements * PART_LEN; -#ifdef WEBRTC_AEC_DEBUG_DUMP - WebRtc_MoveReadPtr(aec->far_time_buf, move_elements); -#endif - } else { - // 2 b) Apply signal based delay correction. - int move_elements = SignalBasedDelayCorrection(aec); - int moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements); - WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements); -#ifdef WEBRTC_AEC_DEBUG_DUMP - WebRtc_MoveReadPtr(aec->far_time_buf, move_elements); -#endif - WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements); - WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend, - moved_elements); - aec->signal_delay_correction += moved_elements; - // TODO(bjornv): Investigate if this is reasonable. I had to add this - // guard when the signal based delay correction replaces the system based - // one. Otherwise there was a buffer underrun in the "qa-new/01/" recording - // when adding 44 ms extra delay. This was not seen if we kept both delay - // correction algorithms running in parallel. - // A first investigation showed that we have a drift in this case that - // causes the buffer underrun. Compared to when delay correction was - // turned off, we get buffer underrun as well which was triggered in 1) - // above. In addition there was a shift in |knownDelay| later increasing - // the buffer. When running in parallel, this if statement was not - // triggered. This suggests two alternatives; (a) use both algorithms, or - // (b) allow for smaller delay corrections when we operate close to the - // buffer limit. At the time of testing we required a change of 6 blocks, - // but could change it to, e.g., 2 blocks. It requires some testing though. - if ((int)WebRtc_available_read(aec->far_buf) < (aec->mult + 1)) { - // We don't have enough data so we stuff the far-end buffers. + // 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. + if (aec->system_delay < FRAME_LEN) { + // We don't have enough data so we rewind 10 ms. WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1)); } - } - // 4) Process as many blocks as possible. - while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) { - ProcessBlock(aec); - } + if (aec->reported_delay_enabled) { + // 2 a) Compensate for a possible change in the system delay. - // 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 = (int)WebRtc_available_read(aec->outFrBuf); - if (out_elements < FRAME_LEN) { - WebRtc_MoveReadPtr(aec->outFrBuf, out_elements - FRAME_LEN); - if (aec->sampFreq == 32000) { - WebRtc_MoveReadPtr(aec->outFrBufH, out_elements - FRAME_LEN); + // TODO(bjornv): Investigate how we should round the delay difference; + // right now we know that incoming |knownDelay| is underestimated when + // it's less than |aec->knownDelay|. We therefore, round (-32) in that + // direction. In the other direction, we don't have this situation, but + // might flush one partition too little. This can cause non-causality, + // 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_buf, move_elements); + WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements); + aec->knownDelay -= moved_elements * PART_LEN; + #ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_MoveReadPtr(aec->far_time_buf, move_elements); + #endif + } else { + // 2 b) Apply signal based delay correction. + int move_elements = SignalBasedDelayCorrection(aec); + int moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements); + WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements); + #ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_MoveReadPtr(aec->far_time_buf, move_elements); + #endif + WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements); + WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend, + moved_elements); + aec->signal_delay_correction += moved_elements; + // TODO(bjornv): Investigate if this is reasonable. I had to add this + // guard when the signal based delay correction replaces the system based + // one. Otherwise there was a buffer underrun in the "qa-new/01/" + // recording when adding 44 ms extra delay. This was not seen if we kept + // both delay correction algorithms running in parallel. + // A first investigation showed that we have a drift in this case that + // causes the buffer underrun. Compared to when delay correction was + // turned off, we get buffer underrun as well which was triggered in 1) + // above. In addition there was a shift in |knownDelay| later increasing + // the buffer. When running in parallel, this if statement was not + // triggered. This suggests two alternatives; (a) use both algorithms, or + // (b) allow for smaller delay corrections when we operate close to the + // buffer limit. At the time of testing we required a change of 6 blocks, + // but could change it to, e.g., 2 blocks. It requires some testing + // though. + if ((int)WebRtc_available_read(aec->far_buf) < (aec->mult + 1)) { + // We don't have enough data so we stuff the far-end buffers. + WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1)); + } + } + + // 4) Process as many blocks as possible. + while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) { + ProcessBlock(aec); + } + + // 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 = (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) { + 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) { + WebRtc_ReadBuffer(aec->outFrBufH[i - 1], NULL, &out[i][j], FRAME_LEN); } - } - // Obtain an output frame. - WebRtc_ReadBuffer(aec->outFrBuf, NULL, out, FRAME_LEN); - // For H band. - if (aec->sampFreq == 32000) { - WebRtc_ReadBuffer(aec->outFrBufH, NULL, outH, FRAME_LEN); } } diff --git a/webrtc/modules/audio_processing/aec/aec_core.h b/webrtc/modules/audio_processing/aec/aec_core.h index 93bfed4668..2bffeec6e4 100644 --- a/webrtc/modules/audio_processing/aec/aec_core.h +++ b/webrtc/modules/audio_processing/aec/aec_core.h @@ -21,6 +21,7 @@ #define PART_LEN 64 // Length of partition #define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients #define PART_LEN2 (PART_LEN * 2) // Length of partition * 2 +#define NUM_HIGH_BANDS_MAX 2 // Max number of high bands typedef float complex_t[2]; // For performance reasons, some arrays of complex numbers are replaced by twice @@ -62,12 +63,12 @@ void WebRtcAec_InitAec_neon(void); #endif void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend); -void WebRtcAec_ProcessFrame(AecCore* aec, - const float* nearend, - const float* nearendH, - int knownDelay, - float* out, - float* outH); +void WebRtcAec_ProcessFrames(AecCore* aec, + const float* const* nearend, + int num_bands, + int num_samples, + int knownDelay, + float* const* out); // A helper function to call WebRtc_MoveReadPtr() for all far-end buffers. // Returns the number of elements moved, and adjusts |system_delay| by the diff --git a/webrtc/modules/audio_processing/aec/aec_core_internal.h b/webrtc/modules/audio_processing/aec/aec_core_internal.h index fd33acd791..2081813f0a 100644 --- a/webrtc/modules/audio_processing/aec/aec_core_internal.h +++ b/webrtc/modules/audio_processing/aec/aec_core_internal.h @@ -59,13 +59,13 @@ struct AecCore { RingBuffer* nearFrBuf; RingBuffer* outFrBuf; - RingBuffer* nearFrBufH; - RingBuffer* outFrBufH; + RingBuffer* nearFrBufH[NUM_HIGH_BANDS_MAX]; + RingBuffer* outFrBufH[NUM_HIGH_BANDS_MAX]; float dBuf[PART_LEN2]; // nearend float eBuf[PART_LEN2]; // error - float dBufH[PART_LEN2]; // nearend + float dBufH[NUM_HIGH_BANDS_MAX][PART_LEN2]; // nearend float xPow[PART_LEN1]; float dPow[PART_LEN1]; @@ -101,6 +101,7 @@ struct AecCore { int mult; // sampling frequency multiple int sampFreq; + int num_bands; uint32_t seed; float normal_mu; // stepsize diff --git a/webrtc/modules/audio_processing/aec/aec_core_mips.c b/webrtc/modules/audio_processing/aec/aec_core_mips.c index 0a975f766b..bb33087aee 100644 --- a/webrtc/modules/audio_processing/aec/aec_core_mips.c +++ b/webrtc/modules/audio_processing/aec/aec_core_mips.c @@ -274,7 +274,7 @@ void WebRtcAec_ComfortNoise_mips(AecCore* aec, noiseAvg = 0.0; tmpAvg = 0.0; num = 0; - if (aec->sampFreq == 32000 && flagHbandCn == 1) { + if ((aec->sampFreq == 32000 || aec->sampFreq == 48000) && flagHbandCn == 1) { for (i = 0; i < PART_LEN; i++) { rand[i] = ((float)randW16[i]) / 32768; } diff --git a/webrtc/modules/audio_processing/aec/echo_cancellation.c b/webrtc/modules/audio_processing/aec/echo_cancellation.c index 99883c4db9..e40336b6d9 100644 --- a/webrtc/modules/audio_processing/aec/echo_cancellation.c +++ b/webrtc/modules/audio_processing/aec/echo_cancellation.c @@ -104,18 +104,16 @@ int webrtc_aec_instance_count = 0; static void EstBufDelayNormal(Aec* aecInst); static void EstBufDelayExtended(Aec* aecInst); static int ProcessNormal(Aec* self, - const float* near, - const float* near_high, - float* out, - float* out_high, + const float* const* near, + int num_bands, + float* const* out, int16_t num_samples, int16_t reported_delay_ms, int32_t skew); static void ProcessExtended(Aec* self, - const float* near, - const float* near_high, - float* out, - float* out_high, + const float* const* near, + int num_bands, + float* const* out, int16_t num_samples, int16_t reported_delay_ms, int32_t skew); @@ -199,7 +197,10 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) { Aec* aecpc = aecInst; AecConfig aecConfig; - if (sampFreq != 8000 && sampFreq != 16000 && sampFreq != 32000) { + if (sampFreq != 8000 && + sampFreq != 16000 && + sampFreq != 32000 && + sampFreq != 48000) { aecpc->lastError = AEC_BAD_PARAMETER_ERROR; return -1; } @@ -227,7 +228,7 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) { aecpc->initFlag = initCheck; // indicates that initialization has been done - if (aecpc->sampFreq == 32000) { + if (aecpc->sampFreq == 32000 || aecpc->sampFreq == 48000) { aecpc->splitSampFreq = 16000; } else { aecpc->splitSampFreq = sampFreq; @@ -338,19 +339,14 @@ int32_t WebRtcAec_BufferFarend(void* aecInst, } int32_t WebRtcAec_Process(void* aecInst, - const float* nearend, - const float* nearendH, - float* out, - float* outH, + const float* const* nearend, + int num_bands, + float* const* out, int16_t nrOfSamples, int16_t msInSndCardBuf, int32_t skew) { Aec* aecpc = aecInst; int32_t retVal = 0; - if (nearend == NULL) { - aecpc->lastError = AEC_NULL_POINTER_ERROR; - return -1; - } if (out == NULL) { aecpc->lastError = AEC_NULL_POINTER_ERROR; @@ -368,12 +364,6 @@ int32_t WebRtcAec_Process(void* aecInst, return -1; } - // Check for valid pointers based on sampling rate - if (aecpc->sampFreq == 32000 && nearendH == NULL) { - aecpc->lastError = AEC_NULL_POINTER_ERROR; - return -1; - } - if (msInSndCardBuf < 0) { msInSndCardBuf = 0; aecpc->lastError = AEC_BAD_PARAMETER_WARNING; @@ -386,14 +376,18 @@ int32_t WebRtcAec_Process(void* aecInst, // This returns the value of aec->extended_filter_enabled. if (WebRtcAec_delay_correction_enabled(aecpc->aec)) { - ProcessExtended( - aecpc, nearend, nearendH, out, outH, nrOfSamples, msInSndCardBuf, skew); + ProcessExtended(aecpc, + nearend, + num_bands, + out, + nrOfSamples, + msInSndCardBuf, + skew); } else { if (ProcessNormal(aecpc, nearend, - nearendH, + num_bands, out, - outH, nrOfSamples, msInSndCardBuf, skew) != 0) { @@ -598,17 +592,15 @@ AecCore* WebRtcAec_aec_core(void* handle) { } static int ProcessNormal(Aec* aecpc, - const float* nearend, - const float* nearendH, - float* out, - float* outH, + const float* const* nearend, + int num_bands, + float* const* out, int16_t nrOfSamples, int16_t msInSndCardBuf, int32_t skew) { int retVal = 0; short i; short nBlocks10ms; - short nFrames; // Limit resampling to doubling/halving of signal const float minSkewEst = -0.5f; const float maxSkewEst = 1.0f; @@ -649,16 +641,14 @@ static int ProcessNormal(Aec* aecpc, } } - nFrames = nrOfSamples / FRAME_LEN; - nBlocks10ms = nFrames / aecpc->rate_factor; + nBlocks10ms = nrOfSamples / (FRAME_LEN * aecpc->rate_factor); if (aecpc->startup_phase) { - // Only needed if they don't already point to the same place. - if (nearend != out) { - memcpy(out, nearend, sizeof(*out) * nrOfSamples); - } - if (nearendH != outH) { - memcpy(outH, nearendH, sizeof(*outH) * nrOfSamples); + for (i = 0; i < num_bands; ++i) { + // Only needed if they don't already point to the same place. + if (nearend[i] != out[i]) { + memcpy(out[i], nearend[i], sizeof(nearend[i][0]) * nrOfSamples); + } } // The AEC is in the start up mode @@ -736,29 +726,25 @@ static int ProcessNormal(Aec* aecpc, EstBufDelayNormal(aecpc); } - // Note that 1 frame is supported for NB and 2 frames for WB. - for (i = 0; i < nFrames; i++) { - // Call the AEC. - WebRtcAec_ProcessFrame(aecpc->aec, - &nearend[FRAME_LEN * i], - &nearendH[FRAME_LEN * i], - aecpc->knownDelay, - &out[FRAME_LEN * i], - &outH[FRAME_LEN * i]); - // TODO(bjornv): Re-structure such that we don't have to pass - // |aecpc->knownDelay| as input. Change name to something like - // |system_buffer_diff|. - } + // Call the AEC. + // TODO(bjornv): Re-structure such that we don't have to pass + // |aecpc->knownDelay| as input. Change name to something like + // |system_buffer_diff|. + WebRtcAec_ProcessFrames(aecpc->aec, + nearend, + num_bands, + nrOfSamples, + aecpc->knownDelay, + out); } return retVal; } static void ProcessExtended(Aec* self, - const float* near, - const float* near_high, - float* out, - float* out_high, + const float* const* near, + int num_bands, + float* const* out, int16_t num_samples, int16_t reported_delay_ms, int32_t skew) { @@ -786,12 +772,11 @@ static void ProcessExtended(Aec* self, self->msInSndCardBuf = reported_delay_ms; if (!self->farend_started) { - // Only needed if they don't already point to the same place. - if (near != out) { - memcpy(out, near, sizeof(*out) * num_samples); - } - if (near_high != out_high) { - memcpy(out_high, near_high, sizeof(*out_high) * num_samples); + for (i = 0; i < num_bands; ++i) { + // Only needed if they don't already point to the same place. + if (near[i] != out[i]) { + memcpy(out[i], near[i], sizeof(near[i][0]) * num_samples); + } } return; } @@ -821,12 +806,12 @@ static void ProcessExtended(Aec* self, WEBRTC_SPL_MAX(0, self->knownDelay + delay_diff_offset); for (i = 0; i < num_frames; ++i) { - WebRtcAec_ProcessFrame(self->aec, - &near[FRAME_LEN * i], - &near_high[FRAME_LEN * i], - adjusted_known_delay, - &out[FRAME_LEN * i], - &out_high[FRAME_LEN * i]); + WebRtcAec_ProcessFrames(self->aec, + near, + num_bands, + FRAME_LEN * i, + adjusted_known_delay, + out); } } } diff --git a/webrtc/modules/audio_processing/aec/include/echo_cancellation.h b/webrtc/modules/audio_processing/aec/include/echo_cancellation.h index 0cf6a5a4c8..51eb37a72d 100644 --- a/webrtc/modules/audio_processing/aec/include/echo_cancellation.h +++ b/webrtc/modules/audio_processing/aec/include/echo_cancellation.h @@ -133,10 +133,9 @@ int32_t WebRtcAec_BufferFarend(void* aecInst, * Inputs Description * ------------------------------------------------------------------- * void* aecInst Pointer to the AEC instance - * float* nearend In buffer containing one frame of - * nearend+echo signal for L band - * float* nearendH In buffer containing one frame of - * nearend+echo signal for H band + * float* const* nearend In buffer containing one frame of + * nearend+echo signal for each band + * int num_bands Number of bands in nearend buffer * int16_t nrOfSamples Number of samples in nearend buffer * int16_t msInSndCardBuf Delay estimate for sound card and * system buffers @@ -146,18 +145,15 @@ int32_t WebRtcAec_BufferFarend(void* aecInst, * * Outputs Description * ------------------------------------------------------------------- - * float* out Out buffer, one frame of processed nearend - * for L band - * float* outH Out buffer, one frame of processed nearend - * for H band + * float* const* out Out buffer, one frame of processed nearend + * for each band * int32_t return 0: OK * -1: error */ int32_t WebRtcAec_Process(void* aecInst, - const float* nearend, - const float* nearendH, - float* out, - float* outH, + const float* const* nearend, + int num_bands, + float* const* out, int16_t nrOfSamples, int16_t msInSndCardBuf, int32_t skew); diff --git a/webrtc/modules/audio_processing/aec/system_delay_unittest.cc b/webrtc/modules/audio_processing/aec/system_delay_unittest.cc index 927c317413..654ae54c7d 100644 --- a/webrtc/modules/audio_processing/aec/system_delay_unittest.cc +++ b/webrtc/modules/audio_processing/aec/system_delay_unittest.cc @@ -50,6 +50,8 @@ class SystemDelayTest : public ::testing::Test { float far_[kSamplesPerChunk]; float near_[kSamplesPerChunk]; float out_[kSamplesPerChunk]; + const float* near_ptr_; + float* out_ptr_; }; SystemDelayTest::SystemDelayTest() @@ -60,6 +62,8 @@ SystemDelayTest::SystemDelayTest() near_[i] = 514.0; } memset(out_, 0, sizeof(out_)); + near_ptr_ = near_; + out_ptr_ = out_; } void SystemDelayTest::SetUp() { @@ -103,10 +107,9 @@ void SystemDelayTest::RenderAndCapture(int device_buffer_ms) { EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_)); EXPECT_EQ(0, WebRtcAec_Process(handle_, - near_, - NULL, - out_, - NULL, + &near_ptr_, + 1, + &out_ptr_, samples_per_frame_, device_buffer_ms, 0)); @@ -268,10 +271,9 @@ TEST_F(SystemDelayTest, for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) { EXPECT_EQ(0, WebRtcAec_Process(handle_, - near_, - NULL, - out_, - NULL, + &near_ptr_, + 1, + &out_ptr_, samples_per_frame_, kDeviceBufMs, 0)); @@ -322,10 +324,9 @@ TEST_F(SystemDelayTest, CorrectDelayWhenBufferUnderrun) { for (int j = 0; j <= kStableConvergenceMs; j += 10) { EXPECT_EQ(0, WebRtcAec_Process(handle_, - near_, - NULL, - out_, - NULL, + &near_ptr_, + 1, + &out_ptr_, samples_per_frame_, kDeviceBufMs, 0)); diff --git a/webrtc/modules/audio_processing/echo_cancellation_impl.cc b/webrtc/modules/audio_processing/echo_cancellation_impl.cc index 863f2d8b1a..bf5ed72db6 100644 --- a/webrtc/modules/audio_processing/echo_cancellation_impl.cc +++ b/webrtc/modules/audio_processing/echo_cancellation_impl.cc @@ -129,10 +129,9 @@ int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { Handle* my_handle = handle(handle_index); err = WebRtcAec_Process( my_handle, - audio->split_bands_const_f(i)[kBand0To8kHz], - audio->split_bands_const_f(i)[kBand8To16kHz], - audio->split_bands_f(i)[kBand0To8kHz], - audio->split_bands_f(i)[kBand8To16kHz], + audio->split_bands_const_f(i), + audio->num_bands(), + audio->split_bands_f(i), static_cast(audio->samples_per_split_channel()), apm_->stream_delay_ms(), stream_drift_samples_);