1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 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. 9 */ 10 11 #include "testing/gtest/include/gtest/gtest.h" 12 extern "C" { 13 #include "webrtc/modules/audio_processing/aec/aec_core.h" 14 } 15 #include "webrtc/modules/audio_processing/aec/echo_cancellation_internal.h" 16 #include "webrtc/modules/audio_processing/aec/include/echo_cancellation.h" 17 #include "webrtc/test/testsupport/gtest_disable.h" 18 #include "webrtc/typedefs.h" 19 20 namespace { 21 22 class SystemDelayTest : public ::testing::Test { 23 protected: 24 SystemDelayTest(); 25 virtual void SetUp(); 26 virtual void TearDown(); 27 28 // Initialization of AEC handle with respect to |sample_rate_hz|. Since the 29 // device sample rate is unimportant we set that value to 48000 Hz. 30 void Init(int sample_rate_hz); 31 32 // Makes one render call and one capture call in that specific order. 33 void RenderAndCapture(int device_buffer_ms); 34 35 // Fills up the far-end buffer with respect to the default device buffer size. 36 int BufferFillUp(); 37 38 // Runs and verifies the behavior in a stable startup procedure. 39 void RunStableStartup(); 40 41 // Maps buffer size in ms into samples, taking the unprocessed frame into 42 // account. 43 int MapBufferSizeToSamples(int size_in_ms); 44 45 void* handle_; 46 aecpc_t* self_; 47 int samples_per_frame_; 48 // Dummy input/output speech data. 49 static const int kSamplesPerChunk = 160; 50 float far_[kSamplesPerChunk]; 51 float near_[kSamplesPerChunk]; 52 float out_[kSamplesPerChunk]; 53 }; 54 55 SystemDelayTest::SystemDelayTest() 56 : handle_(NULL), self_(NULL), samples_per_frame_(0) { 57 // Dummy input data are set with more or less arbitrary non-zero values. 58 for (int i = 0; i < kSamplesPerChunk; i++) { 59 far_[i] = 257.0; 60 near_[i] = 514.0; 61 } 62 memset(out_, 0, sizeof(out_)); 63 } 64 65 void SystemDelayTest::SetUp() { 66 ASSERT_EQ(0, WebRtcAec_Create(&handle_)); 67 self_ = reinterpret_cast<aecpc_t*>(handle_); 68 } 69 70 void SystemDelayTest::TearDown() { 71 // Free AEC 72 ASSERT_EQ(0, WebRtcAec_Free(handle_)); 73 handle_ = NULL; 74 } 75 76 // In SWB mode nothing is added to the buffer handling with respect to 77 // functionality compared to WB. We therefore only verify behavior in NB and WB. 78 static const int kSampleRateHz[] = {8000, 16000}; 79 static const size_t kNumSampleRates = 80 sizeof(kSampleRateHz) / sizeof(*kSampleRateHz); 81 82 // Default audio device buffer size used. 83 static const int kDeviceBufMs = 100; 84 85 // Requirement for a stable device convergence time in ms. Should converge in 86 // less than |kStableConvergenceMs|. 87 static const int kStableConvergenceMs = 100; 88 89 // Maximum convergence time in ms. This means that we should leave the startup 90 // phase after |kMaxConvergenceMs| independent of device buffer stability 91 // conditions. 92 static const int kMaxConvergenceMs = 500; 93 94 void SystemDelayTest::Init(int sample_rate_hz) { 95 // Initialize AEC 96 EXPECT_EQ(0, WebRtcAec_Init(handle_, sample_rate_hz, 48000)); 97 98 // One frame equals 10 ms of data. 99 samples_per_frame_ = sample_rate_hz / 100; 100 } 101 102 void SystemDelayTest::RenderAndCapture(int device_buffer_ms) { 103 EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_)); 104 EXPECT_EQ(0, 105 WebRtcAec_Process(handle_, 106 near_, 107 NULL, 108 out_, 109 NULL, 110 samples_per_frame_, 111 device_buffer_ms, 112 0)); 113 } 114 115 int SystemDelayTest::BufferFillUp() { 116 // To make sure we have a full buffer when we verify stability we first fill 117 // up the far-end buffer with the same amount as we will report in through 118 // Process(). 119 int buffer_size = 0; 120 for (int i = 0; i < kDeviceBufMs / 10; i++) { 121 EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_)); 122 buffer_size += samples_per_frame_; 123 EXPECT_EQ(buffer_size, WebRtcAec_system_delay(self_->aec)); 124 } 125 return buffer_size; 126 } 127 128 void SystemDelayTest::RunStableStartup() { 129 // To make sure we have a full buffer when we verify stability we first fill 130 // up the far-end buffer with the same amount as we will report in through 131 // Process(). 132 int buffer_size = BufferFillUp(); 133 // A stable device should be accepted and put in a regular process mode within 134 // |kStableConvergenceMs|. 135 int process_time_ms = 0; 136 for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) { 137 RenderAndCapture(kDeviceBufMs); 138 buffer_size += samples_per_frame_; 139 if (self_->startup_phase == 0) { 140 // We have left the startup phase. 141 break; 142 } 143 } 144 // Verify convergence time. 145 EXPECT_GT(kStableConvergenceMs, process_time_ms); 146 // Verify that the buffer has been flushed. 147 EXPECT_GE(buffer_size, WebRtcAec_system_delay(self_->aec)); 148 } 149 150 int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms) { 151 // The extra 10 ms corresponds to the unprocessed frame. 152 return (size_in_ms + 10) * samples_per_frame_ / 10; 153 } 154 155 // The tests should meet basic requirements and not be adjusted to what is 156 // actually implemented. If we don't get good code coverage this way we either 157 // lack in tests or have unnecessary code. 158 // General requirements: 159 // 1) If we add far-end data the system delay should be increased with the same 160 // amount we add. 161 // 2) If the far-end buffer is full we should flush the oldest data to make room 162 // for the new. In this case the system delay is unaffected. 163 // 3) There should exist a startup phase in which the buffer size is to be 164 // determined. In this phase no cancellation should be performed. 165 // 4) Under stable conditions (small variations in device buffer sizes) the AEC 166 // should determine an appropriate local buffer size within 167 // |kStableConvergenceMs| ms. 168 // 5) Under unstable conditions the AEC should make a decision within 169 // |kMaxConvergenceMs| ms. 170 // 6) If the local buffer runs out of data we should stuff the buffer with older 171 // frames. 172 // 7) The system delay should within |kMaxConvergenceMs| ms heal from 173 // disturbances like drift, data glitches, toggling events and outliers. 174 // 8) The system delay should never become negative. 175 176 TEST_F(SystemDelayTest, CorrectIncreaseWhenBufferFarend) { 177 // When we add data to the AEC buffer the internal system delay should be 178 // incremented with the same amount as the size of data. 179 for (size_t i = 0; i < kNumSampleRates; i++) { 180 Init(kSampleRateHz[i]); 181 182 // Loop through a couple of calls to make sure the system delay increments 183 // correctly. 184 for (int j = 1; j <= 5; j++) { 185 EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_)); 186 EXPECT_EQ(j * samples_per_frame_, WebRtcAec_system_delay(self_->aec)); 187 } 188 } 189 } 190 191 // TODO(bjornv): Add a test to verify behavior if the far-end buffer is full 192 // when adding new data. 193 194 TEST_F(SystemDelayTest, CorrectDelayAfterStableStartup) { 195 // We run the system in a stable startup. After that we verify that the system 196 // delay meets the requirements. 197 for (size_t i = 0; i < kNumSampleRates; i++) { 198 Init(kSampleRateHz[i]); 199 RunStableStartup(); 200 201 // Verify system delay with respect to requirements, i.e., the 202 // |system_delay| is in the interval [75%, 100%] of what's reported on the 203 // average. 204 int average_reported_delay = kDeviceBufMs * samples_per_frame_ / 10; 205 EXPECT_GE(average_reported_delay, WebRtcAec_system_delay(self_->aec)); 206 EXPECT_LE(average_reported_delay * 3 / 4, 207 WebRtcAec_system_delay(self_->aec)); 208 } 209 } 210 211 TEST_F(SystemDelayTest, CorrectDelayAfterUnstableStartup) { 212 // In an unstable system we would start processing after |kMaxConvergenceMs|. 213 // On the last frame the AEC buffer is adjusted to 60% of the last reported 214 // device buffer size. 215 // We construct an unstable system by altering the device buffer size between 216 // two values |kDeviceBufMs| +- 25 ms. 217 for (size_t i = 0; i < kNumSampleRates; i++) { 218 Init(kSampleRateHz[i]); 219 220 // To make sure we have a full buffer when we verify stability we first fill 221 // up the far-end buffer with the same amount as we will report in on the 222 // average through Process(). 223 int buffer_size = BufferFillUp(); 224 225 int buffer_offset_ms = 25; 226 int reported_delay_ms = 0; 227 int process_time_ms = 0; 228 for (; process_time_ms <= kMaxConvergenceMs; process_time_ms += 10) { 229 reported_delay_ms = kDeviceBufMs + buffer_offset_ms; 230 RenderAndCapture(reported_delay_ms); 231 buffer_size += samples_per_frame_; 232 buffer_offset_ms = -buffer_offset_ms; 233 if (self_->startup_phase == 0) { 234 // We have left the startup phase. 235 break; 236 } 237 } 238 // Verify convergence time. 239 EXPECT_GE(kMaxConvergenceMs, process_time_ms); 240 // Verify that the buffer has been flushed. 241 EXPECT_GE(buffer_size, WebRtcAec_system_delay(self_->aec)); 242 243 // Verify system delay with respect to requirements, i.e., the 244 // |system_delay| is in the interval [60%, 100%] of what's last reported. 245 EXPECT_GE(reported_delay_ms * samples_per_frame_ / 10, 246 WebRtcAec_system_delay(self_->aec)); 247 EXPECT_LE(reported_delay_ms * samples_per_frame_ / 10 * 3 / 5, 248 WebRtcAec_system_delay(self_->aec)); 249 } 250 } 251 252 TEST_F(SystemDelayTest, 253 DISABLED_ON_ANDROID(CorrectDelayAfterStableBufferBuildUp)) { 254 // In this test we start by establishing the device buffer size during stable 255 // conditions, but with an empty internal far-end buffer. Once that is done we 256 // verify that the system delay is increased correctly until we have reach an 257 // internal buffer size of 75% of what's been reported. 258 259 // This test assumes the reported delays are used. 260 WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1); 261 for (size_t i = 0; i < kNumSampleRates; i++) { 262 Init(kSampleRateHz[i]); 263 264 // We assume that running |kStableConvergenceMs| calls will put the 265 // algorithm in a state where the device buffer size has been determined. We 266 // can make that assumption since we have a separate stability test. 267 int process_time_ms = 0; 268 for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) { 269 EXPECT_EQ(0, 270 WebRtcAec_Process(handle_, 271 near_, 272 NULL, 273 out_, 274 NULL, 275 samples_per_frame_, 276 kDeviceBufMs, 277 0)); 278 } 279 // Verify that a buffer size has been established. 280 EXPECT_EQ(0, self_->checkBuffSize); 281 282 // We now have established the required buffer size. Let us verify that we 283 // fill up before leaving the startup phase for normal processing. 284 int buffer_size = 0; 285 int target_buffer_size = kDeviceBufMs * samples_per_frame_ / 10 * 3 / 4; 286 process_time_ms = 0; 287 for (; process_time_ms <= kMaxConvergenceMs; process_time_ms += 10) { 288 RenderAndCapture(kDeviceBufMs); 289 buffer_size += samples_per_frame_; 290 if (self_->startup_phase == 0) { 291 // We have left the startup phase. 292 break; 293 } 294 } 295 // Verify convergence time. 296 EXPECT_GT(kMaxConvergenceMs, process_time_ms); 297 // Verify that the buffer has reached the desired size. 298 EXPECT_LE(target_buffer_size, WebRtcAec_system_delay(self_->aec)); 299 300 // Verify normal behavior (system delay is kept constant) after startup by 301 // running a couple of calls to BufferFarend() and Process(). 302 for (int j = 0; j < 6; j++) { 303 int system_delay_before_calls = WebRtcAec_system_delay(self_->aec); 304 RenderAndCapture(kDeviceBufMs); 305 EXPECT_EQ(system_delay_before_calls, WebRtcAec_system_delay(self_->aec)); 306 } 307 } 308 } 309 310 TEST_F(SystemDelayTest, CorrectDelayWhenBufferUnderrun) { 311 // Here we test a buffer under run scenario. If we keep on calling 312 // WebRtcAec_Process() we will finally run out of data, but should 313 // automatically stuff the buffer. We verify this behavior by checking if the 314 // system delay goes negative. 315 for (size_t i = 0; i < kNumSampleRates; i++) { 316 Init(kSampleRateHz[i]); 317 RunStableStartup(); 318 319 // The AEC has now left the Startup phase. We now have at most 320 // |kStableConvergenceMs| in the buffer. Keep on calling Process() until 321 // we run out of data and verify that the system delay is non-negative. 322 for (int j = 0; j <= kStableConvergenceMs; j += 10) { 323 EXPECT_EQ(0, 324 WebRtcAec_Process(handle_, 325 near_, 326 NULL, 327 out_, 328 NULL, 329 samples_per_frame_, 330 kDeviceBufMs, 331 0)); 332 EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); 333 } 334 } 335 } 336 337 TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(CorrectDelayDuringDrift)) { 338 // This drift test should verify that the system delay is never exceeding the 339 // device buffer. The drift is simulated by decreasing the reported device 340 // buffer size by 1 ms every 100 ms. If the device buffer size goes below 30 341 // ms we jump (add) 10 ms to give a repeated pattern. 342 343 // This test assumes the reported delays are used. 344 WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1); 345 for (size_t i = 0; i < kNumSampleRates; i++) { 346 Init(kSampleRateHz[i]); 347 RunStableStartup(); 348 349 // We have now left the startup phase and proceed with normal processing. 350 int jump = 0; 351 for (int j = 0; j < 1000; j++) { 352 // Drift = -1 ms per 100 ms of data. 353 int device_buf_ms = kDeviceBufMs - (j / 10) + jump; 354 int device_buf = MapBufferSizeToSamples(device_buf_ms); 355 356 if (device_buf_ms < 30) { 357 // Add 10 ms data, taking affect next frame. 358 jump += 10; 359 } 360 RenderAndCapture(device_buf_ms); 361 362 // Verify that the system delay does not exceed the device buffer. 363 EXPECT_GE(device_buf, WebRtcAec_system_delay(self_->aec)); 364 365 // Verify that the system delay is non-negative. 366 EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); 367 } 368 } 369 } 370 371 TEST_F(SystemDelayTest, DISABLED_ON_ANDROID(ShouldRecoverAfterGlitch)) { 372 // This glitch test should verify that the system delay recovers if there is 373 // a glitch in data. The data glitch is constructed as 200 ms of buffering 374 // after which the stable procedure continues. The glitch is never reported by 375 // the device. 376 // The system is said to be in a non-causal state if the difference between 377 // the device buffer and system delay is less than a block (64 samples). 378 379 // This test assumes the reported delays are used. 380 WebRtcAec_enable_reported_delay(WebRtcAec_aec_core(handle_), 1); 381 for (size_t i = 0; i < kNumSampleRates; i++) { 382 Init(kSampleRateHz[i]); 383 RunStableStartup(); 384 int device_buf = MapBufferSizeToSamples(kDeviceBufMs); 385 // Glitch state. 386 for (int j = 0; j < 20; j++) { 387 EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_)); 388 // No need to verify system delay, since that is done in a separate test. 389 } 390 // Verify that we are in a non-causal state, i.e., 391 // |system_delay| > |device_buf|. 392 EXPECT_LT(device_buf, WebRtcAec_system_delay(self_->aec)); 393 394 // Recover state. Should recover at least 4 ms of data per 10 ms, hence a 395 // glitch of 200 ms will take at most 200 * 10 / 4 = 500 ms to recover from. 396 bool non_causal = true; // We are currently in a non-causal state. 397 for (int j = 0; j < 50; j++) { 398 int system_delay_before = WebRtcAec_system_delay(self_->aec); 399 RenderAndCapture(kDeviceBufMs); 400 int system_delay_after = WebRtcAec_system_delay(self_->aec); 401 402 // We have recovered if |device_buf| - |system_delay_after| >= 64 (one 403 // block). During recovery |system_delay_after| < |system_delay_before|, 404 // otherwise they are equal. 405 if (non_causal) { 406 EXPECT_LT(system_delay_after, system_delay_before); 407 if (device_buf - system_delay_after >= 64) { 408 non_causal = false; 409 } 410 } else { 411 EXPECT_EQ(system_delay_before, system_delay_after); 412 } 413 // Verify that the system delay is non-negative. 414 EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); 415 } 416 // Check that we have recovered. 417 EXPECT_FALSE(non_causal); 418 } 419 } 420 421 TEST_F(SystemDelayTest, UnaffectedWhenSpuriousDeviceBufferValues) { 422 // This spurious device buffer data test aims at verifying that the system 423 // delay is unaffected by large outliers. 424 // The system is said to be in a non-causal state if the difference between 425 // the device buffer and system delay is less than a block (64 samples). 426 for (size_t i = 0; i < kNumSampleRates; i++) { 427 Init(kSampleRateHz[i]); 428 RunStableStartup(); 429 int device_buf = MapBufferSizeToSamples(kDeviceBufMs); 430 431 // Normal state. We are currently not in a non-causal state. 432 bool non_causal = false; 433 434 // Run 1 s and replace device buffer size with 500 ms every 100 ms. 435 for (int j = 0; j < 100; j++) { 436 int system_delay_before_calls = WebRtcAec_system_delay(self_->aec); 437 int device_buf_ms = kDeviceBufMs; 438 if (j % 10 == 0) { 439 device_buf_ms = 500; 440 } 441 RenderAndCapture(device_buf_ms); 442 443 // Check for non-causality. 444 if (device_buf - WebRtcAec_system_delay(self_->aec) < 64) { 445 non_causal = true; 446 } 447 EXPECT_FALSE(non_causal); 448 EXPECT_EQ(system_delay_before_calls, WebRtcAec_system_delay(self_->aec)); 449 450 // Verify that the system delay is non-negative. 451 EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); 452 } 453 } 454 } 455 456 TEST_F(SystemDelayTest, CorrectImpactWhenTogglingDeviceBufferValues) { 457 // This test aims at verifying that the system delay is "unaffected" by 458 // toggling values reported by the device. 459 // The test is constructed such that every other device buffer value is zero 460 // and then 2 * |kDeviceBufMs|, hence the size is constant on the average. The 461 // zero values will force us into a non-causal state and thereby lowering the 462 // system delay until we basically runs out of data. Once that happens the 463 // buffer will be stuffed. 464 // TODO(bjornv): This test will have a better impact if we verified that the 465 // delay estimate goes up when the system delay goes done to meet the average 466 // device buffer size. 467 for (size_t i = 0; i < kNumSampleRates; i++) { 468 Init(kSampleRateHz[i]); 469 RunStableStartup(); 470 int device_buf = MapBufferSizeToSamples(kDeviceBufMs); 471 472 // Normal state. We are currently not in a non-causal state. 473 bool non_causal = false; 474 475 // Loop through 100 frames (both render and capture), which equals 1 s of 476 // data. Every odd frame we set the device buffer size to 2 * |kDeviceBufMs| 477 // and even frames we set the device buffer size to zero. 478 for (int j = 0; j < 100; j++) { 479 int system_delay_before_calls = WebRtcAec_system_delay(self_->aec); 480 int device_buf_ms = 2 * (j % 2) * kDeviceBufMs; 481 RenderAndCapture(device_buf_ms); 482 483 // Check for non-causality, compared with the average device buffer size. 484 non_causal |= (device_buf - WebRtcAec_system_delay(self_->aec) < 64); 485 EXPECT_GE(system_delay_before_calls, WebRtcAec_system_delay(self_->aec)); 486 487 // Verify that the system delay is non-negative. 488 EXPECT_LE(0, WebRtcAec_system_delay(self_->aec)); 489 } 490 // Verify we are not in a non-causal state. 491 EXPECT_FALSE(non_causal); 492 } 493 } 494 495 } // namespace 496