1 /*
2  *  Copyright (c) 2016 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 <numeric>
12 #include <vector>
13 
14 #include "api/array_view.h"
15 #include "modules/audio_processing/audio_buffer.h"
16 #include "modules/audio_processing/include/audio_processing.h"
17 #include "modules/audio_processing/level_controller/level_controller.h"
18 #include "modules/audio_processing/test/audio_buffer_tools.h"
19 #include "modules/audio_processing/test/bitexactness_tools.h"
20 #include "modules/audio_processing/test/performance_timer.h"
21 #include "modules/audio_processing/test/simulator_buffers.h"
22 #include "rtc_base/random.h"
23 #include "system_wrappers/include/clock.h"
24 #include "test/gtest.h"
25 #include "test/testsupport/perf_test.h"
26 
27 namespace webrtc {
28 namespace {
29 
30 const size_t kNumFramesToProcess = 300;
31 const size_t kNumFramesToProcessAtWarmup = 300;
32 const size_t kToTalNumFrames =
33     kNumFramesToProcess + kNumFramesToProcessAtWarmup;
34 
RunStandaloneSubmodule(int sample_rate_hz,size_t num_channels)35 void RunStandaloneSubmodule(int sample_rate_hz, size_t num_channels) {
36   test::SimulatorBuffers buffers(sample_rate_hz, sample_rate_hz, sample_rate_hz,
37                                  sample_rate_hz, num_channels, num_channels,
38                                  num_channels, num_channels);
39   test::PerformanceTimer timer(kNumFramesToProcess);
40 
41   LevelController level_controller;
42   level_controller.Initialize(sample_rate_hz);
43 
44   for (size_t frame_no = 0; frame_no < kToTalNumFrames; ++frame_no) {
45     buffers.UpdateInputBuffers();
46 
47     if (frame_no >= kNumFramesToProcessAtWarmup) {
48       timer.StartTimer();
49     }
50     level_controller.Process(buffers.capture_input_buffer.get());
51     if (frame_no >= kNumFramesToProcessAtWarmup) {
52       timer.StopTimer();
53     }
54   }
55   webrtc::test::PrintResultMeanAndError(
56       "level_controller_call_durations",
57       "_" + std::to_string(sample_rate_hz) + "Hz_" +
58           std::to_string(num_channels) + "_channels",
59       "StandaloneLevelControl", timer.GetDurationAverage(),
60       timer.GetDurationStandardDeviation(), "us", false);
61 }
62 
RunTogetherWithApm(const std::string & test_description,int render_input_sample_rate_hz,int render_output_sample_rate_hz,int capture_input_sample_rate_hz,int capture_output_sample_rate_hz,size_t num_channels,bool use_mobile_aec,bool include_default_apm_processing)63 void RunTogetherWithApm(const std::string& test_description,
64                         int render_input_sample_rate_hz,
65                         int render_output_sample_rate_hz,
66                         int capture_input_sample_rate_hz,
67                         int capture_output_sample_rate_hz,
68                         size_t num_channels,
69                         bool use_mobile_aec,
70                         bool include_default_apm_processing) {
71   test::SimulatorBuffers buffers(
72       render_input_sample_rate_hz, capture_input_sample_rate_hz,
73       render_output_sample_rate_hz, capture_output_sample_rate_hz, num_channels,
74       num_channels, num_channels, num_channels);
75   test::PerformanceTimer render_timer(kNumFramesToProcess);
76   test::PerformanceTimer capture_timer(kNumFramesToProcess);
77   test::PerformanceTimer total_timer(kNumFramesToProcess);
78 
79   webrtc::Config config;
80   AudioProcessing::Config apm_config;
81   if (include_default_apm_processing) {
82     config.Set<DelayAgnostic>(new DelayAgnostic(true));
83     config.Set<ExtendedFilter>(new ExtendedFilter(true));
84   }
85   apm_config.level_controller.enabled = true;
86   apm_config.residual_echo_detector.enabled = include_default_apm_processing;
87 
88   std::unique_ptr<AudioProcessing> apm;
89   apm.reset(AudioProcessing::Create(config));
90   ASSERT_TRUE(apm.get());
91   apm->ApplyConfig(apm_config);
92 
93   ASSERT_EQ(AudioProcessing::kNoError,
94             apm->gain_control()->Enable(include_default_apm_processing));
95   if (use_mobile_aec) {
96     ASSERT_EQ(AudioProcessing::kNoError,
97               apm->echo_cancellation()->Enable(false));
98     ASSERT_EQ(AudioProcessing::kNoError, apm->echo_control_mobile()->Enable(
99                                              include_default_apm_processing));
100   } else {
101     ASSERT_EQ(AudioProcessing::kNoError,
102               apm->echo_cancellation()->Enable(include_default_apm_processing));
103     ASSERT_EQ(AudioProcessing::kNoError,
104               apm->echo_control_mobile()->Enable(false));
105   }
106   apm_config.high_pass_filter.enabled = include_default_apm_processing;
107   ASSERT_EQ(AudioProcessing::kNoError,
108             apm->noise_suppression()->Enable(include_default_apm_processing));
109   ASSERT_EQ(AudioProcessing::kNoError,
110             apm->voice_detection()->Enable(include_default_apm_processing));
111   ASSERT_EQ(AudioProcessing::kNoError,
112             apm->level_estimator()->Enable(include_default_apm_processing));
113 
114   StreamConfig render_input_config(render_input_sample_rate_hz, num_channels,
115                                    false);
116   StreamConfig render_output_config(render_output_sample_rate_hz, num_channels,
117                                     false);
118   StreamConfig capture_input_config(capture_input_sample_rate_hz, num_channels,
119                                     false);
120   StreamConfig capture_output_config(capture_output_sample_rate_hz,
121                                      num_channels, false);
122 
123   for (size_t frame_no = 0; frame_no < kToTalNumFrames; ++frame_no) {
124     buffers.UpdateInputBuffers();
125 
126     if (frame_no >= kNumFramesToProcessAtWarmup) {
127       total_timer.StartTimer();
128       render_timer.StartTimer();
129     }
130     ASSERT_EQ(AudioProcessing::kNoError,
131               apm->ProcessReverseStream(
132                   &buffers.render_input[0], render_input_config,
133                   render_output_config, &buffers.render_output[0]));
134 
135     if (frame_no >= kNumFramesToProcessAtWarmup) {
136       render_timer.StopTimer();
137 
138       capture_timer.StartTimer();
139     }
140 
141     ASSERT_EQ(AudioProcessing::kNoError, apm->set_stream_delay_ms(0));
142     ASSERT_EQ(
143         AudioProcessing::kNoError,
144         apm->ProcessStream(&buffers.capture_input[0], capture_input_config,
145                            capture_output_config, &buffers.capture_output[0]));
146 
147     if (frame_no >= kNumFramesToProcessAtWarmup) {
148       capture_timer.StopTimer();
149       total_timer.StopTimer();
150     }
151   }
152 
153   webrtc::test::PrintResultMeanAndError(
154       "level_controller_call_durations",
155       "_" + std::to_string(render_input_sample_rate_hz) + "_" +
156           std::to_string(render_output_sample_rate_hz) + "_" +
157           std::to_string(capture_input_sample_rate_hz) + "_" +
158           std::to_string(capture_output_sample_rate_hz) + "Hz_" +
159           std::to_string(num_channels) + "_channels" + "_render",
160       test_description, render_timer.GetDurationAverage(),
161       render_timer.GetDurationStandardDeviation(), "us", false);
162   webrtc::test::PrintResultMeanAndError(
163       "level_controller_call_durations",
164       "_" + std::to_string(render_input_sample_rate_hz) + "_" +
165           std::to_string(render_output_sample_rate_hz) + "_" +
166           std::to_string(capture_input_sample_rate_hz) + "_" +
167           std::to_string(capture_output_sample_rate_hz) + "Hz_" +
168           std::to_string(num_channels) + "_channels" + "_capture",
169       test_description, capture_timer.GetDurationAverage(),
170       capture_timer.GetDurationStandardDeviation(), "us", false);
171   webrtc::test::PrintResultMeanAndError(
172       "level_controller_call_durations",
173       "_" + std::to_string(render_input_sample_rate_hz) + "_" +
174           std::to_string(render_output_sample_rate_hz) + "_" +
175           std::to_string(capture_input_sample_rate_hz) + "_" +
176           std::to_string(capture_output_sample_rate_hz) + "Hz_" +
177           std::to_string(num_channels) + "_channels" + "_total",
178       test_description, total_timer.GetDurationAverage(),
179       total_timer.GetDurationStandardDeviation(), "us", false);
180 }
181 
182 }  // namespace
183 
184 // TODO(peah): Reactivate once issue 7712 has been resolved.
TEST(LevelControllerPerformanceTest,DISABLED_StandaloneProcessing)185 TEST(LevelControllerPerformanceTest, DISABLED_StandaloneProcessing) {
186   int sample_rates_to_test[] = {
187       AudioProcessing::kSampleRate8kHz, AudioProcessing::kSampleRate16kHz,
188       AudioProcessing::kSampleRate32kHz, AudioProcessing::kSampleRate48kHz};
189   for (auto sample_rate : sample_rates_to_test) {
190     for (size_t num_channels = 1; num_channels <= 2; ++num_channels) {
191       RunStandaloneSubmodule(sample_rate, num_channels);
192     }
193   }
194 }
195 
TestSomeSampleRatesWithApm(const std::string & test_name,bool use_mobile_agc,bool include_default_apm_processing)196 void TestSomeSampleRatesWithApm(const std::string& test_name,
197                                 bool use_mobile_agc,
198                                 bool include_default_apm_processing) {
199   // Test some stereo combinations first.
200   size_t num_channels = 2;
201   RunTogetherWithApm(test_name, 48000, 48000, AudioProcessing::kSampleRate16kHz,
202                      AudioProcessing::kSampleRate32kHz, num_channels,
203                      use_mobile_agc, include_default_apm_processing);
204   RunTogetherWithApm(test_name, 48000, 48000, AudioProcessing::kSampleRate48kHz,
205                      AudioProcessing::kSampleRate8kHz, num_channels,
206                      use_mobile_agc, include_default_apm_processing);
207   RunTogetherWithApm(test_name, 48000, 48000, 44100, 44100, num_channels,
208                      use_mobile_agc, include_default_apm_processing);
209 
210   // Then test mono combinations.
211   num_channels = 1;
212   RunTogetherWithApm(test_name, 48000, 48000, AudioProcessing::kSampleRate48kHz,
213                      AudioProcessing::kSampleRate48kHz, num_channels,
214                      use_mobile_agc, include_default_apm_processing);
215 }
216 
217 // TODO(peah): Reactivate once issue 7712 has been resolved.
218 #if !defined(WEBRTC_ANDROID)
TEST(LevelControllerPerformanceTest,DISABLED_ProcessingViaApm)219 TEST(LevelControllerPerformanceTest, DISABLED_ProcessingViaApm) {
220 #else
221 TEST(LevelControllerPerformanceTest, DISABLED_ProcessingViaApm) {
222 #endif
223   // Run without default APM processing and desktop AGC.
224   TestSomeSampleRatesWithApm("SimpleLevelControlViaApm", false, false);
225 }
226 
227 // TODO(peah): Reactivate once issue 7712 has been resolved.
228 #if !defined(WEBRTC_ANDROID)
229 TEST(LevelControllerPerformanceTest, DISABLED_InteractionWithDefaultApm) {
230 #else
231 TEST(LevelControllerPerformanceTest, DISABLED_InteractionWithDefaultApm) {
232 #endif
233   bool include_default_apm_processing = true;
234   TestSomeSampleRatesWithApm("LevelControlAndDefaultDesktopApm", false,
235                              include_default_apm_processing);
236   TestSomeSampleRatesWithApm("LevelControlAndDefaultMobileApm", true,
237                              include_default_apm_processing);
238 }
239 
240 }  // namespace webrtc
241