blob: fdfaab0f529d06c0a99e206a02c2cd1fc5a6d9c5 [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
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000020#include "webrtc/base/scoped_ptr.h"
andrew@webrtc.org22858d42013-10-23 14:07:17 +000021#include "webrtc/common.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000022#include "webrtc/modules/audio_processing/include/audio_processing.h"
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070023#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000024#include "webrtc/modules/audio_processing/test/test_utils.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010025#include "webrtc/modules/include/module_common_types.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010026#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
27#include "webrtc/system_wrappers/include/tick_util.h"
kjellander@webrtc.org10abe252012-12-17 18:28:07 +000028#include "webrtc/test/testsupport/fileutils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000029#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000030#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000031#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000032#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000033#else
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000034#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:51 +000035#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000036#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000037
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000038namespace webrtc {
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000039
ajm@google.com808e0e02011-08-03 21:08:51 +000040using webrtc::audioproc::Event;
41using webrtc::audioproc::Init;
42using webrtc::audioproc::ReverseStream;
43using webrtc::audioproc::Stream;
44
45namespace {
niklase@google.com470e71d2011-07-07 08:21:25 +000046
andrew@webrtc.org94c74132011-09-19 15:17:57 +000047void PrintStat(const AudioProcessing::Statistic& stat) {
48 printf("%d, %d, %d\n", stat.average,
49 stat.maximum,
50 stat.minimum);
51}
52
niklase@google.com470e71d2011-07-07 08:21:25 +000053void usage() {
54 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000055 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
56 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000057 printf(
58 "process_test is a test application for AudioProcessing.\n\n"
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000059 "When a protobuf debug file is available, specify it with -pb. Alternately,\n"
60 "when -ir or -i is used, the specified files will be processed directly in\n"
61 "a simulation mode. Otherwise the full set of legacy test files is expected\n"
62 "to be present in the working directory. OUT_FILE should be specified\n"
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +000063 "without extension to support both raw and wav output.\n\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000064 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000065 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000066 printf(" -fs SAMPLE_RATE_HZ\n");
67 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
68 printf(" -rch REVERSE_CHANNELS\n");
69 printf("\n");
70 printf("Component configuration:\n");
71 printf(
72 "All components are disabled by default. Each block below begins with a\n"
73 "flag to enable the component with default settings. The subsequent flags\n"
74 "in the block are used to provide configuration settings.\n");
75 printf("\n -aec Echo cancellation\n");
76 printf(" --drift_compensation\n");
77 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +000078 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +000079 printf(" --no_delay_logging\n");
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +000080 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
andrew@webrtc.org22858d42013-10-23 14:07:17 +000081 printf(" --extended_filter\n");
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +000082 printf(" --no_reported_delay\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000083 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +000084 printf(" --aecm_echo_path_in_file FILE\n");
85 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +000086 printf(" --no_comfort_noise\n");
87 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000088 printf("\n -agc Gain control\n");
89 printf(" --analog\n");
90 printf(" --adaptive_digital\n");
91 printf(" --fixed_digital\n");
92 printf(" --target_level LEVEL\n");
93 printf(" --compression_gain GAIN\n");
94 printf(" --limiter\n");
95 printf(" --no_limiter\n");
96 printf("\n -hpf High pass filter\n");
97 printf("\n -ns Noise suppression\n");
98 printf(" --ns_low\n");
99 printf(" --ns_moderate\n");
100 printf(" --ns_high\n");
101 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000102 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000103 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000104 printf(" --vad_out_file FILE\n");
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000105 printf("\n -expns Experimental noise suppression\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000106 printf("\n Level metrics (enabled by default)\n");
107 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 printf("\n");
109 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000110 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000111 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
112 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000113 printf(" --perf Measure performance.\n");
114 printf(" --quiet Suppress text output.\n");
115 printf(" --no_progress Suppress progress.\n");
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000116 printf(" --raw_output Raw output instead of WAV file.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000117 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000118}
119
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000120static float MicLevel2Gain(int level) {
121 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000122}
123
124static void SimulateMic(int mic_level, AudioFrame* frame) {
125 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000126 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000127 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000128 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000129 for (int n = 0; n < num_samples; n++) {
130 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000131 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000132 frame->data_[n] = static_cast<int16_t>(v);
133 }
134}
135
niklase@google.com470e71d2011-07-07 08:21:25 +0000136// void function for gtest.
137void void_main(int argc, char* argv[]) {
138 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
139 usage();
140 return;
141 }
142
143 if (argc < 2) {
144 printf("Did you mean to run without arguments?\n");
145 printf("Try `process_test --help' for more information.\n\n");
146 }
147
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000148 rtc::scoped_ptr<AudioProcessing> apm(AudioProcessing::Create());
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000149 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000150
ajm@google.com808e0e02011-08-03 21:08:51 +0000151 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 const char* far_filename = NULL;
153 const char* near_filename = NULL;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000154 std::string out_filename;
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000156 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000157 const char* aecm_echo_path_in_filename = NULL;
158 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000159
160 int32_t sample_rate_hz = 16000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000161
162 int num_capture_input_channels = 1;
163 int num_capture_output_channels = 1;
164 int num_render_channels = 1;
165
166 int samples_per_channel = sample_rate_hz / 100;
167
168 bool simulating = false;
169 bool perf_testing = false;
170 bool verbose = true;
171 bool progress = true;
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000172 bool raw_output = false;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000173 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000174 int override_delay_ms = 0;
Bjorn Volckerbeb97982015-04-28 13:52:50 +0200175 Config config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000176
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000177 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000179 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000180 i++;
181 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
182 pb_filename = argv[i];
183
184 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 i++;
186 ASSERT_LT(i, argc) << "Specify filename after -ir";
187 far_filename = argv[i];
188 simulating = true;
189
190 } else if (strcmp(argv[i], "-i") == 0) {
191 i++;
192 ASSERT_LT(i, argc) << "Specify filename after -i";
193 near_filename = argv[i];
194 simulating = true;
195
196 } else if (strcmp(argv[i], "-o") == 0) {
197 i++;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000198 ASSERT_LT(i, argc) << "Specify filename without extension after -o";
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 out_filename = argv[i];
200
201 } else if (strcmp(argv[i], "-fs") == 0) {
202 i++;
203 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
204 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
205 samples_per_channel = sample_rate_hz / 100;
206
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 } else if (strcmp(argv[i], "-ch") == 0) {
208 i++;
209 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
210 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
211 i++;
212 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
213
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 } else if (strcmp(argv[i], "-rch") == 0) {
215 i++;
216 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
217 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
218
niklase@google.com470e71d2011-07-07 08:21:25 +0000219 } else if (strcmp(argv[i], "-aec") == 0) {
220 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000221 ASSERT_EQ(apm->kNoError,
222 apm->echo_cancellation()->enable_metrics(true));
223 ASSERT_EQ(apm->kNoError,
224 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000225
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
227 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
228 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
229 // why it can give better performance despite passing zeros.
230 ASSERT_EQ(apm->kNoError,
231 apm->echo_cancellation()->enable_drift_compensation(true));
232 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
233 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
234 ASSERT_EQ(apm->kNoError,
235 apm->echo_cancellation()->enable_drift_compensation(false));
236
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000237 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
238 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
239 ASSERT_EQ(apm->kNoError,
240 apm->echo_cancellation()->enable_metrics(false));
241
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000242 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
243 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
244 ASSERT_EQ(apm->kNoError,
245 apm->echo_cancellation()->enable_delay_logging(false));
246
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000247 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
248 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
249
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000250 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
251 i++;
252 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
253 int suppression_level;
254 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
255 ASSERT_EQ(apm->kNoError,
256 apm->echo_cancellation()->set_suppression_level(
257 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
258 suppression_level)));
259
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000260 } else if (strcmp(argv[i], "--extended_filter") == 0) {
Henrik Lundin441f6342015-06-09 16:03:13 +0200261 config.Set<ExtendedFilter>(new ExtendedFilter(true));
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000262
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000263 } else if (strcmp(argv[i], "--no_reported_delay") == 0) {
henrik.lundin0f133b92015-07-02 00:17:55 -0700264 config.Set<DelayAgnostic>(new DelayAgnostic(true));
265
266 } else if (strcmp(argv[i], "--delay_agnostic") == 0) {
267 config.Set<DelayAgnostic>(new DelayAgnostic(true));
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000268
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 } else if (strcmp(argv[i], "-aecm") == 0) {
270 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
271
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000272 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
273 i++;
274 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
275 aecm_echo_path_in_filename = argv[i];
276
277 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
278 i++;
279 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
280 aecm_echo_path_out_filename = argv[i];
281
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000282 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
283 ASSERT_EQ(apm->kNoError,
284 apm->echo_control_mobile()->enable_comfort_noise(false));
285
286 } else if (strcmp(argv[i], "--routing_mode") == 0) {
287 i++;
288 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
289 int routing_mode;
290 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
291 ASSERT_EQ(apm->kNoError,
292 apm->echo_control_mobile()->set_routing_mode(
293 static_cast<webrtc::EchoControlMobile::RoutingMode>(
294 routing_mode)));
295
niklase@google.com470e71d2011-07-07 08:21:25 +0000296 } else if (strcmp(argv[i], "-agc") == 0) {
297 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
298
299 } else if (strcmp(argv[i], "--analog") == 0) {
300 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
301 ASSERT_EQ(apm->kNoError,
302 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
303
304 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
305 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
306 ASSERT_EQ(apm->kNoError,
307 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
308
309 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
310 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
311 ASSERT_EQ(apm->kNoError,
312 apm->gain_control()->set_mode(GainControl::kFixedDigital));
313
314 } else if (strcmp(argv[i], "--target_level") == 0) {
315 i++;
316 int level;
317 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
318
319 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
320 ASSERT_EQ(apm->kNoError,
321 apm->gain_control()->set_target_level_dbfs(level));
322
323 } else if (strcmp(argv[i], "--compression_gain") == 0) {
324 i++;
325 int gain;
326 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
327
328 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
329 ASSERT_EQ(apm->kNoError,
330 apm->gain_control()->set_compression_gain_db(gain));
331
332 } else if (strcmp(argv[i], "--limiter") == 0) {
333 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
334 ASSERT_EQ(apm->kNoError,
335 apm->gain_control()->enable_limiter(true));
336
337 } else if (strcmp(argv[i], "--no_limiter") == 0) {
338 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
339 ASSERT_EQ(apm->kNoError,
340 apm->gain_control()->enable_limiter(false));
341
342 } else if (strcmp(argv[i], "-hpf") == 0) {
343 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
344
345 } else if (strcmp(argv[i], "-ns") == 0) {
346 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
347
348 } else if (strcmp(argv[i], "--ns_low") == 0) {
349 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
350 ASSERT_EQ(apm->kNoError,
351 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
352
353 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
354 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
355 ASSERT_EQ(apm->kNoError,
356 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
357
358 } else if (strcmp(argv[i], "--ns_high") == 0) {
359 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
360 ASSERT_EQ(apm->kNoError,
361 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
362
363 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
364 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
365 ASSERT_EQ(apm->kNoError,
366 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
367
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000368 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
369 i++;
370 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
371 ns_prob_filename = argv[i];
372
niklase@google.com470e71d2011-07-07 08:21:25 +0000373 } else if (strcmp(argv[i], "-vad") == 0) {
374 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
375
andrew@webrtc.org89752612012-10-12 16:41:45 +0000376 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
377 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
378 ASSERT_EQ(apm->kNoError,
379 apm->voice_detection()->set_likelihood(
380 VoiceDetection::kVeryLowLikelihood));
381
382 } else if (strcmp(argv[i], "--vad_low") == 0) {
383 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
384 ASSERT_EQ(apm->kNoError,
385 apm->voice_detection()->set_likelihood(
386 VoiceDetection::kLowLikelihood));
387
388 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
389 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
390 ASSERT_EQ(apm->kNoError,
391 apm->voice_detection()->set_likelihood(
392 VoiceDetection::kModerateLikelihood));
393
394 } else if (strcmp(argv[i], "--vad_high") == 0) {
395 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
396 ASSERT_EQ(apm->kNoError,
397 apm->voice_detection()->set_likelihood(
398 VoiceDetection::kHighLikelihood));
399
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
401 i++;
402 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
403 vad_out_filename = argv[i];
404
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000405 } else if (strcmp(argv[i], "-expns") == 0) {
aluebs@webrtc.org9825afc2014-06-30 17:39:53 +0000406 config.Set<ExperimentalNs>(new ExperimentalNs(true));
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000407
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000408 } else if (strcmp(argv[i], "--noasm") == 0) {
409 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
410 // We need to reinitialize here if components have already been enabled.
411 ASSERT_EQ(apm->kNoError, apm->Initialize());
412
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000413 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000414 i++;
415 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
416
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000417 } else if (strcmp(argv[i], "--delay") == 0) {
418 i++;
419 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
420
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 } else if (strcmp(argv[i], "--perf") == 0) {
422 perf_testing = true;
423
424 } else if (strcmp(argv[i], "--quiet") == 0) {
425 verbose = false;
426 progress = false;
427
428 } else if (strcmp(argv[i], "--no_progress") == 0) {
429 progress = false;
430
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000431 } else if (strcmp(argv[i], "--raw_output") == 0) {
432 raw_output = true;
433
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000434 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000435 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000436 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000437 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 } else {
439 FAIL() << "Unrecognized argument " << argv[i];
440 }
441 }
Bjorn Volckerbeb97982015-04-28 13:52:50 +0200442 apm->SetExtraOptions(config);
443
ajm@google.com808e0e02011-08-03 21:08:51 +0000444 // If we're reading a protobuf file, ensure a simulation hasn't also
445 // been requested (which makes no sense...)
446 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000447
448 if (verbose) {
449 printf("Sample rate: %d Hz\n", sample_rate_hz);
450 printf("Primary channels: %d (in), %d (out)\n",
451 num_capture_input_channels,
452 num_capture_output_channels);
453 printf("Reverse channels: %d \n", num_render_channels);
454 }
455
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000456 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 const char far_file_default[] = "apm_far.pcm";
458 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 const char event_filename[] = "apm_event.dat";
460 const char delay_filename[] = "apm_delay.dat";
461 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000462 const std::string vad_file_default = out_path + "vad_out.dat";
463 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000464
465 if (!simulating) {
466 far_filename = far_file_default;
467 near_filename = near_file_default;
468 }
469
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000470 if (out_filename.size() == 0) {
471 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 }
473
ajm@google.com808e0e02011-08-03 21:08:51 +0000474 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000475 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 }
477
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000478 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000479 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000480 }
481
ajm@google.com808e0e02011-08-03 21:08:51 +0000482 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 FILE* far_file = NULL;
484 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000485 FILE* event_file = NULL;
486 FILE* delay_file = NULL;
487 FILE* drift_file = NULL;
488 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000489 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000490 FILE* aecm_echo_path_in_file = NULL;
491 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000492
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000493 rtc::scoped_ptr<WavWriter> output_wav_file;
494 rtc::scoped_ptr<RawFile> output_raw_file;
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000495
ajm@google.com808e0e02011-08-03 21:08:51 +0000496 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000497 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000498 } else {
499 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000500 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000501 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000502
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000503 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000504 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000505 event_file = OpenFile(event_filename, "rb");
506 delay_file = OpenFile(delay_filename, "rb");
507 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000508 }
509 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000510
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000511 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000512 if (pb_file) {
513 struct stat st;
514 stat(pb_filename, &st);
515 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000516 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000517 } else {
518 struct stat st;
519 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000520 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 }
522
523 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000524 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 }
526
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000527 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000528 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000529 }
530
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000531 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000532 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000533
ajm@google.com22e65152011-07-18 18:03:01 +0000534 const size_t path_size =
535 apm->echo_control_mobile()->echo_path_size_bytes();
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000536 rtc::scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000537 ASSERT_EQ(path_size, fread(echo_path.get(),
538 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000539 path_size,
540 aecm_echo_path_in_file));
541 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000542 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
543 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000544 fclose(aecm_echo_path_in_file);
545 aecm_echo_path_in_file = NULL;
546 }
547
548 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000549 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000550 }
551
niklase@google.com470e71d2011-07-07 08:21:25 +0000552 size_t read_count = 0;
553 int reverse_count = 0;
554 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000555 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 TickInterval acc_ticks;
557
558 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000560
561 int delay_ms = 0;
562 int drift_samples = 0;
563 int capture_level = 127;
564 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000565 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000566
567 TickTime t0 = TickTime::Now();
568 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000569 int64_t max_time_us = 0;
570 int64_t max_time_reverse_us = 0;
571 int64_t min_time_us = 1e6;
572 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000573
ajm@google.com808e0e02011-08-03 21:08:51 +0000574 // TODO(ajm): Ideally we would refactor this block into separate functions,
575 // but for now we want to share the variables.
576 if (pb_file) {
577 Event event_msg;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000578 rtc::scoped_ptr<ChannelBuffer<float> > reverse_cb;
579 rtc::scoped_ptr<ChannelBuffer<float> > primary_cb;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000580 int output_sample_rate = 32000;
581 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
ajm@google.com808e0e02011-08-03 21:08:51 +0000582 while (ReadMessageFromFile(pb_file, &event_msg)) {
583 std::ostringstream trace_stream;
584 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
585 << primary_count << " (primary)";
586 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000587
ajm@google.com808e0e02011-08-03 21:08:51 +0000588 if (event_msg.type() == Event::INIT) {
589 ASSERT_TRUE(event_msg.has_init());
590 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000591
ajm@google.com808e0e02011-08-03 21:08:51 +0000592 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000593 ASSERT_TRUE(msg.has_num_input_channels());
594 ASSERT_TRUE(msg.has_num_output_channels());
595 ASSERT_TRUE(msg.has_num_reverse_channels());
596 int reverse_sample_rate = msg.sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000597 if (msg.has_reverse_sample_rate()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000598 reverse_sample_rate = msg.reverse_sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000599 }
600 output_sample_rate = msg.sample_rate();
601 if (msg.has_output_sample_rate()) {
602 output_sample_rate = msg.output_sample_rate();
603 }
604 output_layout = LayoutFromChannels(msg.num_output_channels());
605 ASSERT_EQ(kNoErr, apm->Initialize(
606 msg.sample_rate(),
607 output_sample_rate,
608 reverse_sample_rate,
609 LayoutFromChannels(msg.num_input_channels()),
610 output_layout,
611 LayoutFromChannels(msg.num_reverse_channels())));
ajm@google.com808e0e02011-08-03 21:08:51 +0000612
613 samples_per_channel = msg.sample_rate() / 100;
bjornv@webrtc.orgee300822014-11-13 11:00:10 +0000614 far_frame.sample_rate_hz_ = reverse_sample_rate;
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000615 far_frame.samples_per_channel_ = reverse_sample_rate / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000616 far_frame.num_channels_ = msg.num_reverse_channels();
617 near_frame.sample_rate_hz_ = msg.sample_rate();
618 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000619 near_frame.num_channels_ = msg.num_input_channels();
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000620 reverse_cb.reset(new ChannelBuffer<float>(
621 far_frame.samples_per_channel_,
622 msg.num_reverse_channels()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000623 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
624 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000625
626 if (verbose) {
627 printf("Init at frame: %d (primary), %d (reverse)\n",
628 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000629 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
630 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000631 printf(" Primary channels: %d (in), %d (out)\n",
632 msg.num_input_channels(),
633 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000634 printf(" Reverse rate: %d\n", reverse_sample_rate);
635 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000636 }
637
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000638 if (!raw_output) {
kjellanderb7a5c162015-11-05 12:33:18 -0800639 // The WAV file needs to be reset every time, because it cant change
640 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000641 output_wav_file.reset(new WavWriter(out_filename + ".wav",
642 output_sample_rate,
643 msg.num_output_channels()));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000644 }
645
ajm@google.com808e0e02011-08-03 21:08:51 +0000646 } else if (event_msg.type() == Event::REVERSE_STREAM) {
647 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000648 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000649 reverse_count++;
650
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000651 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
652 if (msg.has_data()) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000653 ASSERT_EQ(sizeof(int16_t) * far_frame.samples_per_channel_ *
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000654 far_frame.num_channels_, msg.data().size());
655 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
656 } else {
657 for (int i = 0; i < msg.channel_size(); ++i) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000658 memcpy(reverse_cb->channels()[i],
659 msg.channel(i).data(),
660 reverse_cb->num_frames() *
661 sizeof(reverse_cb->channels()[i][0]));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000662 }
663 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000664
665 if (perf_testing) {
666 t0 = TickTime::Now();
667 }
668
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000669 if (msg.has_data()) {
670 ASSERT_EQ(apm->kNoError,
671 apm->AnalyzeReverseStream(&far_frame));
672 } else {
673 ASSERT_EQ(apm->kNoError,
674 apm->AnalyzeReverseStream(
675 reverse_cb->channels(),
676 far_frame.samples_per_channel_,
677 far_frame.sample_rate_hz_,
678 LayoutFromChannels(far_frame.num_channels_)));
679 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000680
681 if (perf_testing) {
682 t1 = TickTime::Now();
683 TickInterval tick_diff = t1 - t0;
684 acc_ticks += tick_diff;
685 if (tick_diff.Microseconds() > max_time_reverse_us) {
686 max_time_reverse_us = tick_diff.Microseconds();
687 }
688 if (tick_diff.Microseconds() < min_time_reverse_us) {
689 min_time_reverse_us = tick_diff.Microseconds();
690 }
691 }
692
693 } else if (event_msg.type() == Event::STREAM) {
694 ASSERT_TRUE(event_msg.has_stream());
695 const Stream msg = event_msg.stream();
696 primary_count++;
697
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000698 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000699 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000700
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000701 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
702 if (msg.has_input_data()) {
703 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
704 near_frame.num_channels_, msg.input_data().size());
705 memcpy(near_frame.data_,
706 msg.input_data().data(),
707 msg.input_data().size());
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000708 near_read_bytes += msg.input_data().size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000709 } else {
710 for (int i = 0; i < msg.input_channel_size(); ++i) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000711 memcpy(primary_cb->channels()[i],
712 msg.input_channel(i).data(),
713 primary_cb->num_frames() *
714 sizeof(primary_cb->channels()[i][0]));
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000715 near_read_bytes += msg.input_channel(i).size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000716 }
717 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000718
ajm@google.com808e0e02011-08-03 21:08:51 +0000719 if (progress && primary_count % 100 == 0) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000720 near_read_bytes = std::min(near_read_bytes, near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000721 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000722 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000723 fflush(stdout);
724 }
725
726 if (perf_testing) {
727 t0 = TickTime::Now();
728 }
729
730 ASSERT_EQ(apm->kNoError,
731 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000732 delay_ms = msg.delay() + extra_delay_ms;
733 if (override_delay_ms) {
734 delay_ms = override_delay_ms;
735 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000736 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000737 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000738 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000739
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000740 if (msg.has_keypress()) {
741 apm->set_stream_key_pressed(msg.keypress());
742 } else {
743 apm->set_stream_key_pressed(true);
744 }
745
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000746 int err = apm->kNoError;
747 if (msg.has_input_data()) {
748 err = apm->ProcessStream(&near_frame);
749 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
750 } else {
751 err = apm->ProcessStream(
752 primary_cb->channels(),
753 near_frame.samples_per_channel_,
754 near_frame.sample_rate_hz_,
755 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000756 output_sample_rate,
757 output_layout,
758 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000759 }
760
ajm@google.com808e0e02011-08-03 21:08:51 +0000761 if (err == apm->kBadStreamParameterWarning) {
762 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
763 }
764 ASSERT_TRUE(err == apm->kNoError ||
765 err == apm->kBadStreamParameterWarning);
766
ajm@google.com808e0e02011-08-03 21:08:51 +0000767 stream_has_voice =
768 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
769 if (vad_out_file != NULL) {
770 ASSERT_EQ(1u, fwrite(&stream_has_voice,
771 sizeof(stream_has_voice),
772 1,
773 vad_out_file));
774 }
775
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000776 if (ns_prob_file != NULL) {
777 ns_speech_prob = apm->noise_suppression()->speech_probability();
778 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
779 sizeof(ns_speech_prob),
780 1,
781 ns_prob_file));
782 }
783
ajm@google.com808e0e02011-08-03 21:08:51 +0000784 if (perf_testing) {
785 t1 = TickTime::Now();
786 TickInterval tick_diff = t1 - t0;
787 acc_ticks += tick_diff;
788 if (tick_diff.Microseconds() > max_time_us) {
789 max_time_us = tick_diff.Microseconds();
790 }
791 if (tick_diff.Microseconds() < min_time_us) {
792 min_time_us = tick_diff.Microseconds();
793 }
794 }
795
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000796 const size_t samples_per_channel = output_sample_rate / 100;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000797 if (msg.has_input_data()) {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000798 if (raw_output && !output_raw_file) {
799 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
800 }
801 WriteIntData(near_frame.data_,
802 apm->num_output_channels() * samples_per_channel,
803 output_wav_file.get(),
804 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000805 } else {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000806 if (raw_output && !output_raw_file) {
807 output_raw_file.reset(new RawFile(out_filename + ".float"));
808 }
809 WriteFloatData(primary_cb->channels(),
810 samples_per_channel,
811 apm->num_output_channels(),
812 output_wav_file.get(),
813 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000814 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000815 }
816 }
817
818 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000819
820 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000821 enum Events {
822 kInitializeEvent,
823 kRenderEvent,
824 kCaptureEvent,
825 kResetEventDeprecated
826 };
827 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000828 while (simulating || feof(event_file) == 0) {
829 std::ostringstream trace_stream;
830 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
831 << primary_count << " (primary)";
832 SCOPED_TRACE(trace_stream.str());
833
834 if (simulating) {
835 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000836 event = kCaptureEvent;
837 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000838 if (event == kRenderEvent) {
839 event = kCaptureEvent;
840 } else {
841 event = kRenderEvent;
842 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000843 }
844 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000845 read_count = fread(&event, sizeof(event), 1, event_file);
846 if (read_count != 1) {
847 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 }
849 }
850
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000851 far_frame.sample_rate_hz_ = sample_rate_hz;
852 far_frame.samples_per_channel_ = samples_per_channel;
853 far_frame.num_channels_ = num_render_channels;
854 near_frame.sample_rate_hz_ = sample_rate_hz;
855 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000856
ajm@google.com808e0e02011-08-03 21:08:51 +0000857 if (event == kInitializeEvent || event == kResetEventDeprecated) {
858 ASSERT_EQ(1u,
859 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
860 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000861
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000862 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000863 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000864 fread(&unused_device_sample_rate_hz,
865 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000866 1,
867 event_file));
868
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000869 ASSERT_EQ(kNoErr, apm->Initialize(
870 sample_rate_hz,
871 sample_rate_hz,
872 sample_rate_hz,
873 LayoutFromChannels(num_capture_input_channels),
874 LayoutFromChannels(num_capture_output_channels),
875 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000876
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000877 far_frame.sample_rate_hz_ = sample_rate_hz;
878 far_frame.samples_per_channel_ = samples_per_channel;
879 far_frame.num_channels_ = num_render_channels;
880 near_frame.sample_rate_hz_ = sample_rate_hz;
881 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000882
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000883 if (!raw_output) {
bjornv@webrtc.org634c9262014-09-24 12:21:51 +0000884 // The WAV file needs to be reset every time, because it can't change
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000885 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000886 output_wav_file.reset(new WavWriter(out_filename + ".wav",
887 sample_rate_hz,
888 num_capture_output_channels));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000889 }
890
ajm@google.com808e0e02011-08-03 21:08:51 +0000891 if (verbose) {
892 printf("Init at frame: %d (primary), %d (reverse)\n",
893 primary_count, reverse_count);
894 printf(" Sample rate: %d Hz\n", sample_rate_hz);
895 }
896
897 } else if (event == kRenderEvent) {
898 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000899
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000900 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000901 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000902 sizeof(int16_t),
903 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000904 far_file);
905
906 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000907 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000908 // Read an equal amount from the near file to avoid errors due to
909 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000910 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000911 SEEK_CUR));
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700912 break; // This is expected.
ajm@google.com808e0e02011-08-03 21:08:51 +0000913 }
914 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000915 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000916 }
917
918 if (perf_testing) {
919 t0 = TickTime::Now();
920 }
921
922 ASSERT_EQ(apm->kNoError,
923 apm->AnalyzeReverseStream(&far_frame));
924
925 if (perf_testing) {
926 t1 = TickTime::Now();
927 TickInterval tick_diff = t1 - t0;
928 acc_ticks += tick_diff;
929 if (tick_diff.Microseconds() > max_time_reverse_us) {
930 max_time_reverse_us = tick_diff.Microseconds();
931 }
932 if (tick_diff.Microseconds() < min_time_reverse_us) {
933 min_time_reverse_us = tick_diff.Microseconds();
934 }
935 }
936
937 } else if (event == kCaptureEvent) {
938 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000939 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000940
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000941 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000942 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000943 sizeof(int16_t),
944 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000945 near_file);
946
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000947 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000948 if (progress && primary_count % 100 == 0) {
949 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000950 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000951 fflush(stdout);
952 }
953 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000954 if (read_count != size) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700955 break; // This is expected.
ajm@google.com808e0e02011-08-03 21:08:51 +0000956 }
957
958 delay_ms = 0;
959 drift_samples = 0;
960 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000961 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000962
963 // TODO(ajm): sizeof(delay_ms) for current files?
964 ASSERT_EQ(1u,
965 fread(&delay_ms, 2, 1, delay_file));
966 ASSERT_EQ(1u,
967 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
968 }
969
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000970 if (apm->gain_control()->is_enabled() &&
971 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000972 SimulateMic(capture_level, &near_frame);
973 }
974
ajm@google.com808e0e02011-08-03 21:08:51 +0000975 if (perf_testing) {
976 t0 = TickTime::Now();
977 }
978
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000979 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000980 ASSERT_EQ(apm->kNoError,
981 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000982 delay_ms += extra_delay_ms;
983 if (override_delay_ms) {
984 delay_ms = override_delay_ms;
985 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000986 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000987 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000988 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000989
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000990 apm->set_stream_key_pressed(true);
991
ajm@google.com808e0e02011-08-03 21:08:51 +0000992 int err = apm->ProcessStream(&near_frame);
993 if (err == apm->kBadStreamParameterWarning) {
994 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
995 }
996 ASSERT_TRUE(err == apm->kNoError ||
997 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000998 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000999
1000 capture_level = apm->gain_control()->stream_analog_level();
1001
1002 stream_has_voice =
1003 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
1004 if (vad_out_file != NULL) {
1005 ASSERT_EQ(1u, fwrite(&stream_has_voice,
1006 sizeof(stream_has_voice),
1007 1,
1008 vad_out_file));
1009 }
1010
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001011 if (ns_prob_file != NULL) {
1012 ns_speech_prob = apm->noise_suppression()->speech_probability();
1013 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
1014 sizeof(ns_speech_prob),
1015 1,
1016 ns_prob_file));
1017 }
1018
ajm@google.com808e0e02011-08-03 21:08:51 +00001019 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
1020 ASSERT_EQ(capture_level_in, capture_level);
1021 }
1022
1023 if (perf_testing) {
1024 t1 = TickTime::Now();
1025 TickInterval tick_diff = t1 - t0;
1026 acc_ticks += tick_diff;
1027 if (tick_diff.Microseconds() > max_time_us) {
1028 max_time_us = tick_diff.Microseconds();
1029 }
1030 if (tick_diff.Microseconds() < min_time_us) {
1031 min_time_us = tick_diff.Microseconds();
1032 }
1033 }
1034
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001035 if (raw_output && !output_raw_file) {
1036 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
1037 }
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001038 if (!raw_output && !output_wav_file) {
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +00001039 output_wav_file.reset(new WavWriter(out_filename + ".wav",
1040 sample_rate_hz,
1041 num_capture_output_channels));
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001042 }
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001043 WriteIntData(near_frame.data_,
1044 size,
1045 output_wav_file.get(),
1046 output_raw_file.get());
Andrew MacDonaldcb05b722015-05-07 22:17:51 -07001047 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +00001048 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 }
1051 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001052 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001053
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001054 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001055 const size_t path_size =
1056 apm->echo_control_mobile()->echo_path_size_bytes();
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00001057 rtc::scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001058 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1059 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1060 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001061 path_size,
1062 aecm_echo_path_out_file));
1063 fclose(aecm_echo_path_out_file);
1064 aecm_echo_path_out_file = NULL;
1065 }
1066
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 if (verbose) {
1068 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1069 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001070
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001071 if (apm->level_estimator()->is_enabled()) {
1072 printf("\n--Level metrics--\n");
1073 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1074 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001075 if (apm->echo_cancellation()->are_metrics_enabled()) {
1076 EchoCancellation::Metrics metrics;
1077 apm->echo_cancellation()->GetMetrics(&metrics);
1078 printf("\n--Echo metrics--\n");
1079 printf("(avg, max, min)\n");
1080 printf("ERL: ");
1081 PrintStat(metrics.echo_return_loss);
1082 printf("ERLE: ");
1083 PrintStat(metrics.echo_return_loss_enhancement);
1084 printf("ANLP: ");
1085 PrintStat(metrics.a_nlp);
1086 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001087 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1088 int median = 0;
1089 int std = 0;
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001090 float fraction_poor_delays = 0;
1091 apm->echo_cancellation()->GetDelayMetrics(&median, &std,
1092 &fraction_poor_delays);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001093 printf("\n--Delay metrics--\n");
1094 printf("Median: %3d\n", median);
1095 printf("Standard deviation: %3d\n", std);
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001096 printf("Poor delay values: %3.1f%%\n", fraction_poor_delays * 100);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001097 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001098 }
1099
ajm@google.com808e0e02011-08-03 21:08:51 +00001100 if (!pb_file) {
1101 int8_t temp_int8;
1102 if (far_file) {
1103 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1104 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1105 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001106
ajm@google.com808e0e02011-08-03 21:08:51 +00001107 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1108 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1109
1110 if (!simulating) {
1111 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1112 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1113 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1114 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1115 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1116 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1117 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001118 }
1119
1120 if (perf_testing) {
1121 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001122 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001123 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1124 exec_time * 0.001, primary_count * 0.01);
1125 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1126 " %.3f ms (min)\n",
1127 (exec_time * 1.0) / primary_count,
1128 (max_time_us + max_time_reverse_us) / 1000.0,
1129 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001130 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001131 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001132 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001133 } else {
1134 printf("Warning: no capture frames\n");
1135 }
1136 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001137}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001138
ajm@google.com808e0e02011-08-03 21:08:51 +00001139} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001140} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001141
Andrew MacDonaldcb05b722015-05-07 22:17:51 -07001142int main(int argc, char* argv[]) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001143 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001144
andrew@webrtc.org64235092011-08-19 21:22:08 +00001145 // Optional, but removes memory leak noise from Valgrind.
1146 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001147 return 0;
1148}