blob: 8a5d0f5fd6611dfea60397535faa503c78914102 [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
andrew@webrtc.org22858d42013-10-23 14:07:17 +000020#include "webrtc/common.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000021#include "webrtc/modules/audio_processing/include/audio_processing.h"
22#include "webrtc/modules/interface/module_common_types.h"
23#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
24#include "webrtc/system_wrappers/interface/scoped_ptr.h"
25#include "webrtc/system_wrappers/interface/tick_util.h"
kjellander@webrtc.org10abe252012-12-17 18:28:07 +000026#include "webrtc/test/testsupport/fileutils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000027#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000028#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000029#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000030#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000031#else
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000032#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:51 +000033#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000034#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000035
36using webrtc::AudioFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +000037using webrtc::AudioProcessing;
andrew@webrtc.org22858d42013-10-23 14:07:17 +000038using webrtc::Config;
39using webrtc::DelayCorrection;
andrew@webrtc.org94c74132011-09-19 15:17:57 +000040using webrtc::EchoCancellation;
niklase@google.com470e71d2011-07-07 08:21:25 +000041using webrtc::GainControl;
42using webrtc::NoiseSuppression;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000043using webrtc::scoped_array;
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +000044using webrtc::scoped_ptr;
ajm@google.com808e0e02011-08-03 21:08:51 +000045using webrtc::TickInterval;
46using webrtc::TickTime;
andrew@webrtc.org89752612012-10-12 16:41:45 +000047using webrtc::VoiceDetection;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000048
ajm@google.com808e0e02011-08-03 21:08:51 +000049using webrtc::audioproc::Event;
50using webrtc::audioproc::Init;
51using webrtc::audioproc::ReverseStream;
52using webrtc::audioproc::Stream;
53
54namespace {
55// Returns true on success, false on error or end-of-file.
56bool ReadMessageFromFile(FILE* file,
57 ::google::protobuf::MessageLite* msg) {
58 // The "wire format" for the size is little-endian.
59 // Assume process_test is running on a little-endian machine.
andrew@webrtc.orgcb181212011-10-26 00:27:17 +000060 int32_t size = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +000061 if (fread(&size, sizeof(int32_t), 1, file) != 1) {
62 return false;
63 }
64 if (size <= 0) {
65 return false;
66 }
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000067 const size_t usize = static_cast<size_t>(size);
ajm@google.com808e0e02011-08-03 21:08:51 +000068
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000069 scoped_array<char> array(new char[usize]);
70 if (fread(array.get(), sizeof(char), usize, file) != usize) {
ajm@google.com808e0e02011-08-03 21:08:51 +000071 return false;
72 }
73
74 msg->Clear();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000075 return msg->ParseFromArray(array.get(), usize);
ajm@google.com808e0e02011-08-03 21:08:51 +000076}
niklase@google.com470e71d2011-07-07 08:21:25 +000077
andrew@webrtc.org94c74132011-09-19 15:17:57 +000078void PrintStat(const AudioProcessing::Statistic& stat) {
79 printf("%d, %d, %d\n", stat.average,
80 stat.maximum,
81 stat.minimum);
82}
83
niklase@google.com470e71d2011-07-07 08:21:25 +000084void usage() {
85 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000086 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
87 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000088 printf(
89 "process_test is a test application for AudioProcessing.\n\n"
ajm@google.com808e0e02011-08-03 21:08:51 +000090 "When a protobuf debug file is available, specify it with -pb.\n"
91 "Alternately, when -ir or -i is used, the specified files will be\n"
92 "processed directly in a simulation mode. Otherwise the full set of\n"
93 "legacy test files is expected to be present in the working directory.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000094 printf("\n");
95 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000096 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000097 printf(" -fs SAMPLE_RATE_HZ\n");
98 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
99 printf(" -rch REVERSE_CHANNELS\n");
100 printf("\n");
101 printf("Component configuration:\n");
102 printf(
103 "All components are disabled by default. Each block below begins with a\n"
104 "flag to enable the component with default settings. The subsequent flags\n"
105 "in the block are used to provide configuration settings.\n");
106 printf("\n -aec Echo cancellation\n");
107 printf(" --drift_compensation\n");
108 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000109 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000110 printf(" --no_delay_logging\n");
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000111 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000112 printf(" --extended_filter\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +0000114 printf(" --aecm_echo_path_in_file FILE\n");
115 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000116 printf(" --no_comfort_noise\n");
117 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 printf("\n -agc Gain control\n");
119 printf(" --analog\n");
120 printf(" --adaptive_digital\n");
121 printf(" --fixed_digital\n");
122 printf(" --target_level LEVEL\n");
123 printf(" --compression_gain GAIN\n");
124 printf(" --limiter\n");
125 printf(" --no_limiter\n");
126 printf("\n -hpf High pass filter\n");
127 printf("\n -ns Noise suppression\n");
128 printf(" --ns_low\n");
129 printf(" --ns_moderate\n");
130 printf(" --ns_high\n");
131 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000132 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000134 printf(" --vad_out_file FILE\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000135 printf("\n Level metrics (enabled by default)\n");
136 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 printf("\n");
138 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000139 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000140 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
141 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000142 printf(" --perf Measure performance.\n");
143 printf(" --quiet Suppress text output.\n");
144 printf(" --no_progress Suppress progress.\n");
145 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000146}
147
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000148static float MicLevel2Gain(int level) {
149 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000150}
151
152static void SimulateMic(int mic_level, AudioFrame* frame) {
153 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000154 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000155 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000156 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000157 for (int n = 0; n < num_samples; n++) {
158 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000159 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000160 frame->data_[n] = static_cast<int16_t>(v);
161 }
162}
163
niklase@google.com470e71d2011-07-07 08:21:25 +0000164// void function for gtest.
165void void_main(int argc, char* argv[]) {
166 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
167 usage();
168 return;
169 }
170
171 if (argc < 2) {
172 printf("Did you mean to run without arguments?\n");
173 printf("Try `process_test --help' for more information.\n\n");
174 }
175
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000176 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create(0));
177 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178
ajm@google.com808e0e02011-08-03 21:08:51 +0000179 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 const char* far_filename = NULL;
181 const char* near_filename = NULL;
182 const char* out_filename = NULL;
183 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000184 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000185 const char* aecm_echo_path_in_filename = NULL;
186 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187
188 int32_t sample_rate_hz = 16000;
189 int32_t device_sample_rate_hz = 16000;
190
191 int num_capture_input_channels = 1;
192 int num_capture_output_channels = 1;
193 int num_render_channels = 1;
194
195 int samples_per_channel = sample_rate_hz / 100;
196
197 bool simulating = false;
198 bool perf_testing = false;
199 bool verbose = true;
200 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000201 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000202 int override_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 //bool interleaved = true;
204
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000205 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000207 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000208 i++;
209 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
210 pb_filename = argv[i];
211
212 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 i++;
214 ASSERT_LT(i, argc) << "Specify filename after -ir";
215 far_filename = argv[i];
216 simulating = true;
217
218 } else if (strcmp(argv[i], "-i") == 0) {
219 i++;
220 ASSERT_LT(i, argc) << "Specify filename after -i";
221 near_filename = argv[i];
222 simulating = true;
223
224 } else if (strcmp(argv[i], "-o") == 0) {
225 i++;
226 ASSERT_LT(i, argc) << "Specify filename after -o";
227 out_filename = argv[i];
228
229 } else if (strcmp(argv[i], "-fs") == 0) {
230 i++;
231 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
232 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
233 samples_per_channel = sample_rate_hz / 100;
234
niklase@google.com470e71d2011-07-07 08:21:25 +0000235 } else if (strcmp(argv[i], "-ch") == 0) {
236 i++;
237 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
238 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
239 i++;
240 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
241
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 } else if (strcmp(argv[i], "-rch") == 0) {
243 i++;
244 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
245 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
246
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 } else if (strcmp(argv[i], "-aec") == 0) {
248 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000249 ASSERT_EQ(apm->kNoError,
250 apm->echo_cancellation()->enable_metrics(true));
251 ASSERT_EQ(apm->kNoError,
252 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
255 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
256 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
257 // why it can give better performance despite passing zeros.
258 ASSERT_EQ(apm->kNoError,
259 apm->echo_cancellation()->enable_drift_compensation(true));
260 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
261 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
262 ASSERT_EQ(apm->kNoError,
263 apm->echo_cancellation()->enable_drift_compensation(false));
264
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000265 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
266 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
267 ASSERT_EQ(apm->kNoError,
268 apm->echo_cancellation()->enable_metrics(false));
269
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000270 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
271 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
272 ASSERT_EQ(apm->kNoError,
273 apm->echo_cancellation()->enable_delay_logging(false));
274
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000275 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
276 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
277
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000278 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
279 i++;
280 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
281 int suppression_level;
282 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
283 ASSERT_EQ(apm->kNoError,
284 apm->echo_cancellation()->set_suppression_level(
285 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
286 suppression_level)));
287
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000288 } else if (strcmp(argv[i], "--extended_filter") == 0) {
289 Config config;
290 config.Set<DelayCorrection>(new DelayCorrection(true));
291 apm->SetExtraOptions(config);
292
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 } else if (strcmp(argv[i], "-aecm") == 0) {
294 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
295
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000296 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
297 i++;
298 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
299 aecm_echo_path_in_filename = argv[i];
300
301 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
302 i++;
303 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
304 aecm_echo_path_out_filename = argv[i];
305
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000306 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
307 ASSERT_EQ(apm->kNoError,
308 apm->echo_control_mobile()->enable_comfort_noise(false));
309
310 } else if (strcmp(argv[i], "--routing_mode") == 0) {
311 i++;
312 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
313 int routing_mode;
314 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
315 ASSERT_EQ(apm->kNoError,
316 apm->echo_control_mobile()->set_routing_mode(
317 static_cast<webrtc::EchoControlMobile::RoutingMode>(
318 routing_mode)));
319
niklase@google.com470e71d2011-07-07 08:21:25 +0000320 } else if (strcmp(argv[i], "-agc") == 0) {
321 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
322
323 } else if (strcmp(argv[i], "--analog") == 0) {
324 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
325 ASSERT_EQ(apm->kNoError,
326 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
327
328 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
329 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
330 ASSERT_EQ(apm->kNoError,
331 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
332
333 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
334 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
335 ASSERT_EQ(apm->kNoError,
336 apm->gain_control()->set_mode(GainControl::kFixedDigital));
337
338 } else if (strcmp(argv[i], "--target_level") == 0) {
339 i++;
340 int level;
341 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
342
343 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
344 ASSERT_EQ(apm->kNoError,
345 apm->gain_control()->set_target_level_dbfs(level));
346
347 } else if (strcmp(argv[i], "--compression_gain") == 0) {
348 i++;
349 int gain;
350 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
351
352 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
353 ASSERT_EQ(apm->kNoError,
354 apm->gain_control()->set_compression_gain_db(gain));
355
356 } else if (strcmp(argv[i], "--limiter") == 0) {
357 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
358 ASSERT_EQ(apm->kNoError,
359 apm->gain_control()->enable_limiter(true));
360
361 } else if (strcmp(argv[i], "--no_limiter") == 0) {
362 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
363 ASSERT_EQ(apm->kNoError,
364 apm->gain_control()->enable_limiter(false));
365
366 } else if (strcmp(argv[i], "-hpf") == 0) {
367 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
368
369 } else if (strcmp(argv[i], "-ns") == 0) {
370 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
371
372 } else if (strcmp(argv[i], "--ns_low") == 0) {
373 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
374 ASSERT_EQ(apm->kNoError,
375 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
376
377 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
378 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
379 ASSERT_EQ(apm->kNoError,
380 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
381
382 } else if (strcmp(argv[i], "--ns_high") == 0) {
383 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
384 ASSERT_EQ(apm->kNoError,
385 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
386
387 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
388 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
389 ASSERT_EQ(apm->kNoError,
390 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
391
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000392 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
393 i++;
394 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
395 ns_prob_filename = argv[i];
396
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 } else if (strcmp(argv[i], "-vad") == 0) {
398 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
399
andrew@webrtc.org89752612012-10-12 16:41:45 +0000400 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
401 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
402 ASSERT_EQ(apm->kNoError,
403 apm->voice_detection()->set_likelihood(
404 VoiceDetection::kVeryLowLikelihood));
405
406 } else if (strcmp(argv[i], "--vad_low") == 0) {
407 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
408 ASSERT_EQ(apm->kNoError,
409 apm->voice_detection()->set_likelihood(
410 VoiceDetection::kLowLikelihood));
411
412 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
413 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
414 ASSERT_EQ(apm->kNoError,
415 apm->voice_detection()->set_likelihood(
416 VoiceDetection::kModerateLikelihood));
417
418 } else if (strcmp(argv[i], "--vad_high") == 0) {
419 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
420 ASSERT_EQ(apm->kNoError,
421 apm->voice_detection()->set_likelihood(
422 VoiceDetection::kHighLikelihood));
423
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
425 i++;
426 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
427 vad_out_filename = argv[i];
428
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000429 } else if (strcmp(argv[i], "--noasm") == 0) {
430 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
431 // We need to reinitialize here if components have already been enabled.
432 ASSERT_EQ(apm->kNoError, apm->Initialize());
433
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000434 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000435 i++;
436 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
437
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000438 } else if (strcmp(argv[i], "--delay") == 0) {
439 i++;
440 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
441
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 } else if (strcmp(argv[i], "--perf") == 0) {
443 perf_testing = true;
444
445 } else if (strcmp(argv[i], "--quiet") == 0) {
446 verbose = false;
447 progress = false;
448
449 } else if (strcmp(argv[i], "--no_progress") == 0) {
450 progress = false;
451
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000452 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000453 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000454 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000455 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000456 } else {
457 FAIL() << "Unrecognized argument " << argv[i];
458 }
459 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000460 // If we're reading a protobuf file, ensure a simulation hasn't also
461 // been requested (which makes no sense...)
462 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
464 if (verbose) {
465 printf("Sample rate: %d Hz\n", sample_rate_hz);
466 printf("Primary channels: %d (in), %d (out)\n",
467 num_capture_input_channels,
468 num_capture_output_channels);
469 printf("Reverse channels: %d \n", num_render_channels);
470 }
471
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000472 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 const char far_file_default[] = "apm_far.pcm";
474 const char near_file_default[] = "apm_near.pcm";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000475 const std::string out_file_default = out_path + "out.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 const char event_filename[] = "apm_event.dat";
477 const char delay_filename[] = "apm_delay.dat";
478 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000479 const std::string vad_file_default = out_path + "vad_out.dat";
480 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000481
482 if (!simulating) {
483 far_filename = far_file_default;
484 near_filename = near_file_default;
485 }
486
ajm@google.com808e0e02011-08-03 21:08:51 +0000487 if (!out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000488 out_filename = out_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 }
490
ajm@google.com808e0e02011-08-03 21:08:51 +0000491 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000492 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000493 }
494
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000495 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000496 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000497 }
498
ajm@google.com808e0e02011-08-03 21:08:51 +0000499 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000500 FILE* far_file = NULL;
501 FILE* near_file = NULL;
502 FILE* out_file = NULL;
503 FILE* event_file = NULL;
504 FILE* delay_file = NULL;
505 FILE* drift_file = NULL;
506 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000507 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000508 FILE* aecm_echo_path_in_file = NULL;
509 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000510
ajm@google.com808e0e02011-08-03 21:08:51 +0000511 if (pb_filename) {
512 pb_file = fopen(pb_filename, "rb");
513 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
514 << pb_filename;
515 } else {
516 if (far_filename) {
517 far_file = fopen(far_filename, "rb");
518 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
519 << far_filename;
520 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000521
ajm@google.com808e0e02011-08-03 21:08:51 +0000522 near_file = fopen(near_filename, "rb");
523 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
524 << near_filename;
525 if (!simulating) {
526 event_file = fopen(event_filename, "rb");
527 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
528 << event_filename;
529
530 delay_file = fopen(delay_filename, "rb");
531 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
532 << delay_filename;
533
534 drift_file = fopen(drift_filename, "rb");
535 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
536 << drift_filename;
537 }
538 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000539
540 out_file = fopen(out_filename, "wb");
541 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
542 << out_filename;
543
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000544 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000545 if (pb_file) {
546 struct stat st;
547 stat(pb_filename, &st);
548 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000549 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000550 } else {
551 struct stat st;
552 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000553 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000554 }
555
556 if (apm->voice_detection()->is_enabled()) {
557 vad_out_file = fopen(vad_out_filename, "wb");
558 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
559 << vad_out_file;
560 }
561
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000562 if (apm->noise_suppression()->is_enabled()) {
563 ns_prob_file = fopen(ns_prob_filename, "wb");
564 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
565 << ns_prob_file;
566 }
567
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000568 if (aecm_echo_path_in_filename != NULL) {
569 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
570 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
571 << aecm_echo_path_in_filename;
572
ajm@google.com22e65152011-07-18 18:03:01 +0000573 const size_t path_size =
574 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000575 scoped_array<char> echo_path(new char[path_size]);
576 ASSERT_EQ(path_size, fread(echo_path.get(),
577 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000578 path_size,
579 aecm_echo_path_in_file));
580 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000581 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
582 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000583 fclose(aecm_echo_path_in_file);
584 aecm_echo_path_in_file = NULL;
585 }
586
587 if (aecm_echo_path_out_filename != NULL) {
588 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
589 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
590 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000591 }
592
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 size_t read_count = 0;
594 int reverse_count = 0;
595 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000596 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 TickInterval acc_ticks;
598
599 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000601
602 int delay_ms = 0;
603 int drift_samples = 0;
604 int capture_level = 127;
605 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000606 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000607
608 TickTime t0 = TickTime::Now();
609 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000610 int64_t max_time_us = 0;
611 int64_t max_time_reverse_us = 0;
612 int64_t min_time_us = 1e6;
613 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000614
ajm@google.com808e0e02011-08-03 21:08:51 +0000615 // TODO(ajm): Ideally we would refactor this block into separate functions,
616 // but for now we want to share the variables.
617 if (pb_file) {
618 Event event_msg;
619 while (ReadMessageFromFile(pb_file, &event_msg)) {
620 std::ostringstream trace_stream;
621 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
622 << primary_count << " (primary)";
623 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000624
ajm@google.com808e0e02011-08-03 21:08:51 +0000625 if (event_msg.type() == Event::INIT) {
626 ASSERT_TRUE(event_msg.has_init());
627 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000628
ajm@google.com808e0e02011-08-03 21:08:51 +0000629 ASSERT_TRUE(msg.has_sample_rate());
bjornv@webrtc.org6a947342014-01-16 08:41:09 +0000630 // TODO(bjornv): Replace set_sample_rate_hz() when we have a smarter
631 // AnalyzeReverseStream().
632 ASSERT_EQ(apm->kNoError, apm->set_sample_rate_hz(msg.sample_rate()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000633 ASSERT_TRUE(msg.has_device_sample_rate());
634 ASSERT_EQ(apm->kNoError,
635 apm->echo_cancellation()->set_device_sample_rate_hz(
636 msg.device_sample_rate()));
637
638 ASSERT_TRUE(msg.has_num_input_channels());
639 ASSERT_TRUE(msg.has_num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000640 ASSERT_TRUE(msg.has_num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000641
642 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000643 far_frame.sample_rate_hz_ = msg.sample_rate();
644 far_frame.samples_per_channel_ = samples_per_channel;
645 far_frame.num_channels_ = msg.num_reverse_channels();
646 near_frame.sample_rate_hz_ = msg.sample_rate();
647 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000648 near_frame.num_channels_ = msg.num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000649
650 if (verbose) {
651 printf("Init at frame: %d (primary), %d (reverse)\n",
652 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000653 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000654 printf(" Primary channels: %d (in), %d (out)\n",
655 msg.num_input_channels(),
656 msg.num_output_channels());
657 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000658 }
659
660 } else if (event_msg.type() == Event::REVERSE_STREAM) {
661 ASSERT_TRUE(event_msg.has_reverse_stream());
662 const ReverseStream msg = event_msg.reverse_stream();
663 reverse_count++;
664
665 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000666 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000667 far_frame.num_channels_, msg.data().size());
668 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000669
670 if (perf_testing) {
671 t0 = TickTime::Now();
672 }
673
674 ASSERT_EQ(apm->kNoError,
675 apm->AnalyzeReverseStream(&far_frame));
676
677 if (perf_testing) {
678 t1 = TickTime::Now();
679 TickInterval tick_diff = t1 - t0;
680 acc_ticks += tick_diff;
681 if (tick_diff.Microseconds() > max_time_reverse_us) {
682 max_time_reverse_us = tick_diff.Microseconds();
683 }
684 if (tick_diff.Microseconds() < min_time_reverse_us) {
685 min_time_reverse_us = tick_diff.Microseconds();
686 }
687 }
688
689 } else if (event_msg.type() == Event::STREAM) {
690 ASSERT_TRUE(event_msg.has_stream());
691 const Stream msg = event_msg.stream();
692 primary_count++;
693
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000694 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000695 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000696
697 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000698 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000699 near_frame.num_channels_, msg.input_data().size());
700 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000701 msg.input_data().data(),
702 msg.input_data().size());
703
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000704 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000705 if (progress && primary_count % 100 == 0) {
706 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000707 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000708 fflush(stdout);
709 }
710
711 if (perf_testing) {
712 t0 = TickTime::Now();
713 }
714
715 ASSERT_EQ(apm->kNoError,
716 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000717 delay_ms = msg.delay() + extra_delay_ms;
718 if (override_delay_ms) {
719 delay_ms = override_delay_ms;
720 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000721 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000722 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000723 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000724
725 int err = apm->ProcessStream(&near_frame);
726 if (err == apm->kBadStreamParameterWarning) {
727 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
728 }
729 ASSERT_TRUE(err == apm->kNoError ||
730 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000731 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000732
ajm@google.com808e0e02011-08-03 21:08:51 +0000733 stream_has_voice =
734 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
735 if (vad_out_file != NULL) {
736 ASSERT_EQ(1u, fwrite(&stream_has_voice,
737 sizeof(stream_has_voice),
738 1,
739 vad_out_file));
740 }
741
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000742 if (ns_prob_file != NULL) {
743 ns_speech_prob = apm->noise_suppression()->speech_probability();
744 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
745 sizeof(ns_speech_prob),
746 1,
747 ns_prob_file));
748 }
749
ajm@google.com808e0e02011-08-03 21:08:51 +0000750 if (perf_testing) {
751 t1 = TickTime::Now();
752 TickInterval tick_diff = t1 - t0;
753 acc_ticks += tick_diff;
754 if (tick_diff.Microseconds() > max_time_us) {
755 max_time_us = tick_diff.Microseconds();
756 }
757 if (tick_diff.Microseconds() < min_time_us) {
758 min_time_us = tick_diff.Microseconds();
759 }
760 }
761
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000762 size_t size = samples_per_channel * near_frame.num_channels_;
763 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000764 sizeof(int16_t),
765 size,
766 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000767 }
768 }
769
770 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000771
772 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000773 enum Events {
774 kInitializeEvent,
775 kRenderEvent,
776 kCaptureEvent,
777 kResetEventDeprecated
778 };
779 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000780 while (simulating || feof(event_file) == 0) {
781 std::ostringstream trace_stream;
782 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
783 << primary_count << " (primary)";
784 SCOPED_TRACE(trace_stream.str());
785
786 if (simulating) {
787 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000788 event = kCaptureEvent;
789 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000790 if (event == kRenderEvent) {
791 event = kCaptureEvent;
792 } else {
793 event = kRenderEvent;
794 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000795 }
796 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000797 read_count = fread(&event, sizeof(event), 1, event_file);
798 if (read_count != 1) {
799 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000800 }
801 }
802
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000803 far_frame.sample_rate_hz_ = sample_rate_hz;
804 far_frame.samples_per_channel_ = samples_per_channel;
805 far_frame.num_channels_ = num_render_channels;
806 near_frame.sample_rate_hz_ = sample_rate_hz;
807 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000808
ajm@google.com808e0e02011-08-03 21:08:51 +0000809 if (event == kInitializeEvent || event == kResetEventDeprecated) {
810 ASSERT_EQ(1u,
811 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
812 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000813
ajm@google.com808e0e02011-08-03 21:08:51 +0000814 ASSERT_EQ(1u,
815 fread(&device_sample_rate_hz,
816 sizeof(device_sample_rate_hz),
817 1,
818 event_file));
819
bjornv@webrtc.org6a947342014-01-16 08:41:09 +0000820 // TODO(bjornv): Replace set_sample_rate_hz() when we have a smarter
821 // AnalyzeReverseStream().
822 ASSERT_EQ(apm->kNoError, apm->set_sample_rate_hz(sample_rate_hz));
823
ajm@google.com808e0e02011-08-03 21:08:51 +0000824 ASSERT_EQ(apm->kNoError,
ajm@google.com808e0e02011-08-03 21:08:51 +0000825 apm->echo_cancellation()->set_device_sample_rate_hz(
826 device_sample_rate_hz));
827
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000828 far_frame.sample_rate_hz_ = sample_rate_hz;
829 far_frame.samples_per_channel_ = samples_per_channel;
830 far_frame.num_channels_ = num_render_channels;
831 near_frame.sample_rate_hz_ = sample_rate_hz;
832 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000833
834 if (verbose) {
835 printf("Init at frame: %d (primary), %d (reverse)\n",
836 primary_count, reverse_count);
837 printf(" Sample rate: %d Hz\n", sample_rate_hz);
838 }
839
840 } else if (event == kRenderEvent) {
841 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000842
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000843 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000844 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000845 sizeof(int16_t),
846 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000847 far_file);
848
849 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000850 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000851 // Read an equal amount from the near file to avoid errors due to
852 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000853 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000854 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000855 break; // This is expected.
856 }
857 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000858 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000859 }
860
861 if (perf_testing) {
862 t0 = TickTime::Now();
863 }
864
865 ASSERT_EQ(apm->kNoError,
866 apm->AnalyzeReverseStream(&far_frame));
867
868 if (perf_testing) {
869 t1 = TickTime::Now();
870 TickInterval tick_diff = t1 - t0;
871 acc_ticks += tick_diff;
872 if (tick_diff.Microseconds() > max_time_reverse_us) {
873 max_time_reverse_us = tick_diff.Microseconds();
874 }
875 if (tick_diff.Microseconds() < min_time_reverse_us) {
876 min_time_reverse_us = tick_diff.Microseconds();
877 }
878 }
879
880 } else if (event == kCaptureEvent) {
881 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000882 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000883
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000884 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000885 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000886 sizeof(int16_t),
887 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000888 near_file);
889
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000890 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000891 if (progress && primary_count % 100 == 0) {
892 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000893 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000894 fflush(stdout);
895 }
896 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000897 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000898 break; // This is expected.
899 }
900
901 delay_ms = 0;
902 drift_samples = 0;
903 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000904 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000905
906 // TODO(ajm): sizeof(delay_ms) for current files?
907 ASSERT_EQ(1u,
908 fread(&delay_ms, 2, 1, delay_file));
909 ASSERT_EQ(1u,
910 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
911 }
912
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000913 if (apm->gain_control()->is_enabled() &&
914 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000915 SimulateMic(capture_level, &near_frame);
916 }
917
ajm@google.com808e0e02011-08-03 21:08:51 +0000918 if (perf_testing) {
919 t0 = TickTime::Now();
920 }
921
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000922 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000923 ASSERT_EQ(apm->kNoError,
924 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000925 delay_ms += extra_delay_ms;
926 if (override_delay_ms) {
927 delay_ms = override_delay_ms;
928 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000929 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000930 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000931 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000932
933 int err = apm->ProcessStream(&near_frame);
934 if (err == apm->kBadStreamParameterWarning) {
935 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
936 }
937 ASSERT_TRUE(err == apm->kNoError ||
938 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000939 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000940
941 capture_level = apm->gain_control()->stream_analog_level();
942
943 stream_has_voice =
944 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
945 if (vad_out_file != NULL) {
946 ASSERT_EQ(1u, fwrite(&stream_has_voice,
947 sizeof(stream_has_voice),
948 1,
949 vad_out_file));
950 }
951
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000952 if (ns_prob_file != NULL) {
953 ns_speech_prob = apm->noise_suppression()->speech_probability();
954 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
955 sizeof(ns_speech_prob),
956 1,
957 ns_prob_file));
958 }
959
ajm@google.com808e0e02011-08-03 21:08:51 +0000960 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
961 ASSERT_EQ(capture_level_in, capture_level);
962 }
963
964 if (perf_testing) {
965 t1 = TickTime::Now();
966 TickInterval tick_diff = t1 - t0;
967 acc_ticks += tick_diff;
968 if (tick_diff.Microseconds() > max_time_us) {
969 max_time_us = tick_diff.Microseconds();
970 }
971 if (tick_diff.Microseconds() < min_time_us) {
972 min_time_us = tick_diff.Microseconds();
973 }
974 }
975
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000976 size = samples_per_channel * near_frame.num_channels_;
977 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000978 sizeof(int16_t),
979 size,
980 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000981 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000982 else {
983 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000985 }
986 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000987 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000988
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000989 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000990 const size_t path_size =
991 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000992 scoped_array<char> echo_path(new char[path_size]);
993 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
994 ASSERT_EQ(path_size, fwrite(echo_path.get(),
995 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000996 path_size,
997 aecm_echo_path_out_file));
998 fclose(aecm_echo_path_out_file);
999 aecm_echo_path_out_file = NULL;
1000 }
1001
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 if (verbose) {
1003 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1004 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001005
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001006 if (apm->level_estimator()->is_enabled()) {
1007 printf("\n--Level metrics--\n");
1008 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1009 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001010 if (apm->echo_cancellation()->are_metrics_enabled()) {
1011 EchoCancellation::Metrics metrics;
1012 apm->echo_cancellation()->GetMetrics(&metrics);
1013 printf("\n--Echo metrics--\n");
1014 printf("(avg, max, min)\n");
1015 printf("ERL: ");
1016 PrintStat(metrics.echo_return_loss);
1017 printf("ERLE: ");
1018 PrintStat(metrics.echo_return_loss_enhancement);
1019 printf("ANLP: ");
1020 PrintStat(metrics.a_nlp);
1021 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001022 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1023 int median = 0;
1024 int std = 0;
1025 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1026 printf("\n--Delay metrics--\n");
1027 printf("Median: %3d\n", median);
1028 printf("Standard deviation: %3d\n", std);
1029 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 }
1031
ajm@google.com808e0e02011-08-03 21:08:51 +00001032 if (!pb_file) {
1033 int8_t temp_int8;
1034 if (far_file) {
1035 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1036 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1037 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001038
ajm@google.com808e0e02011-08-03 21:08:51 +00001039 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1040 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1041
1042 if (!simulating) {
1043 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1044 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1045 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1046 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1047 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1048 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1049 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 }
1051
1052 if (perf_testing) {
1053 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001054 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1056 exec_time * 0.001, primary_count * 0.01);
1057 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1058 " %.3f ms (min)\n",
1059 (exec_time * 1.0) / primary_count,
1060 (max_time_us + max_time_reverse_us) / 1000.0,
1061 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001062 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001063 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001064 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 } else {
1066 printf("Warning: no capture frames\n");
1067 }
1068 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001069}
ajm@google.com808e0e02011-08-03 21:08:51 +00001070} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001071
1072int main(int argc, char* argv[])
1073{
1074 void_main(argc, argv);
1075
andrew@webrtc.org64235092011-08-19 21:22:08 +00001076 // Optional, but removes memory leak noise from Valgrind.
1077 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001078 return 0;
1079}