diff --git a/webrtc/modules/audio_processing/aec/aec_core.c b/webrtc/modules/audio_processing/aec/aec_core.c index a5a4b0840a..09744db2f7 100644 --- a/webrtc/modules/audio_processing/aec/aec_core.c +++ b/webrtc/modules/audio_processing/aec/aec_core.c @@ -748,6 +748,7 @@ void WebRtcAec_GetEchoStats(aec_t* self, Stats* erl, Stats* erle, *erle = self->erle; *a_nlp = self->aNlp; } + #ifdef WEBRTC_AEC_DEBUG_DUMP void* WebRtcAec_far_time_buf(aec_t* self) { assert(self != NULL); @@ -770,6 +771,17 @@ void WebRtcAec_SetConfigCore(aec_t* self, int nlp_mode, int metrics_mode, } } +int WebRtcAec_system_delay(aec_t* self) { + assert(self != NULL); + return self->system_delay; +} + +void WebRtcAec_SetSystemDelay(aec_t* self, int delay) { + assert(self != NULL); + assert(delay >= 0); + self->system_delay = delay; +} + static void ProcessBlock(aec_t* aec) { int i; float d[PART_LEN], y[PART_LEN], e[PART_LEN], dH[PART_LEN]; diff --git a/webrtc/modules/audio_processing/aec/aec_core.h b/webrtc/modules/audio_processing/aec/aec_core.h index 9e4e12d6f5..0626be6d19 100644 --- a/webrtc/modules/audio_processing/aec/aec_core.h +++ b/webrtc/modules/audio_processing/aec/aec_core.h @@ -12,8 +12,8 @@ * Specifies the interface for the AEC core. */ -#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_ -#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_ +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_ #ifdef WEBRTC_AEC_DEBUG_DUMP #include @@ -196,5 +196,12 @@ void* WebRtcAec_far_time_buf(aec_t* self); // Sets local configuration modes. void WebRtcAec_SetConfigCore(aec_t* self, int nlp_mode, int metrics_mode, int delay_logging); +// Returns the current |system_delay|, i.e., the buffered difference between +// far-end and near-end. +int WebRtcAec_system_delay(aec_t* self); +// Sets the |system_delay| to |value|. Note that if the value is changed +// improperly, there can be a performance regression. So it should be used with +// care. +void WebRtcAec_SetSystemDelay(aec_t* self, int delay); -#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_ +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_ diff --git a/webrtc/modules/audio_processing/aec/echo_cancellation.c b/webrtc/modules/audio_processing/aec/echo_cancellation.c index de26c67cd0..04789e7f9e 100644 --- a/webrtc/modules/audio_processing/aec/echo_cancellation.c +++ b/webrtc/modules/audio_processing/aec/echo_cancellation.c @@ -268,7 +268,8 @@ WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst, const WebRtc_Word16 *farend, farend_ptr = (const int16_t*) newFarend; } - aecpc->aec->system_delay += newNrOfSamples; + WebRtcAec_SetSystemDelay(aecpc->aec, WebRtcAec_system_delay(aecpc->aec) + + newNrOfSamples); #ifdef WEBRTC_AEC_DEBUG_DUMP WebRtc_WriteBuffer(aecpc->far_pre_buf_s16, farend_ptr, @@ -454,7 +455,8 @@ WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend, // for too long). When the far-end buffer is filled with // approximately the same amount of data as reported by the system // we end the startup phase. - int overhead_elements = aecpc->aec->system_delay / PART_LEN - + int overhead_elements = + WebRtcAec_system_delay(aecpc->aec) / PART_LEN - aecpc->bufSizeStart; if (overhead_elements == 0) { // Enable the AEC @@ -493,7 +495,7 @@ WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend, #ifdef WEBRTC_AEC_DEBUG_DUMP { - int16_t far_buf_size_ms = (int16_t)(aecpc->aec->system_delay / + int16_t far_buf_size_ms = (int16_t)(WebRtcAec_system_delay(aecpc->aec) / (sampMsNb * aecpc->rate_factor)); (void)fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile); (void)fwrite(&aecpc->knownDelay, sizeof(aecpc->knownDelay), 1, @@ -700,7 +702,7 @@ WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst) static int EstBufDelay(aecpc_t* aecpc) { int nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->rate_factor; - int current_delay = nSampSndCard - aecpc->aec->system_delay; + int current_delay = nSampSndCard - WebRtcAec_system_delay(aecpc->aec); int delay_difference = 0; // Before we proceed with the delay estimate filtering we: diff --git a/webrtc/modules/audio_processing/aec/system_delay_unittest.cc b/webrtc/modules/audio_processing/aec/system_delay_unittest.cc index 272cb8a78c..97ebea3dfb 100644 --- a/webrtc/modules/audio_processing/aec/system_delay_unittest.cc +++ b/webrtc/modules/audio_processing/aec/system_delay_unittest.cc @@ -8,11 +8,14 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "gtest/gtest.h" +#include "testing/gtest/include/gtest/gtest.h" -#include "modules/audio_processing/aec/include/echo_cancellation.h" -#include "modules/audio_processing/aec/echo_cancellation_internal.h" -#include "typedefs.h" +extern "C" { +#include "webrtc/modules/audio_processing/aec/aec_core.h" +} +#include "webrtc/modules/audio_processing/aec/echo_cancellation_internal.h" +#include "webrtc/modules/audio_processing/aec/include/echo_cancellation.h" +#include "webrtc/typedefs.h" namespace { @@ -109,7 +112,7 @@ int SystemDelayTest::BufferFillUp() { for (int i = 0; i < kDeviceBufMs / 10; i++) { EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_)); buffer_size += samples_per_frame_; - EXPECT_EQ(buffer_size, self_->aec->system_delay); + EXPECT_EQ(buffer_size, WebRtcAec_system_delay(self_->aec)); } return buffer_size; } @@ -133,7 +136,7 @@ void SystemDelayTest::RunStableStartup() { // Verify convergence time. EXPECT_GT(kStableConvergenceMs, process_time_ms); // Verify that the buffer has been flushed. - EXPECT_GE(buffer_size, self_->aec->system_delay); + EXPECT_GE(buffer_size, WebRtcAec_system_delay(self_->aec)); } int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms) { @@ -172,7 +175,7 @@ TEST_F(SystemDelayTest, CorrectIncreaseWhenBufferFarend) { // correctly. for (int j = 1; j <= 5; j++) { EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_)); - EXPECT_EQ(j * samples_per_frame_, self_->aec->system_delay); + EXPECT_EQ(j * samples_per_frame_, WebRtcAec_system_delay(self_->aec)); } } } @@ -191,8 +194,9 @@ TEST_F(SystemDelayTest, CorrectDelayAfterStableStartup) { // |system_delay| is in the interval [75%, 100%] of what's reported on the // average. int average_reported_delay = kDeviceBufMs * samples_per_frame_ / 10; - EXPECT_GE(average_reported_delay, self_->aec->system_delay); - EXPECT_LE(average_reported_delay * 3 / 4, self_->aec->system_delay); + EXPECT_GE(average_reported_delay, WebRtcAec_system_delay(self_->aec)); + EXPECT_LE(average_reported_delay * 3 / 4, + WebRtcAec_system_delay(self_->aec)); } } @@ -226,14 +230,14 @@ TEST_F(SystemDelayTest, CorrectDelayAfterUnstableStartup) { // Verify convergence time. EXPECT_GE(kMaxConvergenceMs, process_time_ms); // Verify that the buffer has been flushed. - EXPECT_GE(buffer_size, self_->aec->system_delay); + EXPECT_GE(buffer_size, WebRtcAec_system_delay(self_->aec)); // Verify system delay with respect to requirements, i.e., the // |system_delay| is in the interval [60%, 100%] of what's last reported. EXPECT_GE(reported_delay_ms * samples_per_frame_ / 10, - self_->aec->system_delay); + WebRtcAec_system_delay(self_->aec)); EXPECT_LE(reported_delay_ms * samples_per_frame_ / 10 * 3 / 5, - self_->aec->system_delay); + WebRtcAec_system_delay(self_->aec)); } } @@ -272,14 +276,14 @@ TEST_F(SystemDelayTest, CorrectDelayAfterStableBufferBuildUp) { // Verify convergence time. EXPECT_GT(kMaxConvergenceMs, process_time_ms); // Verify that the buffer has reached the desired size. - EXPECT_LE(target_buffer_size, self_->aec->system_delay); + EXPECT_LE(target_buffer_size, WebRtcAec_system_delay(self_->aec)); // Verify normal behavior (system delay is kept constant) after startup by // running a couple of calls to BufferFarend() and Process(). for (int j = 0; j < 6; j++) { - int system_delay_before_calls = self_->aec->system_delay; + int system_delay_before_calls = WebRtcAec_system_delay(self_->aec); RenderAndCapture(kDeviceBufMs); - EXPECT_EQ(system_delay_before_calls, self_->aec->system_delay); + EXPECT_EQ(system_delay_before_calls, WebRtcAec_system_delay(self_->aec)); } } } @@ -299,7 +303,7 @@ TEST_F(SystemDelayTest, CorrectDelayWhenBufferUnderrun) { for (int j = 0; j <= kStableConvergenceMs; j += 10) { EXPECT_EQ(0, WebRtcAec_Process(handle_, near_, NULL, out_, NULL, samples_per_frame_, kDeviceBufMs, 0)); - EXPECT_LE(0, self_->aec->system_delay); + EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); } } } @@ -327,10 +331,10 @@ TEST_F(SystemDelayTest, CorrectDelayDuringDrift) { RenderAndCapture(device_buf_ms); // Verify that the system delay does not exceed the device buffer. - EXPECT_GE(device_buf, self_->aec->system_delay); + EXPECT_GE(device_buf, WebRtcAec_system_delay(self_->aec)); // Verify that the system delay is non-negative. - EXPECT_LE(0, self_->aec->system_delay); + EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); } } } @@ -353,15 +357,15 @@ TEST_F(SystemDelayTest, ShouldRecoverAfterGlitch) { } // Verify that we are in a non-causal state, i.e., // |system_delay| > |device_buf|. - EXPECT_LT(device_buf, self_->aec->system_delay); + EXPECT_LT(device_buf, WebRtcAec_system_delay(self_->aec)); // Recover state. Should recover at least 4 ms of data per 10 ms, hence a // glitch of 200 ms will take at most 200 * 10 / 4 = 500 ms to recover from. bool non_causal = true; // We are currently in a non-causal state. for (int j = 0; j < 50; j++) { - int system_delay_before = self_->aec->system_delay; + int system_delay_before = WebRtcAec_system_delay(self_->aec); RenderAndCapture(kDeviceBufMs); - int system_delay_after = self_->aec->system_delay; + int system_delay_after = WebRtcAec_system_delay(self_->aec); // We have recovered if |device_buf| - |system_delay_after| >= 64 (one // block). During recovery |system_delay_after| < |system_delay_before|, @@ -375,7 +379,7 @@ TEST_F(SystemDelayTest, ShouldRecoverAfterGlitch) { EXPECT_EQ(system_delay_before, system_delay_after); } // Verify that the system delay is non-negative. - EXPECT_LE(0, self_->aec->system_delay); + EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); } // Check that we have recovered. EXPECT_FALSE(non_causal); @@ -397,7 +401,7 @@ TEST_F(SystemDelayTest, UnaffectedWhenSpuriousDeviceBufferValues) { // Run 1 s and replace device buffer size with 500 ms every 100 ms. for (int j = 0; j < 100; j++) { - int system_delay_before_calls = self_->aec->system_delay; + int system_delay_before_calls = WebRtcAec_system_delay(self_->aec); int device_buf_ms = kDeviceBufMs; if (j % 10 == 0) { device_buf_ms = 500; @@ -405,14 +409,14 @@ TEST_F(SystemDelayTest, UnaffectedWhenSpuriousDeviceBufferValues) { RenderAndCapture(device_buf_ms); // Check for non-causality. - if (device_buf - self_->aec->system_delay < 64) { + if (device_buf - WebRtcAec_system_delay(self_->aec) < 64) { non_causal = true; } EXPECT_FALSE(non_causal); - EXPECT_EQ(system_delay_before_calls, self_->aec->system_delay); + EXPECT_EQ(system_delay_before_calls, WebRtcAec_system_delay(self_->aec)); // Verify that the system delay is non-negative. - EXPECT_LE(0, self_->aec->system_delay); + EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); } } } @@ -440,16 +444,16 @@ TEST_F(SystemDelayTest, CorrectImpactWhenTogglingDeviceBufferValues) { // data. Every odd frame we set the device buffer size to 2 * |kDeviceBufMs| // and even frames we set the device buffer size to zero. for (int j = 0; j < 100; j++) { - int system_delay_before_calls = self_->aec->system_delay; + int system_delay_before_calls = WebRtcAec_system_delay(self_->aec); int device_buf_ms = 2 * (j % 2) * kDeviceBufMs; RenderAndCapture(device_buf_ms); // Check for non-causality, compared with the average device buffer size. - non_causal |= (device_buf - self_->aec->system_delay < 64); - EXPECT_GE(system_delay_before_calls, self_->aec->system_delay); + non_causal |= (device_buf - WebRtcAec_system_delay(self_->aec) < 64); + EXPECT_GE(system_delay_before_calls, WebRtcAec_system_delay(self_->aec)); // Verify that the system delay is non-negative. - EXPECT_LE(0, self_->aec->system_delay); + EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); } // Verify we are not in a non-causal state. EXPECT_FALSE(non_causal);