blob: cab93fea76e93c02a3418a3c140c0086a832fb87 [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;
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +000041using webrtc::scoped_ptr;
ajm@google.com808e0e02011-08-03 21:08:51 +000042using webrtc::TickInterval;
43using webrtc::TickTime;
andrew@webrtc.org89752612012-10-12 16:41:45 +000044using webrtc::VoiceDetection;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000045
ajm@google.com808e0e02011-08-03 21:08:51 +000046using webrtc::audioproc::Event;
47using webrtc::audioproc::Init;
48using webrtc::audioproc::ReverseStream;
49using webrtc::audioproc::Stream;
50
51namespace {
52// Returns true on success, false on error or end-of-file.
53bool ReadMessageFromFile(FILE* file,
54 ::google::protobuf::MessageLite* msg) {
55 // The "wire format" for the size is little-endian.
56 // Assume process_test is running on a little-endian machine.
andrew@webrtc.orgcb181212011-10-26 00:27:17 +000057 int32_t size = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +000058 if (fread(&size, sizeof(int32_t), 1, file) != 1) {
59 return false;
60 }
61 if (size <= 0) {
62 return false;
63 }
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000064 const size_t usize = static_cast<size_t>(size);
ajm@google.com808e0e02011-08-03 21:08:51 +000065
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000066 scoped_array<char> array(new char[usize]);
67 if (fread(array.get(), sizeof(char), usize, file) != usize) {
ajm@google.com808e0e02011-08-03 21:08:51 +000068 return false;
69 }
70
71 msg->Clear();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000072 return msg->ParseFromArray(array.get(), usize);
ajm@google.com808e0e02011-08-03 21:08:51 +000073}
niklase@google.com470e71d2011-07-07 08:21:25 +000074
andrew@webrtc.org94c74132011-09-19 15:17:57 +000075void PrintStat(const AudioProcessing::Statistic& stat) {
76 printf("%d, %d, %d\n", stat.average,
77 stat.maximum,
78 stat.minimum);
79}
80
niklase@google.com470e71d2011-07-07 08:21:25 +000081void usage() {
82 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000083 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
84 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000085 printf(
86 "process_test is a test application for AudioProcessing.\n\n"
ajm@google.com808e0e02011-08-03 21:08:51 +000087 "When a protobuf debug file is available, specify it with -pb.\n"
88 "Alternately, when -ir or -i is used, the specified files will be\n"
89 "processed directly in a simulation mode. Otherwise the full set of\n"
90 "legacy test files is expected to be present in the working directory.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000091 printf("\n");
92 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000093 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000094 printf(" -fs SAMPLE_RATE_HZ\n");
95 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
96 printf(" -rch REVERSE_CHANNELS\n");
97 printf("\n");
98 printf("Component configuration:\n");
99 printf(
100 "All components are disabled by default. Each block below begins with a\n"
101 "flag to enable the component with default settings. The subsequent flags\n"
102 "in the block are used to provide configuration settings.\n");
103 printf("\n -aec Echo cancellation\n");
104 printf(" --drift_compensation\n");
105 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000106 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000107 printf(" --no_delay_logging\n");
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000108 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000109 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +0000110 printf(" --aecm_echo_path_in_file FILE\n");
111 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000112 printf(" --no_comfort_noise\n");
113 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000114 printf("\n -agc Gain control\n");
115 printf(" --analog\n");
116 printf(" --adaptive_digital\n");
117 printf(" --fixed_digital\n");
118 printf(" --target_level LEVEL\n");
119 printf(" --compression_gain GAIN\n");
120 printf(" --limiter\n");
121 printf(" --no_limiter\n");
122 printf("\n -hpf High pass filter\n");
123 printf("\n -ns Noise suppression\n");
124 printf(" --ns_low\n");
125 printf(" --ns_moderate\n");
126 printf(" --ns_high\n");
127 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000128 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000129 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000130 printf(" --vad_out_file FILE\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000131 printf("\n Level metrics (enabled by default)\n");
132 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 printf("\n");
134 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000135 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000136 printf(" --delay DELAY Add DELAY ms to input value.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000137 printf(" --perf Measure performance.\n");
138 printf(" --quiet Suppress text output.\n");
139 printf(" --no_progress Suppress progress.\n");
140 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000141}
142
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000143static float MicLevel2Gain(int level) {
144 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000145}
146
147static void SimulateMic(int mic_level, AudioFrame* frame) {
148 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000149 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000150 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000151 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000152 for (int n = 0; n < num_samples; n++) {
153 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000154 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000155 frame->data_[n] = static_cast<int16_t>(v);
156 }
157}
158
niklase@google.com470e71d2011-07-07 08:21:25 +0000159// void function for gtest.
160void void_main(int argc, char* argv[]) {
161 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
162 usage();
163 return;
164 }
165
166 if (argc < 2) {
167 printf("Did you mean to run without arguments?\n");
168 printf("Try `process_test --help' for more information.\n\n");
169 }
170
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000171 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create(0));
172 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000173
ajm@google.com808e0e02011-08-03 21:08:51 +0000174 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000175 const char* far_filename = NULL;
176 const char* near_filename = NULL;
177 const char* out_filename = NULL;
178 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000179 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000180 const char* aecm_echo_path_in_filename = NULL;
181 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000182
183 int32_t sample_rate_hz = 16000;
184 int32_t device_sample_rate_hz = 16000;
185
186 int num_capture_input_channels = 1;
187 int num_capture_output_channels = 1;
188 int num_render_channels = 1;
189
190 int samples_per_channel = sample_rate_hz / 100;
191
192 bool simulating = false;
193 bool perf_testing = false;
194 bool verbose = true;
195 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000196 int extra_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 //bool interleaved = true;
198
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000199 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000200 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000201 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000202 i++;
203 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
204 pb_filename = argv[i];
205
206 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 i++;
208 ASSERT_LT(i, argc) << "Specify filename after -ir";
209 far_filename = argv[i];
210 simulating = true;
211
212 } else if (strcmp(argv[i], "-i") == 0) {
213 i++;
214 ASSERT_LT(i, argc) << "Specify filename after -i";
215 near_filename = argv[i];
216 simulating = true;
217
218 } else if (strcmp(argv[i], "-o") == 0) {
219 i++;
220 ASSERT_LT(i, argc) << "Specify filename after -o";
221 out_filename = argv[i];
222
223 } else if (strcmp(argv[i], "-fs") == 0) {
224 i++;
225 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
226 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
227 samples_per_channel = sample_rate_hz / 100;
228
229 ASSERT_EQ(apm->kNoError,
230 apm->set_sample_rate_hz(sample_rate_hz));
231
232 } else if (strcmp(argv[i], "-ch") == 0) {
233 i++;
234 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
235 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
236 i++;
237 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
238
239 ASSERT_EQ(apm->kNoError,
240 apm->set_num_channels(num_capture_input_channels,
241 num_capture_output_channels));
242
243 } else if (strcmp(argv[i], "-rch") == 0) {
244 i++;
245 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
246 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
247
248 ASSERT_EQ(apm->kNoError,
249 apm->set_num_reverse_channels(num_render_channels));
250
251 } else if (strcmp(argv[i], "-aec") == 0) {
252 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000253 ASSERT_EQ(apm->kNoError,
254 apm->echo_cancellation()->enable_metrics(true));
255 ASSERT_EQ(apm->kNoError,
256 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000257
niklase@google.com470e71d2011-07-07 08:21:25 +0000258 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
259 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
260 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
261 // why it can give better performance despite passing zeros.
262 ASSERT_EQ(apm->kNoError,
263 apm->echo_cancellation()->enable_drift_compensation(true));
264 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
265 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
266 ASSERT_EQ(apm->kNoError,
267 apm->echo_cancellation()->enable_drift_compensation(false));
268
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000269 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
270 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
271 ASSERT_EQ(apm->kNoError,
272 apm->echo_cancellation()->enable_metrics(false));
273
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000274 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
275 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
276 ASSERT_EQ(apm->kNoError,
277 apm->echo_cancellation()->enable_delay_logging(false));
278
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000279 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
280 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
281
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000282 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
283 i++;
284 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
285 int suppression_level;
286 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
287 ASSERT_EQ(apm->kNoError,
288 apm->echo_cancellation()->set_suppression_level(
289 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
290 suppression_level)));
291
niklase@google.com470e71d2011-07-07 08:21:25 +0000292 } else if (strcmp(argv[i], "-aecm") == 0) {
293 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
294
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000295 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
296 i++;
297 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
298 aecm_echo_path_in_filename = argv[i];
299
300 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
301 i++;
302 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
303 aecm_echo_path_out_filename = argv[i];
304
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000305 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
306 ASSERT_EQ(apm->kNoError,
307 apm->echo_control_mobile()->enable_comfort_noise(false));
308
309 } else if (strcmp(argv[i], "--routing_mode") == 0) {
310 i++;
311 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
312 int routing_mode;
313 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
314 ASSERT_EQ(apm->kNoError,
315 apm->echo_control_mobile()->set_routing_mode(
316 static_cast<webrtc::EchoControlMobile::RoutingMode>(
317 routing_mode)));
318
niklase@google.com470e71d2011-07-07 08:21:25 +0000319 } else if (strcmp(argv[i], "-agc") == 0) {
320 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
321
322 } else if (strcmp(argv[i], "--analog") == 0) {
323 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
324 ASSERT_EQ(apm->kNoError,
325 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
326
327 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
328 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
329 ASSERT_EQ(apm->kNoError,
330 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
331
332 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
333 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
334 ASSERT_EQ(apm->kNoError,
335 apm->gain_control()->set_mode(GainControl::kFixedDigital));
336
337 } else if (strcmp(argv[i], "--target_level") == 0) {
338 i++;
339 int level;
340 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
341
342 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
343 ASSERT_EQ(apm->kNoError,
344 apm->gain_control()->set_target_level_dbfs(level));
345
346 } else if (strcmp(argv[i], "--compression_gain") == 0) {
347 i++;
348 int gain;
349 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
350
351 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
352 ASSERT_EQ(apm->kNoError,
353 apm->gain_control()->set_compression_gain_db(gain));
354
355 } else if (strcmp(argv[i], "--limiter") == 0) {
356 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
357 ASSERT_EQ(apm->kNoError,
358 apm->gain_control()->enable_limiter(true));
359
360 } else if (strcmp(argv[i], "--no_limiter") == 0) {
361 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
362 ASSERT_EQ(apm->kNoError,
363 apm->gain_control()->enable_limiter(false));
364
365 } else if (strcmp(argv[i], "-hpf") == 0) {
366 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
367
368 } else if (strcmp(argv[i], "-ns") == 0) {
369 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
370
371 } else if (strcmp(argv[i], "--ns_low") == 0) {
372 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
373 ASSERT_EQ(apm->kNoError,
374 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
375
376 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
377 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
378 ASSERT_EQ(apm->kNoError,
379 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
380
381 } else if (strcmp(argv[i], "--ns_high") == 0) {
382 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
383 ASSERT_EQ(apm->kNoError,
384 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
385
386 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
387 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
388 ASSERT_EQ(apm->kNoError,
389 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
390
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000391 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
392 i++;
393 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
394 ns_prob_filename = argv[i];
395
niklase@google.com470e71d2011-07-07 08:21:25 +0000396 } else if (strcmp(argv[i], "-vad") == 0) {
397 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
398
andrew@webrtc.org89752612012-10-12 16:41:45 +0000399 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
400 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
401 ASSERT_EQ(apm->kNoError,
402 apm->voice_detection()->set_likelihood(
403 VoiceDetection::kVeryLowLikelihood));
404
405 } else if (strcmp(argv[i], "--vad_low") == 0) {
406 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
407 ASSERT_EQ(apm->kNoError,
408 apm->voice_detection()->set_likelihood(
409 VoiceDetection::kLowLikelihood));
410
411 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
412 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
413 ASSERT_EQ(apm->kNoError,
414 apm->voice_detection()->set_likelihood(
415 VoiceDetection::kModerateLikelihood));
416
417 } else if (strcmp(argv[i], "--vad_high") == 0) {
418 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
419 ASSERT_EQ(apm->kNoError,
420 apm->voice_detection()->set_likelihood(
421 VoiceDetection::kHighLikelihood));
422
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
424 i++;
425 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
426 vad_out_filename = argv[i];
427
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000428 } else if (strcmp(argv[i], "--noasm") == 0) {
429 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
430 // We need to reinitialize here if components have already been enabled.
431 ASSERT_EQ(apm->kNoError, apm->Initialize());
432
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000433 } else if (strcmp(argv[i], "--delay") == 0) {
434 i++;
435 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
436
niklase@google.com470e71d2011-07-07 08:21:25 +0000437 } 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
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000447 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000448 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000449 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000450 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 } else {
452 FAIL() << "Unrecognized argument " << argv[i];
453 }
454 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000455 // If we're reading a protobuf file, ensure a simulation hasn't also
456 // been requested (which makes no sense...)
457 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000458
459 if (verbose) {
460 printf("Sample rate: %d Hz\n", sample_rate_hz);
461 printf("Primary channels: %d (in), %d (out)\n",
462 num_capture_input_channels,
463 num_capture_output_channels);
464 printf("Reverse channels: %d \n", num_render_channels);
465 }
466
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000467 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 const char far_file_default[] = "apm_far.pcm";
469 const char near_file_default[] = "apm_near.pcm";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000470 const std::string out_file_default = out_path + "out.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 const char event_filename[] = "apm_event.dat";
472 const char delay_filename[] = "apm_delay.dat";
473 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000474 const std::string vad_file_default = out_path + "vad_out.dat";
475 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000476
477 if (!simulating) {
478 far_filename = far_file_default;
479 near_filename = near_file_default;
480 }
481
ajm@google.com808e0e02011-08-03 21:08:51 +0000482 if (!out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000483 out_filename = out_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000484 }
485
ajm@google.com808e0e02011-08-03 21:08:51 +0000486 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000487 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000488 }
489
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000490 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000491 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000492 }
493
ajm@google.com808e0e02011-08-03 21:08:51 +0000494 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000495 FILE* far_file = NULL;
496 FILE* near_file = NULL;
497 FILE* out_file = NULL;
498 FILE* event_file = NULL;
499 FILE* delay_file = NULL;
500 FILE* drift_file = NULL;
501 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000502 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000503 FILE* aecm_echo_path_in_file = NULL;
504 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000505
ajm@google.com808e0e02011-08-03 21:08:51 +0000506 if (pb_filename) {
507 pb_file = fopen(pb_filename, "rb");
508 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
509 << pb_filename;
510 } else {
511 if (far_filename) {
512 far_file = fopen(far_filename, "rb");
513 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
514 << far_filename;
515 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000516
ajm@google.com808e0e02011-08-03 21:08:51 +0000517 near_file = fopen(near_filename, "rb");
518 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
519 << near_filename;
520 if (!simulating) {
521 event_file = fopen(event_filename, "rb");
522 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
523 << event_filename;
524
525 delay_file = fopen(delay_filename, "rb");
526 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
527 << delay_filename;
528
529 drift_file = fopen(drift_filename, "rb");
530 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
531 << drift_filename;
532 }
533 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000534
535 out_file = fopen(out_filename, "wb");
536 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
537 << out_filename;
538
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000539 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000540 if (pb_file) {
541 struct stat st;
542 stat(pb_filename, &st);
543 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000544 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000545 } else {
546 struct stat st;
547 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000548 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000549 }
550
551 if (apm->voice_detection()->is_enabled()) {
552 vad_out_file = fopen(vad_out_filename, "wb");
553 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
554 << vad_out_file;
555 }
556
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000557 if (apm->noise_suppression()->is_enabled()) {
558 ns_prob_file = fopen(ns_prob_filename, "wb");
559 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
560 << ns_prob_file;
561 }
562
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000563 if (aecm_echo_path_in_filename != NULL) {
564 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
565 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
566 << aecm_echo_path_in_filename;
567
ajm@google.com22e65152011-07-18 18:03:01 +0000568 const size_t path_size =
569 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000570 scoped_array<char> echo_path(new char[path_size]);
571 ASSERT_EQ(path_size, fread(echo_path.get(),
572 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000573 path_size,
574 aecm_echo_path_in_file));
575 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000576 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
577 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000578 fclose(aecm_echo_path_in_file);
579 aecm_echo_path_in_file = NULL;
580 }
581
582 if (aecm_echo_path_out_filename != NULL) {
583 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
584 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
585 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000586 }
587
niklase@google.com470e71d2011-07-07 08:21:25 +0000588 size_t read_count = 0;
589 int reverse_count = 0;
590 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000591 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 TickInterval acc_ticks;
593
594 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000595 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000596
597 int delay_ms = 0;
598 int drift_samples = 0;
599 int capture_level = 127;
600 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000601 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000602
603 TickTime t0 = TickTime::Now();
604 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000605 int64_t max_time_us = 0;
606 int64_t max_time_reverse_us = 0;
607 int64_t min_time_us = 1e6;
608 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000609
ajm@google.com808e0e02011-08-03 21:08:51 +0000610 // TODO(ajm): Ideally we would refactor this block into separate functions,
611 // but for now we want to share the variables.
612 if (pb_file) {
613 Event event_msg;
614 while (ReadMessageFromFile(pb_file, &event_msg)) {
615 std::ostringstream trace_stream;
616 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
617 << primary_count << " (primary)";
618 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000619
ajm@google.com808e0e02011-08-03 21:08:51 +0000620 if (event_msg.type() == Event::INIT) {
621 ASSERT_TRUE(event_msg.has_init());
622 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000623
ajm@google.com808e0e02011-08-03 21:08:51 +0000624 ASSERT_TRUE(msg.has_sample_rate());
625 ASSERT_EQ(apm->kNoError,
626 apm->set_sample_rate_hz(msg.sample_rate()));
627
628 ASSERT_TRUE(msg.has_device_sample_rate());
629 ASSERT_EQ(apm->kNoError,
630 apm->echo_cancellation()->set_device_sample_rate_hz(
631 msg.device_sample_rate()));
632
633 ASSERT_TRUE(msg.has_num_input_channels());
634 ASSERT_TRUE(msg.has_num_output_channels());
635 ASSERT_EQ(apm->kNoError,
636 apm->set_num_channels(msg.num_input_channels(),
637 msg.num_output_channels()));
638
639 ASSERT_TRUE(msg.has_num_reverse_channels());
640 ASSERT_EQ(apm->kNoError,
641 apm->set_num_reverse_channels(msg.num_reverse_channels()));
642
643 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000644 far_frame.sample_rate_hz_ = msg.sample_rate();
645 far_frame.samples_per_channel_ = samples_per_channel;
646 far_frame.num_channels_ = msg.num_reverse_channels();
647 near_frame.sample_rate_hz_ = msg.sample_rate();
648 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000649 near_frame.num_channels_ = msg.num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000650
651 if (verbose) {
652 printf("Init at frame: %d (primary), %d (reverse)\n",
653 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000654 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000655 printf(" Primary channels: %d (in), %d (out)\n",
656 msg.num_input_channels(),
657 msg.num_output_channels());
658 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000659 }
660
661 } else if (event_msg.type() == Event::REVERSE_STREAM) {
662 ASSERT_TRUE(event_msg.has_reverse_stream());
663 const ReverseStream msg = event_msg.reverse_stream();
664 reverse_count++;
665
666 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000667 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000668 far_frame.num_channels_, msg.data().size());
669 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000670
671 if (perf_testing) {
672 t0 = TickTime::Now();
673 }
674
675 ASSERT_EQ(apm->kNoError,
676 apm->AnalyzeReverseStream(&far_frame));
677
678 if (perf_testing) {
679 t1 = TickTime::Now();
680 TickInterval tick_diff = t1 - t0;
681 acc_ticks += tick_diff;
682 if (tick_diff.Microseconds() > max_time_reverse_us) {
683 max_time_reverse_us = tick_diff.Microseconds();
684 }
685 if (tick_diff.Microseconds() < min_time_reverse_us) {
686 min_time_reverse_us = tick_diff.Microseconds();
687 }
688 }
689
690 } else if (event_msg.type() == Event::STREAM) {
691 ASSERT_TRUE(event_msg.has_stream());
692 const Stream msg = event_msg.stream();
693 primary_count++;
694
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000695 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000696 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000697
698 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000699 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000700 near_frame.num_channels_, msg.input_data().size());
701 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000702 msg.input_data().data(),
703 msg.input_data().size());
704
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000705 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000706 if (progress && primary_count % 100 == 0) {
707 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000708 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000709 fflush(stdout);
710 }
711
712 if (perf_testing) {
713 t0 = TickTime::Now();
714 }
715
716 ASSERT_EQ(apm->kNoError,
717 apm->gain_control()->set_stream_analog_level(msg.level()));
718 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000719 apm->set_stream_delay_ms(msg.delay() + extra_delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000720 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000721
722 int err = apm->ProcessStream(&near_frame);
723 if (err == apm->kBadStreamParameterWarning) {
724 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
725 }
726 ASSERT_TRUE(err == apm->kNoError ||
727 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000728 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000729
ajm@google.com808e0e02011-08-03 21:08:51 +0000730 stream_has_voice =
731 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
732 if (vad_out_file != NULL) {
733 ASSERT_EQ(1u, fwrite(&stream_has_voice,
734 sizeof(stream_has_voice),
735 1,
736 vad_out_file));
737 }
738
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000739 if (ns_prob_file != NULL) {
740 ns_speech_prob = apm->noise_suppression()->speech_probability();
741 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
742 sizeof(ns_speech_prob),
743 1,
744 ns_prob_file));
745 }
746
ajm@google.com808e0e02011-08-03 21:08:51 +0000747 if (perf_testing) {
748 t1 = TickTime::Now();
749 TickInterval tick_diff = t1 - t0;
750 acc_ticks += tick_diff;
751 if (tick_diff.Microseconds() > max_time_us) {
752 max_time_us = tick_diff.Microseconds();
753 }
754 if (tick_diff.Microseconds() < min_time_us) {
755 min_time_us = tick_diff.Microseconds();
756 }
757 }
758
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000759 size_t size = samples_per_channel * near_frame.num_channels_;
760 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000761 sizeof(int16_t),
762 size,
763 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000764 }
765 }
766
767 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000768
769 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000770 enum Events {
771 kInitializeEvent,
772 kRenderEvent,
773 kCaptureEvent,
774 kResetEventDeprecated
775 };
776 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000777 while (simulating || feof(event_file) == 0) {
778 std::ostringstream trace_stream;
779 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
780 << primary_count << " (primary)";
781 SCOPED_TRACE(trace_stream.str());
782
783 if (simulating) {
784 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000785 event = kCaptureEvent;
786 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000787 if (event == kRenderEvent) {
788 event = kCaptureEvent;
789 } else {
790 event = kRenderEvent;
791 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000792 }
793 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000794 read_count = fread(&event, sizeof(event), 1, event_file);
795 if (read_count != 1) {
796 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000797 }
798 }
799
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000800 far_frame.sample_rate_hz_ = sample_rate_hz;
801 far_frame.samples_per_channel_ = samples_per_channel;
802 far_frame.num_channels_ = num_render_channels;
803 near_frame.sample_rate_hz_ = sample_rate_hz;
804 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000805
ajm@google.com808e0e02011-08-03 21:08:51 +0000806 if (event == kInitializeEvent || event == kResetEventDeprecated) {
807 ASSERT_EQ(1u,
808 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
809 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000810
ajm@google.com808e0e02011-08-03 21:08:51 +0000811 ASSERT_EQ(1u,
812 fread(&device_sample_rate_hz,
813 sizeof(device_sample_rate_hz),
814 1,
815 event_file));
816
817 ASSERT_EQ(apm->kNoError,
818 apm->set_sample_rate_hz(sample_rate_hz));
819
820 ASSERT_EQ(apm->kNoError,
821 apm->echo_cancellation()->set_device_sample_rate_hz(
822 device_sample_rate_hz));
823
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000824 far_frame.sample_rate_hz_ = sample_rate_hz;
825 far_frame.samples_per_channel_ = samples_per_channel;
826 far_frame.num_channels_ = num_render_channels;
827 near_frame.sample_rate_hz_ = sample_rate_hz;
828 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000829
830 if (verbose) {
831 printf("Init at frame: %d (primary), %d (reverse)\n",
832 primary_count, reverse_count);
833 printf(" Sample rate: %d Hz\n", sample_rate_hz);
834 }
835
836 } else if (event == kRenderEvent) {
837 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000838
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000839 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000840 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000841 sizeof(int16_t),
842 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000843 far_file);
844
845 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000846 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000847 // Read an equal amount from the near file to avoid errors due to
848 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000849 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000850 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000851 break; // This is expected.
852 }
853 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000854 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000855 }
856
857 if (perf_testing) {
858 t0 = TickTime::Now();
859 }
860
861 ASSERT_EQ(apm->kNoError,
862 apm->AnalyzeReverseStream(&far_frame));
863
864 if (perf_testing) {
865 t1 = TickTime::Now();
866 TickInterval tick_diff = t1 - t0;
867 acc_ticks += tick_diff;
868 if (tick_diff.Microseconds() > max_time_reverse_us) {
869 max_time_reverse_us = tick_diff.Microseconds();
870 }
871 if (tick_diff.Microseconds() < min_time_reverse_us) {
872 min_time_reverse_us = tick_diff.Microseconds();
873 }
874 }
875
876 } else if (event == kCaptureEvent) {
877 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000878 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000879
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000880 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000881 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000882 sizeof(int16_t),
883 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000884 near_file);
885
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000886 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000887 if (progress && primary_count % 100 == 0) {
888 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000889 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000890 fflush(stdout);
891 }
892 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000893 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000894 break; // This is expected.
895 }
896
897 delay_ms = 0;
898 drift_samples = 0;
899 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000900 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000901
902 // TODO(ajm): sizeof(delay_ms) for current files?
903 ASSERT_EQ(1u,
904 fread(&delay_ms, 2, 1, delay_file));
905 ASSERT_EQ(1u,
906 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
907 }
908
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000909 if (apm->gain_control()->is_enabled() &&
910 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000911 SimulateMic(capture_level, &near_frame);
912 }
913
ajm@google.com808e0e02011-08-03 21:08:51 +0000914 if (perf_testing) {
915 t0 = TickTime::Now();
916 }
917
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000918 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000919 ASSERT_EQ(apm->kNoError,
920 apm->gain_control()->set_stream_analog_level(capture_level));
921 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000922 apm->set_stream_delay_ms(delay_ms + extra_delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000923 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000924
925 int err = apm->ProcessStream(&near_frame);
926 if (err == apm->kBadStreamParameterWarning) {
927 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
928 }
929 ASSERT_TRUE(err == apm->kNoError ||
930 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000931 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000932
933 capture_level = apm->gain_control()->stream_analog_level();
934
935 stream_has_voice =
936 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
937 if (vad_out_file != NULL) {
938 ASSERT_EQ(1u, fwrite(&stream_has_voice,
939 sizeof(stream_has_voice),
940 1,
941 vad_out_file));
942 }
943
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000944 if (ns_prob_file != NULL) {
945 ns_speech_prob = apm->noise_suppression()->speech_probability();
946 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
947 sizeof(ns_speech_prob),
948 1,
949 ns_prob_file));
950 }
951
ajm@google.com808e0e02011-08-03 21:08:51 +0000952 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
953 ASSERT_EQ(capture_level_in, capture_level);
954 }
955
956 if (perf_testing) {
957 t1 = TickTime::Now();
958 TickInterval tick_diff = t1 - t0;
959 acc_ticks += tick_diff;
960 if (tick_diff.Microseconds() > max_time_us) {
961 max_time_us = tick_diff.Microseconds();
962 }
963 if (tick_diff.Microseconds() < min_time_us) {
964 min_time_us = tick_diff.Microseconds();
965 }
966 }
967
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000968 size = samples_per_channel * near_frame.num_channels_;
969 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000970 sizeof(int16_t),
971 size,
972 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000973 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000974 else {
975 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000977 }
978 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000979 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000980
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000981 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000982 const size_t path_size =
983 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000984 scoped_array<char> echo_path(new char[path_size]);
985 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
986 ASSERT_EQ(path_size, fwrite(echo_path.get(),
987 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000988 path_size,
989 aecm_echo_path_out_file));
990 fclose(aecm_echo_path_out_file);
991 aecm_echo_path_out_file = NULL;
992 }
993
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 if (verbose) {
995 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
996 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000997
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000998 if (apm->level_estimator()->is_enabled()) {
999 printf("\n--Level metrics--\n");
1000 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1001 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001002 if (apm->echo_cancellation()->are_metrics_enabled()) {
1003 EchoCancellation::Metrics metrics;
1004 apm->echo_cancellation()->GetMetrics(&metrics);
1005 printf("\n--Echo metrics--\n");
1006 printf("(avg, max, min)\n");
1007 printf("ERL: ");
1008 PrintStat(metrics.echo_return_loss);
1009 printf("ERLE: ");
1010 PrintStat(metrics.echo_return_loss_enhancement);
1011 printf("ANLP: ");
1012 PrintStat(metrics.a_nlp);
1013 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001014 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1015 int median = 0;
1016 int std = 0;
1017 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1018 printf("\n--Delay metrics--\n");
1019 printf("Median: %3d\n", median);
1020 printf("Standard deviation: %3d\n", std);
1021 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 }
1023
ajm@google.com808e0e02011-08-03 21:08:51 +00001024 if (!pb_file) {
1025 int8_t temp_int8;
1026 if (far_file) {
1027 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1028 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1029 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001030
ajm@google.com808e0e02011-08-03 21:08:51 +00001031 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1032 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1033
1034 if (!simulating) {
1035 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1036 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1037 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1038 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1039 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1040 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1041 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 }
1043
1044 if (perf_testing) {
1045 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001046 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1048 exec_time * 0.001, primary_count * 0.01);
1049 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1050 " %.3f ms (min)\n",
1051 (exec_time * 1.0) / primary_count,
1052 (max_time_us + max_time_reverse_us) / 1000.0,
1053 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001054 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001055 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001056 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 } else {
1058 printf("Warning: no capture frames\n");
1059 }
1060 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001061}
ajm@google.com808e0e02011-08-03 21:08:51 +00001062} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001063
1064int main(int argc, char* argv[])
1065{
1066 void_main(argc, argv);
1067
andrew@webrtc.org64235092011-08-19 21:22:08 +00001068 // Optional, but removes memory leak noise from Valgrind.
1069 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 return 0;
1071}