blob: aaaeff42dd4ce4f6d620bcee512e9307172d6e9b [file] [log] [blame]
/*
* 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 };
// Delay history sizes.
enum { kMaxDelay = 100 };
enum { kLookahead = 10 };
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() {
handle_ = WebRtc_CreateDelayEstimator(kSpectrumSize, kMaxDelay, kLookahead);
ASSERT_TRUE(handle_ != NULL);
self_ = reinterpret_cast<DelayEstimator*>(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 a NULL pointer on invalid input
// values.
// Make sure we have a non-NULL value at start, so we can detect NULL after
// create failure.
void* handle = handle_;
handle = WebRtc_CreateDelayEstimator(33, kMaxDelay, kLookahead);
EXPECT_TRUE(handle == NULL);
handle = handle_;
handle = WebRtc_CreateDelayEstimator(kSpectrumSize, -1, kLookahead);
EXPECT_TRUE(handle == NULL);
handle = handle_;
handle = WebRtc_CreateDelayEstimator(kSpectrumSize, kMaxDelay, -1);
EXPECT_TRUE(handle == NULL);
handle = handle_;
handle = WebRtc_CreateDelayEstimator(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;
}
}
// Verify that we have left the initialized state.
EXPECT_NE(-2, WebRtc_last_delay(handle_));
// 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;
}
}
// Verify that we have left the initialized state.
EXPECT_NE(-2, WebRtc_last_delay(handle_));
}
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, kLookahead);
EXPECT_TRUE(binary_handle == NULL);
binary_handle = binary_handle_;
binary_handle = WebRtc_CreateBinaryDelayEstimator(kMaxDelay, -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);
}
TEST_F(DelayEstimatorTest, ExactDelayEstimate) {
// In this test we verify that we get the correct delay estimate if we shift
// the signal accordingly. We verify both causal and non-causal delays.
// Construct a sequence of binary spectra used to verify delay estimate. The
// |sequence_length| has to be long enough for the delay estimation to leave
// the initialized state.
const int sequence_length = 400;
uint32_t binary_spectrum[sequence_length + kMaxDelay + kLookahead];
binary_spectrum[0] = 1;
for (int i = 1; i < (sequence_length + kMaxDelay + kLookahead); i++) {
binary_spectrum[i] = 3 * binary_spectrum[i - 1];
}
// Verify the delay for both causal and non-causal systems. For causal systems
// the delay is equivalent with a positive |offset| of the far-end sequence.
// For non-causal systems the delay is equivalent with a negative |offset| of
// the far-end sequence.
for (int offset = -kLookahead; offset < kMaxDelay; offset++) {
InitBinary();
for (int i = kLookahead; i < (sequence_length + kLookahead); i++) {
int delay = WebRtc_ProcessBinarySpectrum(binary_handle_,
binary_spectrum[i + offset],
binary_spectrum[i]);
// Verify that we WebRtc_binary_last_delay() returns correct delay.
EXPECT_EQ(delay, WebRtc_binary_last_delay(binary_handle_));
if (delay != -2) {
// Verify correct delay estimate. In the non-causal case the true delay
// is equivalent with the |offset|.
EXPECT_EQ(offset, delay - kLookahead);
}
}
// Verify that we have left the initialized state.
EXPECT_NE(-2, WebRtc_binary_last_delay(binary_handle_));
}
}
} // namespace