OLD | NEW |
---|---|
(Empty) | |
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 "testing/gtest/include/gtest/gtest.h" | |
15 #include "webrtc/base/array_view.h" | |
16 #include "webrtc/base/random.h" | |
17 #include "webrtc/modules/audio_processing/audio_buffer.h" | |
18 #include "webrtc/modules/audio_processing/include/audio_processing.h" | |
19 #include "webrtc/modules/audio_processing/level_controller/level_controller.h" | |
20 #include "webrtc/modules/audio_processing/test/audio_buffer_tools.h" | |
21 #include "webrtc/modules/audio_processing/test/bitexactness_tools.h" | |
22 #include "webrtc/system_wrappers/include/clock.h" | |
23 #include "webrtc/test/testsupport/perf_test.h" | |
24 | |
25 namespace webrtc { | |
26 namespace { | |
27 | |
28 const size_t kNumFramesToProcess = 100; | |
29 | |
30 struct SimulatorBuffers { | |
31 SimulatorBuffers(int render_input_sample_rate_hz, | |
32 int capture_input_sample_rate_hz, | |
33 int render_output_sample_rate_hz, | |
34 int capture_output_sample_rate_hz, | |
35 size_t num_render_input_channels, | |
36 size_t num_capture_input_channels, | |
37 size_t num_render_output_channels, | |
38 size_t num_capture_output_channels) { | |
39 Random rand_gen(42); | |
40 CreateConfigAndBuffer(render_input_sample_rate_hz, | |
41 num_render_input_channels, &rand_gen, | |
42 &render_input_buffer, &render_input_config, | |
43 &render_input, &render_input_samples); | |
44 | |
45 CreateConfigAndBuffer(render_output_sample_rate_hz, | |
46 num_render_output_channels, &rand_gen, | |
47 &render_output_buffer, &render_output_config, | |
48 &render_output, &render_output_samples); | |
49 | |
50 CreateConfigAndBuffer(capture_input_sample_rate_hz, | |
51 num_capture_input_channels, &rand_gen, | |
52 &capture_input_buffer, &capture_input_config, | |
53 &capture_input, &capture_input_samples); | |
54 | |
55 CreateConfigAndBuffer(capture_output_sample_rate_hz, | |
56 num_capture_output_channels, &rand_gen, | |
57 &capture_output_buffer, &capture_output_config, | |
58 &capture_output, &capture_output_samples); | |
59 | |
60 UpdateInputBuffers(); | |
61 } | |
62 | |
63 void CreateConfigAndBuffer(int sample_rate_hz, | |
64 size_t num_channels, | |
65 Random* rand_gen, | |
66 std::unique_ptr<AudioBuffer>* buffer, | |
67 StreamConfig* config, | |
68 std::vector<float*>* buffer_data, | |
69 std::vector<float>* buffer_data_samples) { | |
70 int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100); | |
71 *config = StreamConfig(sample_rate_hz, num_channels, false); | |
72 buffer->reset(new AudioBuffer(config->num_frames(), config->num_channels(), | |
73 config->num_frames(), config->num_channels(), | |
74 config->num_frames())); | |
75 | |
76 buffer_data_samples->resize(samples_per_channel * num_channels); | |
77 for (auto& v : *buffer_data_samples) { | |
78 v = rand_gen->Rand<float>(); | |
79 } | |
80 | |
81 buffer_data->resize(num_channels); | |
82 for (size_t ch = 0; ch < num_channels; ++ch) { | |
83 (*buffer_data)[ch] = &(*buffer_data_samples)[ch * samples_per_channel]; | |
84 } | |
85 } | |
86 | |
87 void UpdateInputBuffers() { | |
88 test::CopyVectorToAudioBuffer(capture_input_config, capture_input_samples, | |
89 capture_input_buffer.get()); | |
90 test::CopyVectorToAudioBuffer(render_input_config, render_input_samples, | |
91 render_input_buffer.get()); | |
92 } | |
93 | |
94 std::unique_ptr<AudioBuffer> render_input_buffer; | |
95 std::unique_ptr<AudioBuffer> capture_input_buffer; | |
96 std::unique_ptr<AudioBuffer> render_output_buffer; | |
97 std::unique_ptr<AudioBuffer> capture_output_buffer; | |
98 StreamConfig render_input_config; | |
99 StreamConfig capture_input_config; | |
100 StreamConfig render_output_config; | |
101 StreamConfig capture_output_config; | |
102 std::vector<float*> render_input; | |
103 std::vector<float> render_input_samples; | |
104 std::vector<float*> capture_input; | |
105 std::vector<float> capture_input_samples; | |
106 std::vector<float*> render_output; | |
107 std::vector<float> render_output_samples; | |
108 std::vector<float*> capture_output; | |
109 std::vector<float> capture_output_samples; | |
110 }; | |
111 | |
112 class SubmodulePerformanceTimer { | |
113 public: | |
114 SubmodulePerformanceTimer() : clock_(webrtc::Clock::GetRealTimeClock()) { | |
115 timestamps_us_.resize(kNumFramesToProcess); | |
hlundin-webrtc
2016/06/28 11:29:01
You must use reserve, not resize. reserve allocate
peah-webrtc
2016/06/28 22:19:38
Fully true! Thanks!
Done.
| |
116 } | |
117 | |
118 void StartTimer() { | |
119 start_timestamp_us_ = rtc::Optional<int64_t>(clock_->TimeInMicroseconds()); | |
120 } | |
121 void StopTimer() { | |
122 RTC_DCHECK(start_timestamp_us_); | |
123 timestamps_us_.push_back(clock_->TimeInMicroseconds() - | |
124 *start_timestamp_us_); | |
125 } | |
126 | |
127 double GetDurationAverage() const { | |
128 RTC_DCHECK(!timestamps_us_.empty()); | |
129 return static_cast<double>(std::accumulate(timestamps_us_.begin(), | |
130 timestamps_us_.end(), 0)) / | |
131 timestamps_us_.size(); | |
132 } | |
133 | |
134 double GetDurationStandardDeviation() const { | |
135 RTC_DCHECK(!timestamps_us_.empty()); | |
136 double average_duration = GetDurationAverage(); | |
137 | |
138 int64_t variance = | |
139 std::accumulate(timestamps_us_.begin(), timestamps_us_.end(), 0, | |
140 [average_duration](const int64_t& a, const int64_t& b) { | |
141 return a + (b - average_duration); | |
142 }); | |
143 | |
144 return sqrt(variance / timestamps_us_.size()); | |
145 } | |
146 | |
147 private: | |
148 webrtc::Clock* clock_; | |
149 rtc::Optional<int64_t> start_timestamp_us_; | |
150 std::vector<int64_t> timestamps_us_; | |
151 }; | |
152 | |
153 std::string FormPerformanceMeasureString( | |
154 const SubmodulePerformanceTimer& timer) { | |
155 std::string s = std::to_string(timer.GetDurationAverage()); | |
156 s += ", "; | |
157 s += std::to_string(timer.GetDurationStandardDeviation()); | |
158 return s; | |
159 } | |
160 | |
161 void RunStandaloneSubmodule(int sample_rate_hz, size_t num_channels) { | |
162 SimulatorBuffers buffers(sample_rate_hz, sample_rate_hz, sample_rate_hz, | |
163 sample_rate_hz, num_channels, num_channels, | |
164 num_channels, num_channels); | |
165 SubmodulePerformanceTimer timer; | |
166 | |
167 LevelController level_controller; | |
168 level_controller.Initialize(sample_rate_hz); | |
169 | |
170 for (size_t frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) { | |
171 buffers.UpdateInputBuffers(); | |
172 | |
173 timer.StartTimer(); | |
174 level_controller.Process(buffers.capture_input_buffer.get()); | |
175 timer.StopTimer(); | |
176 } | |
177 webrtc::test::PrintResultMeanAndError( | |
178 "level_controller_call_durations", | |
179 "_" + std::to_string(sample_rate_hz) + "Hz_" + | |
180 std::to_string(num_channels) + "_channels", | |
181 "StandaloneLevelControl", FormPerformanceMeasureString(timer), "us", | |
182 false); | |
183 } | |
184 | |
185 void RunTogetherWithApm(std::string test_description, | |
186 int render_input_sample_rate_hz, | |
187 int render_output_sample_rate_hz, | |
188 int capture_input_sample_rate_hz, | |
189 int capture_output_sample_rate_hz, | |
190 size_t num_channels, | |
191 bool use_mobile_aec, | |
192 bool include_default_apm_processing) { | |
193 SimulatorBuffers buffers( | |
194 render_input_sample_rate_hz, capture_input_sample_rate_hz, | |
195 render_output_sample_rate_hz, capture_output_sample_rate_hz, num_channels, | |
196 num_channels, num_channels, num_channels); | |
197 SubmodulePerformanceTimer render_timer; | |
198 SubmodulePerformanceTimer capture_timer; | |
199 SubmodulePerformanceTimer total_timer; | |
200 | |
201 Config config; | |
202 if (include_default_apm_processing) { | |
203 config.Set<DelayAgnostic>(new DelayAgnostic(true)); | |
204 config.Set<ExtendedFilter>(new ExtendedFilter(true)); | |
205 } | |
206 config.Set<LevelControl>(new LevelControl(true)); | |
207 | |
208 std::unique_ptr<AudioProcessing> apm; | |
209 apm.reset(AudioProcessing::Create(config)); | |
210 ASSERT_TRUE(apm.get()); | |
211 | |
212 ASSERT_EQ(AudioProcessing::kNoError, | |
213 apm->gain_control()->Enable(include_default_apm_processing)); | |
214 if (use_mobile_aec) { | |
215 ASSERT_EQ(AudioProcessing::kNoError, | |
216 apm->echo_cancellation()->Enable(false)); | |
217 ASSERT_EQ(AudioProcessing::kNoError, apm->echo_control_mobile()->Enable( | |
218 include_default_apm_processing)); | |
219 } else { | |
220 ASSERT_EQ(AudioProcessing::kNoError, | |
221 apm->echo_cancellation()->Enable(include_default_apm_processing)); | |
222 ASSERT_EQ(AudioProcessing::kNoError, | |
223 apm->echo_control_mobile()->Enable(false)); | |
224 } | |
225 ASSERT_EQ(AudioProcessing::kNoError, | |
226 apm->high_pass_filter()->Enable(include_default_apm_processing)); | |
227 ASSERT_EQ(AudioProcessing::kNoError, | |
228 apm->noise_suppression()->Enable(include_default_apm_processing)); | |
229 ASSERT_EQ(AudioProcessing::kNoError, | |
230 apm->voice_detection()->Enable(include_default_apm_processing)); | |
231 ASSERT_EQ(AudioProcessing::kNoError, | |
232 apm->level_estimator()->Enable(include_default_apm_processing)); | |
233 | |
234 StreamConfig render_input_config(render_input_sample_rate_hz, num_channels, | |
235 false); | |
236 StreamConfig render_output_config(render_output_sample_rate_hz, num_channels, | |
237 false); | |
238 StreamConfig capture_input_config(capture_input_sample_rate_hz, num_channels, | |
239 false); | |
240 StreamConfig capture_output_config(capture_output_sample_rate_hz, | |
241 num_channels, false); | |
242 | |
243 for (size_t frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) { | |
244 buffers.UpdateInputBuffers(); | |
245 | |
246 total_timer.StartTimer(); | |
247 render_timer.StartTimer(); | |
248 ASSERT_EQ(AudioProcessing::kNoError, | |
249 apm->ProcessReverseStream( | |
250 &buffers.render_input[0], render_input_config, | |
251 render_output_config, &buffers.render_output[0])); | |
252 | |
253 render_timer.StopTimer(); | |
254 | |
255 capture_timer.StartTimer(); | |
256 ASSERT_EQ(AudioProcessing::kNoError, apm->set_stream_delay_ms(0)); | |
257 ASSERT_EQ( | |
258 AudioProcessing::kNoError, | |
259 apm->ProcessStream(&buffers.capture_input[0], capture_input_config, | |
260 capture_output_config, &buffers.capture_output[0])); | |
261 | |
262 capture_timer.StopTimer(); | |
263 total_timer.StopTimer(); | |
264 } | |
265 | |
266 webrtc::test::PrintResultMeanAndError( | |
267 "level_controller_call_durations", | |
268 "_" + std::to_string(render_input_sample_rate_hz) + "_" + | |
269 std::to_string(render_output_sample_rate_hz) + "_" + | |
270 std::to_string(capture_input_sample_rate_hz) + "_" + | |
271 std::to_string(capture_output_sample_rate_hz) + "Hz_" + | |
272 std::to_string(num_channels) + "_channels" + "_render", | |
273 test_description, FormPerformanceMeasureString(render_timer), "us", | |
274 false); | |
275 webrtc::test::PrintResultMeanAndError( | |
276 "level_controller_call_durations", | |
277 "_" + std::to_string(render_input_sample_rate_hz) + "_" + | |
278 std::to_string(render_output_sample_rate_hz) + "_" + | |
279 std::to_string(capture_input_sample_rate_hz) + "_" + | |
280 std::to_string(capture_output_sample_rate_hz) + "Hz_" + | |
281 std::to_string(num_channels) + "_channels" + "_capture", | |
282 test_description, FormPerformanceMeasureString(capture_timer), "us", | |
283 false); | |
284 webrtc::test::PrintResultMeanAndError( | |
285 "level_controller_call_durations", | |
286 "_" + std::to_string(render_input_sample_rate_hz) + "_" + | |
287 std::to_string(render_output_sample_rate_hz) + "_" + | |
288 std::to_string(capture_input_sample_rate_hz) + "_" + | |
289 std::to_string(capture_output_sample_rate_hz) + "Hz_" + | |
290 std::to_string(num_channels) + "_channels" + "_total", | |
291 test_description, FormPerformanceMeasureString(total_timer), "us", false); | |
292 } | |
293 | |
294 } // namespace | |
295 | |
296 TEST(LevelControllerPerformanceTest, StandaloneProcessing) { | |
297 int sample_rates_to_test[] = { | |
298 AudioProcessing::kSampleRate8kHz, AudioProcessing::kSampleRate16kHz, | |
299 AudioProcessing::kSampleRate32kHz, AudioProcessing::kSampleRate48kHz}; | |
300 for (auto sample_rate : sample_rates_to_test) { | |
301 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { | |
302 RunStandaloneSubmodule(sample_rate, num_channels); | |
303 } | |
304 } | |
305 } | |
306 | |
307 TEST(LevelControllerPerformanceTest, ProcessingViaApm) { | |
308 int sample_rates_to_test[] = {AudioProcessing::kSampleRate8kHz, | |
309 AudioProcessing::kSampleRate16kHz, | |
310 AudioProcessing::kSampleRate32kHz, | |
311 AudioProcessing::kSampleRate48kHz, 44100}; | |
312 for (auto capture_input_sample_rate_hz : sample_rates_to_test) { | |
313 for (auto capture_output_sample_rate_hz : sample_rates_to_test) { | |
314 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { | |
315 RunTogetherWithApm("SimpleLevelControlViaApm", 48000, 48000, | |
316 capture_input_sample_rate_hz, | |
317 capture_output_sample_rate_hz, num_channels, false, | |
318 false); | |
319 } | |
320 } | |
321 } | |
322 } | |
323 | |
324 TEST(LevelControllerPerformanceTest, InteractionWithDefaultApm) { | |
325 int sample_rates_to_test[] = {AudioProcessing::kSampleRate8kHz, | |
326 AudioProcessing::kSampleRate16kHz, | |
327 AudioProcessing::kSampleRate32kHz, | |
328 AudioProcessing::kSampleRate48kHz, 44100}; | |
329 for (auto capture_input_sample_rate_hz : sample_rates_to_test) { | |
330 for (auto capture_output_sample_rate_hz : sample_rates_to_test) { | |
331 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { | |
332 RunTogetherWithApm("LevelControlAndDefaultDesktopApm", 48000, 48000, | |
333 capture_input_sample_rate_hz, | |
334 capture_output_sample_rate_hz, num_channels, false, | |
335 true); | |
336 RunTogetherWithApm("LevelControlAndDefaultMobileApm", 48000, 48000, | |
337 capture_input_sample_rate_hz, | |
338 capture_output_sample_rate_hz, num_channels, true, | |
339 true); | |
340 } | |
341 } | |
342 } | |
343 } | |
344 | |
345 } // namespace webrtc | |
OLD | NEW |