OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2015 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 "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/base/platform_thread.h" | |
21 #include "webrtc/base/safe_conversions.h" | |
22 #include "webrtc/config.h" | |
23 #include "webrtc/modules/audio_processing/test/test_utils.h" | |
24 #include "webrtc/modules/include/module_common_types.h" | |
25 #include "webrtc/system_wrappers/include/clock.h" | |
26 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
27 #include "webrtc/system_wrappers/include/sleep.h" | |
28 #include "webrtc/test/random.h" | |
29 #include "webrtc/test/testsupport/perf_test.h" | |
30 | |
31 namespace webrtc { | |
32 | |
33 namespace { | |
34 | |
35 static const bool kPrintAllDurations = false; | |
36 | |
37 class CallSimulator; | |
38 | |
39 // Type of the render thread APM API call to use in the test. | |
40 enum class ProcessorType { kRender, kCapture }; | |
41 | |
42 // Variant of APM processing settings to use in the test. | |
43 enum class SettingsType { | |
44 kDefaultApmDesktop, | |
45 kDefaultApmMobile, | |
46 kDefaultApmDesktopAndBeamformer, | |
47 kDefaultApmDesktopAndIntelligibilityEnhancer, | |
48 kAllSubmodulesTurnedOff, | |
49 kDefaultDesktopApmWithoutDelayAgnostic, | |
50 kDefaultDesktopApmWithoutExtendedFilter | |
51 }; | |
52 | |
53 // Variables related to the audio data and formats. | |
54 struct AudioFrameData { | |
55 explicit AudioFrameData(size_t max_frame_size) { | |
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, SettingsType simulation_settings) | |
79 : sample_rate_hz(sample_rate_hz), | |
80 simulation_settings(simulation_settings) {} | |
81 | |
82 static std::vector<SimulationConfig> GenerateSimulationConfigs() { | |
83 std::vector<SimulationConfig> simulation_configs; | |
84 #ifndef WEBRTC_ANDROID | |
85 const SettingsType desktop_settings[] = { | |
86 SettingsType::kDefaultApmDesktop, SettingsType::kAllSubmodulesTurnedOff, | |
87 SettingsType::kDefaultDesktopApmWithoutDelayAgnostic, | |
88 SettingsType::kDefaultDesktopApmWithoutExtendedFilter}; | |
89 | |
90 const int desktop_sample_rates[] = {8000, 16000, 32000, 48000}; | |
91 | |
92 for (auto sample_rate : desktop_sample_rates) { | |
93 for (auto settings : desktop_settings) { | |
94 simulation_configs.push_back(SimulationConfig(sample_rate, settings)); | |
95 } | |
96 } | |
97 | |
98 const SettingsType intelligibility_enhancer_settings[] = { | |
99 SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer}; | |
100 | |
101 const int intelligibility_enhancer_sample_rates[] = {8000, 16000, 32000, | |
102 48000}; | |
103 | |
104 for (auto sample_rate : intelligibility_enhancer_sample_rates) { | |
105 for (auto settings : intelligibility_enhancer_settings) { | |
106 simulation_configs.push_back(SimulationConfig(sample_rate, settings)); | |
107 } | |
108 } | |
109 | |
110 const SettingsType beamformer_settings[] = { | |
111 SettingsType::kDefaultApmDesktopAndBeamformer}; | |
112 | |
113 const int beamformer_sample_rates[] = {8000, 16000, 32000, 48000}; | |
114 | |
115 for (auto sample_rate : beamformer_sample_rates) { | |
116 for (auto settings : beamformer_settings) { | |
117 simulation_configs.push_back(SimulationConfig(sample_rate, settings)); | |
118 } | |
119 } | |
120 #endif | |
121 | |
122 const SettingsType mobile_settings[] = {SettingsType::kDefaultApmMobile}; | |
123 | |
124 const int mobile_sample_rates[] = {8000, 16000}; | |
125 | |
126 for (auto sample_rate : mobile_sample_rates) { | |
127 for (auto settings : mobile_settings) { | |
128 simulation_configs.push_back(SimulationConfig(sample_rate, settings)); | |
129 } | |
130 } | |
131 | |
132 return simulation_configs; | |
133 } | |
134 | |
135 std::string SettingsDescription() const { | |
136 std::string description; | |
137 switch (simulation_settings) { | |
138 case SettingsType::kDefaultApmMobile: | |
139 description = "DefaultApmMobile"; | |
140 break; | |
141 case SettingsType::kDefaultApmDesktop: | |
142 description = "DefaultApmDesktop"; | |
143 break; | |
144 case SettingsType::kDefaultApmDesktopAndBeamformer: | |
145 description = "DefaultApmDesktopAndBeamformer"; | |
146 break; | |
147 case SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer: | |
148 description = "DefaultApmDesktopAndIntelligibilityEnhancer"; | |
149 break; | |
150 case SettingsType::kAllSubmodulesTurnedOff: | |
151 description = "AllSubmodulesOff"; | |
152 break; | |
153 case SettingsType::kDefaultDesktopApmWithoutDelayAgnostic: | |
154 description = "DefaultDesktopApmWithoutDelayAgnostic"; | |
155 break; | |
156 case SettingsType::kDefaultDesktopApmWithoutExtendedFilter: | |
157 description = "DefaultDesktopApmWithoutExtendedFilter"; | |
158 break; | |
159 } | |
160 return description; | |
161 } | |
162 | |
163 int sample_rate_hz = 16000; | |
164 SettingsType simulation_settings = SettingsType::kDefaultApmDesktop; | |
165 }; | |
166 | |
167 // Handler for the frame counters. | |
168 class FrameCounters { | |
169 public: | |
170 void IncreaseRenderCounter() { | |
171 rtc::CritScope cs(&crit_); | |
172 render_count_++; | |
173 } | |
174 | |
175 void IncreaseCaptureCounter() { | |
176 rtc::CritScope cs(&crit_); | |
177 capture_count_++; | |
178 } | |
179 | |
180 int GetCaptureCounter() const { | |
181 rtc::CritScope cs(&crit_); | |
182 return capture_count_; | |
183 } | |
184 | |
185 int GetRenderCounter() const { | |
186 rtc::CritScope cs(&crit_); | |
187 return render_count_; | |
188 } | |
189 | |
190 int CaptureMinusRenderCounters() const { | |
191 rtc::CritScope cs(&crit_); | |
192 return capture_count_ - render_count_; | |
193 } | |
194 | |
195 int RenderMinusCaptureCounters() const { | |
196 return -CaptureMinusRenderCounters(); | |
197 } | |
198 | |
199 bool BothCountersExceedeThreshold(int threshold) const { | |
200 rtc::CritScope cs(&crit_); | |
201 return (render_count_ > threshold && capture_count_ > threshold); | |
202 } | |
203 | |
204 private: | |
205 mutable rtc::CriticalSection crit_; | |
206 int render_count_ GUARDED_BY(crit_) = 0; | |
207 int capture_count_ GUARDED_BY(crit_) = 0; | |
208 }; | |
209 | |
210 // Class that protects a flag using a lock. | |
211 class LockedFlag { | |
212 public: | |
213 bool get_flag() const { | |
214 rtc::CritScope cs(&crit_); | |
215 return flag_; | |
216 } | |
217 | |
218 void set_flag() { | |
219 rtc::CritScope cs(&crit_); | |
220 flag_ = true; | |
221 } | |
222 | |
223 private: | |
224 mutable rtc::CriticalSection crit_; | |
225 bool flag_ GUARDED_BY(crit_) = false; | |
226 }; | |
227 | |
228 // Parent class for the thread processors. | |
229 class TimedThreadApiProcessor { | |
230 public: | |
231 TimedThreadApiProcessor(ProcessorType processor_type, | |
232 test::Random* rand_gen, | |
233 FrameCounters* shared_counters_state, | |
234 LockedFlag* capture_call_checker, | |
235 CallSimulator* test_framework, | |
236 const SimulationConfig* simulation_config, | |
237 AudioProcessing* apm, | |
238 int num_durations_to_store, | |
239 float input_level, | |
240 int num_channels) | |
241 : rand_gen_(rand_gen), | |
242 frame_counters_(shared_counters_state), | |
243 capture_call_checker_(capture_call_checker), | |
244 test_(test_framework), | |
245 simulation_config_(simulation_config), | |
246 apm_(apm), | |
247 frame_data_(kMaxFrameSize), | |
248 clock_(webrtc::Clock::GetRealTimeClock()), | |
249 num_durations_to_store_(num_durations_to_store), | |
250 input_level_(input_level), | |
251 processor_type_(processor_type), | |
252 num_channels_(num_channels) { | |
253 api_call_durations_.reserve(num_durations_to_store_); | |
254 } | |
255 | |
256 // Implements the callback functionality for the threads. | |
257 bool Process(); | |
258 | |
259 // Method for printing out the simulation statistics. | |
260 void print_processor_statistics(std::string processor_name) const { | |
261 const std::string modifier = "_api_call_duration"; | |
262 | |
263 // Lambda function for creating a test printout string. | |
264 auto create_mean_and_std_string = [](int64_t average, | |
265 int64_t standard_dev) { | |
266 std::string s = std::to_string(average); | |
267 s += ", "; | |
268 s += std::to_string(standard_dev); | |
269 return s; | |
270 }; | |
271 | |
272 const std::string sample_rate_name = | |
273 "_" + std::to_string(simulation_config_->sample_rate_hz) + "Hz"; | |
274 | |
275 webrtc::test::PrintResultMeanAndError( | |
276 "apm_timing", sample_rate_name, processor_name, | |
277 create_mean_and_std_string(GetDurationAverage(), | |
278 GetDurationStandardDeviation()), | |
279 "us", false); | |
280 | |
281 if (kPrintAllDurations) { | |
282 std::string value_string = ""; | |
283 for (int64_t duration : api_call_durations_) { | |
284 value_string += std::to_string(duration) + ","; | |
285 } | |
286 webrtc::test::PrintResultList("apm_call_durations", sample_rate_name, | |
287 processor_name, value_string, "us", false); | |
288 } | |
289 } | |
290 | |
291 void AddDuration(int64_t duration) { | |
292 if (api_call_durations_.size() < num_durations_to_store_) { | |
293 api_call_durations_.push_back(duration); | |
294 } | |
295 } | |
296 | |
297 private: | |
298 static const int kMaxCallDifference = 10; | |
299 static const int kMaxFrameSize = 480; | |
300 static const int kNumInitializationFrames = 5; | |
301 | |
302 int64_t GetDurationStandardDeviation() const { | |
303 double variance = 0; | |
304 const int64_t average_duration = GetDurationAverage(); | |
305 for (size_t k = kNumInitializationFrames; k < api_call_durations_.size(); | |
306 k++) { | |
307 int64_t tmp = api_call_durations_[k] - average_duration; | |
308 variance += static_cast<double>(tmp * tmp); | |
309 } | |
310 const int denominator = rtc::checked_cast<int>(api_call_durations_.size()) - | |
311 kNumInitializationFrames; | |
312 return (denominator > 0 | |
313 ? rtc::checked_cast<int64_t>(sqrt(variance / denominator)) | |
314 : -1); | |
315 } | |
316 | |
317 int64_t GetDurationAverage() const { | |
318 int64_t average_duration = 0; | |
319 for (size_t k = kNumInitializationFrames; k < api_call_durations_.size(); | |
320 k++) { | |
321 average_duration += api_call_durations_[k]; | |
322 } | |
323 const int denominator = rtc::checked_cast<int>(api_call_durations_.size()) - | |
324 kNumInitializationFrames; | |
325 return (denominator > 0 ? average_duration / denominator : -1); | |
326 } | |
327 | |
328 int ProcessCapture() { | |
329 // Set the stream delay. | |
330 apm_->set_stream_delay_ms(30); | |
331 | |
332 // Call and time the specified capture side API processing method. | |
333 const int64_t start_time = clock_->TimeInMicroseconds(); | |
334 const int result = apm_->ProcessStream( | |
335 &frame_data_.input_frame[0], frame_data_.input_stream_config, | |
336 frame_data_.output_stream_config, &frame_data_.output_frame[0]); | |
337 const int64_t end_time = clock_->TimeInMicroseconds(); | |
338 | |
339 frame_counters_->IncreaseCaptureCounter(); | |
340 | |
341 AddDuration(end_time - start_time); | |
342 | |
343 if (first_process_call_) { | |
344 // Flag that the capture side has been called at least once | |
345 // (needed to ensure that a capture call has been done | |
346 // before the first render call is performed (implicitly | |
347 // required by the APM API). | |
348 capture_call_checker_->set_flag(); | |
349 first_process_call_ = false; | |
350 } | |
351 return result; | |
352 } | |
353 | |
354 bool ReadyToProcessCapture() { | |
355 return (frame_counters_->CaptureMinusRenderCounters() <= | |
356 kMaxCallDifference); | |
357 } | |
358 | |
359 int ProcessRender() { | |
360 // Call and time the specified render side API processing method. | |
361 const int64_t start_time = clock_->TimeInMicroseconds(); | |
362 const int result = apm_->ProcessReverseStream( | |
363 &frame_data_.input_frame[0], frame_data_.input_stream_config, | |
364 frame_data_.output_stream_config, &frame_data_.output_frame[0]); | |
365 const int64_t end_time = clock_->TimeInMicroseconds(); | |
366 frame_counters_->IncreaseRenderCounter(); | |
367 | |
368 AddDuration(end_time - start_time); | |
369 | |
370 return result; | |
371 } | |
372 | |
373 bool ReadyToProcessRender() { | |
374 // Do not process until at least one capture call has been done. | |
375 // (implicitly required by the APM API). | |
376 if (first_process_call_ && !capture_call_checker_->get_flag()) { | |
377 return false; | |
378 } | |
379 | |
380 // Ensure that the number of render and capture calls do not differ too | |
381 // much. | |
382 if (frame_counters_->RenderMinusCaptureCounters() > kMaxCallDifference) { | |
383 return false; | |
384 } | |
385 | |
386 first_process_call_ = false; | |
387 return true; | |
388 } | |
389 | |
390 void PrepareFrame() { | |
391 // Lambda function for populating a float multichannel audio frame | |
392 // with random data. | |
393 auto populate_audio_frame = [](float amplitude, size_t num_channels, | |
394 size_t samples_per_channel, | |
395 test::Random* rand_gen, float** frame) { | |
396 for (size_t ch = 0; ch < num_channels; ch++) { | |
397 for (size_t k = 0; k < samples_per_channel; k++) { | |
398 // Store random float number with a value between +-amplitude. | |
399 frame[ch][k] = amplitude * (2 * rand_gen->Rand<float>() - 1); | |
400 } | |
401 } | |
402 }; | |
403 | |
404 // Prepare the audio input data and metadata. | |
405 frame_data_.input_stream_config.set_sample_rate_hz( | |
406 simulation_config_->sample_rate_hz); | |
407 frame_data_.input_stream_config.set_num_channels(num_channels_); | |
408 frame_data_.input_stream_config.set_has_keyboard(false); | |
409 populate_audio_frame(input_level_, num_channels_, | |
410 (simulation_config_->sample_rate_hz * | |
411 AudioProcessing::kChunkSizeMs / 1000), | |
412 rand_gen_, &frame_data_.input_frame[0]); | |
413 | |
414 // Prepare the float audio output data and metadata. | |
415 frame_data_.output_stream_config.set_sample_rate_hz( | |
416 simulation_config_->sample_rate_hz); | |
417 frame_data_.output_stream_config.set_num_channels(1); | |
418 frame_data_.output_stream_config.set_has_keyboard(false); | |
419 } | |
420 | |
421 bool ReadyToProcess() { | |
422 switch (processor_type_) { | |
423 case ProcessorType::kRender: | |
424 return ReadyToProcessRender(); | |
425 break; | |
426 case ProcessorType::kCapture: | |
427 return ReadyToProcessCapture(); | |
428 break; | |
429 } | |
430 | |
431 // Should not be reached, but the return statement is needed for the code to | |
432 // build successfully on Android. | |
433 RTC_NOTREACHED(); | |
434 return false; | |
435 } | |
436 | |
437 test::Random* rand_gen_ = nullptr; | |
438 FrameCounters* frame_counters_ = nullptr; | |
439 LockedFlag* capture_call_checker_ = nullptr; | |
440 CallSimulator* test_ = nullptr; | |
441 const SimulationConfig* const simulation_config_ = nullptr; | |
442 AudioProcessing* apm_ = nullptr; | |
443 AudioFrameData frame_data_; | |
444 webrtc::Clock* clock_; | |
445 const size_t num_durations_to_store_; | |
446 std::vector<int64_t> api_call_durations_; | |
447 const float input_level_; | |
448 bool first_process_call_ = true; | |
449 const ProcessorType processor_type_; | |
450 const int num_channels_ = 1; | |
451 }; | |
452 | |
453 // Class for managing the test simulation. | |
454 class CallSimulator : public ::testing::TestWithParam<SimulationConfig> { | |
455 public: | |
456 CallSimulator() | |
457 : test_complete_(EventWrapper::Create()), | |
458 render_thread_(PlatformThread::CreateThread(RenderProcessorThreadFunc, | |
459 this, | |
460 "render")), | |
461 capture_thread_(PlatformThread::CreateThread(CaptureProcessorThreadFunc, | |
462 this, | |
463 "capture")), | |
464 rand_gen_(42U), | |
465 simulation_config_(static_cast<SimulationConfig>(GetParam())) {} | |
466 | |
467 // Run the call simulation with a timeout. | |
468 EventTypeWrapper Run() { | |
469 StartThreads(); | |
470 | |
471 EventTypeWrapper result = test_complete_->Wait(kTestTimeout); | |
472 | |
473 render_thread_state_->print_processor_statistics( | |
474 simulation_config_.SettingsDescription() + "_render"); | |
475 capture_thread_state_->print_processor_statistics( | |
476 simulation_config_.SettingsDescription() + "_capture"); | |
477 | |
478 return result; | |
479 } | |
480 | |
481 // Tests whether all the required render and capture side calls have been | |
482 // done. | |
483 void MaybeEndTest() { | |
484 if (frame_counters_.BothCountersExceedeThreshold(kMinNumFramesToProcess)) { | |
485 test_complete_->Set(); | |
486 } | |
487 } | |
488 | |
489 private: | |
490 static const float kCaptureInputFloatLevel; | |
491 static const float kRenderInputFloatLevel; | |
492 static const int kMinNumFramesToProcess = 150; | |
493 static const int32_t kTestTimeout = 3 * 10 * kMinNumFramesToProcess; | |
494 | |
495 // ::testing::TestWithParam<> implementation. | |
496 void TearDown() override { | |
497 render_thread_->Stop(); | |
498 capture_thread_->Stop(); | |
499 } | |
500 | |
501 // Simulator and APM setup. | |
502 void SetUp() override { | |
503 // Lambda function for setting the default APM runtime settings for desktop. | |
504 auto set_default_desktop_apm_runtime_settings = [](AudioProcessing* apm) { | |
505 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true)); | |
506 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); | |
507 ASSERT_EQ(apm->kNoError, | |
508 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital)); | |
509 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); | |
510 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); | |
511 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); | |
512 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(false)); | |
513 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); | |
514 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->enable_metrics(true)); | |
515 ASSERT_EQ(apm->kNoError, | |
516 apm->echo_cancellation()->enable_delay_logging(true)); | |
517 }; | |
518 | |
519 // Lambda function for setting the default APM runtime settings for mobile. | |
520 auto set_default_mobile_apm_runtime_settings = [](AudioProcessing* apm) { | |
521 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true)); | |
522 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); | |
523 ASSERT_EQ(apm->kNoError, | |
524 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital)); | |
525 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); | |
526 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); | |
527 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); | |
528 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true)); | |
529 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(false)); | |
530 }; | |
531 | |
532 // Lambda function for turning off all of the APM runtime settings | |
533 // submodules. | |
534 auto turn_off_default_apm_runtime_settings = [](AudioProcessing* apm) { | |
535 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false)); | |
536 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(false)); | |
537 ASSERT_EQ(apm->kNoError, | |
538 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital)); | |
539 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(false)); | |
540 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(false)); | |
541 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(false)); | |
542 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(false)); | |
543 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(false)); | |
544 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->enable_metrics(false)); | |
545 ASSERT_EQ(apm->kNoError, | |
546 apm->echo_cancellation()->enable_delay_logging(false)); | |
547 }; | |
548 | |
549 // Lambda function for adding default desktop APM settings to a config. | |
550 auto add_default_desktop_config = [](Config* config) { | |
551 config->Set<ExtendedFilter>(new ExtendedFilter(true)); | |
552 config->Set<DelayAgnostic>(new DelayAgnostic(true)); | |
553 }; | |
554 | |
555 // Lambda function for adding beamformer settings to a config. | |
556 auto add_beamformer_config = [](Config* config) { | |
557 const size_t num_mics = 2; | |
558 const std::vector<Point> array_geometry = | |
559 ParseArrayGeometry("0 0 0 0.05 0 0", num_mics); | |
560 RTC_CHECK_EQ(array_geometry.size(), num_mics); | |
561 | |
562 config->Set<Beamforming>( | |
563 new Beamforming(true, array_geometry, | |
564 SphericalPointf(DegreesToRadians(90), 0.f, 1.f))); | |
565 }; | |
566 | |
567 int num_capture_channels = 1; | |
568 switch (simulation_config_.simulation_settings) { | |
569 case SettingsType::kDefaultApmMobile: { | |
570 apm_.reset(AudioProcessingImpl::Create()); | |
571 ASSERT_TRUE(!!apm_); | |
572 set_default_mobile_apm_runtime_settings(apm_.get()); | |
573 break; | |
574 } | |
575 case SettingsType::kDefaultApmDesktop: { | |
576 Config config; | |
577 add_default_desktop_config(&config); | |
578 apm_.reset(AudioProcessingImpl::Create(config)); | |
579 ASSERT_TRUE(!!apm_); | |
580 set_default_desktop_apm_runtime_settings(apm_.get()); | |
581 apm_->SetExtraOptions(config); | |
582 break; | |
583 } | |
584 case SettingsType::kDefaultApmDesktopAndBeamformer: { | |
585 Config config; | |
586 add_beamformer_config(&config); | |
587 add_default_desktop_config(&config); | |
588 apm_.reset(AudioProcessingImpl::Create(config)); | |
589 ASSERT_TRUE(!!apm_); | |
590 set_default_desktop_apm_runtime_settings(apm_.get()); | |
591 apm_->SetExtraOptions(config); | |
592 num_capture_channels = 2; | |
593 break; | |
594 } | |
595 case SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer: { | |
596 Config config; | |
597 config.Set<Intelligibility>(new Intelligibility(true)); | |
598 add_default_desktop_config(&config); | |
599 apm_.reset(AudioProcessingImpl::Create(config)); | |
600 ASSERT_TRUE(!!apm_); | |
601 set_default_desktop_apm_runtime_settings(apm_.get()); | |
602 apm_->SetExtraOptions(config); | |
603 break; | |
604 } | |
605 case SettingsType::kAllSubmodulesTurnedOff: { | |
606 apm_.reset(AudioProcessingImpl::Create()); | |
607 ASSERT_TRUE(!!apm_); | |
608 turn_off_default_apm_runtime_settings(apm_.get()); | |
609 break; | |
610 } | |
611 case SettingsType::kDefaultDesktopApmWithoutDelayAgnostic: { | |
612 Config config; | |
613 config.Set<ExtendedFilter>(new ExtendedFilter(true)); | |
614 config.Set<DelayAgnostic>(new DelayAgnostic(false)); | |
615 apm_.reset(AudioProcessingImpl::Create(config)); | |
616 ASSERT_TRUE(!!apm_); | |
617 set_default_desktop_apm_runtime_settings(apm_.get()); | |
618 apm_->SetExtraOptions(config); | |
619 break; | |
620 } | |
621 case SettingsType::kDefaultDesktopApmWithoutExtendedFilter: { | |
622 Config config; | |
623 config.Set<ExtendedFilter>(new ExtendedFilter(false)); | |
624 config.Set<DelayAgnostic>(new DelayAgnostic(true)); | |
625 apm_.reset(AudioProcessingImpl::Create(config)); | |
626 ASSERT_TRUE(!!apm_); | |
627 set_default_desktop_apm_runtime_settings(apm_.get()); | |
628 apm_->SetExtraOptions(config); | |
629 break; | |
630 } | |
631 } | |
632 | |
633 render_thread_state_.reset(new TimedThreadApiProcessor( | |
634 ProcessorType::kRender, &rand_gen_, &frame_counters_, | |
635 &capture_call_checker_, this, &simulation_config_, apm_.get(), | |
636 kMinNumFramesToProcess, kRenderInputFloatLevel, 1)); | |
637 capture_thread_state_.reset(new TimedThreadApiProcessor( | |
638 ProcessorType::kCapture, &rand_gen_, &frame_counters_, | |
639 &capture_call_checker_, this, &simulation_config_, apm_.get(), | |
640 kMinNumFramesToProcess, kCaptureInputFloatLevel, num_capture_channels)); | |
641 } | |
642 | |
643 // Thread callback for the render thread. | |
644 static bool RenderProcessorThreadFunc(void* context) { | |
645 return reinterpret_cast<CallSimulator*>(context) | |
646 ->render_thread_state_->Process(); | |
647 } | |
648 | |
649 // Thread callback for the capture thread. | |
650 static bool CaptureProcessorThreadFunc(void* context) { | |
651 return reinterpret_cast<CallSimulator*>(context) | |
652 ->capture_thread_state_->Process(); | |
653 } | |
654 | |
655 // Start the threads used in the test. | |
656 void StartThreads() { | |
657 ASSERT_NO_FATAL_FAILURE(render_thread_->Start()); | |
658 render_thread_->SetPriority(kRealtimePriority); | |
659 ASSERT_NO_FATAL_FAILURE(capture_thread_->Start()); | |
660 capture_thread_->SetPriority(kRealtimePriority); | |
661 } | |
662 | |
663 // Event handler for the test. | |
664 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
665 | |
666 // Thread related variables. | |
667 rtc::scoped_ptr<PlatformThread> render_thread_; | |
668 rtc::scoped_ptr<PlatformThread> capture_thread_; | |
669 test::Random rand_gen_; | |
670 | |
671 rtc::scoped_ptr<AudioProcessing> apm_; | |
672 const SimulationConfig simulation_config_; | |
673 FrameCounters frame_counters_; | |
674 LockedFlag capture_call_checker_; | |
675 rtc::scoped_ptr<TimedThreadApiProcessor> render_thread_state_; | |
676 rtc::scoped_ptr<TimedThreadApiProcessor> capture_thread_state_; | |
677 }; | |
678 | |
679 // Implements the callback functionality for the threads. | |
680 bool TimedThreadApiProcessor::Process() { | |
681 PrepareFrame(); | |
682 | |
683 // Wait in a spinlock manner until it is ok to start processing. | |
684 // Note that SleepMs is not applicable since it only allows sleeping | |
685 // on a millisecond basis which is too long. | |
686 while (!ReadyToProcess()) { | |
687 } | |
688 | |
689 int result = AudioProcessing::kNoError; | |
690 switch (processor_type_) { | |
691 case ProcessorType::kRender: | |
692 result = ProcessRender(); | |
693 break; | |
694 case ProcessorType::kCapture: | |
695 result = ProcessCapture(); | |
696 break; | |
697 } | |
698 | |
699 EXPECT_EQ(result, AudioProcessing::kNoError); | |
700 | |
701 test_->MaybeEndTest(); | |
702 | |
703 return true; | |
704 } | |
705 | |
706 const float CallSimulator::kRenderInputFloatLevel = 0.5f; | |
707 const float CallSimulator::kCaptureInputFloatLevel = 0.03125f; | |
708 } // anonymous namespace | |
709 | |
710 TEST_P(CallSimulator, ApiCallDurationTest) { | |
711 // Run test and verify that it did not time out. | |
712 EXPECT_EQ(kEventSignaled, Run()); | |
713 } | |
714 | |
715 INSTANTIATE_TEST_CASE_P( | |
716 AudioProcessingPerformanceTest, | |
717 CallSimulator, | |
718 ::testing::ValuesIn(SimulationConfig::GenerateSimulationConfigs())); | |
719 | |
720 } // namespace webrtc | |
OLD | NEW |