blob: 23d4d18bca2b2a0393eae6b84da5fff8f8cd7558 [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"
kma@webrtc.org0e739502012-12-07 15:26:28 +000025#include "webrtc/modules/interface/module_common_types.h"
26#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000027#include "webrtc/system_wrappers/interface/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 Lundin3fbf3f82015-06-05 11:04:13 +0200261 config.Set<DelayCorrection>(new DelayCorrection(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) {
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000264 config.Set<ReportedDelay>(new ReportedDelay(false));
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000265
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 } else if (strcmp(argv[i], "-aecm") == 0) {
267 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
268
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000269 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
270 i++;
271 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
272 aecm_echo_path_in_filename = argv[i];
273
274 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
275 i++;
276 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
277 aecm_echo_path_out_filename = argv[i];
278
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000279 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
280 ASSERT_EQ(apm->kNoError,
281 apm->echo_control_mobile()->enable_comfort_noise(false));
282
283 } else if (strcmp(argv[i], "--routing_mode") == 0) {
284 i++;
285 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
286 int routing_mode;
287 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
288 ASSERT_EQ(apm->kNoError,
289 apm->echo_control_mobile()->set_routing_mode(
290 static_cast<webrtc::EchoControlMobile::RoutingMode>(
291 routing_mode)));
292
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 } else if (strcmp(argv[i], "-agc") == 0) {
294 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
295
296 } else if (strcmp(argv[i], "--analog") == 0) {
297 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
298 ASSERT_EQ(apm->kNoError,
299 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
300
301 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
302 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
303 ASSERT_EQ(apm->kNoError,
304 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
305
306 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
307 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
308 ASSERT_EQ(apm->kNoError,
309 apm->gain_control()->set_mode(GainControl::kFixedDigital));
310
311 } else if (strcmp(argv[i], "--target_level") == 0) {
312 i++;
313 int level;
314 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
315
316 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
317 ASSERT_EQ(apm->kNoError,
318 apm->gain_control()->set_target_level_dbfs(level));
319
320 } else if (strcmp(argv[i], "--compression_gain") == 0) {
321 i++;
322 int gain;
323 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
324
325 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
326 ASSERT_EQ(apm->kNoError,
327 apm->gain_control()->set_compression_gain_db(gain));
328
329 } else if (strcmp(argv[i], "--limiter") == 0) {
330 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
331 ASSERT_EQ(apm->kNoError,
332 apm->gain_control()->enable_limiter(true));
333
334 } else if (strcmp(argv[i], "--no_limiter") == 0) {
335 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
336 ASSERT_EQ(apm->kNoError,
337 apm->gain_control()->enable_limiter(false));
338
339 } else if (strcmp(argv[i], "-hpf") == 0) {
340 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
341
342 } else if (strcmp(argv[i], "-ns") == 0) {
343 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
344
345 } else if (strcmp(argv[i], "--ns_low") == 0) {
346 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
347 ASSERT_EQ(apm->kNoError,
348 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
349
350 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
351 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
352 ASSERT_EQ(apm->kNoError,
353 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
354
355 } else if (strcmp(argv[i], "--ns_high") == 0) {
356 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
357 ASSERT_EQ(apm->kNoError,
358 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
359
360 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
361 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
362 ASSERT_EQ(apm->kNoError,
363 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
364
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000365 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
366 i++;
367 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
368 ns_prob_filename = argv[i];
369
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 } else if (strcmp(argv[i], "-vad") == 0) {
371 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
372
andrew@webrtc.org89752612012-10-12 16:41:45 +0000373 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
374 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
375 ASSERT_EQ(apm->kNoError,
376 apm->voice_detection()->set_likelihood(
377 VoiceDetection::kVeryLowLikelihood));
378
379 } else if (strcmp(argv[i], "--vad_low") == 0) {
380 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
381 ASSERT_EQ(apm->kNoError,
382 apm->voice_detection()->set_likelihood(
383 VoiceDetection::kLowLikelihood));
384
385 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
386 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
387 ASSERT_EQ(apm->kNoError,
388 apm->voice_detection()->set_likelihood(
389 VoiceDetection::kModerateLikelihood));
390
391 } else if (strcmp(argv[i], "--vad_high") == 0) {
392 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
393 ASSERT_EQ(apm->kNoError,
394 apm->voice_detection()->set_likelihood(
395 VoiceDetection::kHighLikelihood));
396
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
398 i++;
399 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
400 vad_out_filename = argv[i];
401
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000402 } else if (strcmp(argv[i], "-expns") == 0) {
aluebs@webrtc.org9825afc2014-06-30 17:39:53 +0000403 config.Set<ExperimentalNs>(new ExperimentalNs(true));
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000404
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000405 } else if (strcmp(argv[i], "--noasm") == 0) {
406 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
407 // We need to reinitialize here if components have already been enabled.
408 ASSERT_EQ(apm->kNoError, apm->Initialize());
409
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000410 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000411 i++;
412 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
413
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000414 } else if (strcmp(argv[i], "--delay") == 0) {
415 i++;
416 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
417
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 } else if (strcmp(argv[i], "--perf") == 0) {
419 perf_testing = true;
420
421 } else if (strcmp(argv[i], "--quiet") == 0) {
422 verbose = false;
423 progress = false;
424
425 } else if (strcmp(argv[i], "--no_progress") == 0) {
426 progress = false;
427
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000428 } else if (strcmp(argv[i], "--raw_output") == 0) {
429 raw_output = true;
430
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000431 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000432 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000433 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000434 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000435 } else {
436 FAIL() << "Unrecognized argument " << argv[i];
437 }
438 }
Bjorn Volckerbeb97982015-04-28 13:52:50 +0200439 apm->SetExtraOptions(config);
440
ajm@google.com808e0e02011-08-03 21:08:51 +0000441 // If we're reading a protobuf file, ensure a simulation hasn't also
442 // been requested (which makes no sense...)
443 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000444
445 if (verbose) {
446 printf("Sample rate: %d Hz\n", sample_rate_hz);
447 printf("Primary channels: %d (in), %d (out)\n",
448 num_capture_input_channels,
449 num_capture_output_channels);
450 printf("Reverse channels: %d \n", num_render_channels);
451 }
452
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000453 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000454 const char far_file_default[] = "apm_far.pcm";
455 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000456 const char event_filename[] = "apm_event.dat";
457 const char delay_filename[] = "apm_delay.dat";
458 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000459 const std::string vad_file_default = out_path + "vad_out.dat";
460 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000461
462 if (!simulating) {
463 far_filename = far_file_default;
464 near_filename = near_file_default;
465 }
466
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000467 if (out_filename.size() == 0) {
468 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000469 }
470
ajm@google.com808e0e02011-08-03 21:08:51 +0000471 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000472 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 }
474
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000475 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000476 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000477 }
478
ajm@google.com808e0e02011-08-03 21:08:51 +0000479 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000480 FILE* far_file = NULL;
481 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 FILE* event_file = NULL;
483 FILE* delay_file = NULL;
484 FILE* drift_file = NULL;
485 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000486 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000487 FILE* aecm_echo_path_in_file = NULL;
488 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000489
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000490 rtc::scoped_ptr<WavWriter> output_wav_file;
491 rtc::scoped_ptr<RawFile> output_raw_file;
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000492
ajm@google.com808e0e02011-08-03 21:08:51 +0000493 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000494 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000495 } else {
496 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000497 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000498 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000499
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000500 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000501 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000502 event_file = OpenFile(event_filename, "rb");
503 delay_file = OpenFile(delay_filename, "rb");
504 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000505 }
506 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000507
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000508 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000509 if (pb_file) {
510 struct stat st;
511 stat(pb_filename, &st);
512 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000513 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000514 } else {
515 struct stat st;
516 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000517 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 }
519
520 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000521 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000522 }
523
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000524 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000525 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000526 }
527
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000528 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000529 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000530
ajm@google.com22e65152011-07-18 18:03:01 +0000531 const size_t path_size =
532 apm->echo_control_mobile()->echo_path_size_bytes();
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000533 rtc::scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000534 ASSERT_EQ(path_size, fread(echo_path.get(),
535 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000536 path_size,
537 aecm_echo_path_in_file));
538 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000539 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
540 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000541 fclose(aecm_echo_path_in_file);
542 aecm_echo_path_in_file = NULL;
543 }
544
545 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000546 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000547 }
548
niklase@google.com470e71d2011-07-07 08:21:25 +0000549 size_t read_count = 0;
550 int reverse_count = 0;
551 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000552 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000553 TickInterval acc_ticks;
554
555 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000557
558 int delay_ms = 0;
559 int drift_samples = 0;
560 int capture_level = 127;
561 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000562 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000563
564 TickTime t0 = TickTime::Now();
565 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000566 int64_t max_time_us = 0;
567 int64_t max_time_reverse_us = 0;
568 int64_t min_time_us = 1e6;
569 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000570
ajm@google.com808e0e02011-08-03 21:08:51 +0000571 // TODO(ajm): Ideally we would refactor this block into separate functions,
572 // but for now we want to share the variables.
573 if (pb_file) {
574 Event event_msg;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000575 rtc::scoped_ptr<ChannelBuffer<float> > reverse_cb;
576 rtc::scoped_ptr<ChannelBuffer<float> > primary_cb;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000577 int output_sample_rate = 32000;
578 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
ajm@google.com808e0e02011-08-03 21:08:51 +0000579 while (ReadMessageFromFile(pb_file, &event_msg)) {
580 std::ostringstream trace_stream;
581 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
582 << primary_count << " (primary)";
583 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
ajm@google.com808e0e02011-08-03 21:08:51 +0000585 if (event_msg.type() == Event::INIT) {
586 ASSERT_TRUE(event_msg.has_init());
587 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000588
ajm@google.com808e0e02011-08-03 21:08:51 +0000589 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000590 ASSERT_TRUE(msg.has_num_input_channels());
591 ASSERT_TRUE(msg.has_num_output_channels());
592 ASSERT_TRUE(msg.has_num_reverse_channels());
593 int reverse_sample_rate = msg.sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000594 if (msg.has_reverse_sample_rate()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000595 reverse_sample_rate = msg.reverse_sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000596 }
597 output_sample_rate = msg.sample_rate();
598 if (msg.has_output_sample_rate()) {
599 output_sample_rate = msg.output_sample_rate();
600 }
601 output_layout = LayoutFromChannels(msg.num_output_channels());
602 ASSERT_EQ(kNoErr, apm->Initialize(
603 msg.sample_rate(),
604 output_sample_rate,
605 reverse_sample_rate,
606 LayoutFromChannels(msg.num_input_channels()),
607 output_layout,
608 LayoutFromChannels(msg.num_reverse_channels())));
ajm@google.com808e0e02011-08-03 21:08:51 +0000609
610 samples_per_channel = msg.sample_rate() / 100;
bjornv@webrtc.orgee300822014-11-13 11:00:10 +0000611 far_frame.sample_rate_hz_ = reverse_sample_rate;
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000612 far_frame.samples_per_channel_ = reverse_sample_rate / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000613 far_frame.num_channels_ = msg.num_reverse_channels();
614 near_frame.sample_rate_hz_ = msg.sample_rate();
615 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000616 near_frame.num_channels_ = msg.num_input_channels();
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000617 reverse_cb.reset(new ChannelBuffer<float>(
618 far_frame.samples_per_channel_,
619 msg.num_reverse_channels()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000620 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
621 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000622
623 if (verbose) {
624 printf("Init at frame: %d (primary), %d (reverse)\n",
625 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000626 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
627 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000628 printf(" Primary channels: %d (in), %d (out)\n",
629 msg.num_input_channels(),
630 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000631 printf(" Reverse rate: %d\n", reverse_sample_rate);
632 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000633 }
634
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000635 if (!raw_output) {
636 // The WAV file needs to be reset every time, because it cant change
637 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000638 output_wav_file.reset(new WavWriter(out_filename + ".wav",
639 output_sample_rate,
640 msg.num_output_channels()));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000641 }
642
ajm@google.com808e0e02011-08-03 21:08:51 +0000643 } else if (event_msg.type() == Event::REVERSE_STREAM) {
644 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000645 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000646 reverse_count++;
647
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000648 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
649 if (msg.has_data()) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000650 ASSERT_EQ(sizeof(int16_t) * far_frame.samples_per_channel_ *
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000651 far_frame.num_channels_, msg.data().size());
652 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
653 } else {
654 for (int i = 0; i < msg.channel_size(); ++i) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000655 memcpy(reverse_cb->channels()[i],
656 msg.channel(i).data(),
657 reverse_cb->num_frames() *
658 sizeof(reverse_cb->channels()[i][0]));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000659 }
660 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000661
662 if (perf_testing) {
663 t0 = TickTime::Now();
664 }
665
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000666 if (msg.has_data()) {
667 ASSERT_EQ(apm->kNoError,
668 apm->AnalyzeReverseStream(&far_frame));
669 } else {
670 ASSERT_EQ(apm->kNoError,
671 apm->AnalyzeReverseStream(
672 reverse_cb->channels(),
673 far_frame.samples_per_channel_,
674 far_frame.sample_rate_hz_,
675 LayoutFromChannels(far_frame.num_channels_)));
676 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000677
678 if (perf_testing) {
679 t1 = TickTime::Now();
680 TickInterval tick_diff = t1 - t0;
681 acc_ticks += tick_diff;
682 if (tick_diff.Microseconds() > max_time_reverse_us) {
683 max_time_reverse_us = tick_diff.Microseconds();
684 }
685 if (tick_diff.Microseconds() < min_time_reverse_us) {
686 min_time_reverse_us = tick_diff.Microseconds();
687 }
688 }
689
690 } else if (event_msg.type() == Event::STREAM) {
691 ASSERT_TRUE(event_msg.has_stream());
692 const Stream msg = event_msg.stream();
693 primary_count++;
694
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000695 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000696 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000697
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000698 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
699 if (msg.has_input_data()) {
700 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
701 near_frame.num_channels_, msg.input_data().size());
702 memcpy(near_frame.data_,
703 msg.input_data().data(),
704 msg.input_data().size());
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000705 near_read_bytes += msg.input_data().size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000706 } else {
707 for (int i = 0; i < msg.input_channel_size(); ++i) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000708 memcpy(primary_cb->channels()[i],
709 msg.input_channel(i).data(),
710 primary_cb->num_frames() *
711 sizeof(primary_cb->channels()[i][0]));
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000712 near_read_bytes += msg.input_channel(i).size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000713 }
714 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000715
ajm@google.com808e0e02011-08-03 21:08:51 +0000716 if (progress && primary_count % 100 == 0) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000717 near_read_bytes = std::min(near_read_bytes, near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000718 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000719 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000720 fflush(stdout);
721 }
722
723 if (perf_testing) {
724 t0 = TickTime::Now();
725 }
726
727 ASSERT_EQ(apm->kNoError,
728 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000729 delay_ms = msg.delay() + extra_delay_ms;
730 if (override_delay_ms) {
731 delay_ms = override_delay_ms;
732 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000733 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000734 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000735 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000736
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000737 if (msg.has_keypress()) {
738 apm->set_stream_key_pressed(msg.keypress());
739 } else {
740 apm->set_stream_key_pressed(true);
741 }
742
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000743 int err = apm->kNoError;
744 if (msg.has_input_data()) {
745 err = apm->ProcessStream(&near_frame);
746 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
747 } else {
748 err = apm->ProcessStream(
749 primary_cb->channels(),
750 near_frame.samples_per_channel_,
751 near_frame.sample_rate_hz_,
752 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000753 output_sample_rate,
754 output_layout,
755 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000756 }
757
ajm@google.com808e0e02011-08-03 21:08:51 +0000758 if (err == apm->kBadStreamParameterWarning) {
759 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
760 }
761 ASSERT_TRUE(err == apm->kNoError ||
762 err == apm->kBadStreamParameterWarning);
763
ajm@google.com808e0e02011-08-03 21:08:51 +0000764 stream_has_voice =
765 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
766 if (vad_out_file != NULL) {
767 ASSERT_EQ(1u, fwrite(&stream_has_voice,
768 sizeof(stream_has_voice),
769 1,
770 vad_out_file));
771 }
772
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000773 if (ns_prob_file != NULL) {
774 ns_speech_prob = apm->noise_suppression()->speech_probability();
775 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
776 sizeof(ns_speech_prob),
777 1,
778 ns_prob_file));
779 }
780
ajm@google.com808e0e02011-08-03 21:08:51 +0000781 if (perf_testing) {
782 t1 = TickTime::Now();
783 TickInterval tick_diff = t1 - t0;
784 acc_ticks += tick_diff;
785 if (tick_diff.Microseconds() > max_time_us) {
786 max_time_us = tick_diff.Microseconds();
787 }
788 if (tick_diff.Microseconds() < min_time_us) {
789 min_time_us = tick_diff.Microseconds();
790 }
791 }
792
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000793 const size_t samples_per_channel = output_sample_rate / 100;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000794 if (msg.has_input_data()) {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000795 if (raw_output && !output_raw_file) {
796 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
797 }
798 WriteIntData(near_frame.data_,
799 apm->num_output_channels() * samples_per_channel,
800 output_wav_file.get(),
801 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000802 } else {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000803 if (raw_output && !output_raw_file) {
804 output_raw_file.reset(new RawFile(out_filename + ".float"));
805 }
806 WriteFloatData(primary_cb->channels(),
807 samples_per_channel,
808 apm->num_output_channels(),
809 output_wav_file.get(),
810 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000811 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000812 }
813 }
814
815 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000816
817 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000818 enum Events {
819 kInitializeEvent,
820 kRenderEvent,
821 kCaptureEvent,
822 kResetEventDeprecated
823 };
824 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000825 while (simulating || feof(event_file) == 0) {
826 std::ostringstream trace_stream;
827 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
828 << primary_count << " (primary)";
829 SCOPED_TRACE(trace_stream.str());
830
831 if (simulating) {
832 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 event = kCaptureEvent;
834 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000835 if (event == kRenderEvent) {
836 event = kCaptureEvent;
837 } else {
838 event = kRenderEvent;
839 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000840 }
841 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000842 read_count = fread(&event, sizeof(event), 1, event_file);
843 if (read_count != 1) {
844 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000845 }
846 }
847
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000848 far_frame.sample_rate_hz_ = sample_rate_hz;
849 far_frame.samples_per_channel_ = samples_per_channel;
850 far_frame.num_channels_ = num_render_channels;
851 near_frame.sample_rate_hz_ = sample_rate_hz;
852 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000853
ajm@google.com808e0e02011-08-03 21:08:51 +0000854 if (event == kInitializeEvent || event == kResetEventDeprecated) {
855 ASSERT_EQ(1u,
856 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
857 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000858
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000859 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000860 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000861 fread(&unused_device_sample_rate_hz,
862 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000863 1,
864 event_file));
865
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000866 ASSERT_EQ(kNoErr, apm->Initialize(
867 sample_rate_hz,
868 sample_rate_hz,
869 sample_rate_hz,
870 LayoutFromChannels(num_capture_input_channels),
871 LayoutFromChannels(num_capture_output_channels),
872 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000873
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000874 far_frame.sample_rate_hz_ = sample_rate_hz;
875 far_frame.samples_per_channel_ = samples_per_channel;
876 far_frame.num_channels_ = num_render_channels;
877 near_frame.sample_rate_hz_ = sample_rate_hz;
878 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000879
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000880 if (!raw_output) {
bjornv@webrtc.org634c9262014-09-24 12:21:51 +0000881 // The WAV file needs to be reset every time, because it can't change
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000882 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000883 output_wav_file.reset(new WavWriter(out_filename + ".wav",
884 sample_rate_hz,
885 num_capture_output_channels));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000886 }
887
ajm@google.com808e0e02011-08-03 21:08:51 +0000888 if (verbose) {
889 printf("Init at frame: %d (primary), %d (reverse)\n",
890 primary_count, reverse_count);
891 printf(" Sample rate: %d Hz\n", sample_rate_hz);
892 }
893
894 } else if (event == kRenderEvent) {
895 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000896
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000897 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000898 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000899 sizeof(int16_t),
900 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000901 far_file);
902
903 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000904 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000905 // Read an equal amount from the near file to avoid errors due to
906 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000907 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000908 SEEK_CUR));
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700909 break; // This is expected.
ajm@google.com808e0e02011-08-03 21:08:51 +0000910 }
911 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000912 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000913 }
914
915 if (perf_testing) {
916 t0 = TickTime::Now();
917 }
918
919 ASSERT_EQ(apm->kNoError,
920 apm->AnalyzeReverseStream(&far_frame));
921
922 if (perf_testing) {
923 t1 = TickTime::Now();
924 TickInterval tick_diff = t1 - t0;
925 acc_ticks += tick_diff;
926 if (tick_diff.Microseconds() > max_time_reverse_us) {
927 max_time_reverse_us = tick_diff.Microseconds();
928 }
929 if (tick_diff.Microseconds() < min_time_reverse_us) {
930 min_time_reverse_us = tick_diff.Microseconds();
931 }
932 }
933
934 } else if (event == kCaptureEvent) {
935 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000936 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000937
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000938 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000939 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000940 sizeof(int16_t),
941 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000942 near_file);
943
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000944 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000945 if (progress && primary_count % 100 == 0) {
946 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000947 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000948 fflush(stdout);
949 }
950 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000951 if (read_count != size) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700952 break; // This is expected.
ajm@google.com808e0e02011-08-03 21:08:51 +0000953 }
954
955 delay_ms = 0;
956 drift_samples = 0;
957 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000958 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000959
960 // TODO(ajm): sizeof(delay_ms) for current files?
961 ASSERT_EQ(1u,
962 fread(&delay_ms, 2, 1, delay_file));
963 ASSERT_EQ(1u,
964 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
965 }
966
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000967 if (apm->gain_control()->is_enabled() &&
968 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000969 SimulateMic(capture_level, &near_frame);
970 }
971
ajm@google.com808e0e02011-08-03 21:08:51 +0000972 if (perf_testing) {
973 t0 = TickTime::Now();
974 }
975
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000976 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000977 ASSERT_EQ(apm->kNoError,
978 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000979 delay_ms += extra_delay_ms;
980 if (override_delay_ms) {
981 delay_ms = override_delay_ms;
982 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000983 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000984 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000985 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000986
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000987 apm->set_stream_key_pressed(true);
988
ajm@google.com808e0e02011-08-03 21:08:51 +0000989 int err = apm->ProcessStream(&near_frame);
990 if (err == apm->kBadStreamParameterWarning) {
991 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
992 }
993 ASSERT_TRUE(err == apm->kNoError ||
994 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000995 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000996
997 capture_level = apm->gain_control()->stream_analog_level();
998
999 stream_has_voice =
1000 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
1001 if (vad_out_file != NULL) {
1002 ASSERT_EQ(1u, fwrite(&stream_has_voice,
1003 sizeof(stream_has_voice),
1004 1,
1005 vad_out_file));
1006 }
1007
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001008 if (ns_prob_file != NULL) {
1009 ns_speech_prob = apm->noise_suppression()->speech_probability();
1010 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
1011 sizeof(ns_speech_prob),
1012 1,
1013 ns_prob_file));
1014 }
1015
ajm@google.com808e0e02011-08-03 21:08:51 +00001016 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
1017 ASSERT_EQ(capture_level_in, capture_level);
1018 }
1019
1020 if (perf_testing) {
1021 t1 = TickTime::Now();
1022 TickInterval tick_diff = t1 - t0;
1023 acc_ticks += tick_diff;
1024 if (tick_diff.Microseconds() > max_time_us) {
1025 max_time_us = tick_diff.Microseconds();
1026 }
1027 if (tick_diff.Microseconds() < min_time_us) {
1028 min_time_us = tick_diff.Microseconds();
1029 }
1030 }
1031
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001032 if (raw_output && !output_raw_file) {
1033 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
1034 }
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001035 if (!raw_output && !output_wav_file) {
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +00001036 output_wav_file.reset(new WavWriter(out_filename + ".wav",
1037 sample_rate_hz,
1038 num_capture_output_channels));
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001039 }
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001040 WriteIntData(near_frame.data_,
1041 size,
1042 output_wav_file.get(),
1043 output_raw_file.get());
Andrew MacDonaldcb05b722015-05-07 22:17:51 -07001044 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +00001045 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +00001046 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 }
1048 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001049 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001050
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001051 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001052 const size_t path_size =
1053 apm->echo_control_mobile()->echo_path_size_bytes();
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00001054 rtc::scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001055 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1056 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1057 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001058 path_size,
1059 aecm_echo_path_out_file));
1060 fclose(aecm_echo_path_out_file);
1061 aecm_echo_path_out_file = NULL;
1062 }
1063
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 if (verbose) {
1065 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1066 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001067
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001068 if (apm->level_estimator()->is_enabled()) {
1069 printf("\n--Level metrics--\n");
1070 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1071 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001072 if (apm->echo_cancellation()->are_metrics_enabled()) {
1073 EchoCancellation::Metrics metrics;
1074 apm->echo_cancellation()->GetMetrics(&metrics);
1075 printf("\n--Echo metrics--\n");
1076 printf("(avg, max, min)\n");
1077 printf("ERL: ");
1078 PrintStat(metrics.echo_return_loss);
1079 printf("ERLE: ");
1080 PrintStat(metrics.echo_return_loss_enhancement);
1081 printf("ANLP: ");
1082 PrintStat(metrics.a_nlp);
1083 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001084 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1085 int median = 0;
1086 int std = 0;
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001087 float fraction_poor_delays = 0;
1088 apm->echo_cancellation()->GetDelayMetrics(&median, &std,
1089 &fraction_poor_delays);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001090 printf("\n--Delay metrics--\n");
1091 printf("Median: %3d\n", median);
1092 printf("Standard deviation: %3d\n", std);
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001093 printf("Poor delay values: %3.1f%%\n", fraction_poor_delays * 100);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001094 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001095 }
1096
ajm@google.com808e0e02011-08-03 21:08:51 +00001097 if (!pb_file) {
1098 int8_t temp_int8;
1099 if (far_file) {
1100 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1101 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1102 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001103
ajm@google.com808e0e02011-08-03 21:08:51 +00001104 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1105 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1106
1107 if (!simulating) {
1108 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1109 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1110 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1111 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1112 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1113 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1114 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 }
1116
1117 if (perf_testing) {
1118 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001119 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1121 exec_time * 0.001, primary_count * 0.01);
1122 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1123 " %.3f ms (min)\n",
1124 (exec_time * 1.0) / primary_count,
1125 (max_time_us + max_time_reverse_us) / 1000.0,
1126 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001127 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001128 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001129 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 } else {
1131 printf("Warning: no capture frames\n");
1132 }
1133 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001134}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001135
ajm@google.com808e0e02011-08-03 21:08:51 +00001136} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001137} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001138
Andrew MacDonaldcb05b722015-05-07 22:17:51 -07001139int main(int argc, char* argv[]) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001140 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001141
andrew@webrtc.org64235092011-08-19 21:22:08 +00001142 // Optional, but removes memory leak noise from Valgrind.
1143 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 return 0;
1145}