blob: b52ac983614d3fa9d7693dbd14b9f878c2b6e86b [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.orgca764ab2013-10-07 16:44:32 +0000136 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
137 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000138 printf(" --perf Measure performance.\n");
139 printf(" --quiet Suppress text output.\n");
140 printf(" --no_progress Suppress progress.\n");
141 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000142}
143
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000144static float MicLevel2Gain(int level) {
145 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000146}
147
148static void SimulateMic(int mic_level, AudioFrame* frame) {
149 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000150 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000151 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000152 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000153 for (int n = 0; n < num_samples; n++) {
154 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000155 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000156 frame->data_[n] = static_cast<int16_t>(v);
157 }
158}
159
niklase@google.com470e71d2011-07-07 08:21:25 +0000160// void function for gtest.
161void void_main(int argc, char* argv[]) {
162 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
163 usage();
164 return;
165 }
166
167 if (argc < 2) {
168 printf("Did you mean to run without arguments?\n");
169 printf("Try `process_test --help' for more information.\n\n");
170 }
171
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000172 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create(0));
173 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
ajm@google.com808e0e02011-08-03 21:08:51 +0000175 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 const char* far_filename = NULL;
177 const char* near_filename = NULL;
178 const char* out_filename = NULL;
179 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000180 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000181 const char* aecm_echo_path_in_filename = NULL;
182 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000183
184 int32_t sample_rate_hz = 16000;
185 int32_t device_sample_rate_hz = 16000;
186
187 int num_capture_input_channels = 1;
188 int num_capture_output_channels = 1;
189 int num_render_channels = 1;
190
191 int samples_per_channel = sample_rate_hz / 100;
192
193 bool simulating = false;
194 bool perf_testing = false;
195 bool verbose = true;
196 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000197 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000198 int override_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 //bool interleaved = true;
200
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000201 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000203 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000204 i++;
205 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
206 pb_filename = argv[i];
207
208 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 i++;
210 ASSERT_LT(i, argc) << "Specify filename after -ir";
211 far_filename = argv[i];
212 simulating = true;
213
214 } else if (strcmp(argv[i], "-i") == 0) {
215 i++;
216 ASSERT_LT(i, argc) << "Specify filename after -i";
217 near_filename = argv[i];
218 simulating = true;
219
220 } else if (strcmp(argv[i], "-o") == 0) {
221 i++;
222 ASSERT_LT(i, argc) << "Specify filename after -o";
223 out_filename = argv[i];
224
225 } else if (strcmp(argv[i], "-fs") == 0) {
226 i++;
227 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
228 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
229 samples_per_channel = sample_rate_hz / 100;
230
231 ASSERT_EQ(apm->kNoError,
232 apm->set_sample_rate_hz(sample_rate_hz));
233
234 } else if (strcmp(argv[i], "-ch") == 0) {
235 i++;
236 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
237 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
238 i++;
239 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
240
241 ASSERT_EQ(apm->kNoError,
242 apm->set_num_channels(num_capture_input_channels,
243 num_capture_output_channels));
244
245 } else if (strcmp(argv[i], "-rch") == 0) {
246 i++;
247 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
248 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
249
250 ASSERT_EQ(apm->kNoError,
251 apm->set_num_reverse_channels(num_render_channels));
252
253 } else if (strcmp(argv[i], "-aec") == 0) {
254 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000255 ASSERT_EQ(apm->kNoError,
256 apm->echo_cancellation()->enable_metrics(true));
257 ASSERT_EQ(apm->kNoError,
258 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000259
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
261 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
262 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
263 // why it can give better performance despite passing zeros.
264 ASSERT_EQ(apm->kNoError,
265 apm->echo_cancellation()->enable_drift_compensation(true));
266 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
267 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
268 ASSERT_EQ(apm->kNoError,
269 apm->echo_cancellation()->enable_drift_compensation(false));
270
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000271 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
272 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
273 ASSERT_EQ(apm->kNoError,
274 apm->echo_cancellation()->enable_metrics(false));
275
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000276 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
277 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
278 ASSERT_EQ(apm->kNoError,
279 apm->echo_cancellation()->enable_delay_logging(false));
280
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000281 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
282 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
283
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000284 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
285 i++;
286 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
287 int suppression_level;
288 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
289 ASSERT_EQ(apm->kNoError,
290 apm->echo_cancellation()->set_suppression_level(
291 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
292 suppression_level)));
293
niklase@google.com470e71d2011-07-07 08:21:25 +0000294 } else if (strcmp(argv[i], "-aecm") == 0) {
295 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
296
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000297 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
298 i++;
299 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
300 aecm_echo_path_in_filename = argv[i];
301
302 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
303 i++;
304 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
305 aecm_echo_path_out_filename = argv[i];
306
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000307 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
308 ASSERT_EQ(apm->kNoError,
309 apm->echo_control_mobile()->enable_comfort_noise(false));
310
311 } else if (strcmp(argv[i], "--routing_mode") == 0) {
312 i++;
313 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
314 int routing_mode;
315 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
316 ASSERT_EQ(apm->kNoError,
317 apm->echo_control_mobile()->set_routing_mode(
318 static_cast<webrtc::EchoControlMobile::RoutingMode>(
319 routing_mode)));
320
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 } else if (strcmp(argv[i], "-agc") == 0) {
322 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
323
324 } else if (strcmp(argv[i], "--analog") == 0) {
325 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
326 ASSERT_EQ(apm->kNoError,
327 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
328
329 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
330 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
331 ASSERT_EQ(apm->kNoError,
332 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
333
334 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
335 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
336 ASSERT_EQ(apm->kNoError,
337 apm->gain_control()->set_mode(GainControl::kFixedDigital));
338
339 } else if (strcmp(argv[i], "--target_level") == 0) {
340 i++;
341 int level;
342 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
343
344 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
345 ASSERT_EQ(apm->kNoError,
346 apm->gain_control()->set_target_level_dbfs(level));
347
348 } else if (strcmp(argv[i], "--compression_gain") == 0) {
349 i++;
350 int gain;
351 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
352
353 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
354 ASSERT_EQ(apm->kNoError,
355 apm->gain_control()->set_compression_gain_db(gain));
356
357 } else if (strcmp(argv[i], "--limiter") == 0) {
358 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
359 ASSERT_EQ(apm->kNoError,
360 apm->gain_control()->enable_limiter(true));
361
362 } else if (strcmp(argv[i], "--no_limiter") == 0) {
363 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
364 ASSERT_EQ(apm->kNoError,
365 apm->gain_control()->enable_limiter(false));
366
367 } else if (strcmp(argv[i], "-hpf") == 0) {
368 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
369
370 } else if (strcmp(argv[i], "-ns") == 0) {
371 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
372
373 } else if (strcmp(argv[i], "--ns_low") == 0) {
374 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
375 ASSERT_EQ(apm->kNoError,
376 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
377
378 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
379 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
380 ASSERT_EQ(apm->kNoError,
381 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
382
383 } else if (strcmp(argv[i], "--ns_high") == 0) {
384 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
385 ASSERT_EQ(apm->kNoError,
386 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
387
388 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
389 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
390 ASSERT_EQ(apm->kNoError,
391 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
392
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000393 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
394 i++;
395 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
396 ns_prob_filename = argv[i];
397
niklase@google.com470e71d2011-07-07 08:21:25 +0000398 } else if (strcmp(argv[i], "-vad") == 0) {
399 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
400
andrew@webrtc.org89752612012-10-12 16:41:45 +0000401 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
402 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
403 ASSERT_EQ(apm->kNoError,
404 apm->voice_detection()->set_likelihood(
405 VoiceDetection::kVeryLowLikelihood));
406
407 } else if (strcmp(argv[i], "--vad_low") == 0) {
408 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
409 ASSERT_EQ(apm->kNoError,
410 apm->voice_detection()->set_likelihood(
411 VoiceDetection::kLowLikelihood));
412
413 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
414 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
415 ASSERT_EQ(apm->kNoError,
416 apm->voice_detection()->set_likelihood(
417 VoiceDetection::kModerateLikelihood));
418
419 } else if (strcmp(argv[i], "--vad_high") == 0) {
420 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
421 ASSERT_EQ(apm->kNoError,
422 apm->voice_detection()->set_likelihood(
423 VoiceDetection::kHighLikelihood));
424
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
426 i++;
427 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
428 vad_out_filename = argv[i];
429
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000430 } else if (strcmp(argv[i], "--noasm") == 0) {
431 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
432 // We need to reinitialize here if components have already been enabled.
433 ASSERT_EQ(apm->kNoError, apm->Initialize());
434
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000435 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000436 i++;
437 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
438
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000439 } else if (strcmp(argv[i], "--delay") == 0) {
440 i++;
441 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
442
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 } else if (strcmp(argv[i], "--perf") == 0) {
444 perf_testing = true;
445
446 } else if (strcmp(argv[i], "--quiet") == 0) {
447 verbose = false;
448 progress = false;
449
450 } else if (strcmp(argv[i], "--no_progress") == 0) {
451 progress = false;
452
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000453 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000454 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000455 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000456 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 } else {
458 FAIL() << "Unrecognized argument " << argv[i];
459 }
460 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000461 // If we're reading a protobuf file, ensure a simulation hasn't also
462 // been requested (which makes no sense...)
463 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000464
465 if (verbose) {
466 printf("Sample rate: %d Hz\n", sample_rate_hz);
467 printf("Primary channels: %d (in), %d (out)\n",
468 num_capture_input_channels,
469 num_capture_output_channels);
470 printf("Reverse channels: %d \n", num_render_channels);
471 }
472
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000473 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000474 const char far_file_default[] = "apm_far.pcm";
475 const char near_file_default[] = "apm_near.pcm";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000476 const std::string out_file_default = out_path + "out.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 const char event_filename[] = "apm_event.dat";
478 const char delay_filename[] = "apm_delay.dat";
479 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000480 const std::string vad_file_default = out_path + "vad_out.dat";
481 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000482
483 if (!simulating) {
484 far_filename = far_file_default;
485 near_filename = near_file_default;
486 }
487
ajm@google.com808e0e02011-08-03 21:08:51 +0000488 if (!out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000489 out_filename = out_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 }
491
ajm@google.com808e0e02011-08-03 21:08:51 +0000492 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000493 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 }
495
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000496 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000497 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000498 }
499
ajm@google.com808e0e02011-08-03 21:08:51 +0000500 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 FILE* far_file = NULL;
502 FILE* near_file = NULL;
503 FILE* out_file = NULL;
504 FILE* event_file = NULL;
505 FILE* delay_file = NULL;
506 FILE* drift_file = NULL;
507 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000508 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000509 FILE* aecm_echo_path_in_file = NULL;
510 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000511
ajm@google.com808e0e02011-08-03 21:08:51 +0000512 if (pb_filename) {
513 pb_file = fopen(pb_filename, "rb");
514 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
515 << pb_filename;
516 } else {
517 if (far_filename) {
518 far_file = fopen(far_filename, "rb");
519 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
520 << far_filename;
521 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000522
ajm@google.com808e0e02011-08-03 21:08:51 +0000523 near_file = fopen(near_filename, "rb");
524 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
525 << near_filename;
526 if (!simulating) {
527 event_file = fopen(event_filename, "rb");
528 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
529 << event_filename;
530
531 delay_file = fopen(delay_filename, "rb");
532 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
533 << delay_filename;
534
535 drift_file = fopen(drift_filename, "rb");
536 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
537 << drift_filename;
538 }
539 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000540
541 out_file = fopen(out_filename, "wb");
542 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
543 << out_filename;
544
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000545 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000546 if (pb_file) {
547 struct stat st;
548 stat(pb_filename, &st);
549 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000550 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000551 } else {
552 struct stat st;
553 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000554 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 }
556
557 if (apm->voice_detection()->is_enabled()) {
558 vad_out_file = fopen(vad_out_filename, "wb");
559 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
560 << vad_out_file;
561 }
562
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000563 if (apm->noise_suppression()->is_enabled()) {
564 ns_prob_file = fopen(ns_prob_filename, "wb");
565 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
566 << ns_prob_file;
567 }
568
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000569 if (aecm_echo_path_in_filename != NULL) {
570 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
571 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
572 << aecm_echo_path_in_filename;
573
ajm@google.com22e65152011-07-18 18:03:01 +0000574 const size_t path_size =
575 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000576 scoped_array<char> echo_path(new char[path_size]);
577 ASSERT_EQ(path_size, fread(echo_path.get(),
578 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000579 path_size,
580 aecm_echo_path_in_file));
581 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000582 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
583 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000584 fclose(aecm_echo_path_in_file);
585 aecm_echo_path_in_file = NULL;
586 }
587
588 if (aecm_echo_path_out_filename != NULL) {
589 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
590 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
591 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000592 }
593
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 size_t read_count = 0;
595 int reverse_count = 0;
596 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000597 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 TickInterval acc_ticks;
599
600 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000601 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000602
603 int delay_ms = 0;
604 int drift_samples = 0;
605 int capture_level = 127;
606 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000607 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000608
609 TickTime t0 = TickTime::Now();
610 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000611 int64_t max_time_us = 0;
612 int64_t max_time_reverse_us = 0;
613 int64_t min_time_us = 1e6;
614 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000615
ajm@google.com808e0e02011-08-03 21:08:51 +0000616 // TODO(ajm): Ideally we would refactor this block into separate functions,
617 // but for now we want to share the variables.
618 if (pb_file) {
619 Event event_msg;
620 while (ReadMessageFromFile(pb_file, &event_msg)) {
621 std::ostringstream trace_stream;
622 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
623 << primary_count << " (primary)";
624 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000625
ajm@google.com808e0e02011-08-03 21:08:51 +0000626 if (event_msg.type() == Event::INIT) {
627 ASSERT_TRUE(event_msg.has_init());
628 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000629
ajm@google.com808e0e02011-08-03 21:08:51 +0000630 ASSERT_TRUE(msg.has_sample_rate());
631 ASSERT_EQ(apm->kNoError,
632 apm->set_sample_rate_hz(msg.sample_rate()));
633
634 ASSERT_TRUE(msg.has_device_sample_rate());
635 ASSERT_EQ(apm->kNoError,
636 apm->echo_cancellation()->set_device_sample_rate_hz(
637 msg.device_sample_rate()));
638
639 ASSERT_TRUE(msg.has_num_input_channels());
640 ASSERT_TRUE(msg.has_num_output_channels());
641 ASSERT_EQ(apm->kNoError,
642 apm->set_num_channels(msg.num_input_channels(),
643 msg.num_output_channels()));
644
645 ASSERT_TRUE(msg.has_num_reverse_channels());
646 ASSERT_EQ(apm->kNoError,
647 apm->set_num_reverse_channels(msg.num_reverse_channels()));
648
649 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000650 far_frame.sample_rate_hz_ = msg.sample_rate();
651 far_frame.samples_per_channel_ = samples_per_channel;
652 far_frame.num_channels_ = msg.num_reverse_channels();
653 near_frame.sample_rate_hz_ = msg.sample_rate();
654 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000655 near_frame.num_channels_ = msg.num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000656
657 if (verbose) {
658 printf("Init at frame: %d (primary), %d (reverse)\n",
659 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000660 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000661 printf(" Primary channels: %d (in), %d (out)\n",
662 msg.num_input_channels(),
663 msg.num_output_channels());
664 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000665 }
666
667 } else if (event_msg.type() == Event::REVERSE_STREAM) {
668 ASSERT_TRUE(event_msg.has_reverse_stream());
669 const ReverseStream msg = event_msg.reverse_stream();
670 reverse_count++;
671
672 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000673 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000674 far_frame.num_channels_, msg.data().size());
675 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000676
677 if (perf_testing) {
678 t0 = TickTime::Now();
679 }
680
681 ASSERT_EQ(apm->kNoError,
682 apm->AnalyzeReverseStream(&far_frame));
683
684 if (perf_testing) {
685 t1 = TickTime::Now();
686 TickInterval tick_diff = t1 - t0;
687 acc_ticks += tick_diff;
688 if (tick_diff.Microseconds() > max_time_reverse_us) {
689 max_time_reverse_us = tick_diff.Microseconds();
690 }
691 if (tick_diff.Microseconds() < min_time_reverse_us) {
692 min_time_reverse_us = tick_diff.Microseconds();
693 }
694 }
695
696 } else if (event_msg.type() == Event::STREAM) {
697 ASSERT_TRUE(event_msg.has_stream());
698 const Stream msg = event_msg.stream();
699 primary_count++;
700
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000701 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000702 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000703
704 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000705 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000706 near_frame.num_channels_, msg.input_data().size());
707 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000708 msg.input_data().data(),
709 msg.input_data().size());
710
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000711 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000712 if (progress && primary_count % 100 == 0) {
713 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000714 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000715 fflush(stdout);
716 }
717
718 if (perf_testing) {
719 t0 = TickTime::Now();
720 }
721
722 ASSERT_EQ(apm->kNoError,
723 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000724 delay_ms = msg.delay() + extra_delay_ms;
725 if (override_delay_ms) {
726 delay_ms = override_delay_ms;
727 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000728 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000729 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000730 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000731
732 int err = apm->ProcessStream(&near_frame);
733 if (err == apm->kBadStreamParameterWarning) {
734 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
735 }
736 ASSERT_TRUE(err == apm->kNoError ||
737 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000738 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000739
ajm@google.com808e0e02011-08-03 21:08:51 +0000740 stream_has_voice =
741 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
742 if (vad_out_file != NULL) {
743 ASSERT_EQ(1u, fwrite(&stream_has_voice,
744 sizeof(stream_has_voice),
745 1,
746 vad_out_file));
747 }
748
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000749 if (ns_prob_file != NULL) {
750 ns_speech_prob = apm->noise_suppression()->speech_probability();
751 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
752 sizeof(ns_speech_prob),
753 1,
754 ns_prob_file));
755 }
756
ajm@google.com808e0e02011-08-03 21:08:51 +0000757 if (perf_testing) {
758 t1 = TickTime::Now();
759 TickInterval tick_diff = t1 - t0;
760 acc_ticks += tick_diff;
761 if (tick_diff.Microseconds() > max_time_us) {
762 max_time_us = tick_diff.Microseconds();
763 }
764 if (tick_diff.Microseconds() < min_time_us) {
765 min_time_us = tick_diff.Microseconds();
766 }
767 }
768
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000769 size_t size = samples_per_channel * near_frame.num_channels_;
770 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000771 sizeof(int16_t),
772 size,
773 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000774 }
775 }
776
777 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000778
779 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000780 enum Events {
781 kInitializeEvent,
782 kRenderEvent,
783 kCaptureEvent,
784 kResetEventDeprecated
785 };
786 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000787 while (simulating || feof(event_file) == 0) {
788 std::ostringstream trace_stream;
789 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
790 << primary_count << " (primary)";
791 SCOPED_TRACE(trace_stream.str());
792
793 if (simulating) {
794 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000795 event = kCaptureEvent;
796 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000797 if (event == kRenderEvent) {
798 event = kCaptureEvent;
799 } else {
800 event = kRenderEvent;
801 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 }
803 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000804 read_count = fread(&event, sizeof(event), 1, event_file);
805 if (read_count != 1) {
806 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 }
808 }
809
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000810 far_frame.sample_rate_hz_ = sample_rate_hz;
811 far_frame.samples_per_channel_ = samples_per_channel;
812 far_frame.num_channels_ = num_render_channels;
813 near_frame.sample_rate_hz_ = sample_rate_hz;
814 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000815
ajm@google.com808e0e02011-08-03 21:08:51 +0000816 if (event == kInitializeEvent || event == kResetEventDeprecated) {
817 ASSERT_EQ(1u,
818 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
819 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000820
ajm@google.com808e0e02011-08-03 21:08:51 +0000821 ASSERT_EQ(1u,
822 fread(&device_sample_rate_hz,
823 sizeof(device_sample_rate_hz),
824 1,
825 event_file));
826
827 ASSERT_EQ(apm->kNoError,
828 apm->set_sample_rate_hz(sample_rate_hz));
829
830 ASSERT_EQ(apm->kNoError,
831 apm->echo_cancellation()->set_device_sample_rate_hz(
832 device_sample_rate_hz));
833
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000834 far_frame.sample_rate_hz_ = sample_rate_hz;
835 far_frame.samples_per_channel_ = samples_per_channel;
836 far_frame.num_channels_ = num_render_channels;
837 near_frame.sample_rate_hz_ = sample_rate_hz;
838 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000839
840 if (verbose) {
841 printf("Init at frame: %d (primary), %d (reverse)\n",
842 primary_count, reverse_count);
843 printf(" Sample rate: %d Hz\n", sample_rate_hz);
844 }
845
846 } else if (event == kRenderEvent) {
847 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000848
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000849 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000850 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000851 sizeof(int16_t),
852 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000853 far_file);
854
855 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000856 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000857 // Read an equal amount from the near file to avoid errors due to
858 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000859 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000860 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000861 break; // This is expected.
862 }
863 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000864 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000865 }
866
867 if (perf_testing) {
868 t0 = TickTime::Now();
869 }
870
871 ASSERT_EQ(apm->kNoError,
872 apm->AnalyzeReverseStream(&far_frame));
873
874 if (perf_testing) {
875 t1 = TickTime::Now();
876 TickInterval tick_diff = t1 - t0;
877 acc_ticks += tick_diff;
878 if (tick_diff.Microseconds() > max_time_reverse_us) {
879 max_time_reverse_us = tick_diff.Microseconds();
880 }
881 if (tick_diff.Microseconds() < min_time_reverse_us) {
882 min_time_reverse_us = tick_diff.Microseconds();
883 }
884 }
885
886 } else if (event == kCaptureEvent) {
887 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000888 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000889
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000890 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000891 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000892 sizeof(int16_t),
893 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000894 near_file);
895
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000896 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000897 if (progress && primary_count % 100 == 0) {
898 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000899 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000900 fflush(stdout);
901 }
902 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000903 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000904 break; // This is expected.
905 }
906
907 delay_ms = 0;
908 drift_samples = 0;
909 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000910 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000911
912 // TODO(ajm): sizeof(delay_ms) for current files?
913 ASSERT_EQ(1u,
914 fread(&delay_ms, 2, 1, delay_file));
915 ASSERT_EQ(1u,
916 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
917 }
918
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000919 if (apm->gain_control()->is_enabled() &&
920 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000921 SimulateMic(capture_level, &near_frame);
922 }
923
ajm@google.com808e0e02011-08-03 21:08:51 +0000924 if (perf_testing) {
925 t0 = TickTime::Now();
926 }
927
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000928 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000929 ASSERT_EQ(apm->kNoError,
930 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000931 delay_ms += extra_delay_ms;
932 if (override_delay_ms) {
933 delay_ms = override_delay_ms;
934 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000935 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000936 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000937 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000938
939 int err = apm->ProcessStream(&near_frame);
940 if (err == apm->kBadStreamParameterWarning) {
941 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
942 }
943 ASSERT_TRUE(err == apm->kNoError ||
944 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000945 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000946
947 capture_level = apm->gain_control()->stream_analog_level();
948
949 stream_has_voice =
950 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
951 if (vad_out_file != NULL) {
952 ASSERT_EQ(1u, fwrite(&stream_has_voice,
953 sizeof(stream_has_voice),
954 1,
955 vad_out_file));
956 }
957
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000958 if (ns_prob_file != NULL) {
959 ns_speech_prob = apm->noise_suppression()->speech_probability();
960 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
961 sizeof(ns_speech_prob),
962 1,
963 ns_prob_file));
964 }
965
ajm@google.com808e0e02011-08-03 21:08:51 +0000966 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
967 ASSERT_EQ(capture_level_in, capture_level);
968 }
969
970 if (perf_testing) {
971 t1 = TickTime::Now();
972 TickInterval tick_diff = t1 - t0;
973 acc_ticks += tick_diff;
974 if (tick_diff.Microseconds() > max_time_us) {
975 max_time_us = tick_diff.Microseconds();
976 }
977 if (tick_diff.Microseconds() < min_time_us) {
978 min_time_us = tick_diff.Microseconds();
979 }
980 }
981
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000982 size = samples_per_channel * near_frame.num_channels_;
983 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000984 sizeof(int16_t),
985 size,
986 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000988 else {
989 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 }
992 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000993 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000994
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000995 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000996 const size_t path_size =
997 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000998 scoped_array<char> echo_path(new char[path_size]);
999 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1000 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1001 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001002 path_size,
1003 aecm_echo_path_out_file));
1004 fclose(aecm_echo_path_out_file);
1005 aecm_echo_path_out_file = NULL;
1006 }
1007
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 if (verbose) {
1009 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1010 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001011
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001012 if (apm->level_estimator()->is_enabled()) {
1013 printf("\n--Level metrics--\n");
1014 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1015 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001016 if (apm->echo_cancellation()->are_metrics_enabled()) {
1017 EchoCancellation::Metrics metrics;
1018 apm->echo_cancellation()->GetMetrics(&metrics);
1019 printf("\n--Echo metrics--\n");
1020 printf("(avg, max, min)\n");
1021 printf("ERL: ");
1022 PrintStat(metrics.echo_return_loss);
1023 printf("ERLE: ");
1024 PrintStat(metrics.echo_return_loss_enhancement);
1025 printf("ANLP: ");
1026 PrintStat(metrics.a_nlp);
1027 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001028 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1029 int median = 0;
1030 int std = 0;
1031 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1032 printf("\n--Delay metrics--\n");
1033 printf("Median: %3d\n", median);
1034 printf("Standard deviation: %3d\n", std);
1035 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 }
1037
ajm@google.com808e0e02011-08-03 21:08:51 +00001038 if (!pb_file) {
1039 int8_t temp_int8;
1040 if (far_file) {
1041 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1042 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1043 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001044
ajm@google.com808e0e02011-08-03 21:08:51 +00001045 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1046 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1047
1048 if (!simulating) {
1049 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1050 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1051 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1052 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1053 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1054 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1055 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001056 }
1057
1058 if (perf_testing) {
1059 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001060 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1062 exec_time * 0.001, primary_count * 0.01);
1063 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1064 " %.3f ms (min)\n",
1065 (exec_time * 1.0) / primary_count,
1066 (max_time_us + max_time_reverse_us) / 1000.0,
1067 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001068 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001069 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001070 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 } else {
1072 printf("Warning: no capture frames\n");
1073 }
1074 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001075}
ajm@google.com808e0e02011-08-03 21:08:51 +00001076} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001077
1078int main(int argc, char* argv[])
1079{
1080 void_main(argc, argv);
1081
andrew@webrtc.org64235092011-08-19 21:22:08 +00001082 // Optional, but removes memory leak noise from Valgrind.
1083 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001084 return 0;
1085}