1 /*
2 * Copyright (c) 2022 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 "modules/audio_processing/aec3/multi_channel_content_detector.h"
12
13 #include "system_wrappers/include/metrics.h"
14 #include "test/gtest.h"
15
16 namespace webrtc {
17
TEST(MultiChannelContentDetector,HandlingOfMono)18 TEST(MultiChannelContentDetector, HandlingOfMono) {
19 MultiChannelContentDetector mc(
20 /*detect_stereo_content=*/true,
21 /*num_render_input_channels=*/1,
22 /*detection_threshold=*/0.0f,
23 /*stereo_detection_timeout_threshold_seconds=*/0,
24 /*stereo_detection_hysteresis_seconds=*/0.0f);
25 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
26 }
27
TEST(MultiChannelContentDetector,HandlingOfMonoAndDetectionOff)28 TEST(MultiChannelContentDetector, HandlingOfMonoAndDetectionOff) {
29 MultiChannelContentDetector mc(
30 /*detect_stereo_content=*/false,
31 /*num_render_input_channels=*/1,
32 /*detection_threshold=*/0.0f,
33 /*stereo_detection_timeout_threshold_seconds=*/0,
34 /*stereo_detection_hysteresis_seconds=*/0.0f);
35 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
36 }
37
TEST(MultiChannelContentDetector,HandlingOfDetectionOff)38 TEST(MultiChannelContentDetector, HandlingOfDetectionOff) {
39 MultiChannelContentDetector mc(
40 /*detect_stereo_content=*/false,
41 /*num_render_input_channels=*/2,
42 /*detection_threshold=*/0.0f,
43 /*stereo_detection_timeout_threshold_seconds=*/0,
44 /*stereo_detection_hysteresis_seconds=*/0.0f);
45 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
46
47 std::vector<std::vector<std::vector<float>>> frame(
48 1, std::vector<std::vector<float>>(2, std::vector<float>(160, 0.0f)));
49 std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f);
50 std::fill(frame[0][1].begin(), frame[0][1].end(), 101.0f);
51
52 EXPECT_FALSE(mc.UpdateDetection(frame));
53 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
54
55 EXPECT_FALSE(mc.UpdateDetection(frame));
56 }
57
TEST(MultiChannelContentDetector,InitialDetectionOfStereo)58 TEST(MultiChannelContentDetector, InitialDetectionOfStereo) {
59 MultiChannelContentDetector mc(
60 /*detect_stereo_content=*/true,
61 /*num_render_input_channels=*/2,
62 /*detection_threshold=*/0.0f,
63 /*stereo_detection_timeout_threshold_seconds=*/0,
64 /*stereo_detection_hysteresis_seconds=*/0.0f);
65 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
66 }
67
TEST(MultiChannelContentDetector,DetectionWhenFakeStereo)68 TEST(MultiChannelContentDetector, DetectionWhenFakeStereo) {
69 MultiChannelContentDetector mc(
70 /*detect_stereo_content=*/true,
71 /*num_render_input_channels=*/2,
72 /*detection_threshold=*/0.0f,
73 /*stereo_detection_timeout_threshold_seconds=*/0,
74 /*stereo_detection_hysteresis_seconds=*/0.0f);
75 std::vector<std::vector<std::vector<float>>> frame(
76 1, std::vector<std::vector<float>>(2, std::vector<float>(160, 0.0f)));
77 std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f);
78 std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f);
79 EXPECT_FALSE(mc.UpdateDetection(frame));
80 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
81
82 EXPECT_FALSE(mc.UpdateDetection(frame));
83 }
84
TEST(MultiChannelContentDetector,DetectionWhenStereo)85 TEST(MultiChannelContentDetector, DetectionWhenStereo) {
86 MultiChannelContentDetector mc(
87 /*detect_stereo_content=*/true,
88 /*num_render_input_channels=*/2,
89 /*detection_threshold=*/0.0f,
90 /*stereo_detection_timeout_threshold_seconds=*/0,
91 /*stereo_detection_hysteresis_seconds=*/0.0f);
92 std::vector<std::vector<std::vector<float>>> frame(
93 1, std::vector<std::vector<float>>(2, std::vector<float>(160, 0.0f)));
94 std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f);
95 std::fill(frame[0][1].begin(), frame[0][1].end(), 101.0f);
96 EXPECT_TRUE(mc.UpdateDetection(frame));
97 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
98
99 EXPECT_FALSE(mc.UpdateDetection(frame));
100 }
101
TEST(MultiChannelContentDetector,DetectionWhenStereoAfterAWhile)102 TEST(MultiChannelContentDetector, DetectionWhenStereoAfterAWhile) {
103 MultiChannelContentDetector mc(
104 /*detect_stereo_content=*/true,
105 /*num_render_input_channels=*/2,
106 /*detection_threshold=*/0.0f,
107 /*stereo_detection_timeout_threshold_seconds=*/0,
108 /*stereo_detection_hysteresis_seconds=*/0.0f);
109 std::vector<std::vector<std::vector<float>>> frame(
110 1, std::vector<std::vector<float>>(2, std::vector<float>(160, 0.0f)));
111
112 std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f);
113 std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f);
114 EXPECT_FALSE(mc.UpdateDetection(frame));
115 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
116
117 EXPECT_FALSE(mc.UpdateDetection(frame));
118
119 std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f);
120 std::fill(frame[0][1].begin(), frame[0][1].end(), 101.0f);
121
122 EXPECT_TRUE(mc.UpdateDetection(frame));
123 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
124
125 EXPECT_FALSE(mc.UpdateDetection(frame));
126 }
127
TEST(MultiChannelContentDetector,DetectionWithStereoBelowThreshold)128 TEST(MultiChannelContentDetector, DetectionWithStereoBelowThreshold) {
129 constexpr float kThreshold = 1.0f;
130 MultiChannelContentDetector mc(
131 /*detect_stereo_content=*/true,
132 /*num_render_input_channels=*/2,
133 /*detection_threshold=*/kThreshold,
134 /*stereo_detection_timeout_threshold_seconds=*/0,
135 /*stereo_detection_hysteresis_seconds=*/0.0f);
136 std::vector<std::vector<std::vector<float>>> frame(
137 1, std::vector<std::vector<float>>(2, std::vector<float>(160, 0.0f)));
138 std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f);
139 std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f + kThreshold);
140
141 EXPECT_FALSE(mc.UpdateDetection(frame));
142 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
143
144 EXPECT_FALSE(mc.UpdateDetection(frame));
145 }
146
TEST(MultiChannelContentDetector,DetectionWithStereoAboveThreshold)147 TEST(MultiChannelContentDetector, DetectionWithStereoAboveThreshold) {
148 constexpr float kThreshold = 1.0f;
149 MultiChannelContentDetector mc(
150 /*detect_stereo_content=*/true,
151 /*num_render_input_channels=*/2,
152 /*detection_threshold=*/kThreshold,
153 /*stereo_detection_timeout_threshold_seconds=*/0,
154 /*stereo_detection_hysteresis_seconds=*/0.0f);
155 std::vector<std::vector<std::vector<float>>> frame(
156 1, std::vector<std::vector<float>>(2, std::vector<float>(160, 0.0f)));
157 std::fill(frame[0][0].begin(), frame[0][0].end(), 100.0f);
158 std::fill(frame[0][1].begin(), frame[0][1].end(), 100.0f + kThreshold + 0.1f);
159
160 EXPECT_TRUE(mc.UpdateDetection(frame));
161 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
162
163 EXPECT_FALSE(mc.UpdateDetection(frame));
164 }
165
166 class MultiChannelContentDetectorTimeoutBehavior
167 : public ::testing::Test,
168 public ::testing::WithParamInterface<std::tuple<bool, int>> {};
169
170 INSTANTIATE_TEST_SUITE_P(MultiChannelContentDetector,
171 MultiChannelContentDetectorTimeoutBehavior,
172 ::testing::Combine(::testing::Values(false, true),
173 ::testing::Values(0, 1, 10)));
174
TEST_P(MultiChannelContentDetectorTimeoutBehavior,TimeOutBehaviorForNonTrueStereo)175 TEST_P(MultiChannelContentDetectorTimeoutBehavior,
176 TimeOutBehaviorForNonTrueStereo) {
177 constexpr int kNumFramesPerSecond = 100;
178 const bool detect_stereo_content = std::get<0>(GetParam());
179 const int stereo_detection_timeout_threshold_seconds =
180 std::get<1>(GetParam());
181 const int stereo_detection_timeout_threshold_frames =
182 stereo_detection_timeout_threshold_seconds * kNumFramesPerSecond;
183
184 MultiChannelContentDetector mc(detect_stereo_content,
185 /*num_render_input_channels=*/2,
186 /*detection_threshold=*/0.0f,
187 stereo_detection_timeout_threshold_seconds,
188 /*stereo_detection_hysteresis_seconds=*/0.0f);
189 std::vector<std::vector<std::vector<float>>> true_stereo_frame = {
190 {std::vector<float>(160, 100.0f), std::vector<float>(160, 101.0f)}};
191
192 std::vector<std::vector<std::vector<float>>> fake_stereo_frame = {
193 {std::vector<float>(160, 100.0f), std::vector<float>(160, 100.0f)}};
194
195 // Pass fake stereo frames and verify the content detection.
196 for (int k = 0; k < 10; ++k) {
197 EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame));
198 if (detect_stereo_content) {
199 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
200 } else {
201 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
202 }
203 }
204
205 // Pass a true stereo frame and verify that it is properly detected.
206 if (detect_stereo_content) {
207 EXPECT_TRUE(mc.UpdateDetection(true_stereo_frame));
208 } else {
209 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
210 }
211 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
212
213 // Pass fake stereo frames until any timeouts are about to occur.
214 for (int k = 0; k < stereo_detection_timeout_threshold_frames - 1; ++k) {
215 EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame));
216 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
217 }
218
219 // Pass a fake stereo frame and verify that any timeouts properly occur.
220 if (detect_stereo_content && stereo_detection_timeout_threshold_frames > 0) {
221 EXPECT_TRUE(mc.UpdateDetection(fake_stereo_frame));
222 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
223 } else {
224 EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame));
225 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
226 }
227
228 // Pass fake stereo frames and verify the behavior after any timeout.
229 for (int k = 0; k < 10; ++k) {
230 EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame));
231 if (detect_stereo_content &&
232 stereo_detection_timeout_threshold_frames > 0) {
233 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
234 } else {
235 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
236 }
237 }
238 }
239
240 class MultiChannelContentDetectorHysteresisBehavior
241 : public ::testing::Test,
242 public ::testing::WithParamInterface<std::tuple<bool, float>> {};
243
244 INSTANTIATE_TEST_SUITE_P(
245 MultiChannelContentDetector,
246 MultiChannelContentDetectorHysteresisBehavior,
247 ::testing::Combine(::testing::Values(false, true),
248 ::testing::Values(0.0f, 0.1f, 0.2f)));
249
TEST_P(MultiChannelContentDetectorHysteresisBehavior,PeriodBeforeStereoDetectionIsTriggered)250 TEST_P(MultiChannelContentDetectorHysteresisBehavior,
251 PeriodBeforeStereoDetectionIsTriggered) {
252 constexpr int kNumFramesPerSecond = 100;
253 const bool detect_stereo_content = std::get<0>(GetParam());
254 const int stereo_detection_hysteresis_seconds = std::get<1>(GetParam());
255 const int stereo_detection_hysteresis_frames =
256 stereo_detection_hysteresis_seconds * kNumFramesPerSecond;
257
258 MultiChannelContentDetector mc(
259 detect_stereo_content,
260 /*num_render_input_channels=*/2,
261 /*detection_threshold=*/0.0f,
262 /*stereo_detection_timeout_threshold_seconds=*/0,
263 stereo_detection_hysteresis_seconds);
264 std::vector<std::vector<std::vector<float>>> true_stereo_frame = {
265 {std::vector<float>(160, 100.0f), std::vector<float>(160, 101.0f)}};
266
267 std::vector<std::vector<std::vector<float>>> fake_stereo_frame = {
268 {std::vector<float>(160, 100.0f), std::vector<float>(160, 100.0f)}};
269
270 // Pass fake stereo frames and verify the content detection.
271 for (int k = 0; k < 10; ++k) {
272 EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame));
273 if (detect_stereo_content) {
274 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
275 } else {
276 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
277 }
278 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
279 }
280
281 // Pass a two true stereo frames and verify that they are properly detected.
282 ASSERT_TRUE(stereo_detection_hysteresis_frames > 2 ||
283 stereo_detection_hysteresis_frames == 0);
284 for (int k = 0; k < 2; ++k) {
285 if (detect_stereo_content) {
286 if (stereo_detection_hysteresis_seconds == 0.0f) {
287 if (k == 0) {
288 EXPECT_TRUE(mc.UpdateDetection(true_stereo_frame));
289 } else {
290 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
291 }
292 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
293 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
294 } else {
295 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
296 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
297 EXPECT_TRUE(mc.IsTemporaryMultiChannelContentDetected());
298 }
299 } else {
300 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
301 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
302 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
303 }
304 }
305
306 if (stereo_detection_hysteresis_seconds == 0.0f) {
307 return;
308 }
309
310 // Pass true stereo frames until any timeouts are about to occur.
311 for (int k = 0; k < stereo_detection_hysteresis_frames - 3; ++k) {
312 if (detect_stereo_content) {
313 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
314 EXPECT_FALSE(mc.IsProperMultiChannelContentDetected());
315 EXPECT_TRUE(mc.IsTemporaryMultiChannelContentDetected());
316 } else {
317 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
318 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
319 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
320 }
321 }
322
323 // Pass a true stereo frame and verify that it is properly detected.
324 if (detect_stereo_content) {
325 EXPECT_TRUE(mc.UpdateDetection(true_stereo_frame));
326 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
327 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
328 } else {
329 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
330 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
331 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
332 }
333
334 // Pass an additional true stereo frame and verify that it is properly
335 // detected.
336 if (detect_stereo_content) {
337 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
338 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
339 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
340 } else {
341 EXPECT_FALSE(mc.UpdateDetection(true_stereo_frame));
342 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
343 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
344 }
345
346 // Pass a fake stereo frame and verify that it is properly detected.
347 if (detect_stereo_content) {
348 EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame));
349 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
350 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
351 } else {
352 EXPECT_FALSE(mc.UpdateDetection(fake_stereo_frame));
353 EXPECT_TRUE(mc.IsProperMultiChannelContentDetected());
354 EXPECT_FALSE(mc.IsTemporaryMultiChannelContentDetected());
355 }
356 }
357
358 class MultiChannelContentDetectorMetricsDisabled
359 : public ::testing::Test,
360 public ::testing::WithParamInterface<std::tuple<bool, int>> {};
361
362 INSTANTIATE_TEST_SUITE_P(
363 /*no prefix*/,
364 MultiChannelContentDetectorMetricsDisabled,
365 ::testing::Values(std::tuple<bool, int>(false, 2),
366 std::tuple<bool, int>(true, 1)));
367
368 // Test that no metrics are logged when they are clearly uninteresting and would
369 // dilute relevant data: when the reference audio is single channel, or when
370 // dynamic detection is disabled.
TEST_P(MultiChannelContentDetectorMetricsDisabled,ReportsNoMetrics)371 TEST_P(MultiChannelContentDetectorMetricsDisabled, ReportsNoMetrics) {
372 metrics::Reset();
373 constexpr int kNumFramesPerSecond = 100;
374 const bool detect_stereo_content = std::get<0>(GetParam());
375 const int channel_count = std::get<1>(GetParam());
376 std::vector<std::vector<std::vector<float>>> audio_frame = {
377 std::vector<std::vector<float>>(channel_count,
378 std::vector<float>(160, 100.0f))};
379 {
380 MultiChannelContentDetector mc(
381 /*detect_stereo_content=*/detect_stereo_content,
382 /*num_render_input_channels=*/channel_count,
383 /*detection_threshold=*/0.0f,
384 /*stereo_detection_timeout_threshold_seconds=*/1,
385 /*stereo_detection_hysteresis_seconds=*/0.0f);
386 for (int k = 0; k < 20 * kNumFramesPerSecond; ++k) {
387 mc.UpdateDetection(audio_frame);
388 }
389 }
390 EXPECT_METRIC_EQ(
391 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller."
392 "ProcessingPersistentMultichannelContent"));
393 EXPECT_METRIC_EQ(
394 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller."
395 "PersistentMultichannelContentEverDetected"));
396 }
397
398 // Tests that after 3 seconds, no metrics are reported.
TEST(MultiChannelContentDetectorMetrics,ReportsNoMetricsForShortLifetime)399 TEST(MultiChannelContentDetectorMetrics, ReportsNoMetricsForShortLifetime) {
400 metrics::Reset();
401 constexpr int kNumFramesPerSecond = 100;
402 constexpr int kTooFewFramesToLogMetrics = 3 * kNumFramesPerSecond;
403 std::vector<std::vector<std::vector<float>>> audio_frame = {
404 std::vector<std::vector<float>>(2, std::vector<float>(160, 100.0f))};
405 {
406 MultiChannelContentDetector mc(
407 /*detect_stereo_content=*/true,
408 /*num_render_input_channels=*/2,
409 /*detection_threshold=*/0.0f,
410 /*stereo_detection_timeout_threshold_seconds=*/1,
411 /*stereo_detection_hysteresis_seconds=*/0.0f);
412 for (int k = 0; k < kTooFewFramesToLogMetrics; ++k) {
413 mc.UpdateDetection(audio_frame);
414 }
415 }
416 EXPECT_METRIC_EQ(
417 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller."
418 "ProcessingPersistentMultichannelContent"));
419 EXPECT_METRIC_EQ(
420 0, metrics::NumSamples("WebRTC.Audio.EchoCanceller."
421 "PersistentMultichannelContentEverDetected"));
422 }
423
424 // Tests that after 25 seconds, metrics are reported.
TEST(MultiChannelContentDetectorMetrics,ReportsMetrics)425 TEST(MultiChannelContentDetectorMetrics, ReportsMetrics) {
426 metrics::Reset();
427 constexpr int kNumFramesPerSecond = 100;
428 std::vector<std::vector<std::vector<float>>> true_stereo_frame = {
429 {std::vector<float>(160, 100.0f), std::vector<float>(160, 101.0f)}};
430 std::vector<std::vector<std::vector<float>>> fake_stereo_frame = {
431 {std::vector<float>(160, 100.0f), std::vector<float>(160, 100.0f)}};
432 {
433 MultiChannelContentDetector mc(
434 /*detect_stereo_content=*/true,
435 /*num_render_input_channels=*/2,
436 /*detection_threshold=*/0.0f,
437 /*stereo_detection_timeout_threshold_seconds=*/1,
438 /*stereo_detection_hysteresis_seconds=*/0.0f);
439 for (int k = 0; k < 10 * kNumFramesPerSecond; ++k) {
440 mc.UpdateDetection(true_stereo_frame);
441 }
442 for (int k = 0; k < 15 * kNumFramesPerSecond; ++k) {
443 mc.UpdateDetection(fake_stereo_frame);
444 }
445 }
446 // After 10 seconds of true stereo and the remainder fake stereo, we expect
447 // one lifetime metric sample (multichannel detected) and two periodic samples
448 // (one multichannel, one mono).
449
450 // Check lifetime metric.
451 EXPECT_METRIC_EQ(
452 1, metrics::NumSamples("WebRTC.Audio.EchoCanceller."
453 "PersistentMultichannelContentEverDetected"));
454 EXPECT_METRIC_EQ(
455 1, metrics::NumEvents("WebRTC.Audio.EchoCanceller."
456 "PersistentMultichannelContentEverDetected", 1));
457
458 // Check periodic metric.
459 EXPECT_METRIC_EQ(
460 2, metrics::NumSamples("WebRTC.Audio.EchoCanceller."
461 "ProcessingPersistentMultichannelContent"));
462 EXPECT_METRIC_EQ(
463 1, metrics::NumEvents("WebRTC.Audio.EchoCanceller."
464 "ProcessingPersistentMultichannelContent", 0));
465 EXPECT_METRIC_EQ(
466 1, metrics::NumEvents("WebRTC.Audio.EchoCanceller."
467 "ProcessingPersistentMultichannelContent", 1));
468 }
469
470 } // namespace webrtc
471