2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
11 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/modules/audio_processing/utility/delay_estimator.h"
15 #include "webrtc/modules/audio_processing/utility/delay_estimator_internal.h"
16 #include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
18 #include "webrtc/typedefs.h"
22 enum { kSpectrumSize = 65 };
23 // Delay history sizes.
24 enum { kMaxDelay = 100 };
25 enum { kLookahead = 10 };
26 // Length of binary spectrum sequence.
27 enum { kSequenceLength = 400 };
29 class DelayEstimatorTest : public ::testing::Test {
33 virtual void TearDown();
37 void VerifyDelay(BinaryDelayEstimator* binary_handle, int offset, int delay);
38 void RunBinarySpectra(BinaryDelayEstimator* binary1,
39 BinaryDelayEstimator* binary2,
40 int near_offset, int lookahead_offset, int far_offset);
41 void RunBinarySpectraTest(int near_offset, int lookahead_offset);
44 DelayEstimator* self_;
46 DelayEstimatorFarend* farend_self_;
47 BinaryDelayEstimator* binary_;
48 BinaryDelayEstimatorFarend* binary_farend_;
50 // Dummy input spectra.
51 float far_f_[kSpectrumSize];
52 float near_f_[kSpectrumSize];
53 uint16_t far_u16_[kSpectrumSize];
54 uint16_t near_u16_[kSpectrumSize];
55 uint32_t binary_spectrum_[kSequenceLength + kMaxDelay + kLookahead];
58 DelayEstimatorTest::DelayEstimatorTest()
65 spectrum_size_(kSpectrumSize) {
66 // Dummy input data are set with more or less arbitrary non-zero values.
67 memset(far_f_, 1, sizeof(far_f_));
68 memset(near_f_, 2, sizeof(near_f_));
69 memset(far_u16_, 1, sizeof(far_u16_));
70 memset(near_u16_, 2, sizeof(near_u16_));
71 // Construct a sequence of binary spectra used to verify delay estimate. The
72 // |kSequenceLength| has to be long enough for the delay estimation to leave
73 // the initialized state.
74 binary_spectrum_[0] = 1;
75 for (int i = 1; i < (kSequenceLength + kMaxDelay + kLookahead); i++) {
76 binary_spectrum_[i] = 3 * binary_spectrum_[i - 1];
80 void DelayEstimatorTest::SetUp() {
81 farend_handle_ = WebRtc_CreateDelayEstimatorFarend(kSpectrumSize,
82 kMaxDelay + kLookahead);
83 ASSERT_TRUE(farend_handle_ != NULL);
84 farend_self_ = reinterpret_cast<DelayEstimatorFarend*>(farend_handle_);
85 handle_ = WebRtc_CreateDelayEstimator(farend_handle_, kLookahead);
86 ASSERT_TRUE(handle_ != NULL);
87 self_ = reinterpret_cast<DelayEstimator*>(handle_);
88 binary_farend_ = WebRtc_CreateBinaryDelayEstimatorFarend(kMaxDelay +
90 ASSERT_TRUE(binary_farend_ != NULL);
91 binary_ = WebRtc_CreateBinaryDelayEstimator(binary_farend_, kLookahead);
92 ASSERT_TRUE(binary_ != NULL);
95 void DelayEstimatorTest::TearDown() {
96 WebRtc_FreeDelayEstimator(handle_);
99 WebRtc_FreeDelayEstimatorFarend(farend_handle_);
100 farend_handle_ = NULL;
102 WebRtc_FreeBinaryDelayEstimator(binary_);
104 WebRtc_FreeBinaryDelayEstimatorFarend(binary_farend_);
105 binary_farend_ = NULL;
108 void DelayEstimatorTest::Init() {
109 // Initialize Delay Estimator
110 EXPECT_EQ(0, WebRtc_InitDelayEstimatorFarend(farend_handle_));
111 EXPECT_EQ(0, WebRtc_InitDelayEstimator(handle_));
112 // Verify initialization.
113 EXPECT_EQ(0, farend_self_->far_spectrum_initialized);
114 EXPECT_EQ(0, self_->near_spectrum_initialized);
115 EXPECT_EQ(-2, WebRtc_last_delay(handle_)); // Delay in initial state.
116 EXPECT_EQ(0, WebRtc_last_delay_quality(handle_)); // Zero quality.
119 void DelayEstimatorTest::InitBinary() {
120 // Initialize Binary Delay Estimator (far-end part).
121 WebRtc_InitBinaryDelayEstimatorFarend(binary_farend_);
122 // Initialize Binary Delay Estimator
123 WebRtc_InitBinaryDelayEstimator(binary_);
124 // Verify initialization. This does not guarantee a complete check, since
125 // |last_delay| may be equal to -2 before initialization if done on the fly.
126 EXPECT_EQ(-2, binary_->last_delay);
129 void DelayEstimatorTest::VerifyDelay(BinaryDelayEstimator* binary_handle,
130 int offset, int delay) {
131 // Verify that we WebRtc_binary_last_delay() returns correct delay.
132 EXPECT_EQ(delay, WebRtc_binary_last_delay(binary_handle));
135 // Verify correct delay estimate. In the non-causal case the true delay
136 // is equivalent with the |offset|.
137 EXPECT_EQ(offset, delay);
141 void DelayEstimatorTest::RunBinarySpectra(BinaryDelayEstimator* binary1,
142 BinaryDelayEstimator* binary2,
144 int lookahead_offset,
146 WebRtc_InitBinaryDelayEstimatorFarend(binary_farend_);
147 WebRtc_InitBinaryDelayEstimator(binary1);
148 WebRtc_InitBinaryDelayEstimator(binary2);
149 // Verify initialization. This does not guarantee a complete check, since
150 // |last_delay| may be equal to -2 before initialization if done on the fly.
151 EXPECT_EQ(-2, binary1->last_delay);
152 EXPECT_EQ(-2, binary2->last_delay);
153 for (int i = kLookahead; i < (kSequenceLength + kLookahead); i++) {
154 WebRtc_AddBinaryFarSpectrum(binary_farend_,
155 binary_spectrum_[i + far_offset]);
156 int delay_1 = WebRtc_ProcessBinarySpectrum(binary1, binary_spectrum_[i]);
158 WebRtc_ProcessBinarySpectrum(binary2,
159 binary_spectrum_[i - near_offset]);
161 VerifyDelay(binary1, far_offset + kLookahead, delay_1);
163 far_offset + kLookahead + lookahead_offset + near_offset,
165 // Expect the two delay estimates to be offset by |lookahead_offset| +
166 // |near_offset| when we have left the initial state.
167 if ((delay_1 != -2) && (delay_2 != -2)) {
168 EXPECT_EQ(delay_1, delay_2 - lookahead_offset - near_offset);
170 if ((near_offset == 0) && (lookahead_offset == 0)) {
171 EXPECT_EQ(delay_1, delay_2);
174 // Verify that we have left the initialized state.
175 EXPECT_NE(-2, WebRtc_binary_last_delay(binary1));
176 EXPECT_NE(0, WebRtc_binary_last_delay_quality(binary1));
177 EXPECT_NE(-2, WebRtc_binary_last_delay(binary2));
178 EXPECT_NE(0, WebRtc_binary_last_delay_quality(binary2));
181 void DelayEstimatorTest::RunBinarySpectraTest(int near_offset,
182 int lookahead_offset) {
183 BinaryDelayEstimator* binary2 =
184 WebRtc_CreateBinaryDelayEstimator(binary_farend_,
185 kLookahead + lookahead_offset);
186 // Verify the delay for both causal and non-causal systems. For causal systems
187 // the delay is equivalent with a positive |offset| of the far-end sequence.
188 // For non-causal systems the delay is equivalent with a negative |offset| of
189 // the far-end sequence.
190 for (int offset = -kLookahead;
191 offset < kMaxDelay - lookahead_offset - near_offset;
193 RunBinarySpectra(binary_, binary2, near_offset, lookahead_offset, offset);
195 WebRtc_FreeBinaryDelayEstimator(binary2);
199 TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfWrapper) {
200 // In this test we verify correct error returns on invalid API calls.
202 // WebRtc_CreateDelayEstimatorFarend() and WebRtc_CreateDelayEstimator()
203 // should return a NULL pointer on invalid input values.
204 // Make sure we have a non-NULL value at start, so we can detect NULL after
206 void* handle = farend_handle_;
207 handle = WebRtc_CreateDelayEstimatorFarend(33, kMaxDelay + kLookahead);
208 EXPECT_TRUE(handle == NULL);
209 handle = farend_handle_;
210 handle = WebRtc_CreateDelayEstimatorFarend(kSpectrumSize, 1);
211 EXPECT_TRUE(handle == NULL);
214 handle = WebRtc_CreateDelayEstimator(NULL, kLookahead);
215 EXPECT_TRUE(handle == NULL);
217 handle = WebRtc_CreateDelayEstimator(farend_handle_, -1);
218 EXPECT_TRUE(handle == NULL);
220 // WebRtc_InitDelayEstimatorFarend() and WebRtc_InitDelayEstimator() should
221 // return -1 if we have a NULL pointer as |handle|.
222 EXPECT_EQ(-1, WebRtc_InitDelayEstimatorFarend(NULL));
223 EXPECT_EQ(-1, WebRtc_InitDelayEstimator(NULL));
225 // WebRtc_AddFarSpectrumFloat() should return -1 if we have:
226 // 1) NULL pointer as |handle|.
227 // 2) NULL pointer as far-end spectrum.
228 // 3) Incorrect spectrum size.
229 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(NULL, far_f_, spectrum_size_));
230 // Use |farend_handle_| which is properly created at SetUp().
231 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(farend_handle_, NULL,
233 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
234 spectrum_size_ + 1));
236 // WebRtc_AddFarSpectrumFix() should return -1 if we have:
237 // 1) NULL pointer as |handle|.
238 // 2) NULL pointer as far-end spectrum.
239 // 3) Incorrect spectrum size.
240 // 4) Too high precision in far-end spectrum (Q-domain > 15).
241 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(NULL, far_u16_, spectrum_size_, 0));
242 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, NULL, spectrum_size_,
244 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
245 spectrum_size_ + 1, 0));
246 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
247 spectrum_size_, 16));
249 // WebRtc_DelayEstimatorProcessFloat() should return -1 if we have:
250 // 1) NULL pointer as |handle|.
251 // 2) NULL pointer as near-end spectrum.
252 // 3) Incorrect spectrum size.
253 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(NULL, near_f_,
255 // Use |handle_| which is properly created at SetUp().
256 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, NULL,
258 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
259 spectrum_size_ + 1));
261 // WebRtc_DelayEstimatorProcessFix() should return -1 if we have:
262 // 1) NULL pointer as |handle|.
263 // 3) NULL pointer as near-end spectrum.
264 // 4) Incorrect spectrum size.
265 // 6) Too high precision in near-end spectrum (Q-domain > 15).
266 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(NULL, near_u16_, spectrum_size_,
268 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, NULL, spectrum_size_,
270 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
271 spectrum_size_ + 1, 0));
272 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
273 spectrum_size_, 16));
275 // WebRtc_last_delay() should return -1 if we have a NULL pointer as |handle|.
276 EXPECT_EQ(-1, WebRtc_last_delay(NULL));
278 // WebRtc_last_delay_quality() should return -1 if we have a NULL pointer as
280 EXPECT_EQ(-1, WebRtc_last_delay_quality(NULL));
282 // Free any local memory if needed.
283 WebRtc_FreeDelayEstimator(handle);
286 TEST_F(DelayEstimatorTest, InitializedSpectrumAfterProcess) {
287 // In this test we verify that the mean spectra are initialized after first
288 // time we call WebRtc_AddFarSpectrum() and Process() respectively.
290 // For floating point operations, process one frame and verify initialization
293 EXPECT_EQ(0, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
295 EXPECT_EQ(1, farend_self_->far_spectrum_initialized);
296 EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
298 EXPECT_EQ(1, self_->near_spectrum_initialized);
300 // For fixed point operations, process one frame and verify initialization
303 EXPECT_EQ(0, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
305 EXPECT_EQ(1, farend_self_->far_spectrum_initialized);
306 EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
308 EXPECT_EQ(1, self_->near_spectrum_initialized);
311 TEST_F(DelayEstimatorTest, CorrectLastDelay) {
312 // In this test we verify that we get the correct last delay upon valid call.
313 // We simply process the same data until we leave the initialized state
314 // (|last_delay| = -2). Then we compare the Process() output with the
315 // last_delay() call.
318 // Floating point operations.
320 for (int i = 0; i < 200; i++) {
321 EXPECT_EQ(0, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
323 last_delay = WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
325 if (last_delay != -2) {
326 EXPECT_EQ(last_delay, WebRtc_last_delay(handle_));
327 EXPECT_EQ(7203, WebRtc_last_delay_quality(handle_));
331 // Verify that we have left the initialized state.
332 EXPECT_NE(-2, WebRtc_last_delay(handle_));
333 EXPECT_NE(0, WebRtc_last_delay_quality(handle_));
335 // Fixed point operations.
337 for (int i = 0; i < 200; i++) {
338 EXPECT_EQ(0, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
340 last_delay = WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
342 if (last_delay != -2) {
343 EXPECT_EQ(last_delay, WebRtc_last_delay(handle_));
344 EXPECT_EQ(7203, WebRtc_last_delay_quality(handle_));
348 // Verify that we have left the initialized state.
349 EXPECT_NE(-2, WebRtc_last_delay(handle_));
350 EXPECT_NE(0, WebRtc_last_delay_quality(handle_));
353 TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfBinaryEstimatorFarend) {
354 // In this test we verify correct output on invalid API calls to the Binary
355 // Delay Estimator (far-end part).
357 BinaryDelayEstimatorFarend* binary = binary_farend_;
358 // WebRtc_CreateBinaryDelayEstimatorFarend() should return -1 if the input
359 // history size is less than 2. This is to make sure the buffer shifting
361 // Make sure we have a non-NULL value at start, so we can detect NULL after
363 binary = WebRtc_CreateBinaryDelayEstimatorFarend(1);
364 EXPECT_TRUE(binary == NULL);
367 TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfBinaryEstimator) {
368 // In this test we verify correct output on invalid API calls to the Binary
371 BinaryDelayEstimator* binary_handle = binary_;
372 // WebRtc_CreateBinaryDelayEstimator() should return -1 if we have a NULL
373 // pointer as |binary_handle| or invalid input values. Upon failure, the
374 // |binary_handle| should be NULL.
375 // Make sure we have a non-NULL value at start, so we can detect NULL after
377 binary_handle = WebRtc_CreateBinaryDelayEstimator(NULL, kLookahead);
378 EXPECT_TRUE(binary_handle == NULL);
379 binary_handle = binary_;
380 binary_handle = WebRtc_CreateBinaryDelayEstimator(binary_farend_, -1);
381 EXPECT_TRUE(binary_handle == NULL);
382 binary_handle = binary_;
383 binary_handle = WebRtc_CreateBinaryDelayEstimator(0, 0);
384 EXPECT_TRUE(binary_handle == NULL);
387 TEST_F(DelayEstimatorTest, MeanEstimatorFix) {
388 // In this test we verify that we update the mean value in correct direction
389 // only. With "direction" we mean increase or decrease.
391 int32_t mean_value = 4000;
392 int32_t mean_value_before = mean_value;
393 int32_t new_mean_value = mean_value * 2;
395 // Increasing |mean_value|.
396 WebRtc_MeanEstimatorFix(new_mean_value, 10, &mean_value);
397 EXPECT_LT(mean_value_before, mean_value);
398 EXPECT_GT(new_mean_value, mean_value);
400 // Decreasing |mean_value|.
401 new_mean_value = mean_value / 2;
402 mean_value_before = mean_value;
403 WebRtc_MeanEstimatorFix(new_mean_value, 10, &mean_value);
404 EXPECT_GT(mean_value_before, mean_value);
405 EXPECT_LT(new_mean_value, mean_value);
408 TEST_F(DelayEstimatorTest, ExactDelayEstimateMultipleNearSameSpectrum) {
409 // In this test we verify that we get the correct delay estimates if we shift
410 // the signal accordingly. We create two Binary Delay Estimators and feed them
411 // with the same signals, so they should output the same results.
412 // We verify both causal and non-causal delays.
414 RunBinarySpectraTest(0, 0);
417 TEST_F(DelayEstimatorTest, ExactDelayEstimateMultipleNearDifferentSpectrum) {
418 // In this test we use the same setup as above, but we now feed the two Binary
419 // Delay Estimators with different signals, so they should output different
422 const int kNearOffset = 1;
423 RunBinarySpectraTest(kNearOffset, 0);
426 TEST_F(DelayEstimatorTest, ExactDelayEstimateMultipleNearDifferentLookahead) {
427 // In this test we use the same setup as above, feeding the two Binary
428 // Delay Estimators with the same signals. The difference is that we create
429 // them with different lookahead.
431 const int kLookaheadOffset = 1;
432 RunBinarySpectraTest(0, kLookaheadOffset);