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