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 #include <vector> | |
hlundin-webrtc
2016/06/27 11:21:15
Nit: I tend to like a blank line after the copyrig
peah-webrtc
2016/06/27 22:51:49
Done.
| |
11 | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 #include "webrtc/base/array_view.h" | |
14 #include "webrtc/base/random.h" | |
15 #include "webrtc/modules/audio_processing/audio_buffer.h" | |
16 #include "webrtc/modules/audio_processing/include/audio_processing.h" | |
17 #include "webrtc/modules/audio_processing/level_controller/level_controller.h" | |
18 #include "webrtc/modules/audio_processing/test/audio_buffer_tools.h" | |
19 #include "webrtc/modules/audio_processing/test/bitexactness_tools.h" | |
20 #include "webrtc/system_wrappers/include/clock.h" | |
21 #include "webrtc/test/testsupport/perf_test.h" | |
22 | |
23 namespace webrtc { | |
24 namespace { | |
25 | |
26 const size_t kNumFramesToProcess = 100; | |
27 | |
28 struct SimulatorBuffers { | |
29 SimulatorBuffers(int render_input_sample_rate_hz, | |
30 int capture_input_sample_rate_hz, | |
31 int render_output_sample_rate_hz, | |
32 int capture_output_sample_rate_hz, | |
33 size_t num_render_input_channels, | |
34 size_t num_capture_input_channels, | |
35 size_t num_render_output_channels, | |
36 size_t num_capture_output_channels) { | |
37 Random rand_gen(42); | |
38 CreateConfigAndBuffer(render_input_sample_rate_hz, | |
39 num_render_input_channels, &rand_gen, | |
40 &render_input_buffer, &render_input_config, | |
41 &render_input, &render_input_samples); | |
42 | |
43 CreateConfigAndBuffer(render_output_sample_rate_hz, | |
44 num_render_output_channels, &rand_gen, | |
45 &render_output_buffer, &render_output_config, | |
46 &render_output, &render_output_samples); | |
47 | |
48 CreateConfigAndBuffer(capture_input_sample_rate_hz, | |
49 num_capture_input_channels, &rand_gen, | |
50 &capture_input_buffer, &capture_input_config, | |
51 &capture_input, &capture_input_samples); | |
52 | |
53 CreateConfigAndBuffer(capture_output_sample_rate_hz, | |
54 num_capture_output_channels, &rand_gen, | |
55 &capture_output_buffer, &capture_output_config, | |
56 &capture_output, &capture_output_samples); | |
57 | |
58 UpdateInputBuffers(); | |
59 } | |
60 | |
61 void CreateConfigAndBuffer(int sample_rate_hz, | |
62 size_t num_channels, | |
63 Random* rand_gen, | |
64 std::unique_ptr<AudioBuffer>* buffer, | |
65 StreamConfig* config, | |
66 std::vector<float*>* buffer_data, | |
67 std::vector<float>* buffer_data_samples) { | |
68 int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100); | |
69 *config = StreamConfig(sample_rate_hz, num_channels, false); | |
70 buffer->reset(new AudioBuffer(config->num_frames(), config->num_channels(), | |
71 config->num_frames(), config->num_channels(), | |
72 config->num_frames())); | |
73 | |
74 buffer_data_samples->resize(samples_per_channel * num_channels); | |
75 for (auto& v : *buffer_data_samples) { | |
76 v = rand_gen->Rand<float>(); | |
77 } | |
78 | |
79 buffer_data->resize(num_channels); | |
80 for (size_t ch = 0; ch < num_channels; ++ch) { | |
81 (*buffer_data)[ch] = &(*buffer_data_samples)[ch * samples_per_channel]; | |
82 } | |
83 } | |
84 | |
85 void UpdateInputBuffers() { | |
86 test::CopyVectorToAudioBuffer(capture_input_config, capture_input_samples, | |
87 capture_input_buffer.get()); | |
88 test::CopyVectorToAudioBuffer(render_input_config, render_input_samples, | |
89 render_input_buffer.get()); | |
90 } | |
91 | |
92 std::unique_ptr<AudioBuffer> render_input_buffer; | |
93 std::unique_ptr<AudioBuffer> capture_input_buffer; | |
94 std::unique_ptr<AudioBuffer> render_output_buffer; | |
95 std::unique_ptr<AudioBuffer> capture_output_buffer; | |
96 StreamConfig render_input_config; | |
97 StreamConfig capture_input_config; | |
98 StreamConfig render_output_config; | |
99 StreamConfig capture_output_config; | |
100 std::vector<float*> render_input; | |
101 std::vector<float> render_input_samples; | |
102 std::vector<float*> capture_input; | |
103 std::vector<float> capture_input_samples; | |
104 std::vector<float*> render_output; | |
105 std::vector<float> render_output_samples; | |
106 std::vector<float*> capture_output; | |
107 std::vector<float> capture_output_samples; | |
108 }; | |
109 | |
110 class SubmodulePerformanceTimer { | |
111 public: | |
112 explicit SubmodulePerformanceTimer(size_t num_values_to_store) | |
hlundin-webrtc
2016/06/27 11:21:15
Why have an explicit limitation on the size? Vecto
peah-webrtc
2016/06/27 22:51:48
Good point! But since some of the timers are neste
| |
113 : clock_(webrtc::Clock::GetRealTimeClock()) { | |
114 timestamps_.resize(num_values_to_store); | |
hlundin-webrtc
2016/06/27 11:21:15
You can do this in the initializer list as timesta
peah-webrtc
2016/06/27 22:51:48
I removed the fixed size limitation so this is no
| |
115 } | |
116 | |
117 void ResetTimer() { start_timestamp_ = clock_->TimeInMicroseconds(); } | |
hlundin-webrtc
2016/06/27 11:21:15
Make start_timestamp_ an rtc::Optional. Initialize
peah-webrtc
2016/06/27 22:51:48
Great suggestion!
Done.
| |
118 void AddTimeStamp() { | |
119 RTC_CHECK_LE(num_timestamps_stored_, timestamps_.size()); | |
120 timestamps_[num_timestamps_stored_] = | |
hlundin-webrtc
2016/06/27 11:21:15
You don't need num_timestamps_stored_. Use vector:
peah-webrtc
2016/06/27 22:51:49
Done.
| |
121 clock_->TimeInMicroseconds() - start_timestamp_; | |
122 ++num_timestamps_stored_; | |
123 } | |
124 | |
125 double GetDurationAverage() const { | |
126 RTC_DCHECK_EQ(num_timestamps_stored_, timestamps_.size()); | |
127 int64_t durations_sum = 0; | |
hlundin-webrtc
2016/06/27 11:21:16
One-liner method:
return timestamps_.empty() ? 0.0
peah-webrtc
2016/06/27 22:51:49
Great suggestion! I chose the latter variant.
Don
| |
128 for (auto timestamp : timestamps_) { | |
129 durations_sum += timestamp; | |
130 } | |
131 | |
132 RTC_DCHECK_LT(0u, timestamps_.size()); | |
133 return static_cast<double>(durations_sum) / timestamps_.size(); | |
134 } | |
135 | |
136 double GetDurationStandardDeviationGetVarianceTime() const { | |
hlundin-webrtc
2016/06/27 11:21:16
This is an awkward method name. What does it mean?
peah-webrtc
2016/06/27 22:51:48
Agree! No idea! Changed the name.
Done.
| |
137 int32_t average_duration = GetDurationAverage(); | |
hlundin-webrtc
2016/06/27 11:21:15
Why int32_t? GetDurationAverage() returns a double
peah-webrtc
2016/06/27 22:51:49
I changed it to double.
Done.
| |
138 int64_t variance = 0; | |
hlundin-webrtc
2016/06/27 11:21:16
You can make this a one-liner too, with a lambda,
peah-webrtc
2016/06/27 22:51:48
Not sure either. But it looks great so I added it!
| |
139 for (auto timestamp : timestamps_) { | |
140 variance += timestamp - average_duration; | |
141 } | |
142 | |
143 RTC_DCHECK_LT(0u, timestamps_.size()); | |
144 return sqrt(static_cast<double>(variance) / timestamps_.size()); | |
145 } | |
146 | |
147 private: | |
148 webrtc::Clock* clock_; | |
149 int64_t start_timestamp_ = 0; | |
150 size_t num_timestamps_stored_ = 0; | |
151 std::vector<int64_t> timestamps_; | |
hlundin-webrtc
2016/06/27 11:21:15
timestamps_us_
peah-webrtc
2016/06/27 22:51:49
Done.
| |
152 }; | |
153 | |
154 std::string FormPerformanceMeasureString( | |
155 const SubmodulePerformanceTimer& timer) { | |
156 double average = timer.GetDurationAverage(); | |
hlundin-webrtc
2016/06/27 11:21:15
You don't need these local variables. Just plug th
peah-webrtc
2016/06/27 22:51:49
Done.
| |
157 double standard_dev = timer.GetDurationStandardDeviationGetVarianceTime(); | |
158 std::string s = std::to_string(average); | |
159 s += ", "; | |
160 s += std::to_string(standard_dev); | |
161 return s; | |
162 } | |
163 | |
164 void RunStandatoleSubmodule(int sample_rate_hz, size_t num_channels) { | |
hlundin-webrtc
2016/06/27 11:21:16
Standatole?
peah-webrtc
2016/06/27 22:51:49
Absolutely!
Done.
| |
165 SimulatorBuffers buffers(sample_rate_hz, sample_rate_hz, sample_rate_hz, | |
166 sample_rate_hz, num_channels, num_channels, | |
167 num_channels, num_channels); | |
168 SubmodulePerformanceTimer timer(kNumFramesToProcess); | |
169 | |
170 LevelController level_controller; | |
171 level_controller.Initialize(sample_rate_hz, num_channels); | |
172 | |
173 for (size_t frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) { | |
174 buffers.UpdateInputBuffers(); | |
175 | |
176 timer.ResetTimer(); | |
hlundin-webrtc
2016/06/27 11:21:15
Based on the use case, I suggest you rename the ti
peah-webrtc
2016/06/27 22:51:48
Makes sense!
Done.
| |
177 level_controller.Process(buffers.capture_input_buffer.get()); | |
178 timer.AddTimeStamp(); | |
179 } | |
180 webrtc::test::PrintResultMeanAndError( | |
181 "level_controller_call_durations", | |
182 "_" + std::to_string(sample_rate_hz) + "Hz_" + | |
183 std::to_string(num_channels) + "_channels", | |
184 "StandaloneLevelControl", FormPerformanceMeasureString(timer), "us", | |
185 false); | |
186 } | |
187 | |
188 void RunTogetherWithApm(std::string test_description, | |
189 int render_input_sample_rate_hz, | |
190 int render_output_sample_rate_hz, | |
191 int capture_input_sample_rate_hz, | |
192 int capture_output_sample_rate_hz, | |
193 size_t num_channels, | |
194 bool use_mobile_aec, | |
195 bool include_default_apm_processing) { | |
196 SimulatorBuffers buffers( | |
197 render_input_sample_rate_hz, capture_input_sample_rate_hz, | |
198 render_output_sample_rate_hz, capture_output_sample_rate_hz, num_channels, | |
199 num_channels, num_channels, num_channels); | |
200 SubmodulePerformanceTimer render_timer(kNumFramesToProcess); | |
201 SubmodulePerformanceTimer capture_timer(kNumFramesToProcess); | |
202 SubmodulePerformanceTimer total_timer(kNumFramesToProcess); | |
203 | |
204 Config config; | |
205 if (include_default_apm_processing) { | |
206 config.Set<DelayAgnostic>(new DelayAgnostic(true)); | |
207 config.Set<ExtendedFilter>(new ExtendedFilter(true)); | |
208 } | |
209 config.Set<LevelControl>(new LevelControl(true)); | |
210 | |
211 std::unique_ptr<AudioProcessing> apm; | |
212 apm.reset(AudioProcessing::Create(config)); | |
hlundin-webrtc
2016/06/27 11:21:16
Can Create fail? If so, ASSERT_TRUE that apm is ok
peah-webrtc
2016/06/27 22:51:49
Good point! It can fail, so I'll add that.
Done.
| |
213 | |
214 apm->gain_control()->Enable(include_default_apm_processing); | |
hlundin-webrtc
2016/06/27 11:21:15
All the Enable methods seem to have a return value
peah-webrtc
2016/06/27 22:51:48
Done.
| |
215 if (use_mobile_aec) { | |
216 apm->echo_cancellation()->Enable(false); | |
217 apm->echo_control_mobile()->Enable(include_default_apm_processing); | |
218 } else { | |
219 apm->echo_cancellation()->Enable(include_default_apm_processing); | |
220 apm->echo_control_mobile()->Enable(false); | |
221 } | |
222 apm->high_pass_filter()->Enable(include_default_apm_processing); | |
223 apm->noise_suppression()->Enable(include_default_apm_processing); | |
224 apm->voice_detection()->Enable(include_default_apm_processing); | |
225 apm->level_estimator()->Enable(include_default_apm_processing); | |
226 | |
227 StreamConfig render_input_config(render_input_sample_rate_hz, num_channels, | |
228 false); | |
229 StreamConfig render_output_config(render_output_sample_rate_hz, num_channels, | |
230 false); | |
231 StreamConfig capture_input_config(capture_input_sample_rate_hz, num_channels, | |
232 false); | |
233 StreamConfig capture_output_config(capture_output_sample_rate_hz, | |
234 num_channels, false); | |
235 | |
236 for (size_t frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) { | |
237 buffers.UpdateInputBuffers(); | |
238 | |
239 total_timer.ResetTimer(); | |
240 render_timer.ResetTimer(); | |
241 int error = apm->ProcessReverseStream( | |
hlundin-webrtc
2016/06/27 11:21:15
Don't store the return value.
ASSERT_EQ(AudioProce
peah-webrtc
2016/06/27 22:51:48
Done.
| |
242 &buffers.render_input[0], render_input_config, render_output_config, | |
243 &buffers.render_output[0]); | |
244 | |
245 ASSERT_EQ(AudioProcessing::kNoError, error); | |
246 | |
247 render_timer.AddTimeStamp(); | |
248 | |
249 capture_timer.ResetTimer(); | |
250 apm->set_stream_delay_ms(0); | |
hlundin-webrtc
2016/06/27 11:21:15
Can it fail? ASSERT_EQ?
peah-webrtc
2016/06/27 22:51:48
Done.
| |
251 error = | |
252 apm->ProcessStream(&buffers.capture_input[0], capture_input_config, | |
253 capture_output_config, &buffers.capture_output[0]); | |
254 | |
255 capture_timer.AddTimeStamp(); | |
256 total_timer.AddTimeStamp(); | |
257 ASSERT_EQ(AudioProcessing::kNoError, error); | |
258 } | |
259 | |
260 webrtc::test::PrintResultMeanAndError( | |
261 "level_controller_call_durations", | |
262 "_" + std::to_string(render_input_sample_rate_hz) + "_" + | |
263 std::to_string(render_output_sample_rate_hz) + "_" + | |
264 std::to_string(capture_input_sample_rate_hz) + "_" + | |
265 std::to_string(capture_output_sample_rate_hz) + "Hz_" + | |
266 std::to_string(num_channels) + "_channels" + "_render", | |
267 test_description, FormPerformanceMeasureString(render_timer), "us", | |
268 false); | |
269 webrtc::test::PrintResultMeanAndError( | |
270 "level_controller_call_durations", | |
271 "_" + std::to_string(render_input_sample_rate_hz) + "_" + | |
272 std::to_string(render_output_sample_rate_hz) + "_" + | |
273 std::to_string(capture_input_sample_rate_hz) + "_" + | |
274 std::to_string(capture_output_sample_rate_hz) + "Hz_" + | |
275 std::to_string(num_channels) + "_channels" + "_capture", | |
276 test_description, FormPerformanceMeasureString(capture_timer), "us", | |
277 false); | |
278 webrtc::test::PrintResultMeanAndError( | |
279 "level_controller_call_durations", | |
280 "_" + std::to_string(render_input_sample_rate_hz) + "_" + | |
281 std::to_string(render_output_sample_rate_hz) + "_" + | |
282 std::to_string(capture_input_sample_rate_hz) + "_" + | |
283 std::to_string(capture_output_sample_rate_hz) + "Hz_" + | |
284 std::to_string(num_channels) + "_channels" + "_total", | |
285 test_description, FormPerformanceMeasureString(total_timer), "us", false); | |
286 } | |
287 | |
288 } // namespace | |
289 | |
290 TEST(LevelControllerPerformanceTest, StandaloneProcessing) { | |
291 int sample_rates_to_test[] = { | |
292 AudioProcessing::kSampleRate8kHz, AudioProcessing::kSampleRate16kHz, | |
293 AudioProcessing::kSampleRate32kHz, AudioProcessing::kSampleRate48kHz}; | |
hlundin-webrtc
2016/06/27 11:21:15
No 44100 Hz here?
peah-webrtc
2016/06/27 22:51:49
No. The submodule only supports native rates (8, 1
hlundin-webrtc
2016/06/28 11:29:00
Acknowledged.
peah-webrtc
2016/06/28 22:19:37
Acknowledged.
| |
294 for (auto sample_rate : sample_rates_to_test) { | |
295 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { | |
296 RunStandatoleSubmodule(sample_rate, num_channels); | |
297 } | |
298 } | |
299 } | |
300 | |
301 TEST(LevelControllerPerformanceTest, ProcessingViaApm) { | |
302 int sample_rates_to_test[] = {AudioProcessing::kSampleRate8kHz, | |
303 AudioProcessing::kSampleRate16kHz, | |
304 AudioProcessing::kSampleRate32kHz, | |
305 AudioProcessing::kSampleRate48kHz, 44100}; | |
306 for (auto capture_input_sample_rate_hz : sample_rates_to_test) { | |
307 for (auto capture_output_sample_rate_hz : sample_rates_to_test) { | |
308 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { | |
309 RunTogetherWithApm("SimpleLevelControlViaApm", 48000, 48000, | |
310 capture_input_sample_rate_hz, | |
311 capture_output_sample_rate_hz, num_channels, false, | |
312 false); | |
313 } | |
314 } | |
315 } | |
316 } | |
317 | |
318 TEST(LevelControllerPerformanceTest, InteractionWithDefaultApm) { | |
319 int sample_rates_to_test[] = {AudioProcessing::kSampleRate8kHz, | |
320 AudioProcessing::kSampleRate16kHz, | |
321 AudioProcessing::kSampleRate32kHz, | |
322 AudioProcessing::kSampleRate48kHz, 44100}; | |
323 for (auto capture_input_sample_rate_hz : sample_rates_to_test) { | |
324 for (auto capture_output_sample_rate_hz : sample_rates_to_test) { | |
325 for (size_t num_channels = 1; num_channels <= 2; ++num_channels) { | |
326 RunTogetherWithApm("LevelControlAndDefaultDesktopApm", 48000, 48000, | |
327 capture_input_sample_rate_hz, | |
328 capture_output_sample_rate_hz, num_channels, false, | |
329 true); | |
330 RunTogetherWithApm("LevelControlAndDefaultMobileApm", 48000, 48000, | |
331 capture_input_sample_rate_hz, | |
332 capture_output_sample_rate_hz, num_channels, true, | |
333 true); | |
334 } | |
335 } | |
336 } | |
337 } | |
338 | |
339 } // namespace webrtc | |
OLD | NEW |