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