blob: 8ab2be7e6f9425ebfe981f2dc0ffccb4f9b71598 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
leozwang@webrtc.org9a85d8e2012-03-16 18:03:18 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
andrew@webrtc.org81865342012-10-27 00:28:27 +000011#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000012#include <stdio.h>
13#include <string.h>
14#ifdef WEBRTC_ANDROID
15#include <sys/stat.h>
16#endif
17
andrew@webrtc.org81865342012-10-27 00:28:27 +000018#include <algorithm>
19
kma@webrtc.org0e739502012-12-07 15:26:28 +000020#include "webrtc/modules/audio_processing/include/audio_processing.h"
21#include "webrtc/modules/interface/module_common_types.h"
22#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
23#include "webrtc/system_wrappers/interface/scoped_ptr.h"
24#include "webrtc/system_wrappers/interface/tick_util.h"
kjellander@webrtc.org10abe252012-12-17 18:28:07 +000025#include "webrtc/test/testsupport/fileutils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000026#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000027#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000028#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000029#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000030#else
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000031#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:51 +000032#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000033#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000034
35using webrtc::AudioFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +000036using webrtc::AudioProcessing;
andrew@webrtc.org94c74132011-09-19 15:17:57 +000037using webrtc::EchoCancellation;
niklase@google.com470e71d2011-07-07 08:21:25 +000038using webrtc::GainControl;
39using webrtc::NoiseSuppression;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000040using webrtc::scoped_array;
ajm@google.com808e0e02011-08-03 21:08:51 +000041using webrtc::TickInterval;
42using webrtc::TickTime;
andrew@webrtc.org89752612012-10-12 16:41:45 +000043using webrtc::VoiceDetection;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000044
ajm@google.com808e0e02011-08-03 21:08:51 +000045using webrtc::audioproc::Event;
46using webrtc::audioproc::Init;
47using webrtc::audioproc::ReverseStream;
48using webrtc::audioproc::Stream;
49
50namespace {
51// Returns true on success, false on error or end-of-file.
52bool ReadMessageFromFile(FILE* file,
53 ::google::protobuf::MessageLite* msg) {
54 // The "wire format" for the size is little-endian.
55 // Assume process_test is running on a little-endian machine.
andrew@webrtc.orgcb181212011-10-26 00:27:17 +000056 int32_t size = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +000057 if (fread(&size, sizeof(int32_t), 1, file) != 1) {
58 return false;
59 }
60 if (size <= 0) {
61 return false;
62 }
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000063 const size_t usize = static_cast<size_t>(size);
ajm@google.com808e0e02011-08-03 21:08:51 +000064
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000065 scoped_array<char> array(new char[usize]);
66 if (fread(array.get(), sizeof(char), usize, file) != usize) {
ajm@google.com808e0e02011-08-03 21:08:51 +000067 return false;
68 }
69
70 msg->Clear();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000071 return msg->ParseFromArray(array.get(), usize);
ajm@google.com808e0e02011-08-03 21:08:51 +000072}
niklase@google.com470e71d2011-07-07 08:21:25 +000073
andrew@webrtc.org94c74132011-09-19 15:17:57 +000074void PrintStat(const AudioProcessing::Statistic& stat) {
75 printf("%d, %d, %d\n", stat.average,
76 stat.maximum,
77 stat.minimum);
78}
79
niklase@google.com470e71d2011-07-07 08:21:25 +000080void usage() {
81 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000082 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
83 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000084 printf(
85 "process_test is a test application for AudioProcessing.\n\n"
ajm@google.com808e0e02011-08-03 21:08:51 +000086 "When a protobuf debug file is available, specify it with -pb.\n"
87 "Alternately, when -ir or -i is used, the specified files will be\n"
88 "processed directly in a simulation mode. Otherwise the full set of\n"
89 "legacy test files is expected to be present in the working directory.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000090 printf("\n");
91 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000092 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000093 printf(" -fs SAMPLE_RATE_HZ\n");
94 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
95 printf(" -rch REVERSE_CHANNELS\n");
96 printf("\n");
97 printf("Component configuration:\n");
98 printf(
99 "All components are disabled by default. Each block below begins with a\n"
100 "flag to enable the component with default settings. The subsequent flags\n"
101 "in the block are used to provide configuration settings.\n");
102 printf("\n -aec Echo cancellation\n");
103 printf(" --drift_compensation\n");
104 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000105 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000106 printf(" --no_delay_logging\n");
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000107 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +0000109 printf(" --aecm_echo_path_in_file FILE\n");
110 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000111 printf(" --no_comfort_noise\n");
112 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 printf("\n -agc Gain control\n");
114 printf(" --analog\n");
115 printf(" --adaptive_digital\n");
116 printf(" --fixed_digital\n");
117 printf(" --target_level LEVEL\n");
118 printf(" --compression_gain GAIN\n");
119 printf(" --limiter\n");
120 printf(" --no_limiter\n");
121 printf("\n -hpf High pass filter\n");
122 printf("\n -ns Noise suppression\n");
123 printf(" --ns_low\n");
124 printf(" --ns_moderate\n");
125 printf(" --ns_high\n");
126 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000127 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000128 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000129 printf(" --vad_out_file FILE\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000130 printf("\n Level metrics (enabled by default)\n");
131 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000132 printf("\n");
133 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000134 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000135 printf(" --delay DELAY Add DELAY ms to input value.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000136 printf(" --perf Measure performance.\n");
137 printf(" --quiet Suppress text output.\n");
138 printf(" --no_progress Suppress progress.\n");
139 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000140}
141
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000142static float MicLevel2Gain(int level) {
143 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000144}
145
146static void SimulateMic(int mic_level, AudioFrame* frame) {
147 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000148 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000149 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000150 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000151 for (int n = 0; n < num_samples; n++) {
152 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000153 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000154 frame->data_[n] = static_cast<int16_t>(v);
155 }
156}
157
niklase@google.com470e71d2011-07-07 08:21:25 +0000158// void function for gtest.
159void void_main(int argc, char* argv[]) {
160 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
161 usage();
162 return;
163 }
164
165 if (argc < 2) {
166 printf("Did you mean to run without arguments?\n");
167 printf("Try `process_test --help' for more information.\n\n");
168 }
169
170 AudioProcessing* apm = AudioProcessing::Create(0);
171 ASSERT_TRUE(apm != NULL);
172
ajm@google.com808e0e02011-08-03 21:08:51 +0000173 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 const char* far_filename = NULL;
175 const char* near_filename = NULL;
176 const char* out_filename = NULL;
177 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000178 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000179 const char* aecm_echo_path_in_filename = NULL;
180 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000181
182 int32_t sample_rate_hz = 16000;
183 int32_t device_sample_rate_hz = 16000;
184
185 int num_capture_input_channels = 1;
186 int num_capture_output_channels = 1;
187 int num_render_channels = 1;
188
189 int samples_per_channel = sample_rate_hz / 100;
190
191 bool simulating = false;
192 bool perf_testing = false;
193 bool verbose = true;
194 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000195 int extra_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 //bool interleaved = true;
197
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000198 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000200 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000201 i++;
202 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
203 pb_filename = argv[i];
204
205 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 i++;
207 ASSERT_LT(i, argc) << "Specify filename after -ir";
208 far_filename = argv[i];
209 simulating = true;
210
211 } else if (strcmp(argv[i], "-i") == 0) {
212 i++;
213 ASSERT_LT(i, argc) << "Specify filename after -i";
214 near_filename = argv[i];
215 simulating = true;
216
217 } else if (strcmp(argv[i], "-o") == 0) {
218 i++;
219 ASSERT_LT(i, argc) << "Specify filename after -o";
220 out_filename = argv[i];
221
222 } else if (strcmp(argv[i], "-fs") == 0) {
223 i++;
224 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
225 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
226 samples_per_channel = sample_rate_hz / 100;
227
228 ASSERT_EQ(apm->kNoError,
229 apm->set_sample_rate_hz(sample_rate_hz));
230
231 } else if (strcmp(argv[i], "-ch") == 0) {
232 i++;
233 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
234 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
235 i++;
236 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
237
238 ASSERT_EQ(apm->kNoError,
239 apm->set_num_channels(num_capture_input_channels,
240 num_capture_output_channels));
241
242 } else if (strcmp(argv[i], "-rch") == 0) {
243 i++;
244 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
245 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
246
247 ASSERT_EQ(apm->kNoError,
248 apm->set_num_reverse_channels(num_render_channels));
249
250 } else if (strcmp(argv[i], "-aec") == 0) {
251 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000252 ASSERT_EQ(apm->kNoError,
253 apm->echo_cancellation()->enable_metrics(true));
254 ASSERT_EQ(apm->kNoError,
255 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000256
niklase@google.com470e71d2011-07-07 08:21:25 +0000257 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
258 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
259 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
260 // why it can give better performance despite passing zeros.
261 ASSERT_EQ(apm->kNoError,
262 apm->echo_cancellation()->enable_drift_compensation(true));
263 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
264 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
265 ASSERT_EQ(apm->kNoError,
266 apm->echo_cancellation()->enable_drift_compensation(false));
267
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000268 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
269 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
270 ASSERT_EQ(apm->kNoError,
271 apm->echo_cancellation()->enable_metrics(false));
272
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000273 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
274 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
275 ASSERT_EQ(apm->kNoError,
276 apm->echo_cancellation()->enable_delay_logging(false));
277
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000278 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
279 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
280
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000281 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
282 i++;
283 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
284 int suppression_level;
285 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
286 ASSERT_EQ(apm->kNoError,
287 apm->echo_cancellation()->set_suppression_level(
288 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
289 suppression_level)));
290
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 } else if (strcmp(argv[i], "-aecm") == 0) {
292 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
293
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000294 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
295 i++;
296 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
297 aecm_echo_path_in_filename = argv[i];
298
299 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
300 i++;
301 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
302 aecm_echo_path_out_filename = argv[i];
303
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000304 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
305 ASSERT_EQ(apm->kNoError,
306 apm->echo_control_mobile()->enable_comfort_noise(false));
307
308 } else if (strcmp(argv[i], "--routing_mode") == 0) {
309 i++;
310 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
311 int routing_mode;
312 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
313 ASSERT_EQ(apm->kNoError,
314 apm->echo_control_mobile()->set_routing_mode(
315 static_cast<webrtc::EchoControlMobile::RoutingMode>(
316 routing_mode)));
317
niklase@google.com470e71d2011-07-07 08:21:25 +0000318 } else if (strcmp(argv[i], "-agc") == 0) {
319 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
320
321 } else if (strcmp(argv[i], "--analog") == 0) {
322 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
323 ASSERT_EQ(apm->kNoError,
324 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
325
326 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
327 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
328 ASSERT_EQ(apm->kNoError,
329 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
330
331 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
332 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
333 ASSERT_EQ(apm->kNoError,
334 apm->gain_control()->set_mode(GainControl::kFixedDigital));
335
336 } else if (strcmp(argv[i], "--target_level") == 0) {
337 i++;
338 int level;
339 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
340
341 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
342 ASSERT_EQ(apm->kNoError,
343 apm->gain_control()->set_target_level_dbfs(level));
344
345 } else if (strcmp(argv[i], "--compression_gain") == 0) {
346 i++;
347 int gain;
348 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
349
350 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
351 ASSERT_EQ(apm->kNoError,
352 apm->gain_control()->set_compression_gain_db(gain));
353
354 } else if (strcmp(argv[i], "--limiter") == 0) {
355 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
356 ASSERT_EQ(apm->kNoError,
357 apm->gain_control()->enable_limiter(true));
358
359 } else if (strcmp(argv[i], "--no_limiter") == 0) {
360 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
361 ASSERT_EQ(apm->kNoError,
362 apm->gain_control()->enable_limiter(false));
363
364 } else if (strcmp(argv[i], "-hpf") == 0) {
365 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
366
367 } else if (strcmp(argv[i], "-ns") == 0) {
368 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
369
370 } else if (strcmp(argv[i], "--ns_low") == 0) {
371 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
372 ASSERT_EQ(apm->kNoError,
373 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
374
375 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
376 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
377 ASSERT_EQ(apm->kNoError,
378 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
379
380 } else if (strcmp(argv[i], "--ns_high") == 0) {
381 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
382 ASSERT_EQ(apm->kNoError,
383 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
384
385 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
386 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
387 ASSERT_EQ(apm->kNoError,
388 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
389
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000390 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
391 i++;
392 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
393 ns_prob_filename = argv[i];
394
niklase@google.com470e71d2011-07-07 08:21:25 +0000395 } else if (strcmp(argv[i], "-vad") == 0) {
396 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
397
andrew@webrtc.org89752612012-10-12 16:41:45 +0000398 } else if (strcmp(argv[i], "--vad_very_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::kVeryLowLikelihood));
403
404 } else if (strcmp(argv[i], "--vad_low") == 0) {
405 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
406 ASSERT_EQ(apm->kNoError,
407 apm->voice_detection()->set_likelihood(
408 VoiceDetection::kLowLikelihood));
409
410 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
411 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
412 ASSERT_EQ(apm->kNoError,
413 apm->voice_detection()->set_likelihood(
414 VoiceDetection::kModerateLikelihood));
415
416 } else if (strcmp(argv[i], "--vad_high") == 0) {
417 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
418 ASSERT_EQ(apm->kNoError,
419 apm->voice_detection()->set_likelihood(
420 VoiceDetection::kHighLikelihood));
421
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
423 i++;
424 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
425 vad_out_filename = argv[i];
426
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000427 } else if (strcmp(argv[i], "--noasm") == 0) {
428 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
429 // We need to reinitialize here if components have already been enabled.
430 ASSERT_EQ(apm->kNoError, apm->Initialize());
431
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000432 } else if (strcmp(argv[i], "--delay") == 0) {
433 i++;
434 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
435
niklase@google.com470e71d2011-07-07 08:21:25 +0000436 } else if (strcmp(argv[i], "--perf") == 0) {
437 perf_testing = true;
438
439 } else if (strcmp(argv[i], "--quiet") == 0) {
440 verbose = false;
441 progress = false;
442
443 } else if (strcmp(argv[i], "--no_progress") == 0) {
444 progress = false;
445
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000446 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000447 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000448 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000449 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000450 } else {
451 FAIL() << "Unrecognized argument " << argv[i];
452 }
453 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000454 // If we're reading a protobuf file, ensure a simulation hasn't also
455 // been requested (which makes no sense...)
456 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000457
458 if (verbose) {
459 printf("Sample rate: %d Hz\n", sample_rate_hz);
460 printf("Primary channels: %d (in), %d (out)\n",
461 num_capture_input_channels,
462 num_capture_output_channels);
463 printf("Reverse channels: %d \n", num_render_channels);
464 }
465
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000466 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 const char far_file_default[] = "apm_far.pcm";
468 const char near_file_default[] = "apm_near.pcm";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000469 const std::string out_file_default = out_path + "out.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 const char event_filename[] = "apm_event.dat";
471 const char delay_filename[] = "apm_delay.dat";
472 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000473 const std::string vad_file_default = out_path + "vad_out.dat";
474 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000475
476 if (!simulating) {
477 far_filename = far_file_default;
478 near_filename = near_file_default;
479 }
480
ajm@google.com808e0e02011-08-03 21:08:51 +0000481 if (!out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000482 out_filename = out_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 }
484
ajm@google.com808e0e02011-08-03 21:08:51 +0000485 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000486 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 }
488
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000489 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000490 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000491 }
492
ajm@google.com808e0e02011-08-03 21:08:51 +0000493 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 FILE* far_file = NULL;
495 FILE* near_file = NULL;
496 FILE* out_file = NULL;
497 FILE* event_file = NULL;
498 FILE* delay_file = NULL;
499 FILE* drift_file = NULL;
500 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000501 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000502 FILE* aecm_echo_path_in_file = NULL;
503 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504
ajm@google.com808e0e02011-08-03 21:08:51 +0000505 if (pb_filename) {
506 pb_file = fopen(pb_filename, "rb");
507 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
508 << pb_filename;
509 } else {
510 if (far_filename) {
511 far_file = fopen(far_filename, "rb");
512 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
513 << far_filename;
514 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000515
ajm@google.com808e0e02011-08-03 21:08:51 +0000516 near_file = fopen(near_filename, "rb");
517 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
518 << near_filename;
519 if (!simulating) {
520 event_file = fopen(event_filename, "rb");
521 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
522 << event_filename;
523
524 delay_file = fopen(delay_filename, "rb");
525 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
526 << delay_filename;
527
528 drift_file = fopen(drift_filename, "rb");
529 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
530 << drift_filename;
531 }
532 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000533
534 out_file = fopen(out_filename, "wb");
535 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
536 << out_filename;
537
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000538 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000539 if (pb_file) {
540 struct stat st;
541 stat(pb_filename, &st);
542 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000543 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000544 } else {
545 struct stat st;
546 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000547 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000548 }
549
550 if (apm->voice_detection()->is_enabled()) {
551 vad_out_file = fopen(vad_out_filename, "wb");
552 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
553 << vad_out_file;
554 }
555
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000556 if (apm->noise_suppression()->is_enabled()) {
557 ns_prob_file = fopen(ns_prob_filename, "wb");
558 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
559 << ns_prob_file;
560 }
561
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000562 if (aecm_echo_path_in_filename != NULL) {
563 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
564 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
565 << aecm_echo_path_in_filename;
566
ajm@google.com22e65152011-07-18 18:03:01 +0000567 const size_t path_size =
568 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000569 scoped_array<char> echo_path(new char[path_size]);
570 ASSERT_EQ(path_size, fread(echo_path.get(),
571 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000572 path_size,
573 aecm_echo_path_in_file));
574 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000575 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
576 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000577 fclose(aecm_echo_path_in_file);
578 aecm_echo_path_in_file = NULL;
579 }
580
581 if (aecm_echo_path_out_filename != NULL) {
582 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
583 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
584 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000585 }
586
niklase@google.com470e71d2011-07-07 08:21:25 +0000587 size_t read_count = 0;
588 int reverse_count = 0;
589 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000590 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000591 TickInterval acc_ticks;
592
593 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000595
596 int delay_ms = 0;
597 int drift_samples = 0;
598 int capture_level = 127;
599 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000600 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000601
602 TickTime t0 = TickTime::Now();
603 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000604 int64_t max_time_us = 0;
605 int64_t max_time_reverse_us = 0;
606 int64_t min_time_us = 1e6;
607 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000608
ajm@google.com808e0e02011-08-03 21:08:51 +0000609 // TODO(ajm): Ideally we would refactor this block into separate functions,
610 // but for now we want to share the variables.
611 if (pb_file) {
612 Event event_msg;
613 while (ReadMessageFromFile(pb_file, &event_msg)) {
614 std::ostringstream trace_stream;
615 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
616 << primary_count << " (primary)";
617 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000618
ajm@google.com808e0e02011-08-03 21:08:51 +0000619 if (event_msg.type() == Event::INIT) {
620 ASSERT_TRUE(event_msg.has_init());
621 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000622
ajm@google.com808e0e02011-08-03 21:08:51 +0000623 ASSERT_TRUE(msg.has_sample_rate());
624 ASSERT_EQ(apm->kNoError,
625 apm->set_sample_rate_hz(msg.sample_rate()));
626
627 ASSERT_TRUE(msg.has_device_sample_rate());
628 ASSERT_EQ(apm->kNoError,
629 apm->echo_cancellation()->set_device_sample_rate_hz(
630 msg.device_sample_rate()));
631
632 ASSERT_TRUE(msg.has_num_input_channels());
633 ASSERT_TRUE(msg.has_num_output_channels());
634 ASSERT_EQ(apm->kNoError,
635 apm->set_num_channels(msg.num_input_channels(),
636 msg.num_output_channels()));
637
638 ASSERT_TRUE(msg.has_num_reverse_channels());
639 ASSERT_EQ(apm->kNoError,
640 apm->set_num_reverse_channels(msg.num_reverse_channels()));
641
642 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000643 far_frame.sample_rate_hz_ = msg.sample_rate();
644 far_frame.samples_per_channel_ = samples_per_channel;
645 far_frame.num_channels_ = msg.num_reverse_channels();
646 near_frame.sample_rate_hz_ = msg.sample_rate();
647 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000648 near_frame.num_channels_ = msg.num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000649
650 if (verbose) {
651 printf("Init at frame: %d (primary), %d (reverse)\n",
652 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000653 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000654 printf(" Primary channels: %d (in), %d (out)\n",
655 msg.num_input_channels(),
656 msg.num_output_channels());
657 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000658 }
659
660 } else if (event_msg.type() == Event::REVERSE_STREAM) {
661 ASSERT_TRUE(event_msg.has_reverse_stream());
662 const ReverseStream msg = event_msg.reverse_stream();
663 reverse_count++;
664
665 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000666 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000667 far_frame.num_channels_, msg.data().size());
668 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000669
670 if (perf_testing) {
671 t0 = TickTime::Now();
672 }
673
674 ASSERT_EQ(apm->kNoError,
675 apm->AnalyzeReverseStream(&far_frame));
676
677 if (perf_testing) {
678 t1 = TickTime::Now();
679 TickInterval tick_diff = t1 - t0;
680 acc_ticks += tick_diff;
681 if (tick_diff.Microseconds() > max_time_reverse_us) {
682 max_time_reverse_us = tick_diff.Microseconds();
683 }
684 if (tick_diff.Microseconds() < min_time_reverse_us) {
685 min_time_reverse_us = tick_diff.Microseconds();
686 }
687 }
688
689 } else if (event_msg.type() == Event::STREAM) {
690 ASSERT_TRUE(event_msg.has_stream());
691 const Stream msg = event_msg.stream();
692 primary_count++;
693
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000694 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000695 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000696
697 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000698 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000699 near_frame.num_channels_, msg.input_data().size());
700 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000701 msg.input_data().data(),
702 msg.input_data().size());
703
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000704 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000705 if (progress && primary_count % 100 == 0) {
706 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000707 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000708 fflush(stdout);
709 }
710
711 if (perf_testing) {
712 t0 = TickTime::Now();
713 }
714
715 ASSERT_EQ(apm->kNoError,
716 apm->gain_control()->set_stream_analog_level(msg.level()));
717 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000718 apm->set_stream_delay_ms(msg.delay() + extra_delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000719 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000720
721 int err = apm->ProcessStream(&near_frame);
722 if (err == apm->kBadStreamParameterWarning) {
723 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
724 }
725 ASSERT_TRUE(err == apm->kNoError ||
726 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000727 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000728
ajm@google.com808e0e02011-08-03 21:08:51 +0000729 stream_has_voice =
730 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
731 if (vad_out_file != NULL) {
732 ASSERT_EQ(1u, fwrite(&stream_has_voice,
733 sizeof(stream_has_voice),
734 1,
735 vad_out_file));
736 }
737
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000738 if (ns_prob_file != NULL) {
739 ns_speech_prob = apm->noise_suppression()->speech_probability();
740 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
741 sizeof(ns_speech_prob),
742 1,
743 ns_prob_file));
744 }
745
ajm@google.com808e0e02011-08-03 21:08:51 +0000746 if (perf_testing) {
747 t1 = TickTime::Now();
748 TickInterval tick_diff = t1 - t0;
749 acc_ticks += tick_diff;
750 if (tick_diff.Microseconds() > max_time_us) {
751 max_time_us = tick_diff.Microseconds();
752 }
753 if (tick_diff.Microseconds() < min_time_us) {
754 min_time_us = tick_diff.Microseconds();
755 }
756 }
757
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000758 size_t size = samples_per_channel * near_frame.num_channels_;
759 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000760 sizeof(int16_t),
761 size,
762 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000763 }
764 }
765
766 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000767
768 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000769 enum Events {
770 kInitializeEvent,
771 kRenderEvent,
772 kCaptureEvent,
773 kResetEventDeprecated
774 };
775 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000776 while (simulating || feof(event_file) == 0) {
777 std::ostringstream trace_stream;
778 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
779 << primary_count << " (primary)";
780 SCOPED_TRACE(trace_stream.str());
781
782 if (simulating) {
783 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000784 event = kCaptureEvent;
785 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000786 if (event == kRenderEvent) {
787 event = kCaptureEvent;
788 } else {
789 event = kRenderEvent;
790 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 }
792 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000793 read_count = fread(&event, sizeof(event), 1, event_file);
794 if (read_count != 1) {
795 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 }
797 }
798
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000799 far_frame.sample_rate_hz_ = sample_rate_hz;
800 far_frame.samples_per_channel_ = samples_per_channel;
801 far_frame.num_channels_ = num_render_channels;
802 near_frame.sample_rate_hz_ = sample_rate_hz;
803 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000804
ajm@google.com808e0e02011-08-03 21:08:51 +0000805 if (event == kInitializeEvent || event == kResetEventDeprecated) {
806 ASSERT_EQ(1u,
807 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
808 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000809
ajm@google.com808e0e02011-08-03 21:08:51 +0000810 ASSERT_EQ(1u,
811 fread(&device_sample_rate_hz,
812 sizeof(device_sample_rate_hz),
813 1,
814 event_file));
815
816 ASSERT_EQ(apm->kNoError,
817 apm->set_sample_rate_hz(sample_rate_hz));
818
819 ASSERT_EQ(apm->kNoError,
820 apm->echo_cancellation()->set_device_sample_rate_hz(
821 device_sample_rate_hz));
822
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000823 far_frame.sample_rate_hz_ = sample_rate_hz;
824 far_frame.samples_per_channel_ = samples_per_channel;
825 far_frame.num_channels_ = num_render_channels;
826 near_frame.sample_rate_hz_ = sample_rate_hz;
827 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000828
829 if (verbose) {
830 printf("Init at frame: %d (primary), %d (reverse)\n",
831 primary_count, reverse_count);
832 printf(" Sample rate: %d Hz\n", sample_rate_hz);
833 }
834
835 } else if (event == kRenderEvent) {
836 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000837
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000838 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000839 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000840 sizeof(int16_t),
841 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000842 far_file);
843
844 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000845 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000846 // Read an equal amount from the near file to avoid errors due to
847 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000848 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000849 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000850 break; // This is expected.
851 }
852 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000853 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000854 }
855
856 if (perf_testing) {
857 t0 = TickTime::Now();
858 }
859
860 ASSERT_EQ(apm->kNoError,
861 apm->AnalyzeReverseStream(&far_frame));
862
863 if (perf_testing) {
864 t1 = TickTime::Now();
865 TickInterval tick_diff = t1 - t0;
866 acc_ticks += tick_diff;
867 if (tick_diff.Microseconds() > max_time_reverse_us) {
868 max_time_reverse_us = tick_diff.Microseconds();
869 }
870 if (tick_diff.Microseconds() < min_time_reverse_us) {
871 min_time_reverse_us = tick_diff.Microseconds();
872 }
873 }
874
875 } else if (event == kCaptureEvent) {
876 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000877 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000878
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000879 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000880 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000881 sizeof(int16_t),
882 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000883 near_file);
884
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000885 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000886 if (progress && primary_count % 100 == 0) {
887 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000888 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000889 fflush(stdout);
890 }
891 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000892 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000893 break; // This is expected.
894 }
895
896 delay_ms = 0;
897 drift_samples = 0;
898 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000899 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000900
901 // TODO(ajm): sizeof(delay_ms) for current files?
902 ASSERT_EQ(1u,
903 fread(&delay_ms, 2, 1, delay_file));
904 ASSERT_EQ(1u,
905 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
906 }
907
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000908 if (apm->gain_control()->is_enabled() &&
909 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000910 SimulateMic(capture_level, &near_frame);
911 }
912
ajm@google.com808e0e02011-08-03 21:08:51 +0000913 if (perf_testing) {
914 t0 = TickTime::Now();
915 }
916
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000917 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000918 ASSERT_EQ(apm->kNoError,
919 apm->gain_control()->set_stream_analog_level(capture_level));
920 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000921 apm->set_stream_delay_ms(delay_ms + extra_delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000922 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000923
924 int err = apm->ProcessStream(&near_frame);
925 if (err == apm->kBadStreamParameterWarning) {
926 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
927 }
928 ASSERT_TRUE(err == apm->kNoError ||
929 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000930 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000931
932 capture_level = apm->gain_control()->stream_analog_level();
933
934 stream_has_voice =
935 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
936 if (vad_out_file != NULL) {
937 ASSERT_EQ(1u, fwrite(&stream_has_voice,
938 sizeof(stream_has_voice),
939 1,
940 vad_out_file));
941 }
942
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000943 if (ns_prob_file != NULL) {
944 ns_speech_prob = apm->noise_suppression()->speech_probability();
945 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
946 sizeof(ns_speech_prob),
947 1,
948 ns_prob_file));
949 }
950
ajm@google.com808e0e02011-08-03 21:08:51 +0000951 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
952 ASSERT_EQ(capture_level_in, capture_level);
953 }
954
955 if (perf_testing) {
956 t1 = TickTime::Now();
957 TickInterval tick_diff = t1 - t0;
958 acc_ticks += tick_diff;
959 if (tick_diff.Microseconds() > max_time_us) {
960 max_time_us = tick_diff.Microseconds();
961 }
962 if (tick_diff.Microseconds() < min_time_us) {
963 min_time_us = tick_diff.Microseconds();
964 }
965 }
966
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000967 size = samples_per_channel * near_frame.num_channels_;
968 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000969 sizeof(int16_t),
970 size,
971 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000973 else {
974 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000975 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 }
977 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000978 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000979
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000980 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000981 const size_t path_size =
982 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000983 scoped_array<char> echo_path(new char[path_size]);
984 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
985 ASSERT_EQ(path_size, fwrite(echo_path.get(),
986 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000987 path_size,
988 aecm_echo_path_out_file));
989 fclose(aecm_echo_path_out_file);
990 aecm_echo_path_out_file = NULL;
991 }
992
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 if (verbose) {
994 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
995 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000996
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000997 if (apm->level_estimator()->is_enabled()) {
998 printf("\n--Level metrics--\n");
999 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1000 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001001 if (apm->echo_cancellation()->are_metrics_enabled()) {
1002 EchoCancellation::Metrics metrics;
1003 apm->echo_cancellation()->GetMetrics(&metrics);
1004 printf("\n--Echo metrics--\n");
1005 printf("(avg, max, min)\n");
1006 printf("ERL: ");
1007 PrintStat(metrics.echo_return_loss);
1008 printf("ERLE: ");
1009 PrintStat(metrics.echo_return_loss_enhancement);
1010 printf("ANLP: ");
1011 PrintStat(metrics.a_nlp);
1012 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001013 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1014 int median = 0;
1015 int std = 0;
1016 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1017 printf("\n--Delay metrics--\n");
1018 printf("Median: %3d\n", median);
1019 printf("Standard deviation: %3d\n", std);
1020 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001021 }
1022
ajm@google.com808e0e02011-08-03 21:08:51 +00001023 if (!pb_file) {
1024 int8_t temp_int8;
1025 if (far_file) {
1026 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1027 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1028 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001029
ajm@google.com808e0e02011-08-03 21:08:51 +00001030 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1031 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1032
1033 if (!simulating) {
1034 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1035 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1036 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1037 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1038 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1039 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1040 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 }
1042
1043 if (perf_testing) {
1044 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001045 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001046 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1047 exec_time * 0.001, primary_count * 0.01);
1048 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1049 " %.3f ms (min)\n",
1050 (exec_time * 1.0) / primary_count,
1051 (max_time_us + max_time_reverse_us) / 1000.0,
1052 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001053 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001054 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001055 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001056 } else {
1057 printf("Warning: no capture frames\n");
1058 }
1059 }
1060
1061 AudioProcessing::Destroy(apm);
1062 apm = NULL;
1063}
ajm@google.com808e0e02011-08-03 21:08:51 +00001064} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001065
1066int main(int argc, char* argv[])
1067{
1068 void_main(argc, argv);
1069
andrew@webrtc.org64235092011-08-19 21:22:08 +00001070 // Optional, but removes memory leak noise from Valgrind.
1071 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 return 0;
1073}