diff --git a/src/modules/audio_processing/apm_tests.gypi b/src/modules/audio_processing/apm_tests.gypi index 0d2a852a56..586b8d4d4a 100644 --- a/src/modules/audio_processing/apm_tests.gypi +++ b/src/modules/audio_processing/apm_tests.gypi @@ -32,6 +32,7 @@ 'sources': [ 'aec/system_delay_unittest.cc', 'test/unit_test.cc', + 'utility/delay_estimator_unittest.cc', ], }, { diff --git a/src/modules/audio_processing/utility/delay_estimator.c b/src/modules/audio_processing/utility/delay_estimator.c index 8526728a7b..3d1d7c49e9 100644 --- a/src/modules/audio_processing/utility/delay_estimator.c +++ b/src/modules/audio_processing/utility/delay_estimator.c @@ -131,7 +131,7 @@ BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(int max_delay, return self; } -int WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* handle) { +void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* handle) { int i = 0; assert(handle != NULL); @@ -149,8 +149,6 @@ int WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* handle) { // Default return value if we're unable to estimate. -1 is used for errors. handle->last_delay = -2; - - return 0; } int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* handle, diff --git a/src/modules/audio_processing/utility/delay_estimator.h b/src/modules/audio_processing/utility/delay_estimator.h index cb7b7c904c..93c4b4e938 100644 --- a/src/modules/audio_processing/utility/delay_estimator.h +++ b/src/modules/audio_processing/utility/delay_estimator.h @@ -63,7 +63,7 @@ BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(int max_delay, // Output: // - handle : Initialized instance. // -int WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* handle); +void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* handle); // Estimates and returns the delay between the binary far-end and binary near- // end spectra. The value will be offset by the lookahead (i.e. the lookahead diff --git a/src/modules/audio_processing/utility/delay_estimator_internal.h b/src/modules/audio_processing/utility/delay_estimator_internal.h new file mode 100644 index 0000000000..46b19cae26 --- /dev/null +++ b/src/modules/audio_processing/utility/delay_estimator_internal.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Header file including the delay estimator handle used for testing. + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_ + +#include "modules/audio_processing/utility/delay_estimator.h" +#include "typedefs.h" + +typedef union { + float float_; + int32_t int32_; +} SpectrumType; + +typedef struct { + // Pointers to mean values of spectrum. + SpectrumType* mean_far_spectrum; + SpectrumType* mean_near_spectrum; + // |mean_*_spectrum| initialization indicator. + int far_spectrum_initialized; + int near_spectrum_initialized; + + int spectrum_size; + + // Binary spectrum based delay estimator + BinaryDelayEstimator* binary_handle; +} DelayEstimator; + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_ diff --git a/src/modules/audio_processing/utility/delay_estimator_unittest.cc b/src/modules/audio_processing/utility/delay_estimator_unittest.cc new file mode 100644 index 0000000000..3ebecca651 --- /dev/null +++ b/src/modules/audio_processing/utility/delay_estimator_unittest.cc @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "gtest/gtest.h" + +extern "C" { +#include "modules/audio_processing/utility/delay_estimator.h" +#include "modules/audio_processing/utility/delay_estimator_internal.h" +#include "modules/audio_processing/utility/delay_estimator_wrapper.h" +} +#include "typedefs.h" + +namespace { + +enum { kSpectrumSize = 65 }; + +class DelayEstimatorTest : public ::testing::Test { + protected: + DelayEstimatorTest(); + virtual void SetUp(); + virtual void TearDown(); + + void Init(); + + void InitBinary(); + + void* handle_; + DelayEstimator* self_; + BinaryDelayEstimator* binary_handle_; + int spectrum_size_; + // Dummy input spectra. + float far_f_[kSpectrumSize]; + float near_f_[kSpectrumSize]; + uint16_t far_u16_[kSpectrumSize]; + uint16_t near_u16_[kSpectrumSize]; +}; + +DelayEstimatorTest::DelayEstimatorTest() + : handle_(NULL), + self_(NULL), + binary_handle_(NULL), + spectrum_size_(kSpectrumSize) { + // Dummy input data are set with more or less arbitrary non-zero values. + memset(far_f_, 1, sizeof(far_f_)); + memset(near_f_, 2, sizeof(near_f_)); + memset(far_u16_, 1, sizeof(far_u16_)); + memset(near_u16_, 2, sizeof(near_u16_)); +} + +void DelayEstimatorTest::SetUp() { + ASSERT_EQ(0, WebRtc_CreateDelayEstimator(&handle_, kSpectrumSize, 100, 10)); + ASSERT_TRUE(handle_ != NULL); + self_ = reinterpret_cast(handle_); + binary_handle_ = self_->binary_handle; +} + +void DelayEstimatorTest::TearDown() { + WebRtc_FreeDelayEstimator(handle_); + handle_ = NULL; + self_ = NULL; + binary_handle_ = NULL; +} + +void DelayEstimatorTest::Init() { + // Initialize Delay Estimator + EXPECT_EQ(0, WebRtc_InitDelayEstimator(handle_)); + // Verify initialization. + EXPECT_EQ(0, self_->far_spectrum_initialized); + EXPECT_EQ(0, self_->near_spectrum_initialized); +} + +void DelayEstimatorTest::InitBinary() { + // Initialize Binary Delay Estimator + WebRtc_InitBinaryDelayEstimator(binary_handle_); + // Verify initialization. This does not guarantee a complete check, since + // |last_delay| may be equal to -2 before initialization if done on the fly. + EXPECT_EQ(-2, binary_handle_->last_delay); +} + +TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfWrapper) { + // In this test we verify correct error returns on invalid API calls. + + // WebRtc_CreateDelayEstimator() should return -1 if we have a NULL pointer + // as |handle| or invalid input values. Upon failure, the handle should be + // NULL. + // Make sure we have a non-NULL value at start, so we can detect NULL after + // create failure. + void* handle = handle_; + EXPECT_EQ(-1, WebRtc_CreateDelayEstimator(NULL, kSpectrumSize, 100, 10)); + EXPECT_EQ(-1, WebRtc_CreateDelayEstimator(&handle, 33, 100, 10)); + EXPECT_TRUE(handle == NULL); + handle = handle_; + EXPECT_EQ(-1, WebRtc_CreateDelayEstimator(&handle, kSpectrumSize, -1, 10)); + EXPECT_TRUE(handle == NULL); + handle = handle_; + EXPECT_EQ(-1, WebRtc_CreateDelayEstimator(&handle, kSpectrumSize, 100, -1)); + EXPECT_TRUE(handle == NULL); + handle = handle_; + EXPECT_EQ(-1, WebRtc_CreateDelayEstimator(&handle, kSpectrumSize, 0, 0)); + EXPECT_TRUE(handle == NULL); + + // WebRtc_InitDelayEstimator() should return -1 if we have a NULL pointer as + // |handle|. + EXPECT_EQ(-1, WebRtc_InitDelayEstimator(NULL)); + + // WebRtc_DelayEstimatorProcessFloat() should return -1 if we have: + // 1) NULL pointer as |handle|. + // 2) NULL pointer as far-end spectrum. + // 3) NULL pointer as near-end spectrum. + // 4) Incorrect spectrum size. + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(NULL, far_f_, near_f_, + spectrum_size_)); + // Use |handle_| which is properly created at SetUp(). + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, NULL, near_f_, + spectrum_size_)); + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, far_f_, NULL, + spectrum_size_)); + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, far_f_, near_f_, + spectrum_size_ + 1)); + + // WebRtc_DelayEstimatorProcessFix() should return -1 if we have: + // 1) NULL pointer as |handle|. + // 2) NULL pointer as far-end spectrum. + // 3) NULL pointer as near-end spectrum. + // 4) Incorrect spectrum size. + // 5) Too high precision in far-end spectrum (Q-domain > 15). + // 6) Too high precision in near-end spectrum (Q-domain > 15). + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(NULL, far_u16_, near_u16_, + spectrum_size_, 0, 0)); + // Use |handle_| which is properly created at SetUp(). + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, NULL, near_u16_, + spectrum_size_, 0, 0)); + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, far_u16_, NULL, + spectrum_size_, 0, 0)); + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, far_u16_, near_u16_, + spectrum_size_ + 1, 0, 0)); + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, far_u16_, near_u16_, + spectrum_size_, 16, 0)); + EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, far_u16_, near_u16_, + spectrum_size_, 0, 16)); + + // WebRtc_last_delay() should return -1 if we have a NULL pointer as |handle|. + EXPECT_EQ(-1, WebRtc_last_delay(NULL)); + + // Free any local memory if needed. + WebRtc_FreeDelayEstimator(handle); +} + +TEST_F(DelayEstimatorTest, InitializedSpectrumAfterProcess) { + // In this test we verify that the mean spectra are initialized after first + // time we call Process(). + + // For floating point operations, process one frame and verify initialization + // flag. + Init(); + EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFloat(handle_, far_f_, near_f_, + spectrum_size_)); + EXPECT_EQ(1, self_->far_spectrum_initialized); + EXPECT_EQ(1, self_->near_spectrum_initialized); + + // For fixed point operations, process one frame and verify initialization + // flag. + Init(); + EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFix(handle_, far_u16_, near_u16_, + spectrum_size_, 0, 0)); + EXPECT_EQ(1, self_->far_spectrum_initialized); + EXPECT_EQ(1, self_->near_spectrum_initialized); +} + +TEST_F(DelayEstimatorTest, CorrectLastDelay) { + // In this test we verify that we get the correct last delay upon valid call. + // We simply process the same data until we leave the initialized state + // (|last_delay| = -2). Then we compare the Process() output with the + // last_delay() call. + + int last_delay = 0; + // Floating point operations. + Init(); + for (int i = 0; i < 200; i++) { + last_delay = WebRtc_DelayEstimatorProcessFloat(handle_, far_f_, near_f_, + spectrum_size_); + if (last_delay != -2) { + EXPECT_EQ(last_delay, WebRtc_last_delay(handle_)); + break; + } + } + + // Fixed point operations. + Init(); + for (int i = 0; i < 200; i++) { + last_delay = WebRtc_DelayEstimatorProcessFix(handle_, far_u16_, near_u16_, + spectrum_size_, 0, 0); + if (last_delay != -2) { + EXPECT_EQ(last_delay, WebRtc_last_delay(handle_)); + break; + } + } +} + +TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfBinaryEstimator) { + // In this test we verify correct output on invalid API calls to the Binary + // Delay Estimator. + + BinaryDelayEstimator* binary_handle = binary_handle_; + // WebRtc_CreateBinaryDelayEstimator() should return -1 if we have a NULL + // pointer as |binary_handle| or invalid input values. Upon failure, the + // |binary_handle| should be NULL. + // Make sure we have a non-NULL value at start, so we can detect NULL after + // create failure. + binary_handle = WebRtc_CreateBinaryDelayEstimator(-1, 10); + EXPECT_TRUE(binary_handle == NULL); + binary_handle = binary_handle_; + binary_handle = WebRtc_CreateBinaryDelayEstimator(100, -1); + EXPECT_TRUE(binary_handle == NULL); + binary_handle = binary_handle_; + binary_handle = WebRtc_CreateBinaryDelayEstimator(0, 0); + EXPECT_TRUE(binary_handle == NULL); + + // TODO(bjornv): It is not feasible to force an error of + // WebRtc_ProcessBinarySpectrum(). This can only happen if we have more than + // 32 bits in our binary spectrum comparison, which by definition can't + // happen. + // We should therefore remove that option from the code. + + // WebRtc_binary_last_delay() can't return -1 either. +} + +TEST_F(DelayEstimatorTest, MeanEstimatorFix) { + // In this test we verify that we update the mean value in correct direction + // only. With "direction" we mean increase or decrease. + + InitBinary(); + + int32_t mean_value = 4000; + int32_t mean_value_before = mean_value; + int32_t new_mean_value = mean_value * 2; + + // Increasing |mean_value|. + WebRtc_MeanEstimatorFix(new_mean_value, 10, &mean_value); + EXPECT_LT(mean_value_before, mean_value); + EXPECT_GT(new_mean_value, mean_value); + + // Decreasing |mean_value|. + new_mean_value = mean_value / 2; + mean_value_before = mean_value; + WebRtc_MeanEstimatorFix(new_mean_value, 10, &mean_value); + EXPECT_GT(mean_value_before, mean_value); + EXPECT_LT(new_mean_value, mean_value); +} + +// TODO(bjornv): Add a test to verify correct delay + +} // namespace diff --git a/src/modules/audio_processing/utility/delay_estimator_wrapper.c b/src/modules/audio_processing/utility/delay_estimator_wrapper.c index 297ae4fc63..006bdf16dc 100644 --- a/src/modules/audio_processing/utility/delay_estimator_wrapper.c +++ b/src/modules/audio_processing/utility/delay_estimator_wrapper.c @@ -15,25 +15,7 @@ #include #include "delay_estimator.h" - -typedef union { - float float_; - int32_t int32_; -} SpectrumType; - -typedef struct { - // Pointers to mean values of spectrum. - SpectrumType* mean_far_spectrum; - SpectrumType* mean_near_spectrum; - // |mean_*_spectrum| initialization indicator. - int far_spectrum_initialized; - int near_spectrum_initialized; - - int spectrum_size; - - // Binary spectrum based delay estimator - BinaryDelayEstimator* binary_handle; -} DelayEstimator; +#include "modules/audio_processing/utility/delay_estimator_internal.h" // Only bit |kBandFirst| through bit |kBandLast| are processed and // |kBandFirst| - |kBandLast| must be < 32. @@ -205,7 +187,7 @@ int WebRtc_CreateDelayEstimator(void** handle, self->spectrum_size = spectrum_size; - if (return_value == -1) { + if (return_value < 0) { WebRtc_FreeDelayEstimator(self); *handle = NULL; } @@ -220,9 +202,8 @@ int WebRtc_InitDelayEstimator(void* handle) { } // Initialize binary delay estimator. - if (WebRtc_InitBinaryDelayEstimator(self->binary_handle) != 0) { - return -1; - } + WebRtc_InitBinaryDelayEstimator(self->binary_handle); + // Set averaged far and near end spectra to zero. memset(self->mean_far_spectrum, 0, sizeof(SpectrumType) * self->spectrum_size); diff --git a/src/modules/audio_processing/utility/util.gypi b/src/modules/audio_processing/utility/util.gypi index 3c3024a3b7..7551322d13 100644 --- a/src/modules/audio_processing/utility/util.gypi +++ b/src/modules/audio_processing/utility/util.gypi @@ -22,6 +22,7 @@ 'sources': [ 'delay_estimator.c', 'delay_estimator.h', + 'delay_estimator_internal.h', 'delay_estimator_wrapper.c', 'delay_estimator_wrapper.h', 'fft4g.c',