Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Side by Side Diff: webrtc/modules/audio_processing/level_controller/level_controller_complexity_unittest.cc

Issue 2090583002: New module for the adaptive level controlling functionality in the audio processing module (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Corrected the initial behavior for the peak level estimate, and ensured a nonzero minimum peak leveā€¦ Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698