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