xref: /aosp_15_r20/external/webrtc/modules/audio_processing/audio_processing_impl_locking_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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