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

Side by Side Diff: webrtc/modules/audio_processing/test/process_test.cc

Issue 2425583002: Removed the deprecated audioproc executable (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/modules/audio_processing/audio_processing_tests.gypi ('k') | no next file » | 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) 2012 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 <math.h>
12 #include <stdio.h>
13 #include <string.h>
14 #ifdef WEBRTC_ANDROID
15 #include <sys/stat.h>
16 #endif
17
18 #include <algorithm>
19 #include <memory>
20
21 #include "webrtc/base/format_macros.h"
22 #include "webrtc/base/ignore_wundef.h"
23 #include "webrtc/base/timeutils.h"
24 #include "webrtc/modules/audio_processing/include/audio_processing.h"
25 #include "webrtc/modules/audio_processing/include/config.h"
26 #include "webrtc/modules/audio_processing/test/protobuf_utils.h"
27 #include "webrtc/modules/audio_processing/test/test_utils.h"
28 #include "webrtc/modules/include/module_common_types.h"
29 #include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
30 #include "webrtc/test/gtest.h"
31 #include "webrtc/test/testsupport/fileutils.h"
32 #include "webrtc/test/testsupport/perf_test.h"
33
34 RTC_PUSH_IGNORING_WUNDEF()
35 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD
36 #include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
37 #else
38 #include "webrtc/modules/audio_processing/debug.pb.h"
39 #endif
40 RTC_POP_IGNORING_WUNDEF()
41
42 namespace webrtc {
43
44 using webrtc::audioproc::Event;
45 using webrtc::audioproc::Init;
46 using webrtc::audioproc::ReverseStream;
47 using webrtc::audioproc::Stream;
48
49 namespace {
50
51 void PrintStat(const AudioProcessing::Statistic& stat) {
52 printf("%d, %d, %d\n", stat.average,
53 stat.maximum,
54 stat.minimum);
55 }
56
57 void usage() {
58 printf(
59 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
60 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
61 printf(
62 "process_test is a test application for AudioProcessing.\n\n"
63 "When a protobuf debug file is available, specify it with -pb. Alternately,\n"
64 "when -ir or -i is used, the specified files will be processed directly in\n"
65 "a simulation mode. Otherwise the full set of legacy test files is expected\n"
66 "to be present in the working directory. OUT_FILE should be specified\n"
67 "without extension to support both raw and wav output.\n\n");
68 printf("Options\n");
69 printf("General configuration (only used for the simulation mode):\n");
70 printf(" -fs SAMPLE_RATE_HZ\n");
71 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
72 printf(" -rch REVERSE_CHANNELS\n");
73 printf("\n");
74 printf("Component configuration:\n");
75 printf(
76 "All components are disabled by default. Each block below begins with a\n"
77 "flag to enable the component with default settings. The subsequent flags\n"
78 "in the block are used to provide configuration settings.\n");
79 printf("\n -aec Echo cancellation\n");
80 printf(" --drift_compensation\n");
81 printf(" --no_drift_compensation\n");
82 printf(" --no_echo_metrics\n");
83 printf(" --no_delay_logging\n");
84 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
85 printf(" --extended_filter\n");
86 printf(" --no_reported_delay\n");
87 printf(" --aec3\n");
88 printf(" --refined_adaptive_filter\n");
89 printf("\n -aecm Echo control mobile\n");
90 printf(" --aecm_echo_path_in_file FILE\n");
91 printf(" --aecm_echo_path_out_file FILE\n");
92 printf(" --no_comfort_noise\n");
93 printf(" --routing_mode MODE [0 - 4]\n");
94 printf("\n -agc Gain control\n");
95 printf(" --analog\n");
96 printf(" --adaptive_digital\n");
97 printf(" --fixed_digital\n");
98 printf(" --target_level LEVEL\n");
99 printf(" --compression_gain GAIN\n");
100 printf(" --limiter\n");
101 printf(" --no_limiter\n");
102 printf("\n -hpf High pass filter\n");
103 printf("\n -ns Noise suppression\n");
104 printf(" --ns_low\n");
105 printf(" --ns_moderate\n");
106 printf(" --ns_high\n");
107 printf(" --ns_very_high\n");
108 printf(" --ns_prob_file FILE\n");
109 printf("\n -vad Voice activity detection\n");
110 printf(" --vad_out_file FILE\n");
111 printf("\n -expns Experimental noise suppression\n");
112 printf("\n Level metrics (enabled by default)\n");
113 printf(" --no_level_metrics\n");
114 printf(" --level_control\n");
115 printf("\n");
116 printf("Modifiers:\n");
117 printf(" --noasm Disable SSE optimization.\n");
118 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
119 printf(" --delay DELAY Override input delay with DELAY ms.\n");
120 printf(" --perf Measure performance.\n");
121 printf(" --quiet Suppress text output.\n");
122 printf(" --no_progress Suppress progress.\n");
123 printf(" --raw_output Raw output instead of WAV file.\n");
124 printf(" --debug_file FILE Dump a debug recording.\n");
125 }
126
127 static float MicLevel2Gain(int level) {
128 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
129 }
130
131 static void SimulateMic(int mic_level, AudioFrame* frame) {
132 mic_level = std::min(std::max(mic_level, 0), 255);
133 float mic_gain = MicLevel2Gain(mic_level);
134 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
135 float v;
136 for (int n = 0; n < num_samples; n++) {
137 v = floor(frame->data_[n] * mic_gain + 0.5);
138 v = std::max(std::min(32767.0f, v), -32768.0f);
139 frame->data_[n] = static_cast<int16_t>(v);
140 }
141 }
142
143 // void function for gtest.
144 void void_main(int argc, char* argv[]) {
145 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
146 usage();
147 return;
148 }
149
150 if (argc < 2) {
151 printf("Did you mean to run without arguments?\n");
152 printf("Try `process_test --help' for more information.\n\n");
153 }
154
155 std::unique_ptr<AudioProcessing> apm(AudioProcessing::Create());
156 ASSERT_TRUE(apm.get() != NULL);
157
158 const char* pb_filename = NULL;
159 const char* far_filename = NULL;
160 const char* near_filename = NULL;
161 std::string out_filename;
162 const char* vad_out_filename = NULL;
163 const char* ns_prob_filename = NULL;
164 const char* aecm_echo_path_in_filename = NULL;
165 const char* aecm_echo_path_out_filename = NULL;
166
167 int32_t sample_rate_hz = 16000;
168
169 size_t num_capture_input_channels = 1;
170 size_t num_capture_output_channels = 1;
171 size_t num_render_channels = 1;
172
173 int samples_per_channel = sample_rate_hz / 100;
174
175 bool simulating = false;
176 bool perf_testing = false;
177 bool verbose = true;
178 bool progress = true;
179 bool raw_output = false;
180 int extra_delay_ms = 0;
181 int override_delay_ms = 0;
182 Config config;
183 AudioProcessing::Config apm_config;
184
185 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
186 for (int i = 1; i < argc; i++) {
187 if (strcmp(argv[i], "-pb") == 0) {
188 i++;
189 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
190 pb_filename = argv[i];
191
192 } else if (strcmp(argv[i], "-ir") == 0) {
193 i++;
194 ASSERT_LT(i, argc) << "Specify filename after -ir";
195 far_filename = argv[i];
196 simulating = true;
197
198 } else if (strcmp(argv[i], "-i") == 0) {
199 i++;
200 ASSERT_LT(i, argc) << "Specify filename after -i";
201 near_filename = argv[i];
202 simulating = true;
203
204 } else if (strcmp(argv[i], "-o") == 0) {
205 i++;
206 ASSERT_LT(i, argc) << "Specify filename without extension after -o";
207 out_filename = argv[i];
208
209 } else if (strcmp(argv[i], "-fs") == 0) {
210 i++;
211 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
212 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
213 samples_per_channel = sample_rate_hz / 100;
214
215 } else if (strcmp(argv[i], "-ch") == 0) {
216 i++;
217 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
218 ASSERT_EQ(1, sscanf(argv[i], "%" PRIuS, &num_capture_input_channels));
219 i++;
220 ASSERT_EQ(1, sscanf(argv[i], "%" PRIuS, &num_capture_output_channels));
221
222 } else if (strcmp(argv[i], "-rch") == 0) {
223 i++;
224 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
225 ASSERT_EQ(1, sscanf(argv[i], "%" PRIuS, &num_render_channels));
226
227 } else if (strcmp(argv[i], "-aec") == 0) {
228 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
229 ASSERT_EQ(apm->kNoError,
230 apm->echo_cancellation()->enable_metrics(true));
231 ASSERT_EQ(apm->kNoError,
232 apm->echo_cancellation()->enable_delay_logging(true));
233
234 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
235 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
236 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
237 // why it can give better performance despite passing zeros.
238 ASSERT_EQ(apm->kNoError,
239 apm->echo_cancellation()->enable_drift_compensation(true));
240 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
241 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
242 ASSERT_EQ(apm->kNoError,
243 apm->echo_cancellation()->enable_drift_compensation(false));
244
245 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
246 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
247 ASSERT_EQ(apm->kNoError,
248 apm->echo_cancellation()->enable_metrics(false));
249
250 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
251 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
252 ASSERT_EQ(apm->kNoError,
253 apm->echo_cancellation()->enable_delay_logging(false));
254
255 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
256 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
257
258 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
259 i++;
260 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
261 int suppression_level;
262 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
263 ASSERT_EQ(apm->kNoError,
264 apm->echo_cancellation()->set_suppression_level(
265 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
266 suppression_level)));
267
268 } else if (strcmp(argv[i], "--level_control") == 0) {
269 apm_config.level_controller.enabled = true;
270 } else if (strcmp(argv[i], "--extended_filter") == 0) {
271 config.Set<ExtendedFilter>(new ExtendedFilter(true));
272
273 } else if (strcmp(argv[i], "--no_reported_delay") == 0) {
274 config.Set<DelayAgnostic>(new DelayAgnostic(true));
275
276 } else if (strcmp(argv[i], "--delay_agnostic") == 0) {
277 config.Set<DelayAgnostic>(new DelayAgnostic(true));
278
279 } else if (strcmp(argv[i], "--aec3") == 0) {
280 config.Set<EchoCanceller3>(new EchoCanceller3(true));
281
282 } else if (strcmp(argv[i], "--refined_adaptive_filter") == 0) {
283 config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(true));
284
285 } else if (strcmp(argv[i], "-aecm") == 0) {
286 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
287
288 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
289 i++;
290 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
291 aecm_echo_path_in_filename = argv[i];
292
293 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
294 i++;
295 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
296 aecm_echo_path_out_filename = argv[i];
297
298 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
299 ASSERT_EQ(apm->kNoError,
300 apm->echo_control_mobile()->enable_comfort_noise(false));
301
302 } else if (strcmp(argv[i], "--routing_mode") == 0) {
303 i++;
304 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
305 int routing_mode;
306 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
307 ASSERT_EQ(apm->kNoError,
308 apm->echo_control_mobile()->set_routing_mode(
309 static_cast<webrtc::EchoControlMobile::RoutingMode>(
310 routing_mode)));
311
312 } else if (strcmp(argv[i], "-agc") == 0) {
313 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
314
315 } else if (strcmp(argv[i], "--analog") == 0) {
316 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
317 ASSERT_EQ(apm->kNoError,
318 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
319
320 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
321 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
322 ASSERT_EQ(apm->kNoError,
323 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
324
325 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
326 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
327 ASSERT_EQ(apm->kNoError,
328 apm->gain_control()->set_mode(GainControl::kFixedDigital));
329
330 } else if (strcmp(argv[i], "--target_level") == 0) {
331 i++;
332 int level;
333 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
334
335 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
336 ASSERT_EQ(apm->kNoError,
337 apm->gain_control()->set_target_level_dbfs(level));
338
339 } else if (strcmp(argv[i], "--compression_gain") == 0) {
340 i++;
341 int gain;
342 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
343
344 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
345 ASSERT_EQ(apm->kNoError,
346 apm->gain_control()->set_compression_gain_db(gain));
347
348 } else if (strcmp(argv[i], "--limiter") == 0) {
349 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
350 ASSERT_EQ(apm->kNoError,
351 apm->gain_control()->enable_limiter(true));
352
353 } else if (strcmp(argv[i], "--no_limiter") == 0) {
354 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
355 ASSERT_EQ(apm->kNoError,
356 apm->gain_control()->enable_limiter(false));
357
358 } else if (strcmp(argv[i], "-hpf") == 0) {
359 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
360
361 } else if (strcmp(argv[i], "-ns") == 0) {
362 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
363
364 } else if (strcmp(argv[i], "--ns_low") == 0) {
365 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
366 ASSERT_EQ(apm->kNoError,
367 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
368
369 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
370 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
371 ASSERT_EQ(apm->kNoError,
372 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
373
374 } else if (strcmp(argv[i], "--ns_high") == 0) {
375 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
376 ASSERT_EQ(apm->kNoError,
377 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
378
379 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
380 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
381 ASSERT_EQ(apm->kNoError,
382 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
383
384 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
385 i++;
386 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
387 ns_prob_filename = argv[i];
388
389 } else if (strcmp(argv[i], "-vad") == 0) {
390 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
391
392 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
393 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
394 ASSERT_EQ(apm->kNoError,
395 apm->voice_detection()->set_likelihood(
396 VoiceDetection::kVeryLowLikelihood));
397
398 } else if (strcmp(argv[i], "--vad_low") == 0) {
399 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
400 ASSERT_EQ(apm->kNoError,
401 apm->voice_detection()->set_likelihood(
402 VoiceDetection::kLowLikelihood));
403
404 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
405 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
406 ASSERT_EQ(apm->kNoError,
407 apm->voice_detection()->set_likelihood(
408 VoiceDetection::kModerateLikelihood));
409
410 } else if (strcmp(argv[i], "--vad_high") == 0) {
411 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
412 ASSERT_EQ(apm->kNoError,
413 apm->voice_detection()->set_likelihood(
414 VoiceDetection::kHighLikelihood));
415
416 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
417 i++;
418 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
419 vad_out_filename = argv[i];
420
421 } else if (strcmp(argv[i], "-expns") == 0) {
422 config.Set<ExperimentalNs>(new ExperimentalNs(true));
423
424 } else if (strcmp(argv[i], "--noasm") == 0) {
425 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
426 // We need to reinitialize here if components have already been enabled.
427 ASSERT_EQ(apm->kNoError, apm->Initialize());
428
429 } else if (strcmp(argv[i], "--add_delay") == 0) {
430 i++;
431 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
432
433 } else if (strcmp(argv[i], "--delay") == 0) {
434 i++;
435 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
436
437 } else if (strcmp(argv[i], "--perf") == 0) {
438 perf_testing = true;
439
440 } else if (strcmp(argv[i], "--quiet") == 0) {
441 verbose = false;
442 progress = false;
443
444 } else if (strcmp(argv[i], "--no_progress") == 0) {
445 progress = false;
446
447 } else if (strcmp(argv[i], "--raw_output") == 0) {
448 raw_output = true;
449
450 } else if (strcmp(argv[i], "--debug_file") == 0) {
451 i++;
452 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
453 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i], -1));
454 } else {
455 FAIL() << "Unrecognized argument " << argv[i];
456 }
457 }
458 apm->ApplyConfig(apm_config);
459 apm->SetExtraOptions(config);
460
461 // If we're reading a protobuf file, ensure a simulation hasn't also
462 // been requested (which makes no sense...)
463 ASSERT_FALSE(pb_filename && simulating);
464
465 if (verbose) {
466 printf("Sample rate: %d Hz\n", sample_rate_hz);
467 printf("Primary channels: %" PRIuS " (in), %" PRIuS " (out)\n",
468 num_capture_input_channels,
469 num_capture_output_channels);
470 printf("Reverse channels: %" PRIuS "\n", num_render_channels);
471 }
472
473 const std::string out_path = webrtc::test::OutputPath();
474 const char far_file_default[] = "apm_far.pcm";
475 const char near_file_default[] = "apm_near.pcm";
476 const char event_filename[] = "apm_event.dat";
477 const char delay_filename[] = "apm_delay.dat";
478 const char drift_filename[] = "apm_drift.dat";
479 const std::string vad_file_default = out_path + "vad_out.dat";
480 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
481
482 if (!simulating) {
483 far_filename = far_file_default;
484 near_filename = near_file_default;
485 }
486
487 if (out_filename.size() == 0) {
488 out_filename = out_path + "out";
489 }
490
491 if (!vad_out_filename) {
492 vad_out_filename = vad_file_default.c_str();
493 }
494
495 if (!ns_prob_filename) {
496 ns_prob_filename = ns_prob_file_default.c_str();
497 }
498
499 FILE* pb_file = NULL;
500 FILE* far_file = NULL;
501 FILE* near_file = NULL;
502 FILE* event_file = NULL;
503 FILE* delay_file = NULL;
504 FILE* drift_file = NULL;
505 FILE* vad_out_file = NULL;
506 FILE* ns_prob_file = NULL;
507 FILE* aecm_echo_path_in_file = NULL;
508 FILE* aecm_echo_path_out_file = NULL;
509
510 std::unique_ptr<WavWriter> output_wav_file;
511 std::unique_ptr<RawFile> output_raw_file;
512
513 if (pb_filename) {
514 pb_file = OpenFile(pb_filename, "rb");
515 } else {
516 if (far_filename) {
517 far_file = OpenFile(far_filename, "rb");
518 }
519
520 near_file = OpenFile(near_filename, "rb");
521 if (!simulating) {
522 event_file = OpenFile(event_filename, "rb");
523 delay_file = OpenFile(delay_filename, "rb");
524 drift_file = OpenFile(drift_filename, "rb");
525 }
526 }
527
528 int near_size_bytes = 0;
529 if (pb_file) {
530 struct stat st;
531 stat(pb_filename, &st);
532 // Crude estimate, but should be good enough.
533 near_size_bytes = st.st_size / 3;
534 } else {
535 struct stat st;
536 stat(near_filename, &st);
537 near_size_bytes = st.st_size;
538 }
539
540 if (apm->voice_detection()->is_enabled()) {
541 vad_out_file = OpenFile(vad_out_filename, "wb");
542 }
543
544 if (apm->noise_suppression()->is_enabled()) {
545 ns_prob_file = OpenFile(ns_prob_filename, "wb");
546 }
547
548 if (aecm_echo_path_in_filename != NULL) {
549 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
550
551 const size_t path_size =
552 apm->echo_control_mobile()->echo_path_size_bytes();
553 std::unique_ptr<char[]> echo_path(new char[path_size]);
554 ASSERT_EQ(path_size, fread(echo_path.get(),
555 sizeof(char),
556 path_size,
557 aecm_echo_path_in_file));
558 EXPECT_EQ(apm->kNoError,
559 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
560 path_size));
561 fclose(aecm_echo_path_in_file);
562 aecm_echo_path_in_file = NULL;
563 }
564
565 if (aecm_echo_path_out_filename != NULL) {
566 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
567 }
568
569 size_t read_count = 0;
570 int reverse_count = 0;
571 int primary_count = 0;
572 int near_read_bytes = 0;
573 int64_t acc_nanos = 0;
574
575 AudioFrame far_frame;
576 AudioFrame near_frame;
577
578 int delay_ms = 0;
579 int drift_samples = 0;
580 int capture_level = 127;
581 int8_t stream_has_voice = 0;
582 float ns_speech_prob = 0.0f;
583
584 int64_t t0 = rtc::TimeNanos();
585 int64_t t1 = t0;
586 int64_t max_time_us = 0;
587 int64_t max_time_reverse_us = 0;
588 int64_t min_time_us = 1e6;
589 int64_t min_time_reverse_us = 1e6;
590
591 // TODO(ajm): Ideally we would refactor this block into separate functions,
592 // but for now we want to share the variables.
593 if (pb_file) {
594 Event event_msg;
595 std::unique_ptr<ChannelBuffer<float> > reverse_cb;
596 std::unique_ptr<ChannelBuffer<float> > primary_cb;
597 int output_sample_rate = 32000;
598 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
599 while (ReadMessageFromFile(pb_file, &event_msg)) {
600 std::ostringstream trace_stream;
601 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
602 << primary_count << " (primary)";
603 SCOPED_TRACE(trace_stream.str());
604
605 if (event_msg.type() == Event::INIT) {
606 ASSERT_TRUE(event_msg.has_init());
607 const Init msg = event_msg.init();
608
609 ASSERT_TRUE(msg.has_sample_rate());
610 ASSERT_TRUE(msg.has_num_input_channels());
611 ASSERT_TRUE(msg.has_num_output_channels());
612 ASSERT_TRUE(msg.has_num_reverse_channels());
613 int reverse_sample_rate = msg.sample_rate();
614 if (msg.has_reverse_sample_rate()) {
615 reverse_sample_rate = msg.reverse_sample_rate();
616 }
617 output_sample_rate = msg.sample_rate();
618 if (msg.has_output_sample_rate()) {
619 output_sample_rate = msg.output_sample_rate();
620 }
621 output_layout =
622 LayoutFromChannels(static_cast<size_t>(msg.num_output_channels()));
623 ASSERT_EQ(kNoErr,
624 apm->Initialize(
625 msg.sample_rate(),
626 output_sample_rate,
627 reverse_sample_rate,
628 LayoutFromChannels(
629 static_cast<size_t>(msg.num_input_channels())),
630 output_layout,
631 LayoutFromChannels(
632 static_cast<size_t>(msg.num_reverse_channels()))));
633
634 samples_per_channel = msg.sample_rate() / 100;
635 far_frame.sample_rate_hz_ = reverse_sample_rate;
636 far_frame.samples_per_channel_ = reverse_sample_rate / 100;
637 far_frame.num_channels_ = msg.num_reverse_channels();
638 near_frame.sample_rate_hz_ = msg.sample_rate();
639 near_frame.samples_per_channel_ = samples_per_channel;
640 near_frame.num_channels_ = msg.num_input_channels();
641 reverse_cb.reset(new ChannelBuffer<float>(
642 far_frame.samples_per_channel_,
643 msg.num_reverse_channels()));
644 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
645 msg.num_input_channels()));
646
647 if (verbose) {
648 printf("Init at frame: %d (primary), %d (reverse)\n",
649 primary_count, reverse_count);
650 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
651 msg.sample_rate(), output_sample_rate);
652 printf(" Primary channels: %d (in), %d (out)\n",
653 msg.num_input_channels(),
654 msg.num_output_channels());
655 printf(" Reverse rate: %d\n", reverse_sample_rate);
656 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
657 }
658
659 if (!raw_output) {
660 // The WAV file needs to be reset every time, because it can't change
661 // its sample rate or number of channels.
662 output_wav_file.reset(new WavWriter(
663 out_filename + ".wav", output_sample_rate,
664 static_cast<size_t>(msg.num_output_channels())));
665 }
666
667 } else if (event_msg.type() == Event::REVERSE_STREAM) {
668 ASSERT_TRUE(event_msg.has_reverse_stream());
669 ReverseStream msg = event_msg.reverse_stream();
670 reverse_count++;
671
672 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
673 if (msg.has_data()) {
674 ASSERT_EQ(sizeof(int16_t) * far_frame.samples_per_channel_ *
675 far_frame.num_channels_, msg.data().size());
676 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
677 } else {
678 for (int i = 0; i < msg.channel_size(); ++i) {
679 memcpy(reverse_cb->channels()[i],
680 msg.channel(i).data(),
681 reverse_cb->num_frames() *
682 sizeof(reverse_cb->channels()[i][0]));
683 }
684 }
685
686 if (perf_testing) {
687 t0 = rtc::TimeNanos();
688 }
689
690 if (msg.has_data()) {
691 ASSERT_EQ(apm->kNoError,
692 apm->ProcessReverseStream(&far_frame));
693 } else {
694 ASSERT_EQ(apm->kNoError,
695 apm->AnalyzeReverseStream(
696 reverse_cb->channels(),
697 far_frame.samples_per_channel_,
698 far_frame.sample_rate_hz_,
699 LayoutFromChannels(far_frame.num_channels_)));
700 }
701
702 if (perf_testing) {
703 t1 = rtc::TimeNanos();
704 int64_t diff_nanos = t1 - t0;
705 acc_nanos += diff_nanos;
706 int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec;
707 if (diff_us > max_time_reverse_us) {
708 max_time_reverse_us = diff_us;
709 }
710 if (diff_us < min_time_reverse_us) {
711 min_time_reverse_us = diff_us;
712 }
713 }
714
715 } else if (event_msg.type() == Event::STREAM) {
716 ASSERT_TRUE(event_msg.has_stream());
717 const Stream msg = event_msg.stream();
718 primary_count++;
719
720 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
721 if (msg.has_input_data()) {
722 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
723 near_frame.num_channels_, msg.input_data().size());
724 memcpy(near_frame.data_,
725 msg.input_data().data(),
726 msg.input_data().size());
727 near_read_bytes += msg.input_data().size();
728 } else {
729 for (int i = 0; i < msg.input_channel_size(); ++i) {
730 memcpy(primary_cb->channels()[i],
731 msg.input_channel(i).data(),
732 primary_cb->num_frames() *
733 sizeof(primary_cb->channels()[i][0]));
734 near_read_bytes += msg.input_channel(i).size();
735 }
736 }
737
738 if (progress && primary_count % 100 == 0) {
739 near_read_bytes = std::min(near_read_bytes, near_size_bytes);
740 printf("%.0f%% complete\r",
741 (near_read_bytes * 100.0) / near_size_bytes);
742 fflush(stdout);
743 }
744
745 if (perf_testing) {
746 t0 = rtc::TimeNanos();
747 }
748
749 ASSERT_EQ(apm->kNoError,
750 apm->gain_control()->set_stream_analog_level(msg.level()));
751 delay_ms = msg.delay() + extra_delay_ms;
752 if (override_delay_ms) {
753 delay_ms = override_delay_ms;
754 }
755 ASSERT_EQ(apm->kNoError,
756 apm->set_stream_delay_ms(delay_ms));
757 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
758
759 if (msg.has_keypress()) {
760 apm->set_stream_key_pressed(msg.keypress());
761 } else {
762 apm->set_stream_key_pressed(true);
763 }
764
765 int err = apm->kNoError;
766 if (msg.has_input_data()) {
767 err = apm->ProcessStream(&near_frame);
768 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
769 } else {
770 err = apm->ProcessStream(
771 primary_cb->channels(),
772 near_frame.samples_per_channel_,
773 near_frame.sample_rate_hz_,
774 LayoutFromChannels(near_frame.num_channels_),
775 output_sample_rate,
776 output_layout,
777 primary_cb->channels());
778 }
779
780 if (err == apm->kBadStreamParameterWarning) {
781 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
782 }
783 ASSERT_TRUE(err == apm->kNoError ||
784 err == apm->kBadStreamParameterWarning);
785
786 stream_has_voice =
787 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
788 if (vad_out_file != NULL) {
789 ASSERT_EQ(1u, fwrite(&stream_has_voice,
790 sizeof(stream_has_voice),
791 1,
792 vad_out_file));
793 }
794
795 if (ns_prob_file != NULL) {
796 ns_speech_prob = apm->noise_suppression()->speech_probability();
797 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
798 sizeof(ns_speech_prob),
799 1,
800 ns_prob_file));
801 }
802
803 if (perf_testing) {
804 t1 = rtc::TimeNanos();
805 int64_t diff_nanos = t1 - t0;
806 acc_nanos += diff_nanos;
807 int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec;
808 if (diff_us > max_time_us) {
809 max_time_us = diff_us;
810 }
811 if (diff_us < min_time_us) {
812 min_time_us = diff_us;
813 }
814 }
815
816 const size_t samples_per_channel = output_sample_rate / 100;
817 if (msg.has_input_data()) {
818 if (raw_output && !output_raw_file) {
819 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
820 }
821 WriteIntData(near_frame.data_,
822 apm->num_output_channels() * samples_per_channel,
823 output_wav_file.get(),
824 output_raw_file.get());
825 } else {
826 if (raw_output && !output_raw_file) {
827 output_raw_file.reset(new RawFile(out_filename + ".float"));
828 }
829 WriteFloatData(primary_cb->channels(),
830 samples_per_channel,
831 apm->num_output_channels(),
832 output_wav_file.get(),
833 output_raw_file.get());
834 }
835 }
836 }
837
838 ASSERT_TRUE(feof(pb_file));
839
840 } else {
841 enum Events {
842 kInitializeEvent,
843 kRenderEvent,
844 kCaptureEvent,
845 kResetEventDeprecated
846 };
847 int16_t event = 0;
848 while (simulating || feof(event_file) == 0) {
849 std::ostringstream trace_stream;
850 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
851 << primary_count << " (primary)";
852 SCOPED_TRACE(trace_stream.str());
853
854 if (simulating) {
855 if (far_file == NULL) {
856 event = kCaptureEvent;
857 } else {
858 event = (event == kCaptureEvent) ? kRenderEvent : kCaptureEvent;
859 }
860 } else {
861 read_count = fread(&event, sizeof(event), 1, event_file);
862 if (read_count != 1) {
863 break;
864 }
865 }
866
867 far_frame.sample_rate_hz_ = sample_rate_hz;
868 far_frame.samples_per_channel_ = samples_per_channel;
869 far_frame.num_channels_ = num_render_channels;
870 near_frame.sample_rate_hz_ = sample_rate_hz;
871 near_frame.samples_per_channel_ = samples_per_channel;
872
873 if (event == kInitializeEvent || event == kResetEventDeprecated) {
874 ASSERT_EQ(1u,
875 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
876 samples_per_channel = sample_rate_hz / 100;
877
878 int32_t unused_device_sample_rate_hz;
879 ASSERT_EQ(1u,
880 fread(&unused_device_sample_rate_hz,
881 sizeof(unused_device_sample_rate_hz),
882 1,
883 event_file));
884
885 ASSERT_EQ(kNoErr, apm->Initialize(
886 sample_rate_hz,
887 sample_rate_hz,
888 sample_rate_hz,
889 LayoutFromChannels(num_capture_input_channels),
890 LayoutFromChannels(num_capture_output_channels),
891 LayoutFromChannels(num_render_channels)));
892
893 far_frame.sample_rate_hz_ = sample_rate_hz;
894 far_frame.samples_per_channel_ = samples_per_channel;
895 far_frame.num_channels_ = num_render_channels;
896 near_frame.sample_rate_hz_ = sample_rate_hz;
897 near_frame.samples_per_channel_ = samples_per_channel;
898
899 if (!raw_output) {
900 // The WAV file needs to be reset every time, because it can't change
901 // it's sample rate or number of channels.
902 output_wav_file.reset(new WavWriter(out_filename + ".wav",
903 sample_rate_hz,
904 num_capture_output_channels));
905 }
906
907 if (verbose) {
908 printf("Init at frame: %d (primary), %d (reverse)\n",
909 primary_count, reverse_count);
910 printf(" Sample rate: %d Hz\n", sample_rate_hz);
911 }
912
913 } else if (event == kRenderEvent) {
914 reverse_count++;
915
916 size_t size = samples_per_channel * num_render_channels;
917 read_count = fread(far_frame.data_,
918 sizeof(int16_t),
919 size,
920 far_file);
921
922 if (simulating) {
923 if (read_count != size) {
924 // Read an equal amount from the near file to avoid errors due to
925 // not reaching end-of-file.
926 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
927 SEEK_CUR));
928 break; // This is expected.
929 }
930 } else {
931 ASSERT_EQ(size, read_count);
932 }
933
934 if (perf_testing) {
935 t0 = rtc::TimeNanos();
936 }
937
938 ASSERT_EQ(apm->kNoError,
939 apm->ProcessReverseStream(&far_frame));
940
941 if (perf_testing) {
942 t1 = rtc::TimeNanos();
943 int64_t diff_nanos = t1 - t0;
944 acc_nanos += diff_nanos;
945 int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec;
946 if (diff_us > max_time_reverse_us) {
947 max_time_reverse_us = diff_us;
948 }
949 if (diff_us < min_time_reverse_us) {
950 min_time_reverse_us = diff_us;
951 }
952 }
953
954 } else if (event == kCaptureEvent) {
955 primary_count++;
956 near_frame.num_channels_ = num_capture_input_channels;
957
958 size_t size = samples_per_channel * num_capture_input_channels;
959 read_count = fread(near_frame.data_,
960 sizeof(int16_t),
961 size,
962 near_file);
963
964 near_read_bytes += read_count * sizeof(int16_t);
965 if (progress && primary_count % 100 == 0) {
966 printf("%.0f%% complete\r",
967 (near_read_bytes * 100.0) / near_size_bytes);
968 fflush(stdout);
969 }
970 if (simulating) {
971 if (read_count != size) {
972 break; // This is expected.
973 }
974
975 delay_ms = 0;
976 drift_samples = 0;
977 } else {
978 ASSERT_EQ(size, read_count);
979
980 // TODO(ajm): sizeof(delay_ms) for current files?
981 ASSERT_EQ(1u,
982 fread(&delay_ms, 2, 1, delay_file));
983 ASSERT_EQ(1u,
984 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
985 }
986
987 if (apm->gain_control()->is_enabled() &&
988 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
989 SimulateMic(capture_level, &near_frame);
990 }
991
992 if (perf_testing) {
993 t0 = rtc::TimeNanos();
994 }
995
996 const int capture_level_in = capture_level;
997 ASSERT_EQ(apm->kNoError,
998 apm->gain_control()->set_stream_analog_level(capture_level));
999 delay_ms += extra_delay_ms;
1000 if (override_delay_ms) {
1001 delay_ms = override_delay_ms;
1002 }
1003 ASSERT_EQ(apm->kNoError,
1004 apm->set_stream_delay_ms(delay_ms));
1005 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
1006
1007 apm->set_stream_key_pressed(true);
1008
1009 int err = apm->ProcessStream(&near_frame);
1010 if (err == apm->kBadStreamParameterWarning) {
1011 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
1012 }
1013 ASSERT_TRUE(err == apm->kNoError ||
1014 err == apm->kBadStreamParameterWarning);
1015 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
1016
1017 capture_level = apm->gain_control()->stream_analog_level();
1018
1019 stream_has_voice =
1020 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
1021 if (vad_out_file != NULL) {
1022 ASSERT_EQ(1u, fwrite(&stream_has_voice,
1023 sizeof(stream_has_voice),
1024 1,
1025 vad_out_file));
1026 }
1027
1028 if (ns_prob_file != NULL) {
1029 ns_speech_prob = apm->noise_suppression()->speech_probability();
1030 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
1031 sizeof(ns_speech_prob),
1032 1,
1033 ns_prob_file));
1034 }
1035
1036 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
1037 ASSERT_EQ(capture_level_in, capture_level);
1038 }
1039
1040 if (perf_testing) {
1041 t1 = rtc::TimeNanos();
1042 int64_t diff_nanos = t1 - t0;
1043 acc_nanos += diff_nanos;
1044 int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec;
1045 if (diff_us > max_time_us) {
1046 max_time_us = diff_us;
1047 }
1048 if (diff_us < min_time_us) {
1049 min_time_us = diff_us;
1050 }
1051 }
1052
1053 if (raw_output && !output_raw_file) {
1054 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
1055 }
1056 if (!raw_output && !output_wav_file) {
1057 output_wav_file.reset(new WavWriter(out_filename + ".wav",
1058 sample_rate_hz,
1059 num_capture_output_channels));
1060 }
1061 WriteIntData(near_frame.data_,
1062 size,
1063 output_wav_file.get(),
1064 output_raw_file.get());
1065 } else {
1066 FAIL() << "Event " << event << " is unrecognized";
1067 }
1068 }
1069 }
1070 if (progress) {
1071 printf("100%% complete\r");
1072 }
1073
1074 if (aecm_echo_path_out_file != NULL) {
1075 const size_t path_size =
1076 apm->echo_control_mobile()->echo_path_size_bytes();
1077 std::unique_ptr<char[]> echo_path(new char[path_size]);
1078 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1079 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1080 sizeof(char),
1081 path_size,
1082 aecm_echo_path_out_file));
1083 fclose(aecm_echo_path_out_file);
1084 aecm_echo_path_out_file = NULL;
1085 }
1086
1087 if (verbose) {
1088 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1089 primary_count, reverse_count);
1090
1091 if (apm->level_estimator()->is_enabled()) {
1092 printf("\n--Level metrics--\n");
1093 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1094 }
1095 if (apm->echo_cancellation()->are_metrics_enabled()) {
1096 EchoCancellation::Metrics metrics;
1097 apm->echo_cancellation()->GetMetrics(&metrics);
1098 printf("\n--Echo metrics--\n");
1099 printf("(avg, max, min)\n");
1100 printf("ERL: ");
1101 PrintStat(metrics.echo_return_loss);
1102 printf("ERLE: ");
1103 PrintStat(metrics.echo_return_loss_enhancement);
1104 printf("ANLP: ");
1105 PrintStat(metrics.a_nlp);
1106 }
1107 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1108 int median = 0;
1109 int std = 0;
1110 float fraction_poor_delays = 0;
1111 apm->echo_cancellation()->GetDelayMetrics(&median, &std,
1112 &fraction_poor_delays);
1113 printf("\n--Delay metrics--\n");
1114 printf("Median: %3d\n", median);
1115 printf("Standard deviation: %3d\n", std);
1116 printf("Poor delay values: %3.1f%%\n", fraction_poor_delays * 100);
1117 }
1118 }
1119
1120 if (!pb_file) {
1121 int8_t temp_int8;
1122 if (far_file) {
1123 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1124 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1125 }
1126
1127 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1128 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1129
1130 if (!simulating) {
1131 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1132 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1133 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1134 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1135 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1136 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1137 }
1138 }
1139
1140 if (perf_testing) {
1141 if (primary_count > 0) {
1142 int64_t exec_time = acc_nanos / rtc::kNumNanosecsPerMillisec;
1143 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1144 exec_time * 0.001, primary_count * 0.01);
1145 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1146 " %.3f ms (min)\n",
1147 (exec_time * 1.0) / primary_count,
1148 (max_time_us + max_time_reverse_us) / 1000.0,
1149 (min_time_us + min_time_reverse_us) / 1000.0);
1150 // Record the results with Perf test tools.
1151 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
1152 (exec_time * 1000) / primary_count, "us", false);
1153 } else {
1154 printf("Warning: no capture frames\n");
1155 }
1156 }
1157 }
1158
1159 } // namespace
1160 } // namespace webrtc
1161
1162 int main(int argc, char* argv[]) {
1163 webrtc::void_main(argc, argv);
1164
1165 // Optional, but removes memory leak noise from Valgrind.
1166 google::protobuf::ShutdownProtobufLibrary();
1167 return 0;
1168 }
OLDNEW
« no previous file with comments | « webrtc/modules/audio_processing/audio_processing_tests.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698