OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | |
hlundin-webrtc
2015/11/13 12:18:32
2015
peah-webrtc
2015/11/18 10:27:26
Done.
| |
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 "webrtc/modules/audio_processing/audio_processing_impl.h" | |
11 | |
12 #include <math.h> | |
13 | |
14 #include <algorithm> | |
15 #include <vector> | |
16 | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "webrtc/base/array_view.h" | |
19 #include "webrtc/base/criticalsection.h" | |
20 #include "webrtc/config.h" | |
21 #include "webrtc/modules/audio_processing/test/test_utils.h" | |
22 #include "webrtc/modules/include/module_common_types.h" | |
23 #include "webrtc/system_wrappers/include/clock.h" | |
24 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
25 #include "webrtc/system_wrappers/include/sleep.h" | |
26 #include "webrtc/system_wrappers/include/thread_wrapper.h" | |
27 #include "webrtc/test/random.h" | |
28 #include "webrtc/test/testsupport/perf_test.h" | |
29 | |
30 namespace webrtc { | |
31 | |
32 namespace { | |
33 | |
34 class CallSimulator; | |
35 | |
36 // Populates a float audio frame with random data. | |
hlundin-webrtc
2015/11/13 12:18:31
It seems to populate more than one frame. Make the
peah-webrtc
2015/11/18 10:27:26
It supports multiple channel frames, and I think i
| |
37 void PopulateAudioFrame(float** frame, | |
hlundin-webrtc
2015/11/13 12:18:31
frame is an output parameter, it should go last in
peah-webrtc
2015/11/18 10:27:27
Done.
| |
38 float amplitude, | |
39 size_t num_channels, | |
40 size_t samples_per_channel, | |
41 test::Random* rand_gen) { | |
42 for (size_t ch = 0; ch < num_channels; ch++) { | |
43 for (size_t k = 0; k < samples_per_channel; k++) { | |
44 // Store random 16 bit quantized float number between +-amplitude. | |
hlundin-webrtc
2015/11/13 12:18:32
Where does the 16-bit quantization happen? Is it i
peah-webrtc
2015/11/18 10:27:27
Sorry, that comment is completely wrong! Removed i
| |
45 frame[ch][k] = amplitude * (2 * rand_gen->Rand<float>() - 1); | |
46 } | |
47 } | |
48 } | |
49 | |
50 // Variant of echo canceller settings to use in the test. | |
51 enum class AecType { BasicWebRtcAecSettings, BasicWebRtcAecmSettings }; | |
52 | |
53 // Variables related to the audio data and formats. | |
54 struct AudioFrameData { | |
55 explicit AudioFrameData(int max_frame_size) { | |
hlundin-webrtc
2015/11/13 12:18:32
size_t
peah-webrtc
2015/11/18 10:27:26
Done.
| |
56 // Set up the two-dimensional arrays needed for the APM API calls. | |
57 input_framechannels.resize(2 * max_frame_size); | |
58 input_frame.resize(2); | |
59 input_frame[0] = &input_framechannels[0]; | |
60 input_frame[1] = &input_framechannels[max_frame_size]; | |
61 | |
62 output_frame_channels.resize(2 * max_frame_size); | |
63 output_frame.resize(2); | |
64 output_frame[0] = &output_frame_channels[0]; | |
65 output_frame[1] = &output_frame_channels[max_frame_size]; | |
66 } | |
67 | |
68 std::vector<float> output_frame_channels; | |
69 std::vector<float*> output_frame; | |
70 std::vector<float> input_framechannels; | |
71 std::vector<float*> input_frame; | |
72 StreamConfig input_stream_config; | |
73 StreamConfig output_stream_config; | |
74 }; | |
75 | |
76 // The configuration for the test. | |
77 struct SimulationConfig { | |
78 SimulationConfig(int sample_rate_hz, | |
79 AecType aec_type, | |
80 int min_number_of_calls, | |
81 bool use_realtime_simulation) | |
82 : sample_rate_hz(sample_rate_hz), | |
83 aec_type(aec_type), | |
84 min_number_of_calls(min_number_of_calls), | |
85 use_realtime_simulation(use_realtime_simulation) {} | |
86 int sample_rate_hz = 16000; | |
87 AecType aec_type = AecType::BasicWebRtcAecSettings; | |
88 int min_number_of_calls = 300; | |
89 bool use_realtime_simulation; | |
hlundin-webrtc
2015/11/13 12:18:32
All members but this one has default values.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
90 }; | |
91 | |
92 // Handler for the frame counters. | |
93 class FrameCounters { | |
94 public: | |
95 int IncreaseRenderCounter() { | |
96 rtc::CritScope cs(&crit_); | |
97 render_count++; | |
98 return render_count; | |
99 } | |
100 | |
101 int IncreaseCaptureCounter() { | |
102 rtc::CritScope cs(&crit_); | |
103 capture_count++; | |
104 return capture_count; | |
105 } | |
106 | |
107 int GetCaptureCounter() { | |
108 rtc::CritScope cs(&crit_); | |
109 return capture_count; | |
110 } | |
111 | |
112 int GetRenderCounter() { | |
113 rtc::CritScope cs(&crit_); | |
114 return render_count; | |
115 } | |
116 | |
117 int CaptureMinusRenderCounters() { | |
118 rtc::CritScope cs(&crit_); | |
119 return capture_count - render_count; | |
120 } | |
121 | |
122 int RenderMinusCaptureCounters() { | |
hlundin-webrtc
2015/11/13 12:18:32
Do you need both "minus" methods? And if you do, y
peah-webrtc
2015/11/18 10:27:25
It is mainly for convenience and to (tiny) increas
| |
123 rtc::CritScope cs(&crit_); | |
124 return render_count - capture_count; | |
125 } | |
126 | |
127 bool BothCountersExceedeThreshold(int threshold) { | |
128 rtc::CritScope cs(&crit_); | |
129 return (render_count > threshold && capture_count > threshold); | |
130 } | |
131 | |
132 private: | |
133 rtc::CriticalSection crit_; | |
134 int render_count GUARDED_BY(crit_) = 0; | |
hlundin-webrtc
2015/11/13 12:18:32
Trailing underscore on both counter variables.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
135 int capture_count GUARDED_BY(crit_) = 0; | |
136 }; | |
137 | |
138 // Checker for whether the capture side has been called. | |
139 class CaptureSideCalledChecker { | |
hlundin-webrtc
2015/11/13 12:18:32
Generalize the name to make it shorter. Nothing wi
peah-webrtc
2015/11/18 10:27:26
Good point! I called it LockedFlag since it is doe
| |
140 public: | |
141 bool CaptureSideCalled() { | |
hlundin-webrtc
2015/11/13 12:18:32
This is a simple "getter" function, albeit with a
peah-webrtc
2015/11/18 10:27:26
Done.
| |
142 rtc::CritScope cs(&crit_); | |
143 return capture_side_called_; | |
144 } | |
145 | |
146 void FlagCaptureSideCalled() { | |
hlundin-webrtc
2015/11/13 12:18:32
This is a "setter" with a lock. Name it such:
void
peah-webrtc
2015/11/18 10:27:26
Done.
| |
147 rtc::CritScope cs(&crit_); | |
148 capture_side_called_ = true; | |
149 } | |
150 | |
151 private: | |
152 rtc::CriticalSection crit_; | |
153 bool capture_side_called_ GUARDED_BY(crit_) = false; | |
154 }; | |
155 | |
156 // Parent class for the thread processors. | |
157 class TimedThreadApiProcessor { | |
158 public: | |
159 TimedThreadApiProcessor(int max_frame_size, | |
160 test::Random* rand_gen, | |
161 FrameCounters* shared_counters_state, | |
162 CaptureSideCalledChecker* capture_call_checker, | |
163 CallSimulator* test_framework, | |
164 SimulationConfig* simulation_config, | |
165 AudioProcessing* apm, | |
166 int min_number_of_calls, | |
167 float input_level); | |
168 virtual ~TimedThreadApiProcessor() {} | |
169 | |
170 bool ProcessClocked10msQuantum(); | |
171 std::vector<int64_t> get_api_call_durations() const { | |
172 return api_call_durations_; | |
173 } | |
174 int64_t GetDurationStandardDeviation() const; | |
175 int64_t GetDurationAverage() const; | |
176 | |
177 protected: | |
178 static const int kMaxCallDifference = 10; | |
179 | |
180 void PrepareFrame(); | |
181 void AddJitter(int max_jitter_microseconds, bool random_jitter); | |
182 virtual int Process() = 0; | |
183 virtual bool ReadyToProcess() = 0; | |
184 | |
185 test::Random* rand_gen_ = nullptr; | |
186 FrameCounters* frame_counters_ = nullptr; | |
187 CaptureSideCalledChecker* capture_call_checker_ = nullptr; | |
188 CallSimulator* test_ = nullptr; | |
189 SimulationConfig* simulation_config_ = nullptr; | |
190 AudioProcessing* apm_ = nullptr; | |
191 AudioFrameData frame_data_; | |
192 webrtc::Clock* clock_; | |
193 int num_durations_to_store_; | |
194 std::vector<int64_t> api_call_durations_; | |
195 const float input_level_; | |
196 }; | |
197 | |
198 // Class for handling the capture side processing. | |
199 class CaptureProcessor : public TimedThreadApiProcessor { | |
hlundin-webrtc
2015/11/13 12:18:31
Mark this class final.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
200 public: | |
201 CaptureProcessor(int max_frame_size, | |
202 test::Random* rand_gen, | |
203 FrameCounters* shared_counters_state, | |
204 CaptureSideCalledChecker* capture_call_checker, | |
205 CallSimulator* test_framework, | |
206 SimulationConfig* simulation_config, | |
207 AudioProcessing* apm, | |
208 int min_number_of_calls, | |
209 float input_level); | |
210 | |
211 private: | |
212 // Overrides from TimedThreadApiProcessor. | |
213 int Process() override; | |
214 bool ReadyToProcess() override; | |
215 | |
216 bool first_capture_side_call_ = true; | |
217 }; | |
218 | |
219 // Class for handling the render side processing. | |
220 class RenderProcessor : public TimedThreadApiProcessor { | |
hlundin-webrtc
2015/11/13 12:18:31
Mark this class final.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
221 public: | |
222 RenderProcessor(int max_frame_size, | |
223 test::Random* rand_gen, | |
224 FrameCounters* shared_counters_state, | |
225 CaptureSideCalledChecker* capture_call_checker, | |
226 CallSimulator* test_framework, | |
227 SimulationConfig* simulation_config, | |
228 AudioProcessing* apm, | |
229 int min_number_of_calls, | |
230 float input_level); | |
231 | |
232 private: | |
233 // Overrides from TimedThreadApiProcessor | |
234 int Process() override; | |
235 bool ReadyToProcess() override; | |
236 | |
237 bool first_render_side_call_ = true; | |
238 }; | |
239 | |
240 // Class for managing the test simulation. | |
241 class CallSimulator { | |
hlundin-webrtc
2015/11/13 12:18:32
I think this class should be made a gtest fixture
peah-webrtc
2015/11/18 10:27:26
Done.
| |
242 public: | |
243 explicit CallSimulator(SimulationConfig simulation_config); | |
244 EventTypeWrapper Run(int time_out_limit); | |
245 | |
246 // Tests whether all the required render and capture side calls have been | |
247 // done. | |
248 void CheckIfSimulationDone() { | |
249 if (frame_counters_.BothCountersExceedeThreshold( | |
250 simulation_config_.min_number_of_calls)) { | |
251 test_complete_->Set(); | |
252 } | |
253 } | |
254 | |
255 const CaptureProcessor* GetCapture() const { return &capture_thread_state_; } | |
256 const RenderProcessor* GetRender() const { return &render_thread_state_; } | |
257 void SetUp(); | |
258 void TearDown(); | |
259 | |
260 private: | |
261 static const int kMaxFrameSize = 480; | |
262 static const float kCaptureInputFloatLevel; | |
263 static const float kRenderInputFloatLevel; | |
264 | |
265 // Thread callback for the render thread. | |
266 static bool RenderProcessorThreadFunc(void* context) { | |
267 return reinterpret_cast<CallSimulator*>(context) | |
268 ->render_thread_state_.ProcessClocked10msQuantum(); | |
269 } | |
270 | |
271 // Thread callback for the capture thread. | |
272 static bool CaptureProcessorThreadFunc(void* context) { | |
273 return reinterpret_cast<CallSimulator*>(context) | |
274 ->capture_thread_state_.ProcessClocked10msQuantum(); | |
275 } | |
276 | |
277 // Start the threads used in the test. | |
278 void StartThreads() { | |
279 ASSERT_TRUE(render_thread_->Start()); | |
280 render_thread_->SetPriority(kRealtimePriority); | |
281 ASSERT_TRUE(capture_thread_->Start()); | |
282 capture_thread_->SetPriority(kRealtimePriority); | |
283 } | |
284 | |
285 // Event handler for the test. | |
286 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
287 | |
288 // Thread related variables. | |
289 rtc::scoped_ptr<ThreadWrapper> render_thread_; | |
290 rtc::scoped_ptr<ThreadWrapper> capture_thread_; | |
291 mutable test::Random rand_gen_; | |
hlundin-webrtc
2015/11/13 12:18:31
Why is this mutable?
peah-webrtc
2015/11/18 10:27:26
Done.
| |
292 | |
293 rtc::scoped_ptr<AudioProcessing> apm_; | |
294 SimulationConfig simulation_config_; | |
295 FrameCounters frame_counters_; | |
296 CaptureSideCalledChecker capture_call_checker_; | |
297 RenderProcessor render_thread_state_; | |
298 CaptureProcessor capture_thread_state_; | |
299 }; | |
300 | |
301 const float CallSimulator::kRenderInputFloatLevel = 0.5f; | |
302 const float CallSimulator::kCaptureInputFloatLevel = 0.03125f; | |
303 | |
304 CallSimulator::CallSimulator(SimulationConfig simulation_config) | |
305 : test_complete_(EventWrapper::Create()), | |
306 render_thread_(ThreadWrapper::CreateThread(RenderProcessorThreadFunc, | |
307 this, | |
308 "render")), | |
309 capture_thread_(ThreadWrapper::CreateThread(CaptureProcessorThreadFunc, | |
310 this, | |
311 "capture")), | |
312 rand_gen_(42U), | |
313 apm_(AudioProcessingImpl::Create()), | |
hlundin-webrtc
2015/11/13 12:18:31
Create() may return null in case of failure. You c
peah-webrtc
2015/11/18 10:27:26
Done.
| |
314 simulation_config_(simulation_config), | |
315 render_thread_state_(kMaxFrameSize, | |
316 &rand_gen_, | |
317 &frame_counters_, | |
318 &capture_call_checker_, | |
319 this, | |
320 &simulation_config_, | |
321 apm_.get(), | |
322 simulation_config_.min_number_of_calls, | |
323 kRenderInputFloatLevel), | |
324 capture_thread_state_(kMaxFrameSize, | |
325 &rand_gen_, | |
326 &frame_counters_, | |
327 &capture_call_checker_, | |
328 this, | |
329 &simulation_config_, | |
330 apm_.get(), | |
331 simulation_config_.min_number_of_calls, | |
332 kCaptureInputFloatLevel) {} | |
333 | |
334 // Run the call simulation with a timeout. | |
335 EventTypeWrapper CallSimulator::Run(int time_out_limit) { | |
336 SetUp(); | |
337 StartThreads(); | |
hlundin-webrtc
2015/11/13 12:18:31
You should make sure that none of the ASSERT_TRUEs
peah-webrtc
2015/11/18 10:27:26
Done.
| |
338 EventTypeWrapper result = test_complete_->Wait(time_out_limit); | |
339 TearDown(); | |
340 return result; | |
341 } | |
342 | |
343 // Simulator and APM setup. | |
344 void CallSimulator::SetUp() { | |
345 ASSERT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true)); | |
346 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); | |
347 ASSERT_EQ(apm_->kNoError, | |
348 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); | |
349 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); | |
350 ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true)); | |
351 ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); | |
352 | |
353 Config config; | |
hlundin-webrtc
2015/11/13 12:18:31
Move the declaration down to within the else-claus
peah-webrtc
2015/11/18 10:27:26
Done.
| |
354 if (simulation_config_.aec_type == AecType::BasicWebRtcAecmSettings) { | |
355 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true)); | |
356 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false)); | |
357 } else { | |
358 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false)); | |
359 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); | |
360 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_metrics(true)); | |
361 ASSERT_EQ(apm_->kNoError, | |
362 apm_->echo_cancellation()->enable_delay_logging(true)); | |
363 | |
364 config.Set<ExtendedFilter>(new ExtendedFilter(true)); | |
365 config.Set<DelayAgnostic>(new DelayAgnostic(true)); | |
366 apm_->SetExtraOptions(config); | |
367 } | |
368 } | |
369 | |
370 void CallSimulator::TearDown() { | |
371 render_thread_->Stop(); | |
372 capture_thread_->Stop(); | |
373 } | |
374 | |
375 TimedThreadApiProcessor::TimedThreadApiProcessor( | |
hlundin-webrtc
2015/11/13 12:18:32
I think you can define all the member methods with
peah-webrtc
2015/11/18 10:27:26
Did this on all methods apart from the Process() m
| |
376 int max_frame_size, | |
377 test::Random* rand_gen, | |
378 FrameCounters* shared_counters_state, | |
379 CaptureSideCalledChecker* capture_call_checker, | |
380 CallSimulator* test_framework, | |
381 SimulationConfig* simulation_config, | |
382 AudioProcessing* apm, | |
383 int num_durations_to_store, | |
384 float input_level) | |
385 : rand_gen_(rand_gen), | |
386 frame_counters_(shared_counters_state), | |
387 capture_call_checker_(capture_call_checker), | |
388 test_(test_framework), | |
389 simulation_config_(simulation_config), | |
390 apm_(apm), | |
391 frame_data_(max_frame_size), | |
hlundin-webrtc
2015/11/13 12:18:31
No need to pass max_frame_size as a parameter; sim
peah-webrtc
2015/11/18 10:27:27
Done.
| |
392 clock_(webrtc::Clock::GetRealTimeClock()), | |
393 num_durations_to_store_(num_durations_to_store), | |
394 api_call_durations_(num_durations_to_store_), | |
395 input_level_(input_level) {} | |
396 | |
397 // Implements the callback functionality for the threads. | |
398 bool TimedThreadApiProcessor::ProcessClocked10msQuantum() { | |
399 PrepareFrame(); | |
400 | |
401 while (!ReadyToProcess()) { | |
402 AddJitter(2, true); | |
403 } | |
404 | |
405 const int64_t start_time = clock_->TimeInMicroseconds(); | |
406 Process(); | |
407 const int64_t end_time = clock_->TimeInMicroseconds(); | |
408 const int duration = static_cast<int>(end_time - start_time); | |
hlundin-webrtc
2015/11/13 12:18:31
duration_us, to convey the unit.
hlundin-webrtc
2015/11/13 12:18:32
use rtc::checked_cast<int> from base/safe_conversi
peah-webrtc
2015/11/18 10:27:26
Done.
peah-webrtc
2015/11/18 10:27:26
Done.
| |
409 const int time_left_of_10_ms_quantum = 10000 - duration; | |
410 | |
411 if (simulation_config_->use_realtime_simulation && | |
412 time_left_of_10_ms_quantum > 0) { | |
413 AddJitter(time_left_of_10_ms_quantum, false); | |
414 } | |
415 | |
416 test_->CheckIfSimulationDone(); | |
417 | |
418 return true; | |
419 } | |
420 | |
421 int64_t TimedThreadApiProcessor::GetDurationStandardDeviation() const { | |
422 double variance = 0; | |
423 const int64_t average_duration = GetDurationAverage(); | |
424 for (int64_t duration : api_call_durations_) { | |
425 int64_t tmp = duration - average_duration; | |
426 variance += static_cast<double>(tmp * tmp); | |
427 } | |
428 return static_cast<int64_t>(sqrt(variance / api_call_durations_.size())); | |
hlundin-webrtc
2015/11/13 12:18:32
rtc::checked_cast
peah-webrtc
2015/11/18 10:27:27
Done.
| |
429 } | |
430 | |
431 int64_t TimedThreadApiProcessor::GetDurationAverage() const { | |
432 int64_t average_duration = 0; | |
433 for (int64_t duration : api_call_durations_) { | |
434 average_duration += duration; | |
435 } | |
436 return average_duration / api_call_durations_.size(); | |
437 } | |
438 | |
439 void TimedThreadApiProcessor::PrepareFrame() { | |
440 // Prepare the audio input data and metadata. | |
441 frame_data_.input_stream_config.set_sample_rate_hz( | |
442 simulation_config_->sample_rate_hz); | |
443 frame_data_.input_stream_config.set_num_channels(1); | |
444 frame_data_.input_stream_config.set_has_keyboard(false); | |
445 PopulateAudioFrame(&frame_data_.input_frame[0], input_level_, 1, | |
446 (simulation_config_->sample_rate_hz * | |
447 AudioProcessing::kChunkSizeMs / 1000), | |
448 rand_gen_); | |
449 | |
450 // Prepare the float audio output data and metadata. | |
451 frame_data_.output_stream_config.set_sample_rate_hz( | |
452 simulation_config_->sample_rate_hz); | |
453 frame_data_.output_stream_config.set_num_channels(1); | |
454 frame_data_.output_stream_config.set_has_keyboard(false); | |
455 } | |
456 | |
457 void TimedThreadApiProcessor::AddJitter(int max_jitter_microseconds, | |
458 bool random_jitter) { | |
459 int min_method_duration; | |
460 if (random_jitter) { | |
461 min_method_duration = rand_gen_->Rand(0, max_jitter_microseconds); | |
462 } else { | |
463 min_method_duration = max_jitter_microseconds; | |
464 } | |
465 | |
466 const int64_t start_time = clock_->TimeInMicroseconds(); | |
hlundin-webrtc
2015/11/13 12:18:32
Please, comment on why you cannot just sleep.
peah-webrtc
2015/11/18 10:27:26
Very good point. As I never use this in the test a
| |
467 int sum = 0; | |
468 while ((clock_->TimeInMicroseconds() - start_time) < min_method_duration) { | |
469 for (int k = 0; k < 100; ++k) | |
470 for (int j = 1; j < 100; ++j) { | |
471 sum += k % j; | |
472 sum = sum % 79; | |
473 } | |
474 if (sum > 100) { | |
475 printf("Will not be print out, just present in order to ensure"); | |
476 printf("that sum is evaluated by the compiler\n"); | |
477 } | |
478 } | |
479 } | |
480 | |
481 CaptureProcessor::CaptureProcessor( | |
hlundin-webrtc
2015/11/13 12:18:32
There is a non-negligible overhead associated with
peah-webrtc
2015/11/18 10:27:25
Good point!!!
Will implement it like that.
Done.
| |
482 int max_frame_size, | |
483 test::Random* rand_gen, | |
484 FrameCounters* shared_counters_state, | |
485 CaptureSideCalledChecker* capture_call_checker, | |
486 CallSimulator* test_framework, | |
487 SimulationConfig* simulation_config, | |
488 AudioProcessing* apm, | |
489 int num_durations_to_store, | |
490 float input_level) | |
491 : TimedThreadApiProcessor(max_frame_size, | |
492 rand_gen, | |
493 shared_counters_state, | |
494 capture_call_checker, | |
495 test_framework, | |
496 simulation_config, | |
497 apm, | |
498 num_durations_to_store, | |
499 input_level) {} | |
500 | |
501 int CaptureProcessor::Process() { | |
502 // Set the stream delay | |
503 apm_->set_stream_delay_ms(30); | |
504 | |
505 // Call and time the specified capture side API processing method. | |
506 const int64_t start_time = clock_->TimeInMicroseconds(); | |
507 const int result = apm_->ProcessStream( | |
508 &frame_data_.input_frame[0], frame_data_.input_stream_config, | |
509 frame_data_.output_stream_config, &frame_data_.output_frame[0]); | |
510 const int64_t end_time = clock_->TimeInMicroseconds(); | |
511 | |
512 const int new_capture_counter = frame_counters_->IncreaseCaptureCounter(); | |
513 | |
514 if (new_capture_counter <= num_durations_to_store_) { | |
515 api_call_durations_[new_capture_counter - 1] = end_time - start_time; | |
hlundin-webrtc
2015/11/13 12:18:32
Why not just api_call_durations_.push_back(...)? Y
peah-webrtc
2015/11/18 10:27:26
Good and very valid point!
Done.
| |
516 } | |
517 | |
518 if (first_capture_side_call_) { | |
519 // Flag that the capture side has been called at least once | |
520 // (needed to ensure that a capture call has been done | |
521 // before the first render call is performed (implicitly | |
522 // required by the APM API). | |
523 capture_call_checker_->FlagCaptureSideCalled(); | |
524 first_capture_side_call_ = false; | |
525 } | |
526 return result; | |
527 } | |
528 | |
529 bool CaptureProcessor::ReadyToProcess() { | |
530 return (frame_counters_->CaptureMinusRenderCounters() <= kMaxCallDifference); | |
531 } | |
532 | |
533 RenderProcessor::RenderProcessor(int max_frame_size, | |
534 test::Random* rand_gen, | |
535 FrameCounters* shared_counters_state, | |
536 CaptureSideCalledChecker* capture_call_checker, | |
537 CallSimulator* test_framework, | |
538 SimulationConfig* simulation_config, | |
539 AudioProcessing* apm, | |
540 int num_durations_to_store, | |
541 float input_level) | |
542 : TimedThreadApiProcessor(max_frame_size, | |
543 rand_gen, | |
544 shared_counters_state, | |
545 capture_call_checker, | |
546 test_framework, | |
547 simulation_config, | |
548 apm, | |
549 num_durations_to_store, | |
550 input_level) {} | |
551 | |
552 int RenderProcessor::Process() { | |
553 // Call and time the specified render side API processing method. | |
554 const int64_t start_time = clock_->TimeInMicroseconds(); | |
555 const int result = apm_->ProcessReverseStream( | |
556 &frame_data_.input_frame[0], frame_data_.input_stream_config, | |
557 frame_data_.output_stream_config, &frame_data_.output_frame[0]); | |
558 const int64_t end_time = clock_->TimeInMicroseconds(); | |
559 | |
560 const int new_render_counter = frame_counters_->IncreaseRenderCounter(); | |
561 | |
562 if (new_render_counter <= num_durations_to_store_) { | |
563 api_call_durations_[new_render_counter - 1] = end_time - start_time; | |
564 } | |
565 | |
566 return result; | |
567 } | |
568 | |
569 bool RenderProcessor::ReadyToProcess() { | |
570 // Do not process until at least one capture call has been done. | |
571 // (implicitly required by the APM API). | |
572 if (first_render_side_call_ && !capture_call_checker_->CaptureSideCalled()) { | |
573 return false; | |
574 } | |
575 | |
576 // Ensure that the number of render and capture calls do not differ too much. | |
577 if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) { | |
578 return false; | |
579 } | |
580 | |
581 first_render_side_call_ = false; | |
582 return true; | |
583 } | |
584 | |
585 // Runs the simulation and reports the results. | |
586 void RunSimulation(SimulationConfig simulation_config, | |
587 int timeout, | |
588 bool print_durations) { | |
589 // Lambda function for printing out the simulation statistics. | |
590 auto print_simulation_statistics = []( | |
591 const TimedThreadApiProcessor* processor, std::string processor_name, | |
592 bool print_durations) { | |
593 const std::string modifier = "_api_call_duration"; | |
594 | |
595 // Lambda function for creating a test printout string. | |
596 auto create_mean_and_variance_string = [](int64_t average, | |
597 int64_t standard_dev) { | |
598 std::string s = std::to_string(average); | |
599 s += ","; | |
600 s += std::to_string(standard_dev); | |
601 return s; | |
602 }; | |
603 | |
604 webrtc::test::PrintResult(processor_name, modifier, "avg,stdev", | |
605 create_mean_and_variance_string( | |
606 processor->GetDurationAverage(), | |
607 processor->GetDurationStandardDeviation()), | |
608 "ms", false); | |
609 | |
610 if (print_durations) { | |
611 std::vector<int64_t> durations = processor->get_api_call_durations(); | |
612 std::string value_string = ""; | |
613 for (int64_t duration : durations) { | |
614 value_string += std::to_string(duration) + ","; | |
615 } | |
616 webrtc::test::PrintResultList(processor_name, modifier, "durations", | |
617 value_string, "ms", false); | |
618 } | |
619 }; | |
620 | |
621 CallSimulator simulator(simulation_config); | |
622 | |
623 // Run simulation and verify that it did not time out. | |
624 ASSERT_EQ(EventTypeWrapper::kEventSignaled, simulator.Run(timeout)); | |
hlundin-webrtc
2015/11/13 12:18:32
Maybe EXPECT_EQ instead. It might still be interes
peah-webrtc
2015/11/18 10:27:27
Done.
| |
625 | |
626 print_simulation_statistics(simulator.GetRender(), "render", print_durations); | |
hlundin-webrtc
2015/11/13 12:18:32
To me it looks like the print_simulation_statistic
peah-webrtc
2015/11/18 10:27:26
Done.
| |
627 print_simulation_statistics(simulator.GetCapture(), "capture", | |
628 print_durations); | |
629 } | |
630 | |
631 const int kMaxFramesToProcess = 300; | |
632 const int32_t kTestTimeout = 3 * 10 * kMaxFramesToProcess; | |
633 const bool kUseTimedSimulation = false; | |
hlundin-webrtc
2015/11/13 12:18:32
I don't think it makes much sense to declare this
peah-webrtc
2015/11/18 10:27:26
Good points and I fully agree. This has been partl
| |
634 const bool kPrintAllDurations = false; | |
635 } // anonymous namespace | |
636 | |
637 TEST(AudioProcessingLockPerformanceTest, Aec8kHz) { | |
638 RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecSettings, | |
639 kMaxFramesToProcess, kUseTimedSimulation), | |
640 kTestTimeout, kPrintAllDurations); | |
641 } | |
642 | |
643 TEST(AudioProcessingLockPerformanceTest, Aec16kHz) { | |
644 RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecSettings, | |
645 kMaxFramesToProcess, kUseTimedSimulation), | |
646 kTestTimeout, kPrintAllDurations); | |
647 } | |
648 | |
649 TEST(AudioProcessingLockPerformanceTest, Aec32kHz) { | |
650 RunSimulation(SimulationConfig(32000, AecType::BasicWebRtcAecSettings, | |
651 kMaxFramesToProcess, kUseTimedSimulation), | |
652 kTestTimeout, kPrintAllDurations); | |
653 } | |
654 | |
655 TEST(AudioProcessingLockPerformanceTest, Aec48kHz) { | |
656 RunSimulation(SimulationConfig(48000, AecType::BasicWebRtcAecSettings, | |
657 kMaxFramesToProcess, kUseTimedSimulation), | |
658 kTestTimeout, kPrintAllDurations); | |
659 } | |
660 | |
661 TEST(AudioProcessingLockPerformanceTest, Aecm8kHz) { | |
662 RunSimulation(SimulationConfig(8000, AecType::BasicWebRtcAecmSettings, | |
663 kMaxFramesToProcess, true), | |
664 kTestTimeout, kPrintAllDurations); | |
665 } | |
666 | |
667 TEST(AudioProcessingLockPerformanceTest, Aecm16kHz) { | |
668 RunSimulation(SimulationConfig(16000, AecType::BasicWebRtcAecmSettings, | |
669 kMaxFramesToProcess, true), | |
670 kTestTimeout, kPrintAllDurations); | |
671 } | |
672 } // namespace webrtc | |
OLD | NEW |