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