OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | |
kwiberg-webrtc
2015/10/08 13:25:22
Use the present year without rounding down to the
peah-webrtc
2015/10/13 06:58:39
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 | |
11 #include "webrtc/modules/audio_processing/audio_processing_impl.h" | |
12 | |
13 #include <algorithm> | |
14 #include <vector> | |
15 | |
16 #include "testing/gmock/include/gmock/gmock.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "webrtc/config.h" | |
19 #include "webrtc/base/criticalsection.h" | |
ivoc
2015/10/09 15:47:15
These should be in alphabetical order, I think.
peah-webrtc
2015/10/13 06:58:40
Done.
| |
20 #include "webrtc/modules/audio_processing/test/test_utils.h" | |
21 #include "webrtc/modules/interface/module_common_types.h" | |
22 #include "webrtc/system_wrappers/interface/event_wrapper.h" | |
23 #include "webrtc/system_wrappers/interface/sleep.h" | |
24 #include "webrtc/system_wrappers/interface/thread_wrapper.h" | |
25 | |
26 namespace webrtc { | |
27 | |
28 namespace { | |
29 | |
30 // Holds the type of the render thread APM API call to use in the test. | |
31 enum class RenderApiFunction { | |
32 ProcessReverseStream1, | |
33 ProcessReverseStream2, | |
34 AnalyzeReverseStream1, | |
35 AnalyzeReverseStream2 | |
36 }; | |
37 // Holds the type of the capture thread APM API call to use in the test. | |
38 enum class CaptureApiFunction { | |
39 ProcessStream1, | |
40 ProcessStream2, | |
41 ProcessStream3 | |
42 }; | |
43 // Holds the runtime parameter setting scheme to use in the test. | |
44 enum class RuntimeParameterSettingScheme { Scheme1, Scheme2, Scheme3, Scheme4 }; | |
ivoc
2015/10/09 15:47:15
I think these enums are a bit cryptic. Is it possi
peah-webrtc
2015/10/13 06:58:39
Done.
peah-webrtc
2015/10/13 06:58:39
Good point! Should be better now!
| |
45 enum class AecType { Aec, NoAec, AecExtFilter, AecDelayAgnostic, Aecm }; | |
46 | |
47 // Holds the configuration for the test to use. | |
kwiberg-webrtc
2015/10/08 13:25:21
You can probably drop the "Holds the" in all these
peah-webrtc
2015/10/13 06:58:40
Done.
| |
48 struct TestConfig { | |
49 RenderApiFunction render_api_function; | |
50 CaptureApiFunction capture_api_function; | |
51 RuntimeParameterSettingScheme runtime_parameter_setting_scheme; | |
52 int initial_sample_rate; | |
53 AecType aec_type; | |
54 }; | |
55 | |
56 // Class for implementing the tests of the locks in the audio processing module. | |
57 class AudioProcessingImpLockTest : public ::testing::TestWithParam<TestConfig> { | |
58 public: | |
59 AudioProcessingImpLockTest() | |
60 : render_thread_( | |
61 ThreadWrapper::CreateThread(CbRenderThread, this, "render")), | |
62 capture_thread_( | |
63 ThreadWrapper::CreateThread(CbCaptureThread, this, "capture")), | |
64 stats_thread_( | |
65 ThreadWrapper::CreateThread(CbStatsThread, this, "stats")), | |
66 render_count_(0), | |
67 capture_count_(0), | |
68 first_render_side_call_(true), | |
69 capture_side_called_(false), | |
70 test_complete_(EventWrapper::Create()), | |
71 render_seed(42), | |
72 capture_seed(37), | |
73 stats_seed(75), | |
74 capture_input_sample_rate_hz_(16000), | |
75 capture_output_sample_rate_hz_(16000), | |
76 render_input_sample_rate_hz_(16000), | |
77 render_output_sample_rate_hz_(16000) { | |
78 // Create the dynamic two-dimensional arrays needed for the APM API calls. | |
79 capture_input_frame_ = new float*[2]; | |
80 capture_input_frame_[0] = new float[480]; | |
81 capture_input_frame_[1] = new float[480]; | |
82 capture_output_frame_ = new float*[2]; | |
83 capture_output_frame_[0] = new float[480]; | |
84 capture_output_frame_[1] = new float[480]; | |
85 render_input_frame_ = new float*[2]; | |
86 render_input_frame_[0] = new float[480]; | |
87 render_input_frame_[1] = new float[480]; | |
88 render_output_frame_ = new float*[2]; | |
89 render_output_frame_[0] = new float[480]; | |
90 render_output_frame_[1] = new float[480]; | |
91 } | |
92 | |
93 virtual ~AudioProcessingImpLockTest() { | |
94 // Delete the dynamic two-dimensional arrays needed for the APM API calls. | |
95 delete[] capture_input_frame_[0]; | |
96 delete[] capture_input_frame_[1]; | |
97 delete[] capture_input_frame_; | |
98 | |
99 delete[] capture_output_frame_[0]; | |
100 delete[] capture_output_frame_[1]; | |
101 delete[] capture_output_frame_; | |
102 | |
103 delete[] render_input_frame_[0]; | |
104 delete[] render_input_frame_[1]; | |
105 delete[] render_input_frame_; | |
106 | |
107 delete[] render_output_frame_[0]; | |
108 delete[] render_output_frame_[1]; | |
109 delete[] render_output_frame_; | |
kwiberg-webrtc
2015/10/08 13:25:22
Use scoped_ptrs to hold these. Or even better: sin
ivoc
2015/10/09 15:47:15
vectors are another option.
peah-webrtc
2015/10/13 06:58:39
Done.
peah-webrtc
2015/10/13 06:58:39
Good point! Now I changed to a scheme using vector
peah-webrtc
2015/10/13 06:58:40
Done.
| |
110 } | |
111 | |
112 // Run the test with a timeout. | |
113 EventTypeWrapper RunTest() { | |
114 StartThreads(); | |
115 return test_complete_->Wait(kTestTimeOutLimit); | |
116 } | |
117 | |
118 virtual void SetUp() { | |
119 apm_.reset(AudioProcessingImpl::Create()); | |
120 test_config_ = static_cast<TestConfig>(GetParam()); | |
121 | |
122 Config config; | |
123 bool use_config = false; | |
kwiberg-webrtc
2015/10/08 13:25:22
Move line 123 to 144, to reduce the scope of use_c
peah-webrtc
2015/10/13 06:58:40
Done.
| |
124 | |
125 EXPECT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true)); | |
126 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); | |
127 | |
128 EXPECT_EQ(apm_->kNoError, | |
129 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); | |
130 EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); | |
131 EXPECT_EQ(apm_->kNoError, | |
132 apm_->gain_control()->set_mode(GainControl::kFixedDigital)); | |
133 | |
134 EXPECT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true)); | |
135 EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); | |
136 | |
137 if (test_config_.aec_type == AecType::NoAec) { | |
138 EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false)); | |
139 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false)); | |
140 } else { | |
141 if (test_config_.aec_type == AecType::Aecm) { | |
142 EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true)); | |
143 } else { | |
144 EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); | |
145 EXPECT_EQ(apm_->kNoError, | |
146 apm_->echo_cancellation()->enable_metrics(true)); | |
147 EXPECT_EQ(apm_->kNoError, | |
148 apm_->echo_cancellation()->enable_delay_logging(true)); | |
149 | |
150 if (test_config_.aec_type == AecType::AecExtFilter) { | |
151 config.Set<ExtendedFilter>(new ExtendedFilter(true)); | |
152 use_config = true; | |
153 } | |
154 | |
155 if (test_config_.aec_type == AecType::AecDelayAgnostic) { | |
156 config.Set<DelayAgnostic>(new DelayAgnostic(true)); | |
157 use_config = true; | |
158 } | |
159 | |
160 if (use_config) | |
161 apm_->SetExtraOptions(config); | |
162 } | |
163 } | |
164 } | |
165 | |
166 virtual void TearDown() { | |
167 render_thread_->Stop(); | |
168 capture_thread_->Stop(); | |
169 stats_thread_->Stop(); | |
170 } | |
171 | |
172 // Function for generating the test configurations to use in the tests | |
173 static std::vector<TestConfig> GenerateTestConfigs() { | |
174 std::vector<TestConfig> test_configs; | |
175 // Loop over all possible test configurations | |
176 for (int render = | |
177 static_cast<int>(RenderApiFunction::ProcessReverseStream1); | |
178 render <= static_cast<int>(RenderApiFunction::AnalyzeReverseStream2); | |
179 render++) | |
180 for (int capture = static_cast<int>(CaptureApiFunction::ProcessStream1); | |
181 capture <= static_cast<int>(CaptureApiFunction::ProcessStream3); | |
182 capture++) | |
183 for (int aec = static_cast<int>(AecType::Aec); | |
184 aec <= static_cast<int>(AecType::Aecm); aec++) | |
185 for (int scheme = | |
186 static_cast<int>(RuntimeParameterSettingScheme::Scheme1); | |
187 scheme <= | |
188 static_cast<int>(RuntimeParameterSettingScheme::Scheme4); | |
189 scheme++) { | |
190 TestConfig test_config; | |
191 test_config.render_api_function = | |
192 static_cast<RenderApiFunction>(render); | |
193 test_config.capture_api_function = | |
194 static_cast<CaptureApiFunction>(capture); | |
195 test_config.aec_type = static_cast<AecType>(aec); | |
196 | |
197 // Check that the selected render and capture API calls are | |
198 // compatible | |
199 if ((((test_config.render_api_function == | |
200 RenderApiFunction::ProcessReverseStream1) || | |
201 (test_config.render_api_function == | |
202 RenderApiFunction::AnalyzeReverseStream1)) && | |
203 (test_config.capture_api_function == | |
204 CaptureApiFunction::ProcessStream1)) || | |
205 (((test_config.render_api_function != | |
206 RenderApiFunction::ProcessReverseStream1) && | |
207 (test_config.render_api_function != | |
208 RenderApiFunction::AnalyzeReverseStream1)) && | |
209 (test_config.capture_api_function != | |
210 CaptureApiFunction::ProcessStream1))) { | |
211 // For the compatible render and capture function combinations | |
212 // add test configs with different initial sample rates and | |
213 // parameter setting schemes | |
214 test_config.runtime_parameter_setting_scheme = | |
215 static_cast<RuntimeParameterSettingScheme>(scheme); | |
216 | |
217 test_config.initial_sample_rate = 8000; | |
218 test_configs.push_back(test_config); | |
219 | |
220 test_config.initial_sample_rate = 16000; | |
221 test_configs.push_back(test_config); | |
222 | |
223 if (test_config.aec_type != AecType::Aecm) { | |
224 test_config.initial_sample_rate = 32000; | |
225 test_configs.push_back(test_config); | |
226 | |
227 test_config.initial_sample_rate = 48000; | |
228 test_configs.push_back(test_config); | |
229 } | |
230 } | |
231 } | |
232 // Return the created test configurations | |
233 return test_configs; | |
234 } | |
235 | |
236 private: | |
237 const int kMinNumCalls = 10000; | |
238 const int kTestTimeOutLimit = 10 * 60 * 1000; | |
239 const int kMaxCallDifference = 10; | |
240 const float kRenderInputFloatLevel = 0.5f; | |
241 const float kCaptureInputFloatLevel = 0.03125f; | |
242 const int kRenderInputFixLevel = 16384; | |
243 const int kCaptureInputFixLevel = 1024; | |
kwiberg-webrtc
2015/10/08 13:25:21
static const for all of these?
peah-webrtc
2015/10/13 06:58:39
Done.
| |
244 | |
245 // Populates a float audio frame with random data. | |
246 static void PopulateAudioFrame(float** frame, | |
247 int max_absolute_value, | |
the sun
2015/10/08 12:38:10
amplitude?
peah-webrtc
2015/10/13 06:58:39
Done.
| |
248 int num_channels, | |
249 int samples_per_channel, | |
250 unsigned int* seed) { | |
251 for (int ch = 0; ch < num_channels; ch++) | |
the sun
2015/10/08 12:38:10
Please, always use braces.
peah-webrtc
2015/10/13 06:58:39
Done.
| |
252 for (int k = 0; k < samples_per_channel; k++) { | |
253 // Store random 16 bit quantized float number between the specified | |
254 // limits. | |
255 frame[ch][k] = | |
256 static_cast<float>((rand_r(seed) % (32768 + 32768 + 1)) - 32768) / | |
ivoc
2015/10/09 15:47:15
I don't understand the "+ 1" here. A 16 bit value
peah-webrtc
2015/10/26 07:34:40
You are totally correct in that! It is now rewritt
| |
257 32768.0f; | |
258 frame[ch][k] *= max_absolute_value; | |
259 } | |
260 } | |
261 | |
262 // Populates an audioframe frame of AudioFrame type with random data. | |
263 static void PopulateAudioFrame(AudioFrame* frame, | |
264 int max_absolute_value, | |
265 unsigned int* seed) { | |
266 for (int ch = 0; ch < frame->num_channels_; ch++) | |
267 for (int k = 0; k < static_cast<int>(frame->samples_per_channel_); k++) | |
268 // Store random 16 bit quantized float number between -1 and 1. | |
the sun
2015/10/08 12:38:09
Assert on the range of max_absolute_value, plus ch
peah-webrtc
2015/10/13 06:58:39
Done.
| |
269 frame->data_[k * ch] = | |
270 ((rand_r(seed) % (max_absolute_value + max_absolute_value + 1)) - | |
271 (max_absolute_value + 1)); | |
the sun
2015/10/08 12:38:09
This computation is not correct. Say that max_abso
kwiberg-webrtc
2015/10/08 13:25:22
I recognize this from 15 lines ago. Subroutine?
ivoc
2015/10/09 15:47:15
Not exactly the same, there's no division and conv
peah-webrtc
2015/10/13 06:58:39
You are definitely correct. I now limited the rang
peah-webrtc
2015/10/13 06:58:39
Done.
peah-webrtc
2015/10/13 06:58:39
Done.
peah-webrtc
2015/10/13 06:58:39
Done.
peah-webrtc
2015/10/13 06:58:40
I think it should be correct now.
| |
272 } | |
273 | |
274 // Thread callback for the render thread | |
275 static bool CbRenderThread(void* context) { | |
276 return reinterpret_cast<AudioProcessingImpLockTest*>(context) | |
277 ->CbRenderImpl(); | |
278 } | |
279 | |
280 // Thread callback for the capture thread | |
281 static bool CbCaptureThread(void* context) { | |
282 return reinterpret_cast<AudioProcessingImpLockTest*>(context) | |
283 ->CbCaptureImpl(); | |
284 } | |
285 | |
286 // Thread callback for the stats thread | |
287 static bool CbStatsThread(void* context) { | |
288 return reinterpret_cast<AudioProcessingImpLockTest*>(context) | |
289 ->CbStatsImpl(); | |
290 } | |
291 | |
292 // Tests whether all the required render and capture side calls have been | |
293 // done. | |
294 bool TestDone() { | |
295 rtc::CritScope cs(&crit_); | |
296 if ((render_count_ > kMinNumCalls) && (capture_count_ > kMinNumCalls)) | |
297 return true; | |
298 return false; | |
kwiberg-webrtc
2015/10/08 13:25:21
Just
return (render_count_ > kMinNumCalls) && (
peah-webrtc
2015/10/13 06:58:40
Done.
| |
299 } | |
300 | |
301 // Sleeps a random time. | |
kwiberg-webrtc
2015/10/08 13:25:21
Time unit?
peah-webrtc
2015/10/13 06:58:40
Done.
| |
302 static void SleepRandomTime(int max_sleep, unsigned int* seed) { | |
303 int sleeptime = rand_r(seed) % (max_sleep + 1); | |
304 SleepMs(sleeptime); | |
305 } | |
306 | |
307 // Implements the callback functionality for the statistics | |
308 // collection thread. | |
309 bool CbStatsImpl() { | |
310 SleepRandomTime(100, &stats_seed); | |
311 | |
312 (void)apm_->echo_cancellation()->is_enabled(); | |
313 (void)apm_->echo_cancellation()->stream_drift_samples(); | |
314 (void)apm_->echo_control_mobile()->is_enabled(); | |
315 (void)apm_->gain_control()->is_enabled(); | |
316 (void)apm_->gain_control()->stream_analog_level(); | |
317 (void)apm_->noise_suppression()->is_enabled(); | |
318 (void)apm_->noise_suppression()->speech_probability(); | |
319 (void)apm_->voice_detection()->is_enabled(); | |
320 | |
321 return true; | |
322 } | |
323 | |
324 // Implements the callback functionality for the render thread. | |
325 bool CbRenderImpl() { | |
326 // Conditional wait to ensure that a capture call has been done | |
327 // before the first render call is performed (implicitly | |
328 // required by the APM API). | |
329 if (first_render_side_call_) { | |
330 bool capture_side_called_local; | |
331 do { | |
332 { | |
333 rtc::CritScope cs(&crit_initial_sync_); | |
334 capture_side_called_local = capture_side_called_; | |
335 } | |
336 SleepRandomTime(3, &render_seed); | |
337 } while (!capture_side_called_local); | |
338 | |
339 first_render_side_call_ = false; | |
340 } | |
341 | |
342 // Sleep a random time to simulate thread jitter. | |
343 SleepRandomTime(3, &render_seed); | |
344 | |
345 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
346 if (HasFatalFailure()) | |
347 test_complete_->Set(); | |
348 | |
349 // Ensure that the number of render and capture calls do not | |
350 // differ too much. | |
351 int frame_counter_difference; | |
352 do { | |
353 { | |
354 rtc::CritScope cs(&crit_); | |
355 frame_counter_difference = | |
356 render_count_ - (capture_count_ + kMaxCallDifference); | |
357 } | |
358 if (frame_counter_difference > 0) | |
359 SleepMs(1); | |
360 } while (frame_counter_difference > 0); | |
361 | |
362 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
363 if (HasFatalFailure()) | |
364 test_complete_->Set(); | |
365 | |
366 // Apply any specified render side APM non-processing runtime calls. | |
367 ApplyRenderRuntimeSettingScheme(); | |
368 | |
369 // Apply the render side processing call. | |
370 CallRenderSide(); | |
371 | |
372 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
373 if (HasFatalFailure()) | |
374 test_complete_->Set(); | |
375 | |
376 // Increase the number of render-side calls. | |
377 rtc::CritScope cs(&crit_); | |
378 render_count_++; | |
379 | |
380 return true; | |
381 } | |
382 | |
383 // Makes the capture side processing API call. | |
384 void CallCaptureSide() { | |
385 // Prepare a proper capture side processing API call input. | |
386 PrepareCaptureFrame(); | |
387 | |
388 // Set the stream delay | |
389 (void)apm_->set_stream_delay_ms(30); | |
ivoc
2015/10/09 15:47:15
What does this (void) thing do?
peah-webrtc
2015/10/13 06:58:40
Done.
peah-webrtc
2015/10/13 06:58:40
It explicitly discards the output of the function,
| |
390 | |
391 // Call the specified capture side API processing method. | |
392 int result = AudioProcessing::kNoError; | |
393 switch (test_config_.capture_api_function) { | |
394 case CaptureApiFunction::ProcessStream1: | |
395 result = apm_->ProcessStream(&capture_frame_); | |
396 break; | |
397 case CaptureApiFunction::ProcessStream2: | |
398 result = apm_->ProcessStream( | |
399 capture_input_frame_, capture_input_samples_per_channel_, | |
400 capture_input_sample_rate_hz_, capture_input_channel_layout_, | |
401 capture_output_sample_rate_hz_, capture_output_channel_layout_, | |
402 capture_output_frame_); | |
403 break; | |
404 case CaptureApiFunction::ProcessStream3: | |
405 result = apm_->ProcessStream( | |
406 capture_input_frame_, capture_input_stream_config_, | |
407 capture_output_stream_config_, capture_output_frame_); | |
408 break; | |
409 default: | |
410 assert(false); | |
ivoc
2015/10/09 15:47:15
Shouldn't this be something like ASSERT_TRUE(false
peah-webrtc
2015/10/13 06:58:39
Done.
peah-webrtc
2015/10/13 06:58:39
Good point! Added that!
| |
411 } | |
412 | |
413 // Check the return code for error. | |
414 EXPECT_EQ(AudioProcessing::kNoError, result); | |
415 } | |
416 | |
417 // Prepares the render side frame and the accompanying metadata | |
418 // with the appropriate information. | |
419 void PrepareRenderFrame() { | |
420 // Restrict to a common fixed sample rate if the AudioFrame interface is | |
421 // used. | |
422 if ((test_config_.render_api_function == | |
423 RenderApiFunction::AnalyzeReverseStream1) || | |
424 (test_config_.render_api_function == | |
425 RenderApiFunction::ProcessReverseStream1) || | |
426 (test_config_.aec_type != AecType::Aecm)) { | |
427 render_input_sample_rate_hz_ = test_config_.initial_sample_rate; | |
428 render_output_sample_rate_hz_ = test_config_.initial_sample_rate; | |
429 } | |
430 | |
431 // Prepare the audioframe data and metadata | |
432 render_input_samples_per_channel_ = | |
433 render_input_sample_rate_hz_ * AudioProcessing::kChunkSizeMs / 1000; | |
434 render_frame_.sample_rate_hz_ = render_input_sample_rate_hz_; | |
435 render_frame_.num_channels_ = render_input_number_of_channels_; | |
436 render_frame_.samples_per_channel_ = render_input_samples_per_channel_; | |
437 memset(render_frame_.data_, 0, | |
438 render_input_samples_per_channel_ * sizeof(render_frame_.data_[0])); | |
439 PopulateAudioFrame(&render_frame_, kRenderInputFixLevel, &render_seed); | |
440 | |
441 // Prepare the float audio input data and metadata. | |
442 render_input_stream_config_.set_sample_rate_hz( | |
443 render_input_sample_rate_hz_); | |
444 render_input_stream_config_.set_num_channels( | |
445 render_input_number_of_channels_); | |
446 render_input_stream_config_.set_has_keyboard(false); | |
447 PopulateAudioFrame(render_input_frame_, kRenderInputFloatLevel, | |
448 render_input_number_of_channels_, | |
449 render_input_samples_per_channel_, &render_seed); | |
450 render_input_channel_layout_ = | |
451 (render_input_number_of_channels_ == 1 | |
452 ? AudioProcessing::ChannelLayout::kMono | |
453 : AudioProcessing::ChannelLayout::kStereo); | |
454 | |
455 // Prepare the float audio output data and metadata. | |
456 render_output_samples_per_channel_ = | |
457 render_output_sample_rate_hz_ * AudioProcessing::kChunkSizeMs / 1000; | |
458 render_output_stream_config_.set_sample_rate_hz( | |
459 render_output_sample_rate_hz_); | |
460 render_output_stream_config_.set_num_channels( | |
461 render_output_number_of_channels_); | |
462 render_output_stream_config_.set_has_keyboard(false); | |
463 render_output_channel_layout_ = | |
464 (render_output_number_of_channels_ == 1 | |
465 ? AudioProcessing::ChannelLayout::kMono | |
466 : AudioProcessing::ChannelLayout::kStereo); | |
467 } | |
468 | |
469 void PrepareCaptureFrame() { | |
470 // Restrict to a common fixed sample rate if the AudioFrame | |
471 // interface is used. | |
472 if (test_config_.capture_api_function == | |
473 CaptureApiFunction::ProcessStream1) { | |
474 capture_input_sample_rate_hz_ = test_config_.initial_sample_rate; | |
475 capture_output_sample_rate_hz_ = test_config_.initial_sample_rate; | |
476 } | |
477 | |
478 // Prepare the audioframe data and metadata. | |
479 capture_input_samples_per_channel_ = | |
480 capture_input_sample_rate_hz_ * AudioProcessing::kChunkSizeMs / 1000; | |
481 capture_frame_.sample_rate_hz_ = capture_input_sample_rate_hz_; | |
482 capture_frame_.num_channels_ = capture_input_number_of_channels_; | |
483 capture_frame_.samples_per_channel_ = capture_input_samples_per_channel_; | |
484 memset(capture_frame_.data_, 0, capture_input_samples_per_channel_ * | |
485 sizeof(capture_frame_.data_[0])); | |
486 PopulateAudioFrame(&capture_frame_, kCaptureInputFixLevel, &capture_seed); | |
487 | |
488 // Prepare the float audio input data and metadata. | |
489 capture_input_stream_config_.set_sample_rate_hz( | |
490 capture_input_sample_rate_hz_); | |
491 capture_input_stream_config_.set_num_channels( | |
492 capture_input_number_of_channels_); | |
493 capture_input_stream_config_.set_has_keyboard(false); | |
494 PopulateAudioFrame(capture_input_frame_, kCaptureInputFloatLevel, | |
495 capture_input_number_of_channels_, | |
496 capture_input_samples_per_channel_, &capture_seed); | |
497 capture_input_channel_layout_ = | |
498 (capture_input_number_of_channels_ == 1 | |
499 ? AudioProcessing::ChannelLayout::kMonoAndKeyboard | |
500 : AudioProcessing::ChannelLayout::kStereoAndKeyboard); | |
501 | |
502 // Prepare the float audio output data and metadata. | |
503 capture_output_samples_per_channel_ = | |
504 capture_output_sample_rate_hz_ * AudioProcessing::kChunkSizeMs / 1000; | |
505 capture_output_stream_config_.set_sample_rate_hz( | |
506 capture_output_sample_rate_hz_); | |
507 capture_output_stream_config_.set_num_channels( | |
508 capture_output_number_of_channels_); | |
509 capture_output_stream_config_.set_has_keyboard(false); | |
510 capture_output_channel_layout_ = | |
511 (capture_output_number_of_channels_ == 1 | |
512 ? AudioProcessing::ChannelLayout::kMono | |
513 : AudioProcessing::ChannelLayout::kStereo); | |
514 } | |
515 | |
516 // Applies any render capture APM API calls and audio stream characteristics | |
517 // specified by the scheme for the test. | |
518 void ApplyRenderRuntimeSettingScheme() { | |
519 int render_count_local; | |
520 { | |
521 rtc::CritScope cs(&crit_); | |
522 render_count_local = render_count_; | |
523 } | |
kwiberg-webrtc
2015/10/08 13:25:22
If you want, you can write it like this:
const
peah-webrtc
2015/10/13 06:58:39
That looks awesome! Unfortunately it seems that we
kwiberg-webrtc
2015/10/13 09:35:12
It looks like that rule is going to get the obviou
peah-webrtc
2015/10/14 07:57:13
Great! That worked super!
| |
524 | |
525 // Update the number of channels and sample rates for the input and output. | |
526 switch (test_config_.runtime_parameter_setting_scheme) { | |
527 case RuntimeParameterSettingScheme::Scheme1: | |
528 if (render_count_local == 0) | |
529 render_input_sample_rate_hz_ = 16000; | |
530 else if ((render_count_local % 47) == 0) | |
kwiberg-webrtc
2015/10/08 13:25:22
Drop the extra parentheses.
peah-webrtc
2015/10/13 06:58:39
Done.
| |
531 render_input_sample_rate_hz_ = 32000; | |
532 else if ((render_count_local % 71) == 0) | |
533 render_input_sample_rate_hz_ = 48000; | |
534 else if ((render_count_local % 79) == 0) | |
535 render_input_sample_rate_hz_ = 16000; | |
536 else if ((render_count_local % 83) == 0) | |
537 render_input_sample_rate_hz_ = 8000; | |
kwiberg-webrtc
2015/10/08 13:25:22
Where do all these numbers come from?
ivoc
2015/10/09 15:47:15
Looks very confusing indeed, needs some comments t
peah-webrtc
2015/10/13 06:58:39
Please let me know if the comment is sufficient!
peah-webrtc
2015/10/13 06:58:39
They are prime numbers that are chosen in order to
| |
538 | |
539 if (render_count_local == 0) | |
540 render_input_number_of_channels_ = 1; | |
541 else if ((render_count_local % 4) == 0) | |
542 render_input_number_of_channels_ = | |
543 (render_input_number_of_channels_ == 1 ? 2 : 1); | |
544 | |
545 if (render_count_local == 0) | |
546 render_output_sample_rate_hz_ = 16000; | |
547 else if ((render_count_local % 17) == 0) | |
548 render_output_sample_rate_hz_ = 32000; | |
549 else if ((render_count_local % 19) == 0) | |
550 render_output_sample_rate_hz_ = 48000; | |
551 else if ((render_count_local % 29) == 0) | |
552 render_output_sample_rate_hz_ = 16000; | |
553 else if ((render_count_local % 61) == 0) | |
554 render_output_sample_rate_hz_ = 8000; | |
555 | |
556 if (render_count_local == 0) | |
557 render_output_number_of_channels_ = 1; | |
558 else if ((render_count_local % 8) == 0) | |
559 render_output_number_of_channels_ = | |
560 (render_output_number_of_channels_ == 1 ? 2 : 1); | |
561 break; | |
562 case RuntimeParameterSettingScheme::Scheme2: | |
563 if (render_count_local == 0) { | |
564 render_input_number_of_channels_ = 1; | |
565 render_input_sample_rate_hz_ = 16000; | |
566 render_output_number_of_channels_ = 1; | |
567 render_output_sample_rate_hz_ = 16000; | |
568 } else { | |
569 render_input_number_of_channels_ = | |
570 (render_input_number_of_channels_ == 1 ? 2 : 1); | |
571 if (render_input_sample_rate_hz_ == 8000) | |
572 render_input_sample_rate_hz_ = 16000; | |
573 else if (render_input_sample_rate_hz_ == 16000) | |
574 render_input_sample_rate_hz_ = 32000; | |
575 else if (render_input_sample_rate_hz_ == 32000) | |
576 render_input_sample_rate_hz_ = 48000; | |
577 else if (render_input_sample_rate_hz_ == 48000) | |
578 render_input_sample_rate_hz_ = 8000; | |
579 | |
580 render_output_number_of_channels_ = | |
581 (render_output_number_of_channels_ == 1 ? 2 : 1); | |
582 if (render_output_sample_rate_hz_ == 8000) | |
583 render_output_sample_rate_hz_ = 16000; | |
584 else if (render_output_sample_rate_hz_ == 16000) | |
585 render_output_sample_rate_hz_ = 32000; | |
586 else if (render_output_sample_rate_hz_ == 32000) | |
587 render_output_sample_rate_hz_ = 48000; | |
588 else if (render_output_sample_rate_hz_ == 48000) | |
589 render_output_sample_rate_hz_ = 8000; | |
590 } | |
591 break; | |
592 case RuntimeParameterSettingScheme::Scheme3: | |
593 if (render_count_local == 0) { | |
594 render_input_sample_rate_hz_ = 16000; | |
595 render_input_number_of_channels_ = 1; | |
596 render_output_sample_rate_hz_ = 16000; | |
597 render_output_number_of_channels_ = 1; | |
598 } | |
599 break; | |
600 case RuntimeParameterSettingScheme::Scheme4: | |
601 if (render_count_local == 0) { | |
602 render_input_sample_rate_hz_ = 16000; | |
603 render_input_number_of_channels_ = 2; | |
604 render_output_sample_rate_hz_ = 16000; | |
605 render_output_number_of_channels_ = 2; | |
606 } | |
607 | |
608 break; | |
609 default: | |
610 assert(false); | |
611 } | |
612 | |
613 // Restric the number of output channels not to exceed | |
614 // the number of input channels. | |
615 render_output_number_of_channels_ = std::min( | |
616 render_output_number_of_channels_, render_input_number_of_channels_); | |
617 } | |
618 | |
619 // Applies any runtime capture APM API calls and audio stream characteristics | |
620 // specified by the scheme for the test. | |
621 void ApplyCaptureRuntimeSettingScheme() { | |
622 int capture_count_local; | |
623 { | |
624 rtc::CritScope cs(&crit_); | |
625 capture_count_local = capture_count_; | |
626 } | |
627 | |
628 // Update the number of channels and sample rates for the input and output. | |
629 switch (test_config_.runtime_parameter_setting_scheme) { | |
630 case RuntimeParameterSettingScheme::Scheme1: | |
631 if (capture_count_local == 0) | |
632 capture_input_sample_rate_hz_ = 16000; | |
633 else if ((capture_count_local % 11) == 0) | |
634 capture_input_sample_rate_hz_ = 32000; | |
635 else if ((capture_count_local % 73) == 0) | |
636 capture_input_sample_rate_hz_ = 48000; | |
637 else if ((capture_count_local % 89) == 0) | |
638 capture_input_sample_rate_hz_ = 16000; | |
639 else if ((capture_count_local % 97) == 0) | |
640 capture_input_sample_rate_hz_ = 8000; | |
641 | |
642 if (capture_count_local == 0) | |
643 capture_input_number_of_channels_ = 1; | |
644 else if ((capture_count_local % 4) == 0) | |
645 capture_input_number_of_channels_ = | |
646 (capture_input_number_of_channels_ == 1 ? 2 : 1); | |
647 | |
648 if (capture_count_local == 0) | |
649 capture_output_sample_rate_hz_ = 16000; | |
650 else if ((capture_count_local % 5) == 0) | |
651 capture_output_sample_rate_hz_ = 32000; | |
652 else if ((capture_count_local % 47) == 0) | |
653 capture_output_sample_rate_hz_ = 48000; | |
654 else if ((capture_count_local % 53) == 0) | |
655 capture_output_sample_rate_hz_ = 16000; | |
656 else if ((capture_count_local % 71) == 0) | |
657 capture_output_sample_rate_hz_ = 8000; | |
658 | |
659 if (capture_count_local == 0) | |
660 capture_output_number_of_channels_ = 1; | |
661 else if ((capture_count_local % 8) == 0) | |
662 capture_output_number_of_channels_ = | |
663 (capture_output_number_of_channels_ == 1 ? 2 : 1); | |
664 break; | |
665 case RuntimeParameterSettingScheme::Scheme2: | |
666 if ((capture_count_local % 2) == 0) { | |
667 capture_input_number_of_channels_ = 1; | |
668 capture_input_sample_rate_hz_ = 16000; | |
669 capture_output_number_of_channels_ = 1; | |
670 capture_output_sample_rate_hz_ = 16000; | |
671 } else { | |
672 capture_input_number_of_channels_ = | |
673 (capture_input_number_of_channels_ == 1 ? 2 : 1); | |
674 if (capture_input_sample_rate_hz_ == 8000) | |
675 capture_input_sample_rate_hz_ = 16000; | |
676 else if (capture_input_sample_rate_hz_ == 16000) | |
677 capture_input_sample_rate_hz_ = 32000; | |
678 else if (capture_input_sample_rate_hz_ == 32000) | |
679 capture_input_sample_rate_hz_ = 48000; | |
680 else if (capture_input_sample_rate_hz_ == 48000) | |
681 capture_input_sample_rate_hz_ = 8000; | |
682 | |
683 capture_output_number_of_channels_ = | |
684 (capture_output_number_of_channels_ == 1 ? 2 : 1); | |
685 if (capture_output_sample_rate_hz_ == 8000) | |
686 capture_output_sample_rate_hz_ = 16000; | |
687 else if (capture_output_sample_rate_hz_ == 16000) | |
688 capture_output_sample_rate_hz_ = 32000; | |
689 else if (capture_output_sample_rate_hz_ == 32000) | |
690 capture_output_sample_rate_hz_ = 48000; | |
691 else if (capture_output_sample_rate_hz_ == 48000) | |
692 capture_output_sample_rate_hz_ = 8000; | |
693 } | |
694 break; | |
695 case RuntimeParameterSettingScheme::Scheme3: | |
696 if (capture_count_local == 0) { | |
697 capture_input_sample_rate_hz_ = 16000; | |
698 capture_input_number_of_channels_ = 1; | |
699 capture_output_sample_rate_hz_ = 16000; | |
700 capture_output_number_of_channels_ = 1; | |
701 } | |
702 break; | |
703 case RuntimeParameterSettingScheme::Scheme4: | |
704 if (capture_count_local == 0) { | |
705 capture_input_sample_rate_hz_ = 16000; | |
706 capture_input_number_of_channels_ = 2; | |
707 capture_output_sample_rate_hz_ = 16000; | |
708 capture_output_number_of_channels_ = 2; | |
709 } | |
710 | |
711 break; | |
712 default: | |
713 assert(false); | |
714 } | |
715 | |
716 // Call any specified runtime APM setter and | |
717 // getter calls. | |
718 switch (test_config_.runtime_parameter_setting_scheme) { | |
719 case RuntimeParameterSettingScheme::Scheme1: | |
720 case RuntimeParameterSettingScheme::Scheme3: | |
721 break; | |
722 case RuntimeParameterSettingScheme::Scheme2: | |
723 case RuntimeParameterSettingScheme::Scheme4: | |
724 if ((capture_count_local % 2) == 0) { | |
725 (void)apm_->set_stream_delay_ms(30); | |
726 apm_->set_stream_key_pressed(true); | |
727 apm_->set_output_will_be_muted(true); | |
728 apm_->set_delay_offset_ms(15); | |
729 (void)apm_->delay_offset_ms(); | |
730 apm_->set_output_will_be_muted(true); | |
731 (void)apm_->num_reverse_channels(); | |
732 } else { | |
733 (void)apm_->set_stream_delay_ms(50); | |
734 apm_->set_stream_key_pressed(false); | |
735 apm_->set_output_will_be_muted(false); | |
736 apm_->set_delay_offset_ms(20); | |
737 (void)apm_->delay_offset_ms(); | |
738 apm_->set_output_will_be_muted(false); | |
739 (void)apm_->num_reverse_channels(); | |
740 } | |
741 break; | |
742 default: | |
743 assert(false); | |
744 } | |
745 | |
746 // Restric the number of output channels not to exceed | |
747 // the number of input channels. | |
748 capture_output_number_of_channels_ = std::min( | |
749 capture_output_number_of_channels_, capture_input_number_of_channels_); | |
750 } | |
751 | |
752 // Makes the render side processing API call. | |
753 void CallRenderSide() { | |
754 // Prepare a proper render side processing API call input. | |
755 PrepareRenderFrame(); | |
756 | |
757 // Call the specified render side API processing method. | |
758 int result = AudioProcessing::kNoError; | |
759 switch (test_config_.render_api_function) { | |
760 case RenderApiFunction::ProcessReverseStream1: | |
761 result = apm_->ProcessReverseStream(&render_frame_); | |
762 break; | |
763 case RenderApiFunction::ProcessReverseStream2: | |
764 result = apm_->ProcessReverseStream( | |
765 render_input_frame_, render_input_stream_config_, | |
766 render_output_stream_config_, render_output_frame_); | |
767 break; | |
768 case RenderApiFunction::AnalyzeReverseStream1: | |
769 result = apm_->AnalyzeReverseStream(&render_frame_); | |
770 break; | |
771 case RenderApiFunction::AnalyzeReverseStream2: | |
772 result = apm_->AnalyzeReverseStream( | |
773 render_input_frame_, render_input_samples_per_channel_, | |
774 render_input_sample_rate_hz_, render_input_channel_layout_); | |
775 break; | |
776 default: | |
777 assert(false); | |
778 } | |
779 | |
780 // Check the return code for error. | |
781 EXPECT_EQ(AudioProcessing::kNoError, result); | |
782 } | |
783 | |
784 // Implements the callback functionality for the capture thread. | |
785 bool CbCaptureImpl() { | |
786 // Sleep a random time to simulate thread jitter. | |
787 SleepRandomTime(3, &capture_seed); | |
788 | |
789 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
790 if (HasFatalFailure()) | |
791 test_complete_->Set(); | |
792 | |
793 // Ensure that there are not more capture side calls than render side | |
794 // calls. | |
795 int frame_counter_difference; | |
796 do { | |
797 { | |
798 rtc::CritScope cs(&crit_); | |
799 frame_counter_difference = capture_count_ - render_count_; | |
800 } | |
801 if (frame_counter_difference > 0) | |
802 SleepMs(1); | |
803 } while (frame_counter_difference > 0); | |
804 | |
805 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
806 if (HasFatalFailure()) | |
807 test_complete_->Set(); | |
808 | |
809 // Apply any specified capture side APM non-processing runtime calls. | |
810 ApplyCaptureRuntimeSettingScheme(); | |
811 | |
812 // Apply the capture side processing call. | |
813 CallCaptureSide(); | |
814 | |
815 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
816 if (HasFatalFailure()) | |
817 test_complete_->Set(); | |
818 | |
819 // Increase the number of capture-side calls. | |
820 { | |
821 rtc::CritScope cs(&crit_); | |
822 capture_count_++; | |
823 } | |
824 | |
825 // Check if the test is done. | |
826 if (TestDone()) | |
827 test_complete_->Set(); | |
828 | |
829 // Flag that the capture side has been called at least once | |
830 // (needed to ensure that a capture call has been done | |
831 // before the first render call is performed (implicitly | |
832 // required by the APM API). | |
833 { | |
834 rtc::CritScope cs(&crit_initial_sync_); | |
835 capture_side_called_ = true; | |
836 } | |
837 | |
838 return true; | |
839 } | |
840 | |
841 // Start the threads used in the test. | |
842 void StartThreads() { | |
843 ASSERT_TRUE(render_thread_->Start()); | |
844 render_thread_->SetPriority(kRealtimePriority); | |
845 ASSERT_TRUE(capture_thread_->Start()); | |
846 capture_thread_->SetPriority(kRealtimePriority); | |
847 ASSERT_TRUE(stats_thread_->Start()); | |
848 stats_thread_->SetPriority(kNormalPriority); | |
849 } | |
850 | |
851 rtc::CriticalSection crit_; | |
852 rtc::CriticalSection crit_initial_sync_; | |
853 rtc::scoped_ptr<ThreadWrapper> render_thread_; | |
854 rtc::scoped_ptr<ThreadWrapper> capture_thread_; | |
855 rtc::scoped_ptr<ThreadWrapper> stats_thread_; | |
856 int render_count_ GUARDED_BY(crit_); | |
857 int capture_count_ GUARDED_BY(crit_); | |
858 bool first_render_side_call_; | |
859 bool capture_side_called_ GUARDED_BY(crit_initial_sync_); | |
860 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
861 rtc::scoped_ptr<AudioProcessing> apm_; | |
862 TestConfig test_config_; | |
863 AudioFrame render_frame_; | |
864 AudioFrame capture_frame_; | |
865 unsigned int render_seed; | |
866 unsigned int capture_seed; | |
867 unsigned int stats_seed; | |
868 | |
869 // Variables related to the capture side audio data and formats. | |
870 float** capture_output_frame_; | |
871 AudioProcessing::ChannelLayout capture_output_channel_layout_; | |
872 int capture_input_sample_rate_hz_; | |
873 int capture_input_number_of_channels_; | |
874 float** capture_input_frame_; | |
875 AudioProcessing::ChannelLayout capture_input_channel_layout_; | |
876 int capture_output_sample_rate_hz_; | |
877 int capture_output_number_of_channels_; | |
878 StreamConfig capture_input_stream_config_; | |
879 StreamConfig capture_output_stream_config_; | |
880 int capture_input_samples_per_channel_; | |
881 int capture_output_samples_per_channel_; | |
882 | |
883 // Variables related to the render side audio data and formats. | |
884 float** render_output_frame_; | |
885 AudioProcessing::ChannelLayout render_output_channel_layout_; | |
886 int render_input_sample_rate_hz_; | |
887 int render_input_number_of_channels_; | |
888 float** render_input_frame_; | |
889 AudioProcessing::ChannelLayout render_input_channel_layout_; | |
890 int render_output_sample_rate_hz_; | |
891 int render_output_number_of_channels_; | |
892 StreamConfig render_input_stream_config_; | |
893 StreamConfig render_output_stream_config_; | |
894 int render_input_samples_per_channel_; | |
895 int render_output_samples_per_channel_; | |
kwiberg-webrtc
2015/10/08 13:25:22
This is a large pile of member variables. Any chan
peah-webrtc
2015/10/13 06:58:40
Done.
| |
896 }; | |
897 | |
898 } // anonymous namespace | |
899 | |
900 TEST_P(AudioProcessingImpLockTest, LockTest) { | |
901 // Run test and verify that it did not time out. | |
902 EXPECT_EQ(kEventSignaled, RunTest()); | |
903 } | |
904 | |
905 // Instantiate tests from the test configurations provided by the generator. | |
906 INSTANTIATE_TEST_CASE_P( | |
907 DISABLED_AudioProcessingImpLockTestAllCombinations, | |
908 AudioProcessingImpLockTest, | |
909 ::testing::ValuesIn(AudioProcessingImpLockTest::GenerateTestConfigs())); | |
910 | |
911 } // namespace webrtc | |
OLD | NEW |