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 const int kEnable[] = { 0, 1 };
30 const size_t kSizeEnable = sizeof(kEnable) / sizeof(*kEnable);
32 class DelayEstimatorTest : public ::testing::Test {
36 virtual void TearDown();
40 void VerifyDelay(BinaryDelayEstimator* binary_handle, int offset, int delay);
41 void RunBinarySpectra(BinaryDelayEstimator* binary1,
42 BinaryDelayEstimator* binary2,
43 int near_offset, int lookahead_offset, int far_offset);
44 void RunBinarySpectraTest(int near_offset, int lookahead_offset,
45 int ref_robust_validation, int robust_validation);
48 DelayEstimator* self_;
50 DelayEstimatorFarend* farend_self_;
51 BinaryDelayEstimator* binary_;
52 BinaryDelayEstimatorFarend* binary_farend_;
54 // Dummy input spectra.
55 float far_f_[kSpectrumSize];
56 float near_f_[kSpectrumSize];
57 uint16_t far_u16_[kSpectrumSize];
58 uint16_t near_u16_[kSpectrumSize];
59 uint32_t binary_spectrum_[kSequenceLength + kMaxDelay + kLookahead];
62 DelayEstimatorTest::DelayEstimatorTest()
69 spectrum_size_(kSpectrumSize) {
70 // Dummy input data are set with more or less arbitrary non-zero values.
71 memset(far_f_, 1, sizeof(far_f_));
72 memset(near_f_, 2, sizeof(near_f_));
73 memset(far_u16_, 1, sizeof(far_u16_));
74 memset(near_u16_, 2, sizeof(near_u16_));
75 // Construct a sequence of binary spectra used to verify delay estimate. The
76 // |kSequenceLength| has to be long enough for the delay estimation to leave
77 // the initialized state.
78 binary_spectrum_[0] = 1;
79 for (int i = 1; i < (kSequenceLength + kMaxDelay + kLookahead); i++) {
80 binary_spectrum_[i] = 3 * binary_spectrum_[i - 1];
84 void DelayEstimatorTest::SetUp() {
85 farend_handle_ = WebRtc_CreateDelayEstimatorFarend(kSpectrumSize,
86 kMaxDelay + kLookahead);
87 ASSERT_TRUE(farend_handle_ != NULL);
88 farend_self_ = reinterpret_cast<DelayEstimatorFarend*>(farend_handle_);
89 handle_ = WebRtc_CreateDelayEstimator(farend_handle_, kLookahead, kLookahead);
90 ASSERT_TRUE(handle_ != NULL);
91 self_ = reinterpret_cast<DelayEstimator*>(handle_);
92 binary_farend_ = WebRtc_CreateBinaryDelayEstimatorFarend(kMaxDelay +
94 ASSERT_TRUE(binary_farend_ != NULL);
95 binary_ = WebRtc_CreateBinaryDelayEstimator(binary_farend_, kLookahead,
97 ASSERT_TRUE(binary_ != NULL);
100 void DelayEstimatorTest::TearDown() {
101 WebRtc_FreeDelayEstimator(handle_);
104 WebRtc_FreeDelayEstimatorFarend(farend_handle_);
105 farend_handle_ = NULL;
107 WebRtc_FreeBinaryDelayEstimator(binary_);
109 WebRtc_FreeBinaryDelayEstimatorFarend(binary_farend_);
110 binary_farend_ = NULL;
113 void DelayEstimatorTest::Init() {
114 // Initialize Delay Estimator
115 EXPECT_EQ(0, WebRtc_InitDelayEstimatorFarend(farend_handle_));
116 EXPECT_EQ(0, WebRtc_InitDelayEstimator(handle_));
117 // Verify initialization.
118 EXPECT_EQ(0, farend_self_->far_spectrum_initialized);
119 EXPECT_EQ(0, self_->near_spectrum_initialized);
120 EXPECT_EQ(-2, WebRtc_last_delay(handle_)); // Delay in initial state.
121 EXPECT_FLOAT_EQ(0, WebRtc_last_delay_quality(handle_)); // Zero quality.
124 void DelayEstimatorTest::InitBinary() {
125 // Initialize Binary Delay Estimator (far-end part).
126 WebRtc_InitBinaryDelayEstimatorFarend(binary_farend_);
127 // Initialize Binary Delay Estimator
128 WebRtc_InitBinaryDelayEstimator(binary_);
129 // Verify initialization. This does not guarantee a complete check, since
130 // |last_delay| may be equal to -2 before initialization if done on the fly.
131 EXPECT_EQ(-2, binary_->last_delay);
134 void DelayEstimatorTest::VerifyDelay(BinaryDelayEstimator* binary_handle,
135 int offset, int delay) {
136 // Verify that we WebRtc_binary_last_delay() returns correct delay.
137 EXPECT_EQ(delay, WebRtc_binary_last_delay(binary_handle));
140 // Verify correct delay estimate. In the non-causal case the true delay
141 // is equivalent with the |offset|.
142 EXPECT_EQ(offset, delay);
146 void DelayEstimatorTest::RunBinarySpectra(BinaryDelayEstimator* binary1,
147 BinaryDelayEstimator* binary2,
149 int lookahead_offset,
151 int different_validations = binary1->robust_validation_enabled ^
152 binary2->robust_validation_enabled;
153 WebRtc_InitBinaryDelayEstimatorFarend(binary_farend_);
154 WebRtc_InitBinaryDelayEstimator(binary1);
155 WebRtc_InitBinaryDelayEstimator(binary2);
156 // Verify initialization. This does not guarantee a complete check, since
157 // |last_delay| may be equal to -2 before initialization if done on the fly.
158 EXPECT_EQ(-2, binary1->last_delay);
159 EXPECT_EQ(-2, binary2->last_delay);
160 for (int i = kLookahead; i < (kSequenceLength + kLookahead); i++) {
161 WebRtc_AddBinaryFarSpectrum(binary_farend_,
162 binary_spectrum_[i + far_offset]);
163 int delay_1 = WebRtc_ProcessBinarySpectrum(binary1, binary_spectrum_[i]);
165 WebRtc_ProcessBinarySpectrum(binary2,
166 binary_spectrum_[i - near_offset]);
168 VerifyDelay(binary1, far_offset + kLookahead, delay_1);
170 far_offset + kLookahead + lookahead_offset + near_offset,
172 // Expect the two delay estimates to be offset by |lookahead_offset| +
173 // |near_offset| when we have left the initial state.
174 if ((delay_1 != -2) && (delay_2 != -2)) {
175 EXPECT_EQ(delay_1, delay_2 - lookahead_offset - near_offset);
177 // For the case of identical signals |delay_1| and |delay_2| should match
178 // all the time, unless one of them has robust validation turned on. In
179 // that case the robust validation leaves the initial state faster.
180 if ((near_offset == 0) && (lookahead_offset == 0)) {
181 if (!different_validations) {
182 EXPECT_EQ(delay_1, delay_2);
184 if (binary1->robust_validation_enabled) {
185 EXPECT_GE(delay_1, delay_2);
187 EXPECT_GE(delay_2, delay_1);
192 // Verify that we have left the initialized state.
193 EXPECT_NE(-2, WebRtc_binary_last_delay(binary1));
194 EXPECT_LT(0, WebRtc_binary_last_delay_quality(binary1));
195 EXPECT_NE(-2, WebRtc_binary_last_delay(binary2));
196 EXPECT_LT(0, WebRtc_binary_last_delay_quality(binary2));
199 void DelayEstimatorTest::RunBinarySpectraTest(int near_offset,
200 int lookahead_offset,
201 int ref_robust_validation,
202 int robust_validation) {
203 BinaryDelayEstimator* binary2 =
204 WebRtc_CreateBinaryDelayEstimator(binary_farend_,
205 kLookahead + lookahead_offset,
206 kLookahead + lookahead_offset);
207 // Verify the delay for both causal and non-causal systems. For causal systems
208 // the delay is equivalent with a positive |offset| of the far-end sequence.
209 // For non-causal systems the delay is equivalent with a negative |offset| of
210 // the far-end sequence.
211 binary_->robust_validation_enabled = ref_robust_validation;
212 binary2->robust_validation_enabled = robust_validation;
213 for (int offset = -kLookahead;
214 offset < kMaxDelay - lookahead_offset - near_offset;
216 RunBinarySpectra(binary_, binary2, near_offset, lookahead_offset, offset);
218 WebRtc_FreeBinaryDelayEstimator(binary2);
220 binary_->robust_validation_enabled = 0; // Reset reference.
223 TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfWrapper) {
224 // In this test we verify correct error returns on invalid API calls.
226 // WebRtc_CreateDelayEstimatorFarend() and WebRtc_CreateDelayEstimator()
227 // should return a NULL pointer on invalid input values.
228 // Make sure we have a non-NULL value at start, so we can detect NULL after
230 void* handle = farend_handle_;
231 handle = WebRtc_CreateDelayEstimatorFarend(33, kMaxDelay + kLookahead);
232 EXPECT_TRUE(handle == NULL);
233 handle = WebRtc_CreateDelayEstimatorFarend(kSpectrumSize, 1);
234 EXPECT_TRUE(handle == NULL);
237 handle = WebRtc_CreateDelayEstimator(NULL, kLookahead, kLookahead);
238 EXPECT_TRUE(handle == NULL);
239 handle = WebRtc_CreateDelayEstimator(farend_handle_, kLookahead, -1);
240 EXPECT_TRUE(handle == NULL);
241 handle = WebRtc_CreateDelayEstimator(farend_handle_, kLookahead - 1,
243 EXPECT_TRUE(handle == NULL);
245 // WebRtc_InitDelayEstimatorFarend() and WebRtc_InitDelayEstimator() should
246 // return -1 if we have a NULL pointer as |handle|.
247 EXPECT_EQ(-1, WebRtc_InitDelayEstimatorFarend(NULL));
248 EXPECT_EQ(-1, WebRtc_InitDelayEstimator(NULL));
250 // WebRtc_AddFarSpectrumFloat() should return -1 if we have:
251 // 1) NULL pointer as |handle|.
252 // 2) NULL pointer as far-end spectrum.
253 // 3) Incorrect spectrum size.
254 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(NULL, far_f_, spectrum_size_));
255 // Use |farend_handle_| which is properly created at SetUp().
256 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(farend_handle_, NULL,
258 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
259 spectrum_size_ + 1));
261 // WebRtc_AddFarSpectrumFix() should return -1 if we have:
262 // 1) NULL pointer as |handle|.
263 // 2) NULL pointer as far-end spectrum.
264 // 3) Incorrect spectrum size.
265 // 4) Too high precision in far-end spectrum (Q-domain > 15).
266 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(NULL, far_u16_, spectrum_size_, 0));
267 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, NULL, spectrum_size_,
269 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
270 spectrum_size_ + 1, 0));
271 EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
272 spectrum_size_, 16));
274 // WebRtc_set_allowed_offset() should return -1 if we have:
275 // 1) NULL pointer as |handle|.
276 // 2) |allowed_offset| < 0.
277 EXPECT_EQ(-1, WebRtc_set_allowed_offset(NULL, 0));
278 EXPECT_EQ(-1, WebRtc_set_allowed_offset(handle_, -1));
280 EXPECT_EQ(-1, WebRtc_get_allowed_offset(NULL));
282 // WebRtc_enable_robust_validation() should return -1 if we have:
283 // 1) NULL pointer as |handle|.
284 // 2) Incorrect |enable| value (not 0 or 1).
285 EXPECT_EQ(-1, WebRtc_enable_robust_validation(NULL, kEnable[0]));
286 EXPECT_EQ(-1, WebRtc_enable_robust_validation(handle_, -1));
287 EXPECT_EQ(-1, WebRtc_enable_robust_validation(handle_, 2));
289 // WebRtc_is_robust_validation_enabled() should return -1 if we have NULL
290 // pointer as |handle|.
291 EXPECT_EQ(-1, WebRtc_is_robust_validation_enabled(NULL));
293 // WebRtc_DelayEstimatorProcessFloat() should return -1 if we have:
294 // 1) NULL pointer as |handle|.
295 // 2) NULL pointer as near-end spectrum.
296 // 3) Incorrect spectrum size.
297 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(NULL, near_f_,
299 // Use |handle_| which is properly created at SetUp().
300 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, NULL,
302 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
303 spectrum_size_ + 1));
305 // WebRtc_DelayEstimatorProcessFix() should return -1 if we have:
306 // 1) NULL pointer as |handle|.
307 // 3) NULL pointer as near-end spectrum.
308 // 4) Incorrect spectrum size.
309 // 6) Too high precision in near-end spectrum (Q-domain > 15).
310 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(NULL, near_u16_, spectrum_size_,
312 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, NULL, spectrum_size_,
314 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
315 spectrum_size_ + 1, 0));
316 EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
317 spectrum_size_, 16));
319 // WebRtc_last_delay() should return -1 if we have a NULL pointer as |handle|.
320 EXPECT_EQ(-1, WebRtc_last_delay(NULL));
322 // Free any local memory if needed.
323 WebRtc_FreeDelayEstimator(handle);
326 TEST_F(DelayEstimatorTest, VerifyAllowedOffset) {
327 // Is set to zero by default.
328 EXPECT_EQ(0, WebRtc_get_allowed_offset(handle_));
329 for (int i = 1; i >= 0; i--) {
330 EXPECT_EQ(0, WebRtc_set_allowed_offset(handle_, i));
331 EXPECT_EQ(i, WebRtc_get_allowed_offset(handle_));
333 // Unaffected over a reset.
334 EXPECT_EQ(i, WebRtc_get_allowed_offset(handle_));
338 TEST_F(DelayEstimatorTest, VerifyEnableRobustValidation) {
339 // Disabled by default.
340 EXPECT_EQ(0, WebRtc_is_robust_validation_enabled(handle_));
341 for (size_t i = 0; i < kSizeEnable; ++i) {
342 EXPECT_EQ(0, WebRtc_enable_robust_validation(handle_, kEnable[i]));
343 EXPECT_EQ(kEnable[i], WebRtc_is_robust_validation_enabled(handle_));
345 // Unaffected over a reset.
346 EXPECT_EQ(kEnable[i], WebRtc_is_robust_validation_enabled(handle_));
350 TEST_F(DelayEstimatorTest, InitializedSpectrumAfterProcess) {
351 // In this test we verify that the mean spectra are initialized after first
352 // time we call WebRtc_AddFarSpectrum() and Process() respectively.
354 // For floating point operations, process one frame and verify initialization
357 EXPECT_EQ(0, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
359 EXPECT_EQ(1, farend_self_->far_spectrum_initialized);
360 EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
362 EXPECT_EQ(1, self_->near_spectrum_initialized);
364 // For fixed point operations, process one frame and verify initialization
367 EXPECT_EQ(0, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
369 EXPECT_EQ(1, farend_self_->far_spectrum_initialized);
370 EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
372 EXPECT_EQ(1, self_->near_spectrum_initialized);
375 TEST_F(DelayEstimatorTest, CorrectLastDelay) {
376 // In this test we verify that we get the correct last delay upon valid call.
377 // We simply process the same data until we leave the initialized state
378 // (|last_delay| = -2). Then we compare the Process() output with the
379 // last_delay() call.
381 // TODO(bjornv): Update quality values for robust validation.
383 // Floating point operations.
385 for (int i = 0; i < 200; i++) {
386 EXPECT_EQ(0, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
388 last_delay = WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
390 if (last_delay != -2) {
391 EXPECT_EQ(last_delay, WebRtc_last_delay(handle_));
392 if (!WebRtc_is_robust_validation_enabled(handle_)) {
393 EXPECT_FLOAT_EQ(7203.f / kMaxBitCountsQ9,
394 WebRtc_last_delay_quality(handle_));
399 // Verify that we have left the initialized state.
400 EXPECT_NE(-2, WebRtc_last_delay(handle_));
401 EXPECT_LT(0, WebRtc_last_delay_quality(handle_));
403 // Fixed point operations.
405 for (int i = 0; i < 200; i++) {
406 EXPECT_EQ(0, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
408 last_delay = WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
410 if (last_delay != -2) {
411 EXPECT_EQ(last_delay, WebRtc_last_delay(handle_));
412 if (!WebRtc_is_robust_validation_enabled(handle_)) {
413 EXPECT_FLOAT_EQ(7203.f / kMaxBitCountsQ9,
414 WebRtc_last_delay_quality(handle_));
419 // Verify that we have left the initialized state.
420 EXPECT_NE(-2, WebRtc_last_delay(handle_));
421 EXPECT_LT(0, WebRtc_last_delay_quality(handle_));
424 TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfBinaryEstimatorFarend) {
425 // In this test we verify correct output on invalid API calls to the Binary
426 // Delay Estimator (far-end part).
428 BinaryDelayEstimatorFarend* binary = binary_farend_;
429 // WebRtc_CreateBinaryDelayEstimatorFarend() should return -1 if the input
430 // history size is less than 2. This is to make sure the buffer shifting
432 // Make sure we have a non-NULL value at start, so we can detect NULL after
434 binary = WebRtc_CreateBinaryDelayEstimatorFarend(1);
435 EXPECT_TRUE(binary == NULL);
438 TEST_F(DelayEstimatorTest, CorrectErrorReturnsOfBinaryEstimator) {
439 // In this test we verify correct output on invalid API calls to the Binary
442 BinaryDelayEstimator* binary_handle = binary_;
443 // WebRtc_CreateBinaryDelayEstimator() should return -1 if we have a NULL
444 // pointer as |binary_farend| or invalid input values. Upon failure, the
445 // |binary_handle| should be NULL.
446 // Make sure we have a non-NULL value at start, so we can detect NULL after
448 binary_handle = WebRtc_CreateBinaryDelayEstimator(NULL, kLookahead,
450 EXPECT_TRUE(binary_handle == NULL);
451 binary_handle = WebRtc_CreateBinaryDelayEstimator(binary_farend_, kLookahead,
453 EXPECT_TRUE(binary_handle == NULL);
454 binary_handle = WebRtc_CreateBinaryDelayEstimator(binary_farend_,
455 kLookahead - 1, kLookahead);
456 EXPECT_TRUE(binary_handle == NULL);
459 TEST_F(DelayEstimatorTest, MeanEstimatorFix) {
460 // In this test we verify that we update the mean value in correct direction
461 // only. With "direction" we mean increase or decrease.
463 int32_t mean_value = 4000;
464 int32_t mean_value_before = mean_value;
465 int32_t new_mean_value = mean_value * 2;
467 // Increasing |mean_value|.
468 WebRtc_MeanEstimatorFix(new_mean_value, 10, &mean_value);
469 EXPECT_LT(mean_value_before, mean_value);
470 EXPECT_GT(new_mean_value, mean_value);
472 // Decreasing |mean_value|.
473 new_mean_value = mean_value / 2;
474 mean_value_before = mean_value;
475 WebRtc_MeanEstimatorFix(new_mean_value, 10, &mean_value);
476 EXPECT_GT(mean_value_before, mean_value);
477 EXPECT_LT(new_mean_value, mean_value);
480 TEST_F(DelayEstimatorTest, ExactDelayEstimateMultipleNearSameSpectrum) {
481 // In this test we verify that we get the correct delay estimates if we shift
482 // the signal accordingly. We create two Binary Delay Estimators and feed them
483 // with the same signals, so they should output the same results.
484 // We verify both causal and non-causal delays.
485 // For these noise free signals, the robust validation should not have an
486 // impact, hence we turn robust validation on/off for both reference and
489 for (size_t i = 0; i < kSizeEnable; ++i) {
490 for (size_t j = 0; j < kSizeEnable; ++j) {
491 RunBinarySpectraTest(0, 0, kEnable[i], kEnable[j]);
496 TEST_F(DelayEstimatorTest, ExactDelayEstimateMultipleNearDifferentSpectrum) {
497 // In this test we use the same setup as above, but we now feed the two Binary
498 // Delay Estimators with different signals, so they should output different
500 // For these noise free signals, the robust validation should not have an
501 // impact, hence we turn robust validation on/off for both reference and
504 const int kNearOffset = 1;
505 for (size_t i = 0; i < kSizeEnable; ++i) {
506 for (size_t j = 0; j < kSizeEnable; ++j) {
507 RunBinarySpectraTest(kNearOffset, 0, kEnable[i], kEnable[j]);
512 TEST_F(DelayEstimatorTest, ExactDelayEstimateMultipleNearDifferentLookahead) {
513 // In this test we use the same setup as above, feeding the two Binary
514 // Delay Estimators with the same signals. The difference is that we create
515 // them with different lookahead.
516 // For these noise free signals, the robust validation should not have an
517 // impact, hence we turn robust validation on/off for both reference and
520 const int kLookaheadOffset = 1;
521 for (size_t i = 0; i < kSizeEnable; ++i) {
522 for (size_t j = 0; j < kSizeEnable; ++j) {
523 RunBinarySpectraTest(0, kLookaheadOffset, kEnable[i], kEnable[j]);
528 TEST_F(DelayEstimatorTest, AllowedOffsetNoImpactWhenRobustValidationDisabled) {
529 // The same setup as in ExactDelayEstimateMultipleNearSameSpectrum with the
530 // difference that |allowed_offset| is set for the reference binary delay
533 binary_->allowed_offset = 10;
534 RunBinarySpectraTest(0, 0, 0, 0);
535 binary_->allowed_offset = 0; // Reset reference.
538 TEST_F(DelayEstimatorTest, VerifyLookaheadAtCreate) {
539 void* farend_handle = WebRtc_CreateDelayEstimatorFarend(kSpectrumSize,
541 ASSERT_TRUE(farend_handle != NULL);
542 void* handle = WebRtc_CreateDelayEstimator(farend_handle, kLookahead,
544 ASSERT_TRUE(handle != NULL);
545 EXPECT_EQ(kLookahead, WebRtc_lookahead(handle));
546 WebRtc_FreeDelayEstimator(handle);
547 WebRtc_FreeDelayEstimatorFarend(farend_handle);
550 // TODO(bjornv): Add tests for SoftReset...(...).