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 <algorithm>
12 #include <memory>
13 #include <vector>
14
15 #include "api/array_view.h"
16 #include "modules/audio_processing/audio_processing_impl.h"
17 #include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
18 #include "modules/audio_processing/test/test_utils.h"
19 #include "rtc_base/event.h"
20 #include "rtc_base/platform_thread.h"
21 #include "rtc_base/random.h"
22 #include "rtc_base/synchronization/mutex.h"
23 #include "system_wrappers/include/sleep.h"
24 #include "test/gtest.h"
25
26 namespace webrtc {
27
28 namespace {
29
30 class AudioProcessingImplLockTest;
31
32 // Type of the render thread APM API call to use in the test.
33 enum class RenderApiImpl {
34 ProcessReverseStreamImplInteger,
35 ProcessReverseStreamImplFloat,
36 AnalyzeReverseStreamImplFloat,
37 };
38
39 // Type of the capture thread APM API call to use in the test.
40 enum class CaptureApiImpl { ProcessStreamImplInteger, ProcessStreamImplFloat };
41
42 // The runtime parameter setting scheme to use in the test.
43 enum class RuntimeParameterSettingScheme {
44 SparseStreamMetadataChangeScheme,
45 ExtremeStreamMetadataChangeScheme,
46 FixedMonoStreamMetadataScheme,
47 FixedStereoStreamMetadataScheme
48 };
49
50 // Variant of echo canceller settings to use in the test.
51 enum class AecType {
52 BasicWebRtcAecSettings,
53 AecTurnedOff,
54 BasicWebRtcAecSettingsWithExtentedFilter,
55 BasicWebRtcAecSettingsWithDelayAgnosticAec,
56 BasicWebRtcAecSettingsWithAecMobile
57 };
58
59 // Thread-safe random number generator wrapper.
60 class RandomGenerator {
61 public:
RandomGenerator()62 RandomGenerator() : rand_gen_(42U) {}
63
RandInt(int min,int max)64 int RandInt(int min, int max) {
65 MutexLock lock(&mutex_);
66 return rand_gen_.Rand(min, max);
67 }
68
RandInt(int max)69 int RandInt(int max) {
70 MutexLock lock(&mutex_);
71 return rand_gen_.Rand(max);
72 }
73
RandFloat()74 float RandFloat() {
75 MutexLock lock(&mutex_);
76 return rand_gen_.Rand<float>();
77 }
78
79 private:
80 Mutex mutex_;
81 Random rand_gen_ RTC_GUARDED_BY(mutex_);
82 };
83
84 // Variables related to the audio data and formats.
85 struct AudioFrameData {
AudioFrameDatawebrtc::__anon26b22f840111::AudioFrameData86 explicit AudioFrameData(int max_frame_size) {
87 // Set up the two-dimensional arrays needed for the APM API calls.
88 input_framechannels.resize(2 * max_frame_size);
89 input_frame.resize(2);
90 input_frame[0] = &input_framechannels[0];
91 input_frame[1] = &input_framechannels[max_frame_size];
92
93 output_frame_channels.resize(2 * max_frame_size);
94 output_frame.resize(2);
95 output_frame[0] = &output_frame_channels[0];
96 output_frame[1] = &output_frame_channels[max_frame_size];
97
98 frame.resize(2 * max_frame_size);
99 }
100
101 std::vector<int16_t> frame;
102
103 std::vector<float*> output_frame;
104 std::vector<float> output_frame_channels;
105 std::vector<float*> input_frame;
106 std::vector<float> input_framechannels;
107
108 int input_sample_rate_hz = 16000;
109 int input_number_of_channels = 1;
110 int output_sample_rate_hz = 16000;
111 int output_number_of_channels = 1;
112 };
113
114 // The configuration for the test.
115 struct TestConfig {
116 // Test case generator for the test configurations to use in the brief tests.
GenerateBriefTestConfigswebrtc::__anon26b22f840111::TestConfig117 static std::vector<TestConfig> GenerateBriefTestConfigs() {
118 std::vector<TestConfig> test_configs;
119 AecType aec_types[] = {AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec,
120 AecType::BasicWebRtcAecSettingsWithAecMobile};
121 for (auto aec_type : aec_types) {
122 TestConfig test_config;
123 test_config.aec_type = aec_type;
124
125 test_config.min_number_of_calls = 300;
126
127 // Perform tests only with the extreme runtime parameter setting scheme.
128 test_config.runtime_parameter_setting_scheme =
129 RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme;
130
131 // Only test 16 kHz for this test suite.
132 test_config.initial_sample_rate_hz = 16000;
133
134 // Create test config for the Int16 processing API function set.
135 test_config.render_api_function =
136 RenderApiImpl::ProcessReverseStreamImplInteger;
137 test_config.capture_api_function =
138 CaptureApiImpl::ProcessStreamImplInteger;
139 test_configs.push_back(test_config);
140
141 // Create test config for the StreamConfig processing API function set.
142 test_config.render_api_function =
143 RenderApiImpl::ProcessReverseStreamImplFloat;
144 test_config.capture_api_function = CaptureApiImpl::ProcessStreamImplFloat;
145 test_configs.push_back(test_config);
146 }
147
148 // Return the created test configurations.
149 return test_configs;
150 }
151
152 // Test case generator for the test configurations to use in the extensive
153 // tests.
GenerateExtensiveTestConfigswebrtc::__anon26b22f840111::TestConfig154 static std::vector<TestConfig> GenerateExtensiveTestConfigs() {
155 // Lambda functions for the test config generation.
156 auto add_processing_apis = [](TestConfig test_config) {
157 struct AllowedApiCallCombinations {
158 RenderApiImpl render_api;
159 CaptureApiImpl capture_api;
160 };
161
162 const AllowedApiCallCombinations api_calls[] = {
163 {RenderApiImpl::ProcessReverseStreamImplInteger,
164 CaptureApiImpl::ProcessStreamImplInteger},
165 {RenderApiImpl::ProcessReverseStreamImplFloat,
166 CaptureApiImpl::ProcessStreamImplFloat},
167 {RenderApiImpl::AnalyzeReverseStreamImplFloat,
168 CaptureApiImpl::ProcessStreamImplFloat},
169 {RenderApiImpl::ProcessReverseStreamImplInteger,
170 CaptureApiImpl::ProcessStreamImplFloat},
171 {RenderApiImpl::ProcessReverseStreamImplFloat,
172 CaptureApiImpl::ProcessStreamImplInteger}};
173 std::vector<TestConfig> out;
174 for (auto api_call : api_calls) {
175 test_config.render_api_function = api_call.render_api;
176 test_config.capture_api_function = api_call.capture_api;
177 out.push_back(test_config);
178 }
179 return out;
180 };
181
182 auto add_aec_settings = [](const std::vector<TestConfig>& in) {
183 std::vector<TestConfig> out;
184 AecType aec_types[] = {
185 AecType::BasicWebRtcAecSettings, AecType::AecTurnedOff,
186 AecType::BasicWebRtcAecSettingsWithExtentedFilter,
187 AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec,
188 AecType::BasicWebRtcAecSettingsWithAecMobile};
189 for (auto test_config : in) {
190 // Due to a VisualStudio 2015 compiler issue, the internal loop
191 // variable here cannot override a previously defined name.
192 // In other words "type" cannot be named "aec_type" here.
193 // https://connect.microsoft.com/VisualStudio/feedback/details/2291755
194 for (auto type : aec_types) {
195 test_config.aec_type = type;
196 out.push_back(test_config);
197 }
198 }
199 return out;
200 };
201
202 auto add_settings_scheme = [](const std::vector<TestConfig>& in) {
203 std::vector<TestConfig> out;
204 RuntimeParameterSettingScheme schemes[] = {
205 RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme,
206 RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme,
207 RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme,
208 RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme};
209
210 for (auto test_config : in) {
211 for (auto scheme : schemes) {
212 test_config.runtime_parameter_setting_scheme = scheme;
213 out.push_back(test_config);
214 }
215 }
216 return out;
217 };
218
219 auto add_sample_rates = [](const std::vector<TestConfig>& in) {
220 const int sample_rates[] = {8000, 16000, 32000, 48000};
221
222 std::vector<TestConfig> out;
223 for (auto test_config : in) {
224 auto available_rates =
225 (test_config.aec_type ==
226 AecType::BasicWebRtcAecSettingsWithAecMobile
227 ? rtc::ArrayView<const int>(sample_rates, 2)
228 : rtc::ArrayView<const int>(sample_rates));
229
230 for (auto rate : available_rates) {
231 test_config.initial_sample_rate_hz = rate;
232 out.push_back(test_config);
233 }
234 }
235 return out;
236 };
237
238 // Generate test configurations of the relevant combinations of the
239 // parameters to
240 // test.
241 TestConfig test_config;
242 test_config.min_number_of_calls = 10000;
243 return add_sample_rates(add_settings_scheme(
244 add_aec_settings(add_processing_apis(test_config))));
245 }
246
247 RenderApiImpl render_api_function =
248 RenderApiImpl::ProcessReverseStreamImplFloat;
249 CaptureApiImpl capture_api_function = CaptureApiImpl::ProcessStreamImplFloat;
250 RuntimeParameterSettingScheme runtime_parameter_setting_scheme =
251 RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme;
252 int initial_sample_rate_hz = 16000;
253 AecType aec_type = AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec;
254 int min_number_of_calls = 300;
255 };
256
257 // Handler for the frame counters.
258 class FrameCounters {
259 public:
IncreaseRenderCounter()260 void IncreaseRenderCounter() {
261 MutexLock lock(&mutex_);
262 render_count++;
263 }
264
IncreaseCaptureCounter()265 void IncreaseCaptureCounter() {
266 MutexLock lock(&mutex_);
267 capture_count++;
268 }
269
GetCaptureCounter() const270 int GetCaptureCounter() const {
271 MutexLock lock(&mutex_);
272 return capture_count;
273 }
274
GetRenderCounter() const275 int GetRenderCounter() const {
276 MutexLock lock(&mutex_);
277 return render_count;
278 }
279
CaptureMinusRenderCounters() const280 int CaptureMinusRenderCounters() const {
281 MutexLock lock(&mutex_);
282 return capture_count - render_count;
283 }
284
RenderMinusCaptureCounters() const285 int RenderMinusCaptureCounters() const {
286 return -CaptureMinusRenderCounters();
287 }
288
BothCountersExceedeThreshold(int threshold)289 bool BothCountersExceedeThreshold(int threshold) {
290 MutexLock lock(&mutex_);
291 return (render_count > threshold && capture_count > threshold);
292 }
293
294 private:
295 mutable Mutex mutex_;
296 int render_count RTC_GUARDED_BY(mutex_) = 0;
297 int capture_count RTC_GUARDED_BY(mutex_) = 0;
298 };
299
300 // Class for handling the capture side processing.
301 class CaptureProcessor {
302 public:
303 CaptureProcessor(int max_frame_size,
304 RandomGenerator* rand_gen,
305 rtc::Event* render_call_event,
306 rtc::Event* capture_call_event,
307 FrameCounters* shared_counters_state,
308 TestConfig* test_config,
309 AudioProcessing* apm);
310 void Process();
311
312 private:
313 static const int kMaxCallDifference = 10;
314 static const float kCaptureInputFloatLevel;
315 static const int kCaptureInputFixLevel = 1024;
316
317 void PrepareFrame();
318 void CallApmCaptureSide();
319 void ApplyRuntimeSettingScheme();
320
321 RandomGenerator* const rand_gen_ = nullptr;
322 rtc::Event* const render_call_event_ = nullptr;
323 rtc::Event* const capture_call_event_ = nullptr;
324 FrameCounters* const frame_counters_ = nullptr;
325 const TestConfig* const test_config_ = nullptr;
326 AudioProcessing* const apm_ = nullptr;
327 AudioFrameData frame_data_;
328 };
329
330 // Class for handling the stats processing.
331 class StatsProcessor {
332 public:
333 StatsProcessor(RandomGenerator* rand_gen,
334 TestConfig* test_config,
335 AudioProcessing* apm);
336 void Process();
337
338 private:
339 RandomGenerator* rand_gen_ = nullptr;
340 TestConfig* test_config_ = nullptr;
341 AudioProcessing* apm_ = nullptr;
342 };
343
344 // Class for handling the render side processing.
345 class RenderProcessor {
346 public:
347 RenderProcessor(int max_frame_size,
348 RandomGenerator* rand_gen,
349 rtc::Event* render_call_event,
350 rtc::Event* capture_call_event,
351 FrameCounters* shared_counters_state,
352 TestConfig* test_config,
353 AudioProcessing* apm);
354 void Process();
355
356 private:
357 static const int kMaxCallDifference = 10;
358 static const int kRenderInputFixLevel = 16384;
359 static const float kRenderInputFloatLevel;
360
361 void PrepareFrame();
362 void CallApmRenderSide();
363 void ApplyRuntimeSettingScheme();
364
365 RandomGenerator* const rand_gen_ = nullptr;
366 rtc::Event* const render_call_event_ = nullptr;
367 rtc::Event* const capture_call_event_ = nullptr;
368 FrameCounters* const frame_counters_ = nullptr;
369 const TestConfig* const test_config_ = nullptr;
370 AudioProcessing* const apm_ = nullptr;
371 AudioFrameData frame_data_;
372 bool first_render_call_ = true;
373 };
374
375 class AudioProcessingImplLockTest
376 : public ::testing::TestWithParam<TestConfig> {
377 public:
378 AudioProcessingImplLockTest();
379 bool RunTest();
380 bool MaybeEndTest();
381
382 private:
383 static const int kTestTimeOutLimit = 10 * 60 * 1000;
384 static const int kMaxFrameSize = 480;
385
386 // ::testing::TestWithParam<> implementation
387 void SetUp() override;
388 void TearDown() override;
389
390 // Thread callback for the render thread
RenderProcessorThreadFunc(void * context)391 static void RenderProcessorThreadFunc(void* context) {
392 AudioProcessingImplLockTest* impl =
393 reinterpret_cast<AudioProcessingImplLockTest*>(context);
394 while (!impl->MaybeEndTest()) {
395 impl->render_thread_state_.Process();
396 }
397 }
398
399 // Thread callback for the capture thread
CaptureProcessorThreadFunc(void * context)400 static void CaptureProcessorThreadFunc(void* context) {
401 AudioProcessingImplLockTest* impl =
402 reinterpret_cast<AudioProcessingImplLockTest*>(context);
403 while (!impl->MaybeEndTest()) {
404 impl->capture_thread_state_.Process();
405 }
406 }
407
408 // Thread callback for the stats thread
StatsProcessorThreadFunc(void * context)409 static void StatsProcessorThreadFunc(void* context) {
410 AudioProcessingImplLockTest* impl =
411 reinterpret_cast<AudioProcessingImplLockTest*>(context);
412 while (!impl->MaybeEndTest()) {
413 impl->stats_thread_state_.Process();
414 }
415 }
416
417 // Tests whether all the required render and capture side calls have been
418 // done.
TestDone()419 bool TestDone() {
420 return frame_counters_.BothCountersExceedeThreshold(
421 test_config_.min_number_of_calls);
422 }
423
424 // Start the threads used in the test.
StartThreads()425 void StartThreads() {
426 render_thread_.Start();
427 capture_thread_.Start();
428 stats_thread_.Start();
429 }
430
431 // Event handlers for the test.
432 rtc::Event test_complete_;
433 rtc::Event render_call_event_;
434 rtc::Event capture_call_event_;
435
436 // Thread related variables.
437 rtc::PlatformThread render_thread_;
438 rtc::PlatformThread capture_thread_;
439 rtc::PlatformThread stats_thread_;
440 mutable RandomGenerator rand_gen_;
441
442 std::unique_ptr<AudioProcessing> apm_;
443 TestConfig test_config_;
444 FrameCounters frame_counters_;
445 RenderProcessor render_thread_state_;
446 CaptureProcessor capture_thread_state_;
447 StatsProcessor stats_thread_state_;
448 };
449
450 // Sleeps a random time between 0 and max_sleep milliseconds.
SleepRandomMs(int max_sleep,RandomGenerator * rand_gen)451 void SleepRandomMs(int max_sleep, RandomGenerator* rand_gen) {
452 int sleeptime = rand_gen->RandInt(0, max_sleep);
453 SleepMs(sleeptime);
454 }
455
456 // Populates a float audio frame with random data.
PopulateAudioFrame(float ** frame,float amplitude,size_t num_channels,size_t samples_per_channel,RandomGenerator * rand_gen)457 void PopulateAudioFrame(float** frame,
458 float amplitude,
459 size_t num_channels,
460 size_t samples_per_channel,
461 RandomGenerator* rand_gen) {
462 for (size_t ch = 0; ch < num_channels; ch++) {
463 for (size_t k = 0; k < samples_per_channel; k++) {
464 // Store random 16 bit quantized float number between +-amplitude.
465 frame[ch][k] = amplitude * (2 * rand_gen->RandFloat() - 1);
466 }
467 }
468 }
469
470 // Populates an integer audio frame with random data.
PopulateAudioFrame(float amplitude,size_t num_channels,size_t samples_per_channel,rtc::ArrayView<int16_t> frame,RandomGenerator * rand_gen)471 void PopulateAudioFrame(float amplitude,
472 size_t num_channels,
473 size_t samples_per_channel,
474 rtc::ArrayView<int16_t> frame,
475 RandomGenerator* rand_gen) {
476 ASSERT_GT(amplitude, 0);
477 ASSERT_LE(amplitude, 32767);
478 for (size_t ch = 0; ch < num_channels; ch++) {
479 for (size_t k = 0; k < samples_per_channel; k++) {
480 // Store random 16 bit number between -(amplitude+1) and
481 // amplitude.
482 frame[k * ch] = rand_gen->RandInt(2 * amplitude + 1) - amplitude - 1;
483 }
484 }
485 }
486
AudioProcessingImplLockTest()487 AudioProcessingImplLockTest::AudioProcessingImplLockTest()
488 : render_thread_(RenderProcessorThreadFunc,
489 this,
490 "render",
491 rtc::kRealtimePriority),
492 capture_thread_(CaptureProcessorThreadFunc,
493 this,
494 "capture",
495 rtc::kRealtimePriority),
496 stats_thread_(StatsProcessorThreadFunc,
497 this,
498 "stats",
499 rtc::kNormalPriority),
500 apm_(AudioProcessingBuilderForTesting().Create()),
501 render_thread_state_(kMaxFrameSize,
502 &rand_gen_,
503 &render_call_event_,
504 &capture_call_event_,
505 &frame_counters_,
506 &test_config_,
507 apm_.get()),
508 capture_thread_state_(kMaxFrameSize,
509 &rand_gen_,
510 &render_call_event_,
511 &capture_call_event_,
512 &frame_counters_,
513 &test_config_,
514 apm_.get()),
515 stats_thread_state_(&rand_gen_, &test_config_, apm_.get()) {}
516
517 // Run the test with a timeout.
RunTest()518 bool AudioProcessingImplLockTest::RunTest() {
519 StartThreads();
520 return test_complete_.Wait(kTestTimeOutLimit);
521 }
522
MaybeEndTest()523 bool AudioProcessingImplLockTest::MaybeEndTest() {
524 if (HasFatalFailure() || TestDone()) {
525 test_complete_.Set();
526 return true;
527 }
528 return false;
529 }
530
531 // Setup of test and APM.
SetUp()532 void AudioProcessingImplLockTest::SetUp() {
533 test_config_ = static_cast<TestConfig>(GetParam());
534
535 AudioProcessing::Config apm_config = apm_->GetConfig();
536 apm_config.echo_canceller.enabled =
537 (test_config_.aec_type != AecType::AecTurnedOff);
538 apm_config.echo_canceller.mobile_mode =
539 (test_config_.aec_type == AecType::BasicWebRtcAecSettingsWithAecMobile);
540 apm_config.gain_controller1.enabled = true;
541 apm_config.gain_controller1.mode =
542 AudioProcessing::Config::GainController1::kAdaptiveDigital;
543 apm_config.noise_suppression.enabled = true;
544 apm_config.voice_detection.enabled = true;
545 apm_config.level_estimation.enabled = true;
546 apm_->ApplyConfig(apm_config);
547 }
548
TearDown()549 void AudioProcessingImplLockTest::TearDown() {
550 render_call_event_.Set();
551 capture_call_event_.Set();
552 render_thread_.Stop();
553 capture_thread_.Stop();
554 stats_thread_.Stop();
555 }
556
StatsProcessor(RandomGenerator * rand_gen,TestConfig * test_config,AudioProcessing * apm)557 StatsProcessor::StatsProcessor(RandomGenerator* rand_gen,
558 TestConfig* test_config,
559 AudioProcessing* apm)
560 : rand_gen_(rand_gen), test_config_(test_config), apm_(apm) {}
561
562 // Implements the callback functionality for the statistics
563 // collection thread.
Process()564 void StatsProcessor::Process() {
565 SleepRandomMs(100, rand_gen_);
566
567 AudioProcessing::Config apm_config = apm_->GetConfig();
568 if (test_config_->aec_type != AecType::AecTurnedOff) {
569 EXPECT_TRUE(apm_config.echo_canceller.enabled);
570 EXPECT_EQ(apm_config.echo_canceller.mobile_mode,
571 (test_config_->aec_type ==
572 AecType::BasicWebRtcAecSettingsWithAecMobile));
573 } else {
574 EXPECT_FALSE(apm_config.echo_canceller.enabled);
575 }
576 EXPECT_TRUE(apm_config.gain_controller1.enabled);
577 EXPECT_TRUE(apm_config.noise_suppression.enabled);
578
579 // The below return value is not testable.
580 apm_->GetStatistics();
581 }
582
583 const float CaptureProcessor::kCaptureInputFloatLevel = 0.03125f;
584
CaptureProcessor(int max_frame_size,RandomGenerator * rand_gen,rtc::Event * render_call_event,rtc::Event * capture_call_event,FrameCounters * shared_counters_state,TestConfig * test_config,AudioProcessing * apm)585 CaptureProcessor::CaptureProcessor(int max_frame_size,
586 RandomGenerator* rand_gen,
587 rtc::Event* render_call_event,
588 rtc::Event* capture_call_event,
589 FrameCounters* shared_counters_state,
590 TestConfig* test_config,
591 AudioProcessing* apm)
592 : rand_gen_(rand_gen),
593 render_call_event_(render_call_event),
594 capture_call_event_(capture_call_event),
595 frame_counters_(shared_counters_state),
596 test_config_(test_config),
597 apm_(apm),
598 frame_data_(max_frame_size) {}
599
600 // Implements the callback functionality for the capture thread.
Process()601 void CaptureProcessor::Process() {
602 // Sleep a random time to simulate thread jitter.
603 SleepRandomMs(3, rand_gen_);
604
605 // Ensure that the number of render and capture calls do not
606 // differ too much.
607 if (frame_counters_->CaptureMinusRenderCounters() > kMaxCallDifference) {
608 render_call_event_->Wait(rtc::Event::kForever);
609 }
610
611 // Apply any specified capture side APM non-processing runtime calls.
612 ApplyRuntimeSettingScheme();
613
614 // Apply the capture side processing call.
615 CallApmCaptureSide();
616
617 // Increase the number of capture-side calls.
618 frame_counters_->IncreaseCaptureCounter();
619
620 // Flag to the render thread that another capture API call has occurred
621 // by triggering this threads call event.
622 capture_call_event_->Set();
623 }
624
625 // Prepares a frame with relevant audio data and metadata.
PrepareFrame()626 void CaptureProcessor::PrepareFrame() {
627 // Restrict to a common fixed sample rate if the integer
628 // interface is used.
629 if (test_config_->capture_api_function ==
630 CaptureApiImpl::ProcessStreamImplInteger) {
631 frame_data_.input_sample_rate_hz = test_config_->initial_sample_rate_hz;
632 frame_data_.output_sample_rate_hz = test_config_->initial_sample_rate_hz;
633 }
634
635 // Prepare the audio data.
636 StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
637 frame_data_.input_number_of_channels,
638 /*has_keyboard=*/false);
639
640 PopulateAudioFrame(kCaptureInputFixLevel, input_stream_config.num_channels(),
641 input_stream_config.num_frames(), frame_data_.frame,
642 rand_gen_);
643
644 PopulateAudioFrame(&frame_data_.input_frame[0], kCaptureInputFloatLevel,
645 input_stream_config.num_channels(),
646 input_stream_config.num_frames(), rand_gen_);
647 }
648
649 // Applies the capture side processing API call.
CallApmCaptureSide()650 void CaptureProcessor::CallApmCaptureSide() {
651 // Prepare a proper capture side processing API call input.
652 PrepareFrame();
653
654 // Set the stream delay.
655 apm_->set_stream_delay_ms(30);
656
657 // Set the analog level.
658 apm_->set_stream_analog_level(80);
659
660 // Call the specified capture side API processing method.
661 StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
662 frame_data_.input_number_of_channels,
663 /*has_keyboard=*/false);
664 StreamConfig output_stream_config(frame_data_.output_sample_rate_hz,
665 frame_data_.output_number_of_channels,
666 /*has_keyboard=*/false);
667 int result = AudioProcessing::kNoError;
668 switch (test_config_->capture_api_function) {
669 case CaptureApiImpl::ProcessStreamImplInteger:
670 result =
671 apm_->ProcessStream(frame_data_.frame.data(), input_stream_config,
672 output_stream_config, frame_data_.frame.data());
673 break;
674 case CaptureApiImpl::ProcessStreamImplFloat:
675 result = apm_->ProcessStream(&frame_data_.input_frame[0],
676 input_stream_config, output_stream_config,
677 &frame_data_.output_frame[0]);
678 break;
679 default:
680 FAIL();
681 }
682
683 // Retrieve the new analog level.
684 apm_->recommended_stream_analog_level();
685
686 // Check the return code for error.
687 ASSERT_EQ(AudioProcessing::kNoError, result);
688 }
689
690 // Applies any runtime capture APM API calls and audio stream characteristics
691 // specified by the scheme for the test.
ApplyRuntimeSettingScheme()692 void CaptureProcessor::ApplyRuntimeSettingScheme() {
693 const int capture_count_local = frame_counters_->GetCaptureCounter();
694
695 // Update the number of channels and sample rates for the input and output.
696 // Note that the counts frequencies for when to set parameters
697 // are set using prime numbers in order to ensure that the
698 // permutation scheme in the parameter setting changes.
699 switch (test_config_->runtime_parameter_setting_scheme) {
700 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
701 if (capture_count_local == 0)
702 frame_data_.input_sample_rate_hz = 16000;
703 else if (capture_count_local % 11 == 0)
704 frame_data_.input_sample_rate_hz = 32000;
705 else if (capture_count_local % 73 == 0)
706 frame_data_.input_sample_rate_hz = 48000;
707 else if (capture_count_local % 89 == 0)
708 frame_data_.input_sample_rate_hz = 16000;
709 else if (capture_count_local % 97 == 0)
710 frame_data_.input_sample_rate_hz = 8000;
711
712 if (capture_count_local == 0)
713 frame_data_.input_number_of_channels = 1;
714 else if (capture_count_local % 4 == 0)
715 frame_data_.input_number_of_channels =
716 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
717
718 if (capture_count_local == 0)
719 frame_data_.output_sample_rate_hz = 16000;
720 else if (capture_count_local % 5 == 0)
721 frame_data_.output_sample_rate_hz = 32000;
722 else if (capture_count_local % 47 == 0)
723 frame_data_.output_sample_rate_hz = 48000;
724 else if (capture_count_local % 53 == 0)
725 frame_data_.output_sample_rate_hz = 16000;
726 else if (capture_count_local % 71 == 0)
727 frame_data_.output_sample_rate_hz = 8000;
728
729 if (capture_count_local == 0)
730 frame_data_.output_number_of_channels = 1;
731 else if (capture_count_local % 8 == 0)
732 frame_data_.output_number_of_channels =
733 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
734 break;
735 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
736 if (capture_count_local % 2 == 0) {
737 frame_data_.input_number_of_channels = 1;
738 frame_data_.input_sample_rate_hz = 16000;
739 frame_data_.output_number_of_channels = 1;
740 frame_data_.output_sample_rate_hz = 16000;
741 } else {
742 frame_data_.input_number_of_channels =
743 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
744 if (frame_data_.input_sample_rate_hz == 8000)
745 frame_data_.input_sample_rate_hz = 16000;
746 else if (frame_data_.input_sample_rate_hz == 16000)
747 frame_data_.input_sample_rate_hz = 32000;
748 else if (frame_data_.input_sample_rate_hz == 32000)
749 frame_data_.input_sample_rate_hz = 48000;
750 else if (frame_data_.input_sample_rate_hz == 48000)
751 frame_data_.input_sample_rate_hz = 8000;
752
753 frame_data_.output_number_of_channels =
754 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
755 if (frame_data_.output_sample_rate_hz == 8000)
756 frame_data_.output_sample_rate_hz = 16000;
757 else if (frame_data_.output_sample_rate_hz == 16000)
758 frame_data_.output_sample_rate_hz = 32000;
759 else if (frame_data_.output_sample_rate_hz == 32000)
760 frame_data_.output_sample_rate_hz = 48000;
761 else if (frame_data_.output_sample_rate_hz == 48000)
762 frame_data_.output_sample_rate_hz = 8000;
763 }
764 break;
765 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
766 if (capture_count_local == 0) {
767 frame_data_.input_sample_rate_hz = 16000;
768 frame_data_.input_number_of_channels = 1;
769 frame_data_.output_sample_rate_hz = 16000;
770 frame_data_.output_number_of_channels = 1;
771 }
772 break;
773 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
774 if (capture_count_local == 0) {
775 frame_data_.input_sample_rate_hz = 16000;
776 frame_data_.input_number_of_channels = 2;
777 frame_data_.output_sample_rate_hz = 16000;
778 frame_data_.output_number_of_channels = 2;
779 }
780 break;
781 default:
782 FAIL();
783 }
784
785 // Call any specified runtime APM setter and
786 // getter calls.
787 switch (test_config_->runtime_parameter_setting_scheme) {
788 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
789 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
790 break;
791 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
792 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
793 if (capture_count_local % 2 == 0) {
794 ASSERT_EQ(AudioProcessing::Error::kNoError,
795 apm_->set_stream_delay_ms(30));
796 apm_->set_stream_key_pressed(true);
797 } else {
798 ASSERT_EQ(AudioProcessing::Error::kNoError,
799 apm_->set_stream_delay_ms(50));
800 apm_->set_stream_key_pressed(false);
801 }
802 break;
803 default:
804 FAIL();
805 }
806
807 // Restric the number of output channels not to exceed
808 // the number of input channels.
809 frame_data_.output_number_of_channels =
810 std::min(frame_data_.output_number_of_channels,
811 frame_data_.input_number_of_channels);
812 }
813
814 const float RenderProcessor::kRenderInputFloatLevel = 0.5f;
815
RenderProcessor(int max_frame_size,RandomGenerator * rand_gen,rtc::Event * render_call_event,rtc::Event * capture_call_event,FrameCounters * shared_counters_state,TestConfig * test_config,AudioProcessing * apm)816 RenderProcessor::RenderProcessor(int max_frame_size,
817 RandomGenerator* rand_gen,
818 rtc::Event* render_call_event,
819 rtc::Event* capture_call_event,
820 FrameCounters* shared_counters_state,
821 TestConfig* test_config,
822 AudioProcessing* apm)
823 : rand_gen_(rand_gen),
824 render_call_event_(render_call_event),
825 capture_call_event_(capture_call_event),
826 frame_counters_(shared_counters_state),
827 test_config_(test_config),
828 apm_(apm),
829 frame_data_(max_frame_size) {}
830
831 // Implements the callback functionality for the render thread.
Process()832 void RenderProcessor::Process() {
833 // Conditional wait to ensure that a capture call has been done
834 // before the first render call is performed (implicitly
835 // required by the APM API).
836 if (first_render_call_) {
837 capture_call_event_->Wait(rtc::Event::kForever);
838 first_render_call_ = false;
839 }
840
841 // Sleep a random time to simulate thread jitter.
842 SleepRandomMs(3, rand_gen_);
843
844 // Ensure that the number of render and capture calls do not
845 // differ too much.
846 if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) {
847 capture_call_event_->Wait(rtc::Event::kForever);
848 }
849
850 // Apply any specified render side APM non-processing runtime calls.
851 ApplyRuntimeSettingScheme();
852
853 // Apply the render side processing call.
854 CallApmRenderSide();
855
856 // Increase the number of render-side calls.
857 frame_counters_->IncreaseRenderCounter();
858
859 // Flag to the capture thread that another render API call has occurred
860 // by triggering this threads call event.
861 render_call_event_->Set();
862 }
863
864 // Prepares the render side frame and the accompanying metadata
865 // with the appropriate information.
PrepareFrame()866 void RenderProcessor::PrepareFrame() {
867 // Restrict to a common fixed sample rate if the integer interface is
868 // used.
869 if ((test_config_->render_api_function ==
870 RenderApiImpl::ProcessReverseStreamImplInteger) ||
871 (test_config_->aec_type !=
872 AecType::BasicWebRtcAecSettingsWithAecMobile)) {
873 frame_data_.input_sample_rate_hz = test_config_->initial_sample_rate_hz;
874 frame_data_.output_sample_rate_hz = test_config_->initial_sample_rate_hz;
875 }
876
877 // Prepare the audio data.
878 StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
879 frame_data_.input_number_of_channels,
880 /*has_keyboard=*/false);
881
882 PopulateAudioFrame(kRenderInputFixLevel, input_stream_config.num_channels(),
883 input_stream_config.num_frames(), frame_data_.frame,
884 rand_gen_);
885
886 PopulateAudioFrame(&frame_data_.input_frame[0], kRenderInputFloatLevel,
887 input_stream_config.num_channels(),
888 input_stream_config.num_frames(), rand_gen_);
889 }
890
891 // Makes the render side processing API call.
CallApmRenderSide()892 void RenderProcessor::CallApmRenderSide() {
893 // Prepare a proper render side processing API call input.
894 PrepareFrame();
895
896 // Call the specified render side API processing method.
897 StreamConfig input_stream_config(frame_data_.input_sample_rate_hz,
898 frame_data_.input_number_of_channels,
899 /*has_keyboard=*/false);
900 StreamConfig output_stream_config(frame_data_.output_sample_rate_hz,
901 frame_data_.output_number_of_channels,
902 /*has_keyboard=*/false);
903 int result = AudioProcessing::kNoError;
904 switch (test_config_->render_api_function) {
905 case RenderApiImpl::ProcessReverseStreamImplInteger:
906 result = apm_->ProcessReverseStream(
907 frame_data_.frame.data(), input_stream_config, output_stream_config,
908 frame_data_.frame.data());
909 break;
910 case RenderApiImpl::ProcessReverseStreamImplFloat:
911 result = apm_->ProcessReverseStream(
912 &frame_data_.input_frame[0], input_stream_config,
913 output_stream_config, &frame_data_.output_frame[0]);
914 break;
915 case RenderApiImpl::AnalyzeReverseStreamImplFloat:
916 result = apm_->AnalyzeReverseStream(&frame_data_.input_frame[0],
917 input_stream_config);
918 break;
919 default:
920 FAIL();
921 }
922
923 // Check the return code for error.
924 ASSERT_EQ(AudioProcessing::kNoError, result);
925 }
926
927 // Applies any render capture side APM API calls and audio stream
928 // characteristics
929 // specified by the scheme for the test.
ApplyRuntimeSettingScheme()930 void RenderProcessor::ApplyRuntimeSettingScheme() {
931 const int render_count_local = frame_counters_->GetRenderCounter();
932
933 // Update the number of channels and sample rates for the input and output.
934 // Note that the counts frequencies for when to set parameters
935 // are set using prime numbers in order to ensure that the
936 // permutation scheme in the parameter setting changes.
937 switch (test_config_->runtime_parameter_setting_scheme) {
938 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
939 if (render_count_local == 0)
940 frame_data_.input_sample_rate_hz = 16000;
941 else if (render_count_local % 47 == 0)
942 frame_data_.input_sample_rate_hz = 32000;
943 else if (render_count_local % 71 == 0)
944 frame_data_.input_sample_rate_hz = 48000;
945 else if (render_count_local % 79 == 0)
946 frame_data_.input_sample_rate_hz = 16000;
947 else if (render_count_local % 83 == 0)
948 frame_data_.input_sample_rate_hz = 8000;
949
950 if (render_count_local == 0)
951 frame_data_.input_number_of_channels = 1;
952 else if (render_count_local % 4 == 0)
953 frame_data_.input_number_of_channels =
954 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
955
956 if (render_count_local == 0)
957 frame_data_.output_sample_rate_hz = 16000;
958 else if (render_count_local % 17 == 0)
959 frame_data_.output_sample_rate_hz = 32000;
960 else if (render_count_local % 19 == 0)
961 frame_data_.output_sample_rate_hz = 48000;
962 else if (render_count_local % 29 == 0)
963 frame_data_.output_sample_rate_hz = 16000;
964 else if (render_count_local % 61 == 0)
965 frame_data_.output_sample_rate_hz = 8000;
966
967 if (render_count_local == 0)
968 frame_data_.output_number_of_channels = 1;
969 else if (render_count_local % 8 == 0)
970 frame_data_.output_number_of_channels =
971 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
972 break;
973 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
974 if (render_count_local == 0) {
975 frame_data_.input_number_of_channels = 1;
976 frame_data_.input_sample_rate_hz = 16000;
977 frame_data_.output_number_of_channels = 1;
978 frame_data_.output_sample_rate_hz = 16000;
979 } else {
980 frame_data_.input_number_of_channels =
981 (frame_data_.input_number_of_channels == 1 ? 2 : 1);
982 if (frame_data_.input_sample_rate_hz == 8000)
983 frame_data_.input_sample_rate_hz = 16000;
984 else if (frame_data_.input_sample_rate_hz == 16000)
985 frame_data_.input_sample_rate_hz = 32000;
986 else if (frame_data_.input_sample_rate_hz == 32000)
987 frame_data_.input_sample_rate_hz = 48000;
988 else if (frame_data_.input_sample_rate_hz == 48000)
989 frame_data_.input_sample_rate_hz = 8000;
990
991 frame_data_.output_number_of_channels =
992 (frame_data_.output_number_of_channels == 1 ? 2 : 1);
993 if (frame_data_.output_sample_rate_hz == 8000)
994 frame_data_.output_sample_rate_hz = 16000;
995 else if (frame_data_.output_sample_rate_hz == 16000)
996 frame_data_.output_sample_rate_hz = 32000;
997 else if (frame_data_.output_sample_rate_hz == 32000)
998 frame_data_.output_sample_rate_hz = 48000;
999 else if (frame_data_.output_sample_rate_hz == 48000)
1000 frame_data_.output_sample_rate_hz = 8000;
1001 }
1002 break;
1003 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
1004 if (render_count_local == 0) {
1005 frame_data_.input_sample_rate_hz = 16000;
1006 frame_data_.input_number_of_channels = 1;
1007 frame_data_.output_sample_rate_hz = 16000;
1008 frame_data_.output_number_of_channels = 1;
1009 }
1010 break;
1011 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
1012 if (render_count_local == 0) {
1013 frame_data_.input_sample_rate_hz = 16000;
1014 frame_data_.input_number_of_channels = 2;
1015 frame_data_.output_sample_rate_hz = 16000;
1016 frame_data_.output_number_of_channels = 2;
1017 }
1018 break;
1019 default:
1020 FAIL();
1021 }
1022
1023 // Restric the number of output channels not to exceed
1024 // the number of input channels.
1025 frame_data_.output_number_of_channels =
1026 std::min(frame_data_.output_number_of_channels,
1027 frame_data_.input_number_of_channels);
1028 }
1029
1030 } // anonymous namespace
1031
TEST_P(AudioProcessingImplLockTest,LockTest)1032 TEST_P(AudioProcessingImplLockTest, LockTest) {
1033 // Run test and verify that it did not time out.
1034 ASSERT_TRUE(RunTest());
1035 }
1036
1037 // Instantiate tests from the extreme test configuration set.
1038 INSTANTIATE_TEST_SUITE_P(
1039 DISABLED_AudioProcessingImplLockExtensive,
1040 AudioProcessingImplLockTest,
1041 ::testing::ValuesIn(TestConfig::GenerateExtensiveTestConfigs()));
1042
1043 INSTANTIATE_TEST_SUITE_P(
1044 AudioProcessingImplLockBrief,
1045 AudioProcessingImplLockTest,
1046 ::testing::ValuesIn(TestConfig::GenerateBriefTestConfigs()));
1047
1048 } // namespace webrtc
1049