Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: webrtc/modules/audio_processing/audio_processing_impl_locking_unittest.cc

Issue 1394803002: Unittest for the locking in APM (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Changes in response to lastest reviewer comments Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | webrtc/modules/modules.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2015 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 "webrtc/modules/audio_processing/audio_processing_impl.h"
12
13 #include <algorithm>
14 #include <vector>
15
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "webrtc/base/criticalsection.h"
18 #include "webrtc/config.h"
19 #include "webrtc/modules/audio_processing/test/test_utils.h"
20 #include "webrtc/modules/interface/module_common_types.h"
21 #include "webrtc/system_wrappers/include/event_wrapper.h"
22 #include "webrtc/system_wrappers/include/sleep.h"
23 #include "webrtc/system_wrappers/include/thread_wrapper.h"
24 #include "webrtc/test/random.h"
25
26 namespace webrtc {
27
28 namespace {
29
30 class AudioProcessingImplLockTest;
31
32 // Sleeps a random time between 0 and max_sleep milliseconds.
33 void SleepRandomMs(int max_sleep, test::Random* rand_gen) {
34 int sleeptime = rand_gen->Rand(0, max_sleep);
35 SleepMs(sleeptime);
36 }
37
38 // Populates a float audio frame with random data.
39 void PopulateAudioFrame(float** frame,
40 float amplitude,
41 size_t num_channels,
42 size_t samples_per_channel,
43 test::Random* rand_gen) {
44 for (size_t ch = 0; ch < num_channels; ch++) {
45 for (size_t k = 0; k < samples_per_channel; k++) {
46 // Store random 16 bit quantized float number between +-amplitude.
47 frame[ch][k] = amplitude * rand_gen->Rand(-32767 - 1, 32767) / 32768.0f;
48 }
49 }
50 }
51
52 // Populates an audioframe frame of AudioFrame type with random data.
53 void PopulateAudioFrame(AudioFrame* frame,
54 int16_t amplitude,
55 test::Random* rand_gen) {
56 ASSERT_GT(amplitude, 0);
57 ASSERT_LE(amplitude, 32767);
58 for (int ch = 0; ch < frame->num_channels_; ch++) {
59 for (int k = 0; k < static_cast<int>(frame->samples_per_channel_); k++) {
60 // Store random 16 bit number between -(amplitude+1) and
61 // amplitude.
62 frame->data_[k * ch] = rand_gen->Rand(-amplitude - 1, amplitude);
63 }
64 }
65 }
66
67 // Type of the render thread APM API call to use in the test.
68 enum class RenderApiImpl {
69 ProcessReverseStreamImpl1,
70 ProcessReverseStreamImpl2,
71 AnalyzeReverseStreamImpl1,
72 AnalyzeReverseStreamImpl2
73 };
74
75 // Type of the capture thread APM API call to use in the test.
76 enum class CaptureApiImpl {
77 ProcessStreamImpl1,
78 ProcessStreamImpl2,
79 ProcessStreamImpl3
80 };
81
82 // The runtime parameter setting scheme to use in the test.
83 enum class RuntimeParameterSettingScheme {
84 SparseStreamMetadataChangeScheme,
85 ExtremeStreamMetadataChangeScheme,
86 FixedMonoStreamMetadataScheme,
87 FixedStereoStreamMetadataScheme
88 };
89
90 // Variant of echo canceller settings to use in the test.
91 enum class AecType {
92 BasicWebRtcAecSettings,
93 AecTurnedOff,
94 BasicWebRtcAecSettingsWithExtentedFilter,
95 BasicWebRtcAecSettingsWithDelayAgnosticAec,
96 BasicWebRtcAecSettingsWithAecMobile
97 };
98
99 // Variables related to the audio data and formats.
100 struct AudioFrameData {
101 explicit AudioFrameData(int max_frame_size) {
102 // Set up the two-dimensional arrays needed for the APM API calls.
103 input_framechannels.resize(2 * max_frame_size);
104 input_frame.resize(2);
105 input_frame[0] = &input_framechannels[0];
106 input_frame[1] = &input_framechannels[max_frame_size];
107
108 output_frame_channels.resize(2 * max_frame_size);
109 output_frame.resize(2);
110 output_frame[0] = &output_frame_channels[0];
111 output_frame[1] = &output_frame_channels[max_frame_size];
112 }
113
114 AudioFrame frame;
115 std::vector<float*> output_frame;
116 std::vector<float> output_frame_channels;
117 AudioProcessing::ChannelLayout output_channel_layout =
118 AudioProcessing::ChannelLayout::kMono;
119 int input_sample_rate_hz = 16000;
120 int input_number_of_channels = -1;
121 std::vector<float*> input_frame;
122 std::vector<float> input_framechannels;
123 AudioProcessing::ChannelLayout input_channel_layout =
124 AudioProcessing::ChannelLayout::kMono;
125 int output_sample_rate_hz = 16000;
126 int output_number_of_channels = -1;
127 StreamConfig input_stream_config;
128 StreamConfig output_stream_config;
129 int input_samples_per_channel = -1;
130 int output_samples_per_channel = -1;
131 };
132
133 // The configuration for the test.
134 struct TestConfig {
135 // Test case generator for the test configurations to use in the brief tests.
136 static std::vector<TestConfig> GenerateBriefTestConfigs() {
137 std::vector<TestConfig> test_configs;
138 AecType aec_types[] = {AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec,
139 AecType::BasicWebRtcAecSettingsWithAecMobile};
140 for (auto aec_type : aec_types) {
141 TestConfig test_config;
142 test_config.aec_type = aec_type;
143
144 test_config.min_number_of_calls = 300;
145
146 // Perform tests only with the extreme runtime parameter setting scheme.
147 test_config.runtime_parameter_setting_scheme =
148 RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme;
149
150 // Only test 16 kHz for this test suite.
151 test_config.initial_sample_rate_hz = 16000;
152
153 // Create test config for the second processing API function set.
154 test_config.render_api_function =
155 RenderApiImpl::ProcessReverseStreamImpl2;
156 test_config.capture_api_function = CaptureApiImpl::ProcessStreamImpl2;
157
158 // Create test config for the first processing API function set.
159 test_configs.push_back(test_config);
160 test_config.render_api_function =
161 RenderApiImpl::AnalyzeReverseStreamImpl2;
162 test_config.capture_api_function = CaptureApiImpl::ProcessStreamImpl3;
163 test_configs.push_back(test_config);
164 }
165
166 // Return the created test configurations.
167 return test_configs;
168 }
169
170 // Checker for whether the a test configuration is valid.
171 static bool ValidTestConfig(const TestConfig& test_config) {
172 // It is not ok to combine API calls that use AudioFrame with the other
173 // API calls. The rest of the calls are fine.
174 bool render_audio_frame_api_used =
175 (test_config.render_api_function ==
176 RenderApiImpl::ProcessReverseStreamImpl1) ||
177 (test_config.render_api_function ==
178 RenderApiImpl::AnalyzeReverseStreamImpl1);
179
180 bool capture_audio_frame_api_used = (test_config.capture_api_function ==
181 CaptureApiImpl::ProcessStreamImpl1);
182
183 if (render_audio_frame_api_used || capture_audio_frame_api_used) {
184 return (render_audio_frame_api_used && capture_audio_frame_api_used);
185 }
186
187 return true;
188 }
189
190 // Test case generator for the test configurations to use in the extensive
191 // tests.
192 static std::vector<TestConfig> GenerateExtensiveTestConfigs() {
193 // Lambda functions for the test config generation.
194 auto add_processing_apis = [](TestConfig test_config) {
195 struct AllowedApiCallCombinations {
196 RenderApiImpl render_api;
197 CaptureApiImpl capture_api;
198 };
199
200 const AllowedApiCallCombinations api_calls[] = {
201 {RenderApiImpl::ProcessReverseStreamImpl1,
202 CaptureApiImpl::ProcessStreamImpl1},
203 {RenderApiImpl::AnalyzeReverseStreamImpl1,
204 CaptureApiImpl::ProcessStreamImpl1},
205 {RenderApiImpl::ProcessReverseStreamImpl2,
206 CaptureApiImpl::ProcessStreamImpl2},
207 {RenderApiImpl::ProcessReverseStreamImpl2,
208 CaptureApiImpl::ProcessStreamImpl3},
209 {RenderApiImpl::AnalyzeReverseStreamImpl2,
210 CaptureApiImpl::ProcessStreamImpl2},
211 {RenderApiImpl::AnalyzeReverseStreamImpl2,
212 CaptureApiImpl::ProcessStreamImpl3}};
213 std::vector<TestConfig> out;
214 for (auto api_call : api_calls) {
215 test_config.render_api_function = api_call.render_api;
216 test_config.capture_api_function = api_call.capture_api;
217 out.push_back(test_config);
218 }
219 return out;
220 };
221
222 auto add_aec_settings = [](const std::vector<TestConfig>& in) {
223 std::vector<TestConfig> out;
224 AecType aec_types[] = {
225 AecType::BasicWebRtcAecSettings, AecType::AecTurnedOff,
226 AecType::BasicWebRtcAecSettingsWithExtentedFilter,
227 AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec,
228 AecType::BasicWebRtcAecSettingsWithAecMobile};
229 for (auto test_config : in) {
230 for (auto aec_type : aec_types) {
231 test_config.aec_type = aec_type;
232 out.push_back(test_config);
233 }
234 }
235 return out;
236 };
237
238 auto add_settings_scheme = [](const std::vector<TestConfig>& in) {
239 std::vector<TestConfig> out;
240 RuntimeParameterSettingScheme schemes[] = {
241 RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme,
242 RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme,
243 RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme,
244 RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme};
245
246 for (auto test_config : in) {
247 for (auto scheme : schemes) {
248 // Only produce test configs with compatible render and capture API
249 // calls.
250 if (ValidTestConfig(test_config)) {
the sun 2015/11/06 09:02:05 So this shouldn't be needed now that you *only* ge
peah-webrtc 2015/11/06 10:14:38 My bad! Done.
251 // Add test configs with different initial sample rates and
252 // parameter setting schemes.
253 test_config.runtime_parameter_setting_scheme = scheme;
254 out.push_back(test_config);
255 }
256 }
257 }
258 return out;
259 };
260
261 auto add_sample_rates = [](const std::vector<TestConfig>& in) {
262 const int sample_rates[] = {8000, 16000, 32000, 48000};
263 const int sample_rates_mobile[] = {8000, 16000};
264
265 std::vector<TestConfig> out;
266 struct RatesInfo {
the sun 2015/11/06 09:02:05 Why is this necessary? You can range-iterate over
peah-webrtc 2015/11/06 10:14:38 On your suggestion, the code is now rewritten usin
267 RatesInfo(const int* rates, int num_rates)
268 : rates(rates), num_rates(num_rates) {}
269
270 const int* rates;
271 int num_rates;
272 };
273 for (auto test_config : in) {
274 auto available_rates =
275 (test_config.aec_type ==
276 AecType::BasicWebRtcAecSettingsWithAecMobile
277 ? RatesInfo(sample_rates_mobile,
278 sizeof(sample_rates_mobile) /
279 sizeof(sample_rates_mobile[0]))
280 : RatesInfo(sample_rates,
281 sizeof(sample_rates) / sizeof(sample_rates[0])));
282 for (int k = 0; k < available_rates.num_rates; k++) {
283 test_config.initial_sample_rate_hz = available_rates.rates[k];
284 out.push_back(test_config);
285 }
286 }
287 return out;
288 };
289
290 // Generate test configurations of the relevant combinations of the
291 // parameters to
292 // test.
293 TestConfig test_config;
294 test_config.min_number_of_calls = 10000;
295 return add_sample_rates(add_settings_scheme(
296 add_aec_settings(add_processing_apis(test_config))));
297 }
298
299 RenderApiImpl render_api_function = RenderApiImpl::ProcessReverseStreamImpl2;
300 CaptureApiImpl capture_api_function = CaptureApiImpl::ProcessStreamImpl2;
301 RuntimeParameterSettingScheme runtime_parameter_setting_scheme =
302 RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme;
303 int initial_sample_rate_hz = 16000;
304 AecType aec_type = AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec;
305 int min_number_of_calls = 300;
306 };
307
308 // Handler for the frame counters.
309 class FrameCounters {
310 public:
311 void IncreaseRenderCounter() {
312 rtc::CritScope cs(&crit_);
313 render_count++;
314 }
315
316 void IncreaseCaptureCounter() {
317 rtc::CritScope cs(&crit_);
318 capture_count++;
319 }
320
321 int GetCaptureCounter() {
322 rtc::CritScope cs(&crit_);
323 return capture_count;
324 }
325
326 int GetRenderCounter() {
327 rtc::CritScope cs(&crit_);
328 return render_count;
329 }
330
331 int CaptureMinusRenderCounters() {
332 rtc::CritScope cs(&crit_);
333 return capture_count - render_count;
334 }
335
336 bool BothCountersExceedeThreshold(int threshold) {
337 rtc::CritScope cs(&crit_);
338 return (render_count > threshold && capture_count > threshold);
339 }
340
341 private:
342 rtc::CriticalSection crit_;
343 int render_count GUARDED_BY(crit_) = 0;
344 int capture_count GUARDED_BY(crit_) = 0;
345 };
346
347 // Checker for whether the capture side has been called.
348 class CaptureSideCalledChecker {
349 public:
350 bool CaptureSideCalled() {
351 rtc::CritScope cs(&crit_);
352 return capture_side_called_;
353 }
354
355 void FlagCaptureSideCalled() {
356 rtc::CritScope cs(&crit_);
357 capture_side_called_ = true;
358 }
359
360 private:
361 rtc::CriticalSection crit_;
362 bool capture_side_called_ GUARDED_BY(crit_) = false;
363 };
364
365 // Class for handling the capture side processing.
366 class CaptureProcessor {
367 public:
368 CaptureProcessor(int max_frame_size,
369 test::Random* rand_gen,
370 FrameCounters* shared_counters_state,
371 CaptureSideCalledChecker* capture_call_checker,
372 AudioProcessingImplLockTest* test_framework,
373 TestConfig* test_config,
374 AudioProcessing* apm);
375 bool Process();
376
377 private:
378 static const int kMaxCallDifference = 10;
379 static const float kCaptureInputFloatLevel;
380 static const int kCaptureInputFixLevel = 1024;
381
382 void PrepareFrame();
383 void CallApmCaptureSide();
384 void ApplyRuntimeSettingScheme();
385
386 test::Random* rand_gen_ = nullptr;
387 FrameCounters* frame_counters_ = nullptr;
388 CaptureSideCalledChecker* capture_call_checker_ = nullptr;
389 AudioProcessingImplLockTest* test_ = nullptr;
390 TestConfig* test_config_ = nullptr;
391 AudioProcessing* apm_ = nullptr;
392 AudioFrameData frame_data_;
393 };
394
395 // Class for handling the stats processing.
396 class StatsProcessor {
397 public:
398 StatsProcessor(test::Random* rand_gen,
399 TestConfig* test_config,
400 AudioProcessing* apm);
401 bool Process();
402
403 private:
404 test::Random* rand_gen_ = nullptr;
405 TestConfig* test_config_ = nullptr;
406 AudioProcessing* apm_ = nullptr;
407 };
408
409 // Class for handling the render side processing.
410 class RenderProcessor {
411 public:
412 RenderProcessor(int max_frame_size,
413 test::Random* rand_gen,
414 FrameCounters* shared_counters_state,
415 CaptureSideCalledChecker* capture_call_checker,
416 AudioProcessingImplLockTest* test_framework,
417 TestConfig* test_config,
418 AudioProcessing* apm);
419 bool Process();
420
421 private:
422 static const int kMaxCallDifference = 10;
423 static const int kRenderInputFixLevel = 16384;
424 static const float kRenderInputFloatLevel;
425
426 void PrepareFrame();
427 void CallApmRenderSide();
428 void ApplyRuntimeSettingScheme();
429
430 test::Random* rand_gen_ = nullptr;
431 FrameCounters* frame_counters_ = nullptr;
432 CaptureSideCalledChecker* capture_call_checker_ = nullptr;
433 AudioProcessingImplLockTest* test_ = nullptr;
434 TestConfig* test_config_ = nullptr;
435 AudioProcessing* apm_ = nullptr;
436 bool first_render_side_call_ = true;
437 AudioFrameData frame_data_;
438 };
439
440 class AudioProcessingImplLockTest
441 : public ::testing::TestWithParam<TestConfig> {
442 public:
443 AudioProcessingImplLockTest();
444 EventTypeWrapper RunTest();
445 void CheckTestCompleteness();
446
447 private:
448 static const int kTestTimeOutLimit = 10 * 60 * 1000;
449 static const int kMaxFrameSize = 480;
450
451 // ::testing::TestWithParam<> implementation
452 void SetUp() override;
453 void TearDown() override;
454
455 // Thread callback for the render thread
456 static bool RenderProcessorThreadFunc(void* context) {
457 return reinterpret_cast<AudioProcessingImplLockTest*>(context)
458 ->render_thread_state_.Process();
459 }
460
461 // Thread callback for the capture thread
462 static bool CaptureProcessorThreadFunc(void* context) {
463 return reinterpret_cast<AudioProcessingImplLockTest*>(context)
464 ->capture_thread_state_.Process();
465 }
466
467 // Thread callback for the stats thread
468 static bool StatsProcessorThreadFunc(void* context) {
469 return reinterpret_cast<AudioProcessingImplLockTest*>(context)
470 ->stats_thread_state_.Process();
471 }
472
473 // Tests whether all the required render and capture side calls have been
474 // done.
475 bool TestDone() {
476 return frame_counters_.BothCountersExceedeThreshold(
477 test_config_.min_number_of_calls);
478 }
479
480 // Start the threads used in the test.
481 void StartThreads() {
482 ASSERT_TRUE(render_thread_->Start());
483 render_thread_->SetPriority(kRealtimePriority);
484 ASSERT_TRUE(capture_thread_->Start());
485 capture_thread_->SetPriority(kRealtimePriority);
486 ASSERT_TRUE(stats_thread_->Start());
487 stats_thread_->SetPriority(kNormalPriority);
488 }
489
490 // Event handler for the test.
491 const rtc::scoped_ptr<EventWrapper> test_complete_;
492
493 // Thread related variables.
494 rtc::scoped_ptr<ThreadWrapper> render_thread_;
495 rtc::scoped_ptr<ThreadWrapper> capture_thread_;
496 rtc::scoped_ptr<ThreadWrapper> stats_thread_;
497 mutable test::Random rand_gen_;
498
499 rtc::scoped_ptr<AudioProcessing> apm_;
500 TestConfig test_config_;
501 FrameCounters frame_counters_;
502 CaptureSideCalledChecker capture_call_checker_;
503 RenderProcessor render_thread_state_;
504 CaptureProcessor capture_thread_state_;
505 StatsProcessor stats_thread_state_;
506 };
507
508 AudioProcessingImplLockTest::AudioProcessingImplLockTest()
509 : test_complete_(EventWrapper::Create()),
510 render_thread_(ThreadWrapper::CreateThread(RenderProcessorThreadFunc,
511 this,
512 "render")),
513 capture_thread_(ThreadWrapper::CreateThread(CaptureProcessorThreadFunc,
514 this,
515 "capture")),
516 stats_thread_(
517 ThreadWrapper::CreateThread(StatsProcessorThreadFunc, this, "stats")),
518 rand_gen_(42U),
519 apm_(AudioProcessingImpl::Create()),
520 render_thread_state_(kMaxFrameSize,
521 &rand_gen_,
522 &frame_counters_,
523 &capture_call_checker_,
524 this,
525 &test_config_,
526 apm_.get()),
527 capture_thread_state_(kMaxFrameSize,
528 &rand_gen_,
529 &frame_counters_,
530 &capture_call_checker_,
531 this,
532 &test_config_,
533 apm_.get()),
534 stats_thread_state_(&rand_gen_, &test_config_, apm_.get()) {}
535
536 // Run the test with a timeout.
537 EventTypeWrapper AudioProcessingImplLockTest::RunTest() {
538 StartThreads();
539 return test_complete_->Wait(kTestTimeOutLimit);
540 }
541
542 void AudioProcessingImplLockTest::CheckTestCompleteness() {
543 if (HasFatalFailure() || TestDone()) {
544 test_complete_->Set();
545 }
546 }
547
548 // Setup of test and APM.
549 void AudioProcessingImplLockTest::SetUp() {
550 test_config_ = static_cast<TestConfig>(GetParam());
551
552 ASSERT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
553 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
554
555 ASSERT_EQ(apm_->kNoError,
556 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
557 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
558
559 ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true));
560 ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
561
562 Config config;
563 if (test_config_.aec_type == AecType::AecTurnedOff) {
564 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
565 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
566 } else if (test_config_.aec_type ==
567 AecType::BasicWebRtcAecSettingsWithAecMobile) {
568 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
569 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
570 } else {
571 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
572 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
573 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_metrics(true));
574 ASSERT_EQ(apm_->kNoError,
575 apm_->echo_cancellation()->enable_delay_logging(true));
576
577 config.Set<ExtendedFilter>(
578 new ExtendedFilter(test_config_.aec_type ==
579 AecType::BasicWebRtcAecSettingsWithExtentedFilter));
580
581 config.Set<DelayAgnostic>(
582 new DelayAgnostic(test_config_.aec_type ==
583 AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec));
584
585 apm_->SetExtraOptions(config);
586 }
587 }
588
589 void AudioProcessingImplLockTest::TearDown() {
590 render_thread_->Stop();
591 capture_thread_->Stop();
592 stats_thread_->Stop();
593 }
594
595 StatsProcessor::StatsProcessor(test::Random* rand_gen,
596 TestConfig* test_config,
597 AudioProcessing* apm)
598 : rand_gen_(rand_gen), test_config_(test_config), apm_(apm) {}
599
600 // Implements the callback functionality for the statistics
601 // collection thread.
602 bool StatsProcessor::Process() {
603 SleepRandomMs(100, rand_gen_);
604
605 EXPECT_EQ(apm_->echo_cancellation()->is_enabled(),
606 ((test_config_->aec_type != AecType::AecTurnedOff) &&
607 (test_config_->aec_type !=
608 AecType::BasicWebRtcAecSettingsWithAecMobile)));
609 apm_->echo_cancellation()->stream_drift_samples();
610 EXPECT_EQ(apm_->echo_control_mobile()->is_enabled(),
611 (test_config_->aec_type != AecType::AecTurnedOff) &&
612 (test_config_->aec_type ==
613 AecType::BasicWebRtcAecSettingsWithAecMobile));
614 EXPECT_TRUE(apm_->gain_control()->is_enabled());
615 apm_->gain_control()->stream_analog_level();
616 EXPECT_TRUE(apm_->noise_suppression()->is_enabled());
617
618 // The below return values are not testable.
619 apm_->noise_suppression()->speech_probability();
620 apm_->voice_detection()->is_enabled();
621
622 return true;
623 }
624
625 const float CaptureProcessor::kCaptureInputFloatLevel = 0.03125f;
626
627 CaptureProcessor::CaptureProcessor(
628 int max_frame_size,
629 test::Random* rand_gen,
630 FrameCounters* shared_counters_state,
631 CaptureSideCalledChecker* capture_call_checker,
632 AudioProcessingImplLockTest* test_framework,
633 TestConfig* test_config,
634 AudioProcessing* apm)
635 : rand_gen_(rand_gen),
636 frame_counters_(shared_counters_state),
637 capture_call_checker_(capture_call_checker),
638 test_(test_framework),
639 test_config_(test_config),
640 apm_(apm),
641 frame_data_(max_frame_size) {}
642
643 // Implements the callback functionality for the capture thread.
644 bool CaptureProcessor::Process() {
645 // Sleep a random time to simulate thread jitter.
646 SleepRandomMs(3, rand_gen_);
647
648 // End the test if complete.
649 test_->CheckTestCompleteness();
650
651 // Ensure that there are not more capture side calls than render side
652 // calls.
653 if (capture_call_checker_->CaptureSideCalled()) {
654 while (kMaxCallDifference < frame_counters_->CaptureMinusRenderCounters()) {
655 SleepMs(1);
656 }
657 }
658
659 // Apply any specified capture side APM non-processing runtime calls.
660 ApplyRuntimeSettingScheme();
661
662 // Apply the capture side processing call.
663 CallApmCaptureSide();
664
665 // Increase the number of capture-side calls.
666 frame_counters_->IncreaseCaptureCounter();
667
668 // Flag that the capture side has been called at least once
669 // (needed to ensure that a capture call has been done
670 // before the first render call is performed (implicitly
671 // required by the APM API).
672 capture_call_checker_->FlagCaptureSideCalled();
673
674 return true;
675 }
676
677 // Prepares a frame with relevant audio data and metadata.
678 void CaptureProcessor::PrepareFrame() {
679 // Restrict to a common fixed sample rate if the AudioFrame
680 // interface is used.
681 if (test_config_->capture_api_function ==
682 CaptureApiImpl::ProcessStreamImpl1) {
683 frame_data_.input_sample_rate_hz = test_config_->initial_sample_rate_hz;
684 frame_data_.output_sample_rate_hz = test_config_->initial_sample_rate_hz;
685 }
686
687 // Prepare the audioframe data and metadata.
688 frame_data_.input_samples_per_channel =
689 frame_data_.input_sample_rate_hz * AudioProcessing::kChunkSizeMs / 1000;
690 frame_data_.frame.sample_rate_hz_ = frame_data_.input_sample_rate_hz;
691 frame_data_.frame.num_channels_ = frame_data_.input_number_of_channels;
692 frame_data_.frame.samples_per_channel_ =
693 frame_data_.input_samples_per_channel;
694 PopulateAudioFrame(&frame_data_.frame, kCaptureInputFixLevel, rand_gen_);
695
696 // Prepare the float audio input data and metadata.
697 frame_data_.input_stream_config.set_sample_rate_hz(
698 frame_data_.input_sample_rate_hz);
699 frame_data_.input_stream_config.set_num_channels(
700 frame_data_.input_number_of_channels);
701 frame_data_.input_stream_config.set_has_keyboard(false);
702 PopulateAudioFrame(&frame_data_.input_frame[0], kCaptureInputFloatLevel,
703 frame_data_.input_number_of_channels,
704 frame_data_.input_samples_per_channel, rand_gen_);
705 frame_data_.input_channel_layout =
706 (frame_data_.input_number_of_channels == 1
707 ? AudioProcessing::ChannelLayout::kMonoAndKeyboard
708 : AudioProcessing::ChannelLayout::kStereoAndKeyboard);
709
710 // Prepare the float audio output data and metadata.
711 frame_data_.output_samples_per_channel =
712 frame_data_.output_sample_rate_hz * AudioProcessing::kChunkSizeMs / 1000;
713 frame_data_.output_stream_config.set_sample_rate_hz(
714 frame_data_.output_sample_rate_hz);
715 frame_data_.output_stream_config.set_num_channels(
716 frame_data_.output_number_of_channels);
717 frame_data_.output_stream_config.set_has_keyboard(false);
718 frame_data_.output_channel_layout =
719 (frame_data_.output_number_of_channels == 1
720 ? AudioProcessing::ChannelLayout::kMono
721 : AudioProcessing::ChannelLayout::kStereo);
722 }
723
724 // Applies the capture side processing API call.
725 void CaptureProcessor::CallApmCaptureSide() {
726 // Prepare a proper capture side processing API call input.
727 PrepareFrame();
728
729 // Set the stream delay
730 apm_->set_stream_delay_ms(30);
731
732 // Call the specified capture side API processing method.
733 int result = AudioProcessing::kNoError;
734 switch (test_config_->capture_api_function) {
735 case CaptureApiImpl::ProcessStreamImpl1:
736 result = apm_->ProcessStream(&frame_data_.frame);
737 break;
738 case CaptureApiImpl::ProcessStreamImpl2:
739 result = apm_->ProcessStream(
740 &frame_data_.input_frame[0], frame_data_.input_samples_per_channel,
741 frame_data_.input_sample_rate_hz, frame_data_.input_channel_layout,
742 frame_data_.output_sample_rate_hz, frame_data_.output_channel_layout,
743 &frame_data_.output_frame[0]);
744 break;
745 case CaptureApiImpl::ProcessStreamImpl3:
746 result = apm_->ProcessStream(
747 &frame_data_.input_frame[0], frame_data_.input_stream_config,
748 frame_data_.output_stream_config, &frame_data_.output_frame[0]);
749 break;
750 default:
751 FAIL();
752 }
753
754 // Check the return code for error.
755 ASSERT_EQ(AudioProcessing::kNoError, result);
756 }
757
758 // Applies any runtime capture APM API calls and audio stream characteristics
759 // specified by the scheme for the test.
760 void CaptureProcessor::ApplyRuntimeSettingScheme() {
761 const int capture_count_local = frame_counters_->GetCaptureCounter();
762
763 // Update the number of channels and sample rates for the input and output.
764 // Note that the counts frequencies for when to set parameters
765 // are set using prime numbers in order to ensure that the
766 // permutation scheme in the parameter setting changes.
767 switch (test_config_->runtime_parameter_setting_scheme) {
768 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
769 if (capture_count_local == 0)
770 frame_data_.input_sample_rate_hz = 16000;
771 else if (capture_count_local % 11 == 0)
772 frame_data_.input_sample_rate_hz = 32000;
773 else if (capture_count_local % 73 == 0)
774 frame_data_.input_sample_rate_hz = 48000;
775 else if (capture_count_local % 89 == 0)
776 frame_data_.input_sample_rate_hz = 16000;
777 else if (capture_count_local % 97 == 0)
778 frame_data_.input_sample_rate_hz = 8000;
779
780 if (capture_count_local == 0)
781 frame_data_.input_number_of_channels = 1;
782 else if (capture_count_local % 4 == 0)
783 frame_data_.input_number_of_channels =
784 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
785
786 if (capture_count_local == 0)
787 frame_data_.output_sample_rate_hz = 16000;
788 else if (capture_count_local % 5 == 0)
789 frame_data_.output_sample_rate_hz = 32000;
790 else if (capture_count_local % 47 == 0)
791 frame_data_.output_sample_rate_hz = 48000;
792 else if (capture_count_local % 53 == 0)
793 frame_data_.output_sample_rate_hz = 16000;
794 else if (capture_count_local % 71 == 0)
795 frame_data_.output_sample_rate_hz = 8000;
796
797 if (capture_count_local == 0)
798 frame_data_.output_number_of_channels = 1;
799 else if (capture_count_local % 8 == 0)
800 frame_data_.output_number_of_channels =
801 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
802 break;
803 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
804 if (capture_count_local % 2 == 0) {
805 frame_data_.input_number_of_channels = 1;
806 frame_data_.input_sample_rate_hz = 16000;
807 frame_data_.output_number_of_channels = 1;
808 frame_data_.output_sample_rate_hz = 16000;
809 } else {
810 frame_data_.input_number_of_channels =
811 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
812 if (frame_data_.input_sample_rate_hz == 8000)
813 frame_data_.input_sample_rate_hz = 16000;
814 else if (frame_data_.input_sample_rate_hz == 16000)
815 frame_data_.input_sample_rate_hz = 32000;
816 else if (frame_data_.input_sample_rate_hz == 32000)
817 frame_data_.input_sample_rate_hz = 48000;
818 else if (frame_data_.input_sample_rate_hz == 48000)
819 frame_data_.input_sample_rate_hz = 8000;
820
821 frame_data_.output_number_of_channels =
822 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
823 if (frame_data_.output_sample_rate_hz == 8000)
824 frame_data_.output_sample_rate_hz = 16000;
825 else if (frame_data_.output_sample_rate_hz == 16000)
826 frame_data_.output_sample_rate_hz = 32000;
827 else if (frame_data_.output_sample_rate_hz == 32000)
828 frame_data_.output_sample_rate_hz = 48000;
829 else if (frame_data_.output_sample_rate_hz == 48000)
830 frame_data_.output_sample_rate_hz = 8000;
831 }
832 break;
833 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
834 if (capture_count_local == 0) {
835 frame_data_.input_sample_rate_hz = 16000;
836 frame_data_.input_number_of_channels = 1;
837 frame_data_.output_sample_rate_hz = 16000;
838 frame_data_.output_number_of_channels = 1;
839 }
840 break;
841 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
842 if (capture_count_local == 0) {
843 frame_data_.input_sample_rate_hz = 16000;
844 frame_data_.input_number_of_channels = 2;
845 frame_data_.output_sample_rate_hz = 16000;
846 frame_data_.output_number_of_channels = 2;
847 }
848 break;
849 default:
850 FAIL();
851 }
852
853 // Call any specified runtime APM setter and
854 // getter calls.
855 switch (test_config_->runtime_parameter_setting_scheme) {
856 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
857 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
858 break;
859 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
860 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
861 if (capture_count_local % 2 == 0) {
862 ASSERT_EQ(AudioProcessing::Error::kNoError,
863 apm_->set_stream_delay_ms(30));
864 apm_->set_stream_key_pressed(true);
865 apm_->set_output_will_be_muted(true);
866 apm_->set_delay_offset_ms(15);
867 EXPECT_EQ(apm_->delay_offset_ms(), 15);
868 EXPECT_GE(apm_->num_reverse_channels(), 0);
869 EXPECT_LE(apm_->num_reverse_channels(), 2);
870 } else {
871 ASSERT_EQ(AudioProcessing::Error::kNoError,
872 apm_->set_stream_delay_ms(50));
873 apm_->set_stream_key_pressed(false);
874 apm_->set_output_will_be_muted(false);
875 apm_->set_delay_offset_ms(20);
876 EXPECT_EQ(apm_->delay_offset_ms(), 20);
877 apm_->delay_offset_ms();
878 apm_->num_reverse_channels();
879 EXPECT_GE(apm_->num_reverse_channels(), 0);
880 EXPECT_LE(apm_->num_reverse_channels(), 2);
881 }
882 break;
883 default:
884 FAIL();
885 }
886
887 // Restric the number of output channels not to exceed
888 // the number of input channels.
889 frame_data_.output_number_of_channels =
890 std::min(frame_data_.output_number_of_channels,
891 frame_data_.input_number_of_channels);
892 }
893
894 const float RenderProcessor::kRenderInputFloatLevel = 0.5f;
895
896 RenderProcessor::RenderProcessor(int max_frame_size,
897 test::Random* rand_gen,
898 FrameCounters* shared_counters_state,
899 CaptureSideCalledChecker* capture_call_checker,
900 AudioProcessingImplLockTest* test_framework,
901 TestConfig* test_config,
902 AudioProcessing* apm)
903 : rand_gen_(rand_gen),
904 frame_counters_(shared_counters_state),
905 capture_call_checker_(capture_call_checker),
906 test_(test_framework),
907 test_config_(test_config),
908 apm_(apm),
909 frame_data_(max_frame_size) {}
910
911 // Implements the callback functionality for the render thread.
912 bool RenderProcessor::Process() {
913 // Conditional wait to ensure that a capture call has been done
914 // before the first render call is performed (implicitly
915 // required by the APM API).
916 if (first_render_side_call_) {
917 while (!capture_call_checker_->CaptureSideCalled()) {
918 SleepRandomMs(3, rand_gen_);
919 }
920
921 first_render_side_call_ = false;
922 }
923
924 // Sleep a random time to simulate thread jitter.
925 SleepRandomMs(3, rand_gen_);
926
927 // End the test early if a fatal failure (ASSERT_*) has occurred.
928 test_->CheckTestCompleteness();
929
930 // Ensure that the number of render and capture calls do not
931 // differ too much.
932 while (kMaxCallDifference < -frame_counters_->CaptureMinusRenderCounters()) {
933 SleepMs(1);
934 }
935
936 // Apply any specified render side APM non-processing runtime calls.
937 ApplyRuntimeSettingScheme();
938
939 // Apply the render side processing call.
940 CallApmRenderSide();
941
942 // Increase the number of render-side calls.
943 frame_counters_->IncreaseRenderCounter();
944
945 return true;
946 }
947
948 // Prepares the render side frame and the accompanying metadata
949 // with the appropriate information.
950 void RenderProcessor::PrepareFrame() {
951 // Restrict to a common fixed sample rate if the AudioFrame interface is
952 // used.
953 if ((test_config_->render_api_function ==
954 RenderApiImpl::AnalyzeReverseStreamImpl1) ||
955 (test_config_->render_api_function ==
956 RenderApiImpl::ProcessReverseStreamImpl1) ||
957 (test_config_->aec_type !=
958 AecType::BasicWebRtcAecSettingsWithAecMobile)) {
959 frame_data_.input_sample_rate_hz = test_config_->initial_sample_rate_hz;
960 frame_data_.output_sample_rate_hz = test_config_->initial_sample_rate_hz;
961 }
962
963 // Prepare the audioframe data and metadata
964 frame_data_.input_samples_per_channel =
965 frame_data_.input_sample_rate_hz * AudioProcessing::kChunkSizeMs / 1000;
966 frame_data_.frame.sample_rate_hz_ = frame_data_.input_sample_rate_hz;
967 frame_data_.frame.num_channels_ = frame_data_.input_number_of_channels;
968 frame_data_.frame.samples_per_channel_ =
969 frame_data_.input_samples_per_channel;
970 PopulateAudioFrame(&frame_data_.frame, kRenderInputFixLevel, rand_gen_);
971
972 // Prepare the float audio input data and metadata.
973 frame_data_.input_stream_config.set_sample_rate_hz(
974 frame_data_.input_sample_rate_hz);
975 frame_data_.input_stream_config.set_num_channels(
976 frame_data_.input_number_of_channels);
977 frame_data_.input_stream_config.set_has_keyboard(false);
978 PopulateAudioFrame(&frame_data_.input_frame[0], kRenderInputFloatLevel,
979 frame_data_.input_number_of_channels,
980 frame_data_.input_samples_per_channel, rand_gen_);
981 frame_data_.input_channel_layout =
982 (frame_data_.input_number_of_channels == 1
983 ? AudioProcessing::ChannelLayout::kMono
984 : AudioProcessing::ChannelLayout::kStereo);
985
986 // Prepare the float audio output data and metadata.
987 frame_data_.output_samples_per_channel =
988 frame_data_.output_sample_rate_hz * AudioProcessing::kChunkSizeMs / 1000;
989 frame_data_.output_stream_config.set_sample_rate_hz(
990 frame_data_.output_sample_rate_hz);
991 frame_data_.output_stream_config.set_num_channels(
992 frame_data_.output_number_of_channels);
993 frame_data_.output_stream_config.set_has_keyboard(false);
994 frame_data_.output_channel_layout =
995 (frame_data_.output_number_of_channels == 1
996 ? AudioProcessing::ChannelLayout::kMono
997 : AudioProcessing::ChannelLayout::kStereo);
998 }
999
1000 // Makes the render side processing API call.
1001 void RenderProcessor::CallApmRenderSide() {
1002 // Prepare a proper render side processing API call input.
1003 PrepareFrame();
1004
1005 // Call the specified render side API processing method.
1006 int result = AudioProcessing::kNoError;
1007 switch (test_config_->render_api_function) {
1008 case RenderApiImpl::ProcessReverseStreamImpl1:
1009 result = apm_->ProcessReverseStream(&frame_data_.frame);
1010 break;
1011 case RenderApiImpl::ProcessReverseStreamImpl2:
1012 result = apm_->ProcessReverseStream(
1013 &frame_data_.input_frame[0], frame_data_.input_stream_config,
1014 frame_data_.output_stream_config, &frame_data_.output_frame[0]);
1015 break;
1016 case RenderApiImpl::AnalyzeReverseStreamImpl1:
1017 result = apm_->AnalyzeReverseStream(&frame_data_.frame);
1018 break;
1019 case RenderApiImpl::AnalyzeReverseStreamImpl2:
1020 result = apm_->AnalyzeReverseStream(
1021 &frame_data_.input_frame[0], frame_data_.input_samples_per_channel,
1022 frame_data_.input_sample_rate_hz, frame_data_.input_channel_layout);
1023 break;
1024 default:
1025 FAIL();
1026 }
1027
1028 // Check the return code for error.
1029 ASSERT_EQ(AudioProcessing::kNoError, result);
1030 }
1031
1032 // Applies any render capture side APM API calls and audio stream
1033 // characteristics
1034 // specified by the scheme for the test.
1035 void RenderProcessor::ApplyRuntimeSettingScheme() {
1036 const int render_count_local = frame_counters_->GetRenderCounter();
1037
1038 // Update the number of channels and sample rates for the input and output.
1039 // Note that the counts frequencies for when to set parameters
1040 // are set using prime numbers in order to ensure that the
1041 // permutation scheme in the parameter setting changes.
1042 switch (test_config_->runtime_parameter_setting_scheme) {
1043 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
1044 if (render_count_local == 0)
1045 frame_data_.input_sample_rate_hz = 16000;
1046 else if (render_count_local % 47 == 0)
1047 frame_data_.input_sample_rate_hz = 32000;
1048 else if (render_count_local % 71 == 0)
1049 frame_data_.input_sample_rate_hz = 48000;
1050 else if (render_count_local % 79 == 0)
1051 frame_data_.input_sample_rate_hz = 16000;
1052 else if (render_count_local % 83 == 0)
1053 frame_data_.input_sample_rate_hz = 8000;
1054
1055 if (render_count_local == 0)
1056 frame_data_.input_number_of_channels = 1;
1057 else if (render_count_local % 4 == 0)
1058 frame_data_.input_number_of_channels =
1059 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
1060
1061 if (render_count_local == 0)
1062 frame_data_.output_sample_rate_hz = 16000;
1063 else if (render_count_local % 17 == 0)
1064 frame_data_.output_sample_rate_hz = 32000;
1065 else if (render_count_local % 19 == 0)
1066 frame_data_.output_sample_rate_hz = 48000;
1067 else if (render_count_local % 29 == 0)
1068 frame_data_.output_sample_rate_hz = 16000;
1069 else if (render_count_local % 61 == 0)
1070 frame_data_.output_sample_rate_hz = 8000;
1071
1072 if (render_count_local == 0)
1073 frame_data_.output_number_of_channels = 1;
1074 else if (render_count_local % 8 == 0)
1075 frame_data_.output_number_of_channels =
1076 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
1077 break;
1078 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
1079 if (render_count_local == 0) {
1080 frame_data_.input_number_of_channels = 1;
1081 frame_data_.input_sample_rate_hz = 16000;
1082 frame_data_.output_number_of_channels = 1;
1083 frame_data_.output_sample_rate_hz = 16000;
1084 } else {
1085 frame_data_.input_number_of_channels =
1086 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
1087 if (frame_data_.input_sample_rate_hz == 8000)
1088 frame_data_.input_sample_rate_hz = 16000;
1089 else if (frame_data_.input_sample_rate_hz == 16000)
1090 frame_data_.input_sample_rate_hz = 32000;
1091 else if (frame_data_.input_sample_rate_hz == 32000)
1092 frame_data_.input_sample_rate_hz = 48000;
1093 else if (frame_data_.input_sample_rate_hz == 48000)
1094 frame_data_.input_sample_rate_hz = 8000;
1095
1096 frame_data_.output_number_of_channels =
1097 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
1098 if (frame_data_.output_sample_rate_hz == 8000)
1099 frame_data_.output_sample_rate_hz = 16000;
1100 else if (frame_data_.output_sample_rate_hz == 16000)
1101 frame_data_.output_sample_rate_hz = 32000;
1102 else if (frame_data_.output_sample_rate_hz == 32000)
1103 frame_data_.output_sample_rate_hz = 48000;
1104 else if (frame_data_.output_sample_rate_hz == 48000)
1105 frame_data_.output_sample_rate_hz = 8000;
1106 }
1107 break;
1108 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
1109 if (render_count_local == 0) {
1110 frame_data_.input_sample_rate_hz = 16000;
1111 frame_data_.input_number_of_channels = 1;
1112 frame_data_.output_sample_rate_hz = 16000;
1113 frame_data_.output_number_of_channels = 1;
1114 }
1115 break;
1116 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
1117 if (render_count_local == 0) {
1118 frame_data_.input_sample_rate_hz = 16000;
1119 frame_data_.input_number_of_channels = 2;
1120 frame_data_.output_sample_rate_hz = 16000;
1121 frame_data_.output_number_of_channels = 2;
1122 }
1123 break;
1124 default:
1125 FAIL();
1126 }
1127
1128 // Restric the number of output channels not to exceed
1129 // the number of input channels.
1130 frame_data_.output_number_of_channels =
1131 std::min(frame_data_.output_number_of_channels,
1132 frame_data_.input_number_of_channels);
1133 }
1134
1135 } // anonymous namespace
1136
1137 TEST_P(AudioProcessingImplLockTest, LockTest) {
1138 // Run test and verify that it did not time out.
1139 ASSERT_EQ(kEventSignaled, RunTest());
1140 }
1141
1142 // Instantiate tests from the extreme test configuration set.
1143 INSTANTIATE_TEST_CASE_P(
1144 DISABLED_AudioProcessingImplLockExtensive,
1145 AudioProcessingImplLockTest,
1146 ::testing::ValuesIn(TestConfig::GenerateExtensiveTestConfigs()));
1147
1148 INSTANTIATE_TEST_CASE_P(
1149 AudioProcessingImplLockBrief,
1150 AudioProcessingImplLockTest,
1151 ::testing::ValuesIn(TestConfig::GenerateBriefTestConfigs()));
1152
1153 } // namespace webrtc
OLDNEW
« no previous file with comments | « no previous file | webrtc/modules/modules.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698