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

Side by Side Diff: webrtc/modules/audio_processing/audio_processing_impl_locking_unittest.cc

Issue 1394803002: Unittest for the locking in APM (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Various fixes in response to reviewer comments Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | webrtc/modules/modules.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
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/base/criticalsection.h"
19 #include "webrtc/config.h"
20 #include "webrtc/modules/audio_processing/test/test_utils.h"
21 #include "webrtc/modules/interface/module_common_types.h"
22 #include "webrtc/system_wrappers/include/event_wrapper.h"
23 #include "webrtc/system_wrappers/include/sleep.h"
24 #include "webrtc/system_wrappers/include/thread_wrapper.h"
25 #include "webrtc/test/random.h"
26
27 namespace webrtc {
28
29 namespace {
30
31 // Type of the render thread APM API call to use in the test.
32 enum class RenderApiFunctionImplementation {
33 ProcessReverseStreamImplementation1,
34 ProcessReverseStreamImplementation2,
35 AnalyzeReverseStreamImplementation1,
36 AnalyzeReverseStreamImplementation2
37 };
the sun 2015/10/29 10:31:30 nit: space between the enum declarations
peah-webrtc 2015/10/29 14:26:51 Done.
38 // Type of the capture thread APM API call to use in the test.
39 enum class CaptureApiFunctionImplementation {
40 ProcessStreamImplementation1,
41 ProcessStreamImplementation2,
42 ProcessStreamImplementation3
43 };
44 // The runtime parameter setting scheme to use in the test.
45 enum class RuntimeParameterSettingScheme {
46 SparseStreamMetadataChangeScheme,
47 ExtremeStreamMetadataChangeScheme,
48 FixedMonoStreamMetadataScheme,
49 FixedStereoStreamMetadataScheme
50 };
51 enum class AecType {
52 BasicWebRtcAecSettings,
53 AecTurnedOff,
54 BasicWebRtcAecSettingsWithExtentedFilter,
55 BasicWebRtcAecSettingsWithDelayAgnosticAec,
56 BasicWebRtcAecSettingsWithAecMobile
57 };
58
59 // The configuration for the test to use.
60 struct TestConfig {
61 RenderApiFunctionImplementation render_api_function;
62 CaptureApiFunctionImplementation capture_api_function;
63 RuntimeParameterSettingScheme runtime_parameter_setting_scheme;
64 int initial_sample_rate_hz;
65 AecType aec_type;
66 int min_number_of_calls;
67 };
68
69 // Class for implementing the tests of the locks in the audio processing module.
70 class AudioProcessingImpLockTest : public ::testing::TestWithParam<TestConfig> {
71 public:
72 AudioProcessingImpLockTest()
73 : test_complete_(EventWrapper::Create()),
74 render_thread_(
75 ThreadWrapper::CreateThread(RenderThread, this, "render")),
76 capture_thread_(
77 ThreadWrapper::CreateThread(CaptureThread, this, "capture")),
78 stats_thread_(ThreadWrapper::CreateThread(StatsThread, this, "stats")),
79 rand_gen_(42U) {
80 // Set up the two-dimensional arrays needed for the APM API calls.
the sun 2015/10/29 10:31:30 Why doesn't this setting up go in the c-tors of th
peah-webrtc 2015/10/29 14:26:51 Done.
81 capture_thread_state_.input_framechannels_.resize(2 * 480);
the sun 2015/10/29 10:31:30 nit: Use a constant for 480
peah-webrtc 2015/10/29 14:26:51 Done.
82 capture_thread_state_.input_frame.resize(2);
83 capture_thread_state_.input_frame[0] =
84 &capture_thread_state_.input_framechannels_[0];
85 capture_thread_state_.input_frame[1] =
86 &capture_thread_state_.input_framechannels_[480];
87
88 capture_thread_state_.output_frame_channels.resize(2 * 480);
89 capture_thread_state_.output_frame.resize(2);
90 capture_thread_state_.output_frame[0] =
91 &capture_thread_state_.output_frame_channels[0];
92 capture_thread_state_.output_frame[1] =
93 &capture_thread_state_.output_frame_channels[480];
94
95 render_thread_state_.input_frame_channels.resize(2 * 480);
96 render_thread_state_.input_frame.resize(2);
97 render_thread_state_.input_frame[0] =
98 &render_thread_state_.input_frame_channels[0];
99 render_thread_state_.input_frame[1] =
100 &render_thread_state_.input_frame_channels[480];
101
102 render_thread_state_.output_frame_channels.resize(2 * 480);
103 render_thread_state_.output_frame.resize(2);
104 render_thread_state_.output_frame[0] =
105 &render_thread_state_.output_frame_channels[0];
106 render_thread_state_.output_frame[1] =
107 &render_thread_state_.output_frame_channels[480];
108 }
109
110 // Run the test with a timeout.
111 EventTypeWrapper RunTest() {
112 StartThreads();
113 return test_complete_->Wait(kTestTimeOutLimit);
114 }
115
116 void SetUp() override {
117 apm_.reset(AudioProcessingImpl::Create());
118 test_config_ = static_cast<TestConfig>(GetParam());
119
120 ASSERT_EQ(apm_->kNoError, apm_->level_estimator()->Enable(true));
121 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
122
123 ASSERT_EQ(apm_->kNoError,
124 apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
125 ASSERT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
126 ASSERT_EQ(apm_->kNoError,
127 apm_->gain_control()->set_mode(GainControl::kFixedDigital));
128
129 ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true));
130 ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
131
132 Config config;
133 if (test_config_.aec_type == AecType::AecTurnedOff) {
134 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
135 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
136 } else {
137 if (test_config_.aec_type ==
138 AecType::BasicWebRtcAecSettingsWithAecMobile) {
139 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
140 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
141 } else {
142 ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
143 ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
144 ASSERT_EQ(apm_->kNoError,
145 apm_->echo_cancellation()->enable_metrics(true));
146 ASSERT_EQ(apm_->kNoError,
147 apm_->echo_cancellation()->enable_delay_logging(true));
148
149 config.Set<ExtendedFilter>(new ExtendedFilter(
150 test_config_.aec_type ==
151 AecType::BasicWebRtcAecSettingsWithExtentedFilter));
152
153 config.Set<DelayAgnostic>(new DelayAgnostic(
154 test_config_.aec_type ==
155 AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec));
156
157 apm_->SetExtraOptions(config);
158 }
159 }
160 }
161
162 void TearDown() override {
163 render_thread_->Stop();
164 capture_thread_->Stop();
165 stats_thread_->Stop();
166 }
167
168 // Function for generating the test configurations to use in the brief tests.
169 static std::vector<TestConfig> GenerateBriefTestConfigs() {
the sun 2015/10/29 10:31:30 Move this function out of this class. Maybe put it
peah-webrtc 2015/10/29 14:26:51 Done.
170 std::vector<TestConfig> test_configs;
171 for (int aec = static_cast<int>(
172 AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec);
173 aec <= static_cast<int>(AecType::BasicWebRtcAecSettingsWithAecMobile);
174 aec++) {
175 TestConfig test_config;
176
177 test_config.min_number_of_calls = 300;
178
179 // Perform tests only with the extreme runtime parameter setting scheme.
180 test_config.runtime_parameter_setting_scheme =
181 RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme;
182
183 // Only test 16 kHz for this test suite.
184 test_config.initial_sample_rate_hz = 16000;
185
186 // Create test config for the second processing API function set.
187 test_config.render_api_function =
188 RenderApiFunctionImplementation::ProcessReverseStreamImplementation2;
189 test_config.capture_api_function =
190 CaptureApiFunctionImplementation::ProcessStreamImplementation2;
191
192 // Create test config for the first processing API function set.
193 test_configs.push_back(test_config);
194 test_config.render_api_function =
195 RenderApiFunctionImplementation::AnalyzeReverseStreamImplementation2;
196 test_config.capture_api_function =
197 CaptureApiFunctionImplementation::ProcessStreamImplementation3;
198 test_configs.push_back(test_config);
199 }
200
201 // Return the created test configurations.
202 return test_configs;
203 }
204
205 // Function for generating the test configurations to use in the extensive
206 // tests.
207 static std::vector<TestConfig> GenerateExtensiveTestConfigs() {
the sun 2015/10/29 10:31:30 Move out of this class. Into TestConfig?
peah-webrtc 2015/10/29 14:26:51 Done.
208 std::vector<TestConfig> test_configs;
209 // Loop over all possible test configurations.
210 for (int render = static_cast<int>(RenderApiFunctionImplementation::
211 ProcessReverseStreamImplementation1);
212 render <= static_cast<int>(RenderApiFunctionImplementation::
213 AnalyzeReverseStreamImplementation2);
214 render++)
215 for (int capture = static_cast<int>(
216 CaptureApiFunctionImplementation::ProcessStreamImplementation1);
217 capture <=
218 static_cast<int>(
219 CaptureApiFunctionImplementation::ProcessStreamImplementation3);
220 capture++)
221 for (int aec = static_cast<int>(AecType::BasicWebRtcAecSettings);
222 aec <=
223 static_cast<int>(AecType::BasicWebRtcAecSettingsWithAecMobile);
224 aec++)
225 for (int scheme =
226 static_cast<int>(RuntimeParameterSettingScheme::
227 SparseStreamMetadataChangeScheme);
228 scheme <= static_cast<int>(RuntimeParameterSettingScheme::
229 FixedStereoStreamMetadataScheme);
230 scheme++) {
231 TestConfig test_config;
232 test_config.min_number_of_calls = 10000;
233
234 test_config.render_api_function =
235 static_cast<RenderApiFunctionImplementation>(render);
236 test_config.capture_api_function =
237 static_cast<CaptureApiFunctionImplementation>(capture);
238 test_config.aec_type = static_cast<AecType>(aec);
239
240 // Check that the selected render and capture API calls are
241 // compatible
242 if ((((test_config.render_api_function ==
243 RenderApiFunctionImplementation::
244 ProcessReverseStreamImplementation1) ||
245 (test_config.render_api_function ==
246 RenderApiFunctionImplementation::
247 AnalyzeReverseStreamImplementation1)) &&
248 (test_config.capture_api_function ==
249 CaptureApiFunctionImplementation::
250 ProcessStreamImplementation1)) ||
251 (((test_config.render_api_function !=
252 RenderApiFunctionImplementation::
253 ProcessReverseStreamImplementation1) &&
254 (test_config.render_api_function !=
255 RenderApiFunctionImplementation::
256 AnalyzeReverseStreamImplementation1)) &&
257 (test_config.capture_api_function !=
258 CaptureApiFunctionImplementation::
259 ProcessStreamImplementation1))) {
260 // For the compatible render and capture function combinations
261 // add test configs with different initial sample rates and
262 // parameter setting schemes.
263 test_config.runtime_parameter_setting_scheme =
264 static_cast<RuntimeParameterSettingScheme>(scheme);
265
266 test_config.initial_sample_rate_hz = 8000;
267 test_configs.push_back(test_config);
268
269 test_config.initial_sample_rate_hz = 16000;
270 test_configs.push_back(test_config);
271
272 if (test_config.aec_type !=
273 AecType::BasicWebRtcAecSettingsWithAecMobile) {
274 test_config.initial_sample_rate_hz = 32000;
275 test_configs.push_back(test_config);
276
277 test_config.initial_sample_rate_hz = 48000;
278 test_configs.push_back(test_config);
279 }
280 }
281 }
282 // Return the created test configurations.
283 return test_configs;
284 }
285
286 private:
287 static const int kTestTimeOutLimit = 10 * 60 * 1000;
288 static const int kMaxCallDifference = 10;
289 static const float kRenderInputFloatLevel;
290 static const float kCaptureInputFloatLevel;
291 static const int kRenderInputFixLevel = 16384;
292 static const int kCaptureInputFixLevel = 1024;
293
294 // Generates random number between -(amplitude+1) and amplitude
295 int16_t GenerateRandomInt16(int16_t amplitude) const {
296 return rand_gen_.Rand(-amplitude, amplitude);
hlundin-webrtc 2015/10/29 09:13:22 Does this really generate "random number between -
peah-webrtc 2015/10/29 14:26:51 Good find! Fixed! Done.
297 }
298
299 // Populates a float audio frame with random data.
300 void PopulateAudioFrame(float** frame,
301 float amplitude,
302 size_t num_channels,
303 size_t samples_per_channel) const {
304 for (size_t ch = 0; ch < num_channels; ch++) {
305 for (size_t k = 0; k < samples_per_channel; k++) {
306 // Store random 16 bit quantized float number between the specified
307 // limits.
308 frame[ch][k] = amplitude *
309 static_cast<float>(GenerateRandomInt16(32767)) /
310 32768.0f;
311 }
312 }
313 }
314
315 // Populates an audioframe frame of AudioFrame type with random data.
316 void PopulateAudioFrame(AudioFrame* frame, int16_t amplitude) const {
317 ASSERT_GT(amplitude, 0);
318 ASSERT_LE(amplitude, 32767);
319 for (int ch = 0; ch < frame->num_channels_; ch++) {
320 for (int k = 0; k < static_cast<int>(frame->samples_per_channel_); k++) {
321 // Store random 16 bit quantized float number between -1 and 1.
322 frame->data_[k * ch] = GenerateRandomInt16(amplitude);
323 }
324 }
325 }
326
327 // Thread callback for the render thread
328 static bool RenderThread(void* context) {
329 return reinterpret_cast<AudioProcessingImpLockTest*>(context)
330 ->RenderThreadImpl();
331 }
332
333 // Thread callback for the capture thread
334 static bool CaptureThread(void* context) {
335 return reinterpret_cast<AudioProcessingImpLockTest*>(context)
336 ->CaptureThreadImpl();
337 }
338
339 // Thread callback for the stats thread
340 static bool StatsThread(void* context) {
341 return reinterpret_cast<AudioProcessingImpLockTest*>(context)
342 ->StatsThreadImpl();
343 }
344
345 // Tests whether all the required render and capture side calls have been
346 // done.
347 bool TestDone() {
348 rtc::CritScope cs(&crit_);
349 return ((shared_thread_counter_state_.render_count >
350 test_config_.min_number_of_calls) &&
351 (shared_thread_counter_state_.capture_count >
352 test_config_.min_number_of_calls));
353 }
354
355 // Sleeps a random time between 0 and max_sleep milliseconds.
356 void SleepRandomMs(int max_sleep) const {
357 int sleeptime = rand_gen_.Rand(0, max_sleep);
358 SleepMs(sleeptime);
359 }
360
361 // Implements the callback functionality for the statistics
362 // collection thread.
363 bool StatsThreadImpl() {
364 SleepRandomMs(100);
365
366 EXPECT_EQ(apm_->echo_cancellation()->is_enabled(),
367 ((test_config_.aec_type != AecType::AecTurnedOff) &&
368 (test_config_.aec_type !=
369 AecType::BasicWebRtcAecSettingsWithAecMobile)));
370 apm_->echo_cancellation()->stream_drift_samples();
371 EXPECT_EQ(apm_->echo_control_mobile()->is_enabled(),
372 (test_config_.aec_type != AecType::AecTurnedOff) &&
373 (test_config_.aec_type ==
374 AecType::BasicWebRtcAecSettingsWithAecMobile));
375 EXPECT_TRUE(apm_->gain_control()->is_enabled());
376 apm_->gain_control()->stream_analog_level();
377 EXPECT_TRUE(apm_->noise_suppression()->is_enabled());
378 float speech_probablitity = apm_->noise_suppression()->speech_probability();
379 EXPECT_TRUE(speech_probablitity < (apm_->kUnsupportedFunctionError + 0.5f ||
380 speech_probablitity >= 0));
381 apm_->voice_detection()->is_enabled();
382
383 return true;
384 }
385
386 // Implements the callback functionality for the render thread.
387 bool RenderThreadImpl() {
388 // Conditional wait to ensure that a capture call has been done
389 // before the first render call is performed (implicitly
390 // required by the APM API).
391 if (render_thread_state_.first_render_side_call_) {
392 bool capture_side_called_local;
393 do {
394 {
395 rtc::CritScope cs(&crit_initial_sync_);
396 capture_side_called_local =
397 shared_thread_init_state_.capture_side_called;
398 }
399 SleepRandomMs(3);
400 } while (!capture_side_called_local);
401
402 render_thread_state_.first_render_side_call_ = false;
403 }
404
405 // Sleep a random time to simulate thread jitter.
406 SleepRandomMs(3);
407
408 // End the test early if a fatal failure (ASSERT_*) has occurred.
409 if (HasFatalFailure())
410 test_complete_->Set();
411
412 // Ensure that the number of render and capture calls do not
413 // differ too much.
414 int frame_counter_difference;
415 do {
416 {
417 rtc::CritScope cs(&crit_);
418 frame_counter_difference =
419 (shared_thread_counter_state_.render_count -
420 (shared_thread_counter_state_.capture_count + kMaxCallDifference));
421 }
422 if (frame_counter_difference > 0)
423 SleepMs(1);
424 } while (frame_counter_difference > 0);
425
426 // Apply any specified render side APM non-processing runtime calls.
427 ApplyRenderRuntimeSettingScheme();
428
429 // Apply the render side processing call.
430 CallRenderSide();
431
432 // Increase the number of render-side calls.
433 rtc::CritScope cs(&crit_);
434 shared_thread_counter_state_.render_count++;
435
436 return true;
437 }
438
439 // Makes the capture side processing API call.
440 void CallCaptureSide() {
441 // Prepare a proper capture side processing API call input.
442 PrepareCaptureFrame();
443
444 // Set the stream delay
445 apm_->set_stream_delay_ms(30);
446
447 // Call the specified capture side API processing method.
448 int result = AudioProcessing::kNoError;
449 switch (test_config_.capture_api_function) {
450 case CaptureApiFunctionImplementation::ProcessStreamImplementation1:
451 result = apm_->ProcessStream(&capture_thread_state_.frame);
452 break;
453 case CaptureApiFunctionImplementation::ProcessStreamImplementation2:
454 result =
455 apm_->ProcessStream(&capture_thread_state_.input_frame[0],
456 capture_thread_state_.input_samples_per_channel,
457 capture_thread_state_.input_sample_rate_hz,
458 capture_thread_state_.input_channel_layout,
459 capture_thread_state_.output_sample_rate_hz,
460 capture_thread_state_.output_channel_layout,
461 &capture_thread_state_.output_frame[0]);
462 break;
463 case CaptureApiFunctionImplementation::ProcessStreamImplementation3:
464 result = apm_->ProcessStream(&capture_thread_state_.input_frame[0],
465 capture_thread_state_.input_stream_config,
466 capture_thread_state_.output_stream_config,
467 &capture_thread_state_.output_frame[0]);
468 break;
469 default:
470 assert(false);
471 }
472
473 // Check the return code for error.
474 ASSERT_EQ(AudioProcessing::kNoError, result);
475 }
476
477 // Prepares the render side frame and the accompanying metadata
478 // with the appropriate information.
479 void PrepareRenderFrame() {
480 // Restrict to a common fixed sample rate if the AudioFrame interface is
481 // used.
482 if ((test_config_.render_api_function ==
483 RenderApiFunctionImplementation::
484 AnalyzeReverseStreamImplementation1) ||
485 (test_config_.render_api_function ==
486 RenderApiFunctionImplementation::
487 ProcessReverseStreamImplementation1) ||
488 (test_config_.aec_type !=
489 AecType::BasicWebRtcAecSettingsWithAecMobile)) {
490 render_thread_state_.input_sample_rate_hz =
491 test_config_.initial_sample_rate_hz;
492 render_thread_state_.output_sample_rate_hz =
493 test_config_.initial_sample_rate_hz;
494 }
495
496 // Prepare the audioframe data and metadata
497 render_thread_state_.input_samples_per_channel =
498 render_thread_state_.input_sample_rate_hz *
499 AudioProcessing::kChunkSizeMs / 1000;
500 render_thread_state_.frame.sample_rate_hz_ =
501 render_thread_state_.input_sample_rate_hz;
502 render_thread_state_.frame.num_channels_ =
503 render_thread_state_.input_number_of_channels;
504 render_thread_state_.frame.samples_per_channel_ =
505 render_thread_state_.input_samples_per_channel;
506 memset(render_thread_state_.frame.data_, 0,
507 render_thread_state_.input_samples_per_channel *
508 sizeof(render_thread_state_.frame.data_[0]));
509 PopulateAudioFrame(&render_thread_state_.frame, kRenderInputFixLevel);
510
511 // Prepare the float audio input data and metadata.
512 render_thread_state_.input_stream_config.set_sample_rate_hz(
513 render_thread_state_.input_sample_rate_hz);
514 render_thread_state_.input_stream_config.set_num_channels(
515 render_thread_state_.input_number_of_channels);
516 render_thread_state_.input_stream_config.set_has_keyboard(false);
517 PopulateAudioFrame(&render_thread_state_.input_frame[0],
518 kRenderInputFloatLevel,
519 render_thread_state_.input_number_of_channels,
520 render_thread_state_.input_samples_per_channel);
521 render_thread_state_.input_channel_layout =
522 (render_thread_state_.input_number_of_channels == 1
523 ? AudioProcessing::ChannelLayout::kMono
524 : AudioProcessing::ChannelLayout::kStereo);
525
526 // Prepare the float audio output data and metadata.
527 render_thread_state_.output_samples_per_channel =
528 render_thread_state_.output_sample_rate_hz *
529 AudioProcessing::kChunkSizeMs / 1000;
530 render_thread_state_.output_stream_config.set_sample_rate_hz(
531 render_thread_state_.output_sample_rate_hz);
532 render_thread_state_.output_stream_config.set_num_channels(
533 render_thread_state_.output_number_of_channels);
534 render_thread_state_.output_stream_config.set_has_keyboard(false);
535 render_thread_state_.output_channel_layout =
536 (render_thread_state_.output_number_of_channels == 1
537 ? AudioProcessing::ChannelLayout::kMono
538 : AudioProcessing::ChannelLayout::kStereo);
539 }
540
541 void PrepareCaptureFrame() {
542 // Restrict to a common fixed sample rate if the AudioFrame
543 // interface is used.
544 if (test_config_.capture_api_function ==
545 CaptureApiFunctionImplementation::ProcessStreamImplementation1) {
546 capture_thread_state_.input_sample_rate_hz =
547 test_config_.initial_sample_rate_hz;
548 capture_thread_state_.output_sample_rate_hz =
549 test_config_.initial_sample_rate_hz;
550 }
551
552 // Prepare the audioframe data and metadata.
553 capture_thread_state_.input_samples_per_channel =
554 capture_thread_state_.input_sample_rate_hz *
555 AudioProcessing::kChunkSizeMs / 1000;
556 capture_thread_state_.frame.sample_rate_hz_ =
557 capture_thread_state_.input_sample_rate_hz;
558 capture_thread_state_.frame.num_channels_ =
559 capture_thread_state_.input_number_of_channels;
560 capture_thread_state_.frame.samples_per_channel_ =
561 capture_thread_state_.input_samples_per_channel;
562 memset(capture_thread_state_.frame.data_, 0,
563 capture_thread_state_.input_samples_per_channel *
564 sizeof(capture_thread_state_.frame.data_[0]));
565 PopulateAudioFrame(&capture_thread_state_.frame, kCaptureInputFixLevel);
566
567 // Prepare the float audio input data and metadata.
568 capture_thread_state_.input_stream_config.set_sample_rate_hz(
569 capture_thread_state_.input_sample_rate_hz);
570 capture_thread_state_.input_stream_config.set_num_channels(
571 capture_thread_state_.input_number_of_channels);
572 capture_thread_state_.input_stream_config.set_has_keyboard(false);
573 PopulateAudioFrame(&capture_thread_state_.input_frame[0],
574 kCaptureInputFloatLevel,
575 capture_thread_state_.input_number_of_channels,
576 capture_thread_state_.input_samples_per_channel);
577 capture_thread_state_.input_channel_layout =
578 (capture_thread_state_.input_number_of_channels == 1
579 ? AudioProcessing::ChannelLayout::kMonoAndKeyboard
580 : AudioProcessing::ChannelLayout::kStereoAndKeyboard);
581
582 // Prepare the float audio output data and metadata.
583 capture_thread_state_.output_samples_per_channel =
584 capture_thread_state_.output_sample_rate_hz *
585 AudioProcessing::kChunkSizeMs / 1000;
586 capture_thread_state_.output_stream_config.set_sample_rate_hz(
587 capture_thread_state_.output_sample_rate_hz);
588 capture_thread_state_.output_stream_config.set_num_channels(
589 capture_thread_state_.output_number_of_channels);
590 capture_thread_state_.output_stream_config.set_has_keyboard(false);
591 capture_thread_state_.output_channel_layout =
592 (capture_thread_state_.output_number_of_channels == 1
593 ? AudioProcessing::ChannelLayout::kMono
594 : AudioProcessing::ChannelLayout::kStereo);
595 }
596
597 // Applies any render capture APM API calls and audio stream characteristics
598 // specified by the scheme for the test.
599 void ApplyRenderRuntimeSettingScheme() {
600 const int render_count_local = [this] {
601 rtc::CritScope cs(&crit_);
602 return shared_thread_counter_state_.render_count;
603 }();
604
605 // Update the number of channels and sample rates for the input and output.
606 // Note that the counts frequencies for when to set parameters
607 // are set using prime numbers in order to ensure that the
608 // permutation scheme in the parameter setting changes.
609 switch (test_config_.runtime_parameter_setting_scheme) {
610 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
611 if (render_count_local == 0)
612 render_thread_state_.input_sample_rate_hz = 16000;
613 else if (render_count_local % 47 == 0)
614 render_thread_state_.input_sample_rate_hz = 32000;
615 else if (render_count_local % 71 == 0)
616 render_thread_state_.input_sample_rate_hz = 48000;
617 else if (render_count_local % 79 == 0)
618 render_thread_state_.input_sample_rate_hz = 16000;
619 else if (render_count_local % 83 == 0)
620 render_thread_state_.input_sample_rate_hz = 8000;
621
622 if (render_count_local == 0)
623 render_thread_state_.input_number_of_channels = 1;
624 else if (render_count_local % 4 == 0)
625 render_thread_state_.input_number_of_channels =
626 (render_thread_state_.input_number_of_channels == 1 ? 2 : 1);
627
628 if (render_count_local == 0)
629 render_thread_state_.output_sample_rate_hz = 16000;
630 else if (render_count_local % 17 == 0)
631 render_thread_state_.output_sample_rate_hz = 32000;
632 else if (render_count_local % 19 == 0)
633 render_thread_state_.output_sample_rate_hz = 48000;
634 else if (render_count_local % 29 == 0)
635 render_thread_state_.output_sample_rate_hz = 16000;
636 else if (render_count_local % 61 == 0)
637 render_thread_state_.output_sample_rate_hz = 8000;
638
639 if (render_count_local == 0)
640 render_thread_state_.output_number_of_channels = 1;
641 else if (render_count_local % 8 == 0)
642 render_thread_state_.output_number_of_channels =
643 (render_thread_state_.output_number_of_channels == 1 ? 2 : 1);
644 break;
645 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
646 if (render_count_local == 0) {
647 render_thread_state_.input_number_of_channels = 1;
648 render_thread_state_.input_sample_rate_hz = 16000;
649 render_thread_state_.output_number_of_channels = 1;
650 render_thread_state_.output_sample_rate_hz = 16000;
651 } else {
652 render_thread_state_.input_number_of_channels =
653 (render_thread_state_.input_number_of_channels == 1 ? 2 : 1);
654 if (render_thread_state_.input_sample_rate_hz == 8000)
655 render_thread_state_.input_sample_rate_hz = 16000;
656 else if (render_thread_state_.input_sample_rate_hz == 16000)
657 render_thread_state_.input_sample_rate_hz = 32000;
658 else if (render_thread_state_.input_sample_rate_hz == 32000)
659 render_thread_state_.input_sample_rate_hz = 48000;
660 else if (render_thread_state_.input_sample_rate_hz == 48000)
661 render_thread_state_.input_sample_rate_hz = 8000;
662
663 render_thread_state_.output_number_of_channels =
664 (render_thread_state_.output_number_of_channels == 1 ? 2 : 1);
665 if (render_thread_state_.output_sample_rate_hz == 8000)
666 render_thread_state_.output_sample_rate_hz = 16000;
667 else if (render_thread_state_.output_sample_rate_hz == 16000)
668 render_thread_state_.output_sample_rate_hz = 32000;
669 else if (render_thread_state_.output_sample_rate_hz == 32000)
670 render_thread_state_.output_sample_rate_hz = 48000;
671 else if (render_thread_state_.output_sample_rate_hz == 48000)
672 render_thread_state_.output_sample_rate_hz = 8000;
673 }
674 break;
675 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
676 if (render_count_local == 0) {
677 render_thread_state_.input_sample_rate_hz = 16000;
678 render_thread_state_.input_number_of_channels = 1;
679 render_thread_state_.output_sample_rate_hz = 16000;
680 render_thread_state_.output_number_of_channels = 1;
681 }
682 break;
683 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
684 if (render_count_local == 0) {
685 render_thread_state_.input_sample_rate_hz = 16000;
686 render_thread_state_.input_number_of_channels = 2;
687 render_thread_state_.output_sample_rate_hz = 16000;
688 render_thread_state_.output_number_of_channels = 2;
689 }
690
691 break;
692 default:
693 assert(false);
694 }
695
696 // Restric the number of output channels not to exceed
697 // the number of input channels.
698 render_thread_state_.output_number_of_channels =
699 std::min(render_thread_state_.output_number_of_channels,
700 render_thread_state_.input_number_of_channels);
701 }
702
703 // Applies any runtime capture APM API calls and audio stream characteristics
704 // specified by the scheme for the test.
705 void ApplyCaptureRuntimeSettingScheme() {
706 const int capture_count_local = [this] {
707 rtc::CritScope cs(&crit_);
708 return shared_thread_counter_state_.capture_count;
709 }();
710
711 // Update the number of channels and sample rates for the input and output.
712 // Note that the counts frequencies for when to set parameters
713 // are set using prime numbers in order to ensure that the
714 // permutation scheme in the parameter setting changes.
715 switch (test_config_.runtime_parameter_setting_scheme) {
716 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
717 if (capture_count_local == 0)
718 capture_thread_state_.input_sample_rate_hz = 16000;
719 else if (capture_count_local % 11 == 0)
720 capture_thread_state_.input_sample_rate_hz = 32000;
721 else if (capture_count_local % 73 == 0)
722 capture_thread_state_.input_sample_rate_hz = 48000;
723 else if (capture_count_local % 89 == 0)
724 capture_thread_state_.input_sample_rate_hz = 16000;
725 else if (capture_count_local % 97 == 0)
726 capture_thread_state_.input_sample_rate_hz = 8000;
727
728 if (capture_count_local == 0)
729 capture_thread_state_.input_number_of_channels = 1;
730 else if (capture_count_local % 4 == 0)
731 capture_thread_state_.input_number_of_channels =
732 (capture_thread_state_.input_number_of_channels == 1 ? 2 : 1);
733
734 if (capture_count_local == 0)
735 capture_thread_state_.output_sample_rate_hz = 16000;
736 else if (capture_count_local % 5 == 0)
737 capture_thread_state_.output_sample_rate_hz = 32000;
738 else if (capture_count_local % 47 == 0)
739 capture_thread_state_.output_sample_rate_hz = 48000;
740 else if (capture_count_local % 53 == 0)
741 capture_thread_state_.output_sample_rate_hz = 16000;
742 else if (capture_count_local % 71 == 0)
743 capture_thread_state_.output_sample_rate_hz = 8000;
744
745 if (capture_count_local == 0)
746 capture_thread_state_.output_number_of_channels = 1;
747 else if (capture_count_local % 8 == 0)
748 capture_thread_state_.output_number_of_channels =
749 (capture_thread_state_.output_number_of_channels == 1 ? 2 : 1);
750 break;
751 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
752 if (capture_count_local % 2 == 0) {
753 capture_thread_state_.input_number_of_channels = 1;
754 capture_thread_state_.input_sample_rate_hz = 16000;
755 capture_thread_state_.output_number_of_channels = 1;
756 capture_thread_state_.output_sample_rate_hz = 16000;
757 } else {
758 capture_thread_state_.input_number_of_channels =
759 (capture_thread_state_.input_number_of_channels == 1 ? 2 : 1);
760 if (capture_thread_state_.input_sample_rate_hz == 8000)
761 capture_thread_state_.input_sample_rate_hz = 16000;
762 else if (capture_thread_state_.input_sample_rate_hz == 16000)
763 capture_thread_state_.input_sample_rate_hz = 32000;
764 else if (capture_thread_state_.input_sample_rate_hz == 32000)
765 capture_thread_state_.input_sample_rate_hz = 48000;
766 else if (capture_thread_state_.input_sample_rate_hz == 48000)
767 capture_thread_state_.input_sample_rate_hz = 8000;
768
769 capture_thread_state_.output_number_of_channels =
770 (capture_thread_state_.output_number_of_channels == 1 ? 2 : 1);
771 if (capture_thread_state_.output_sample_rate_hz == 8000)
772 capture_thread_state_.output_sample_rate_hz = 16000;
773 else if (capture_thread_state_.output_sample_rate_hz == 16000)
774 capture_thread_state_.output_sample_rate_hz = 32000;
775 else if (capture_thread_state_.output_sample_rate_hz == 32000)
776 capture_thread_state_.output_sample_rate_hz = 48000;
777 else if (capture_thread_state_.output_sample_rate_hz == 48000)
778 capture_thread_state_.output_sample_rate_hz = 8000;
779 }
780 break;
781 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
782 if (capture_count_local == 0) {
783 capture_thread_state_.input_sample_rate_hz = 16000;
784 capture_thread_state_.input_number_of_channels = 1;
785 capture_thread_state_.output_sample_rate_hz = 16000;
786 capture_thread_state_.output_number_of_channels = 1;
787 }
788 break;
789 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
790 if (capture_count_local == 0) {
791 capture_thread_state_.input_sample_rate_hz = 16000;
792 capture_thread_state_.input_number_of_channels = 2;
793 capture_thread_state_.output_sample_rate_hz = 16000;
794 capture_thread_state_.output_number_of_channels = 2;
795 }
796
797 break;
798 default:
799 assert(false);
800 }
801
802 // Call any specified runtime APM setter and
803 // getter calls.
804 switch (test_config_.runtime_parameter_setting_scheme) {
805 case RuntimeParameterSettingScheme::SparseStreamMetadataChangeScheme:
806 case RuntimeParameterSettingScheme::FixedMonoStreamMetadataScheme:
807 break;
808 case RuntimeParameterSettingScheme::ExtremeStreamMetadataChangeScheme:
809 case RuntimeParameterSettingScheme::FixedStereoStreamMetadataScheme:
810 if ((capture_count_local % 2) == 0) {
811 ASSERT_EQ(AudioProcessing::Error::kNoError,
812 apm_->set_stream_delay_ms(30));
813 apm_->set_stream_key_pressed(true);
814 apm_->set_output_will_be_muted(true);
815 apm_->set_delay_offset_ms(15);
816 EXPECT_EQ(apm_->delay_offset_ms(), 15);
817 EXPECT_GE(apm_->num_reverse_channels(), 0);
818 EXPECT_LE(apm_->num_reverse_channels(), 2);
819 } else {
820 ASSERT_EQ(AudioProcessing::Error::kNoError,
821 apm_->set_stream_delay_ms(50));
822 apm_->set_stream_key_pressed(false);
823 apm_->set_output_will_be_muted(false);
824 apm_->set_delay_offset_ms(20);
825 EXPECT_EQ(apm_->delay_offset_ms(), 20);
826 apm_->delay_offset_ms();
827 apm_->num_reverse_channels();
828 EXPECT_GE(apm_->num_reverse_channels(), 0);
829 EXPECT_LE(apm_->num_reverse_channels(), 2);
830 }
831 break;
832 default:
833 FAIL();
834 }
835
836 // Restric the number of output channels not to exceed
837 // the number of input channels.
838 capture_thread_state_.output_number_of_channels =
839 std::min(capture_thread_state_.output_number_of_channels,
840 capture_thread_state_.input_number_of_channels);
841 }
842
843 // Makes the render side processing API call.
844 void CallRenderSide() {
845 // Prepare a proper render side processing API call input.
846 PrepareRenderFrame();
847
848 // Call the specified render side API processing method.
849 int result = AudioProcessing::kNoError;
850 switch (test_config_.render_api_function) {
851 case RenderApiFunctionImplementation::ProcessReverseStreamImplementation1:
852 result = apm_->ProcessReverseStream(&render_thread_state_.frame);
853 break;
854 case RenderApiFunctionImplementation::ProcessReverseStreamImplementation2:
855 result = apm_->ProcessReverseStream(
856 &render_thread_state_.input_frame[0],
857 render_thread_state_.input_stream_config,
858 render_thread_state_.output_stream_config,
859 &render_thread_state_.output_frame[0]);
860 break;
861 case RenderApiFunctionImplementation::AnalyzeReverseStreamImplementation1:
862 result = apm_->AnalyzeReverseStream(&render_thread_state_.frame);
863 break;
864 case RenderApiFunctionImplementation::AnalyzeReverseStreamImplementation2:
865 result = apm_->AnalyzeReverseStream(
866 &render_thread_state_.input_frame[0],
867 render_thread_state_.input_samples_per_channel,
868 render_thread_state_.input_sample_rate_hz,
869 render_thread_state_.input_channel_layout);
870 break;
871 default:
872 assert(false);
873 }
874
875 // Check the return code for error.
876 ASSERT_EQ(AudioProcessing::kNoError, result);
877 }
878
879 // Implements the callback functionality for the capture thread.
880 bool CaptureThreadImpl() {
881 // Sleep a random time to simulate thread jitter.
882 SleepRandomMs(3);
883
884 // End the test early if a fatal failure (ASSERT_*) has occurred.
885 if (HasFatalFailure())
886 test_complete_->Set();
887
888 // Ensure that there are not more capture side calls than render side
889 // calls.
890 int frame_counter_difference;
891 do {
892 {
893 rtc::CritScope cs(&crit_);
894 frame_counter_difference = shared_thread_counter_state_.capture_count -
895 shared_thread_counter_state_.render_count;
896 }
897 if (frame_counter_difference > 0)
898 SleepMs(1);
899 } while (frame_counter_difference > 0);
900
901 // Apply any specified capture side APM non-processing runtime calls.
902 ApplyCaptureRuntimeSettingScheme();
903
904 // Apply the capture side processing call.
905 CallCaptureSide();
906
907 // Increase the number of capture-side calls.
908 {
909 rtc::CritScope cs(&crit_);
910 shared_thread_counter_state_.capture_count++;
911 }
912
913 // Check if the test is done.
914 if (TestDone())
915 test_complete_->Set();
916
917 // Flag that the capture side has been called at least once
918 // (needed to ensure that a capture call has been done
919 // before the first render call is performed (implicitly
920 // required by the APM API).
921 {
922 rtc::CritScope cs(&crit_initial_sync_);
923 shared_thread_init_state_.capture_side_called = true;
924 }
925
926 return true;
927 }
928
929 // Start the threads used in the test.
930 void StartThreads() {
931 ASSERT_TRUE(render_thread_->Start());
932 render_thread_->SetPriority(kRealtimePriority);
933 ASSERT_TRUE(capture_thread_->Start());
934 capture_thread_->SetPriority(kRealtimePriority);
935 ASSERT_TRUE(stats_thread_->Start());
936 stats_thread_->SetPriority(kNormalPriority);
937 }
938
939 // Event handler for the test.
940 const rtc::scoped_ptr<EventWrapper> test_complete_;
941
942 // Thread related variables.
943 rtc::CriticalSection crit_;
944 rtc::CriticalSection crit_initial_sync_;
945 rtc::scoped_ptr<ThreadWrapper> render_thread_;
946 rtc::scoped_ptr<ThreadWrapper> capture_thread_;
947 rtc::scoped_ptr<ThreadWrapper> stats_thread_;
948 mutable test::Random rand_gen_;
949
950 // The APM object.
951 rtc::scoped_ptr<AudioProcessing> apm_;
952
953 // The test configuration.
954 TestConfig test_config_;
955
956 // Variables shared by the threads during the whole test.
957 struct {
958 int render_count = 0;
959 int capture_count = 0;
960 } shared_thread_counter_state_ GUARDED_BY(crit_);
961
962 // Variable shared by the threads during the initialization phase.
963 struct {
964 bool capture_side_called;
965 } shared_thread_init_state_ GUARDED_BY(crit_initial_sync_);
966
967 // Variables only used on the capture side thread.
968 struct {
969 // Variables related to the capture side audio data and formats.
970 AudioFrame frame;
971 std::vector<float*> output_frame;
972 std::vector<float> output_frame_channels;
973 AudioProcessing::ChannelLayout output_channel_layout;
974 int input_sample_rate_hz = 16000;
975 int input_number_of_channels;
976 std::vector<float*> input_frame;
977 std::vector<float> input_framechannels_;
978 AudioProcessing::ChannelLayout input_channel_layout;
979 int output_sample_rate_hz = 16000;
980 int output_number_of_channels;
981 StreamConfig input_stream_config;
982 StreamConfig output_stream_config;
983 int input_samples_per_channel;
984 int output_samples_per_channel;
985 } capture_thread_state_;
986
987 // Variables only used on the render side thread.
988 struct {
989 bool first_render_side_call_ = true;
990
991 // Variables related to the render side audio data and formats.
992 AudioFrame frame;
993 std::vector<float*> output_frame;
994 std::vector<float> output_frame_channels;
995 AudioProcessing::ChannelLayout output_channel_layout;
996 int input_sample_rate_hz = 16000;
997 int input_number_of_channels;
998 std::vector<float*> input_frame;
999 std::vector<float> input_frame_channels;
1000 AudioProcessing::ChannelLayout input_channel_layout;
1001 int output_sample_rate_hz = 16000;
1002 int output_number_of_channels;
1003 StreamConfig input_stream_config;
1004 StreamConfig output_stream_config;
1005 int input_samples_per_channel;
1006 int output_samples_per_channel;
1007 } render_thread_state_;
1008 };
1009
1010 const float AudioProcessingImpLockTest::kRenderInputFloatLevel = 0.5f;
1011 const float AudioProcessingImpLockTest::kCaptureInputFloatLevel = 0.03125f;
1012
1013 } // anonymous namespace
1014
1015 TEST_P(AudioProcessingImpLockTest, LockTest) {
1016 // Run test and verify that it did not time out.
1017 ASSERT_EQ(kEventSignaled, RunTest());
1018 }
1019
1020 // Instantiate tests from the extreme test configuration set.
1021 INSTANTIATE_TEST_CASE_P(
1022 DISABLED_AudioProcessingImpLockExtensive,
1023 AudioProcessingImpLockTest,
1024 ::testing::ValuesIn(
1025 AudioProcessingImpLockTest::GenerateExtensiveTestConfigs()));
1026
1027 INSTANTIATE_TEST_CASE_P(
1028 AudioProcessingImpLockBrief,
1029 AudioProcessingImpLockTest,
1030 ::testing::ValuesIn(
1031 AudioProcessingImpLockTest::GenerateBriefTestConfigs()));
1032
1033 } // namespace webrtc
OLDNEW
« no previous file with comments | « no previous file | webrtc/modules/modules.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698