blob: 3218243359999e2c7fb8f035a9a2b6dff115145c [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@webrtc.orga8b97372014-03-10 22:26:12 +000023#include "webrtc/modules/audio_processing/test/test_utils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000024#include "webrtc/modules/interface/module_common_types.h"
25#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000026#include "webrtc/system_wrappers/interface/tick_util.h"
kjellander@webrtc.org10abe252012-12-17 18:28:07 +000027#include "webrtc/test/testsupport/fileutils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000028#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000029#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000030#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000031#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000032#else
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000033#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:51 +000034#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000035#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000036
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000037namespace webrtc {
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000038
ajm@google.com808e0e02011-08-03 21:08:51 +000039using webrtc::audioproc::Event;
40using webrtc::audioproc::Init;
41using webrtc::audioproc::ReverseStream;
42using webrtc::audioproc::Stream;
43
44namespace {
niklase@google.com470e71d2011-07-07 08:21:25 +000045
andrew@webrtc.org94c74132011-09-19 15:17:57 +000046void PrintStat(const AudioProcessing::Statistic& stat) {
47 printf("%d, %d, %d\n", stat.average,
48 stat.maximum,
49 stat.minimum);
50}
51
niklase@google.com470e71d2011-07-07 08:21:25 +000052void usage() {
53 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000054 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
55 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000056 printf(
57 "process_test is a test application for AudioProcessing.\n\n"
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000058 "When a protobuf debug file is available, specify it with -pb. Alternately,\n"
59 "when -ir or -i is used, the specified files will be processed directly in\n"
60 "a simulation mode. Otherwise the full set of legacy test files is expected\n"
61 "to be present in the working directory. OUT_FILE should be specified\n"
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +000062 "without extension to support both raw and wav output.\n\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000063 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000064 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000065 printf(" -fs SAMPLE_RATE_HZ\n");
66 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
67 printf(" -rch REVERSE_CHANNELS\n");
68 printf("\n");
69 printf("Component configuration:\n");
70 printf(
71 "All components are disabled by default. Each block below begins with a\n"
72 "flag to enable the component with default settings. The subsequent flags\n"
73 "in the block are used to provide configuration settings.\n");
74 printf("\n -aec Echo cancellation\n");
75 printf(" --drift_compensation\n");
76 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +000077 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +000078 printf(" --no_delay_logging\n");
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +000079 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
andrew@webrtc.org22858d42013-10-23 14:07:17 +000080 printf(" --extended_filter\n");
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +000081 printf(" --no_reported_delay\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000082 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +000083 printf(" --aecm_echo_path_in_file FILE\n");
84 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +000085 printf(" --no_comfort_noise\n");
86 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000087 printf("\n -agc Gain control\n");
88 printf(" --analog\n");
89 printf(" --adaptive_digital\n");
90 printf(" --fixed_digital\n");
91 printf(" --target_level LEVEL\n");
92 printf(" --compression_gain GAIN\n");
93 printf(" --limiter\n");
94 printf(" --no_limiter\n");
95 printf("\n -hpf High pass filter\n");
96 printf("\n -ns Noise suppression\n");
97 printf(" --ns_low\n");
98 printf(" --ns_moderate\n");
99 printf(" --ns_high\n");
100 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000101 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000102 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000103 printf(" --vad_out_file FILE\n");
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000104 printf("\n -expns Experimental noise suppression\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000105 printf("\n Level metrics (enabled by default)\n");
106 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 printf("\n");
108 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000109 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000110 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
111 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000112 printf(" --perf Measure performance.\n");
113 printf(" --quiet Suppress text output.\n");
114 printf(" --no_progress Suppress progress.\n");
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000115 printf(" --raw_output Raw output instead of WAV file.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000116 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000119static float MicLevel2Gain(int level) {
120 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000121}
122
123static void SimulateMic(int mic_level, AudioFrame* frame) {
124 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000125 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000126 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000127 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000128 for (int n = 0; n < num_samples; n++) {
129 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000130 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000131 frame->data_[n] = static_cast<int16_t>(v);
132 }
133}
134
niklase@google.com470e71d2011-07-07 08:21:25 +0000135// void function for gtest.
136void void_main(int argc, char* argv[]) {
137 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
138 usage();
139 return;
140 }
141
142 if (argc < 2) {
143 printf("Did you mean to run without arguments?\n");
144 printf("Try `process_test --help' for more information.\n\n");
145 }
146
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000147 rtc::scoped_ptr<AudioProcessing> apm(AudioProcessing::Create());
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000148 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
ajm@google.com808e0e02011-08-03 21:08:51 +0000150 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 const char* far_filename = NULL;
152 const char* near_filename = NULL;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000153 std::string out_filename;
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000155 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000156 const char* aecm_echo_path_in_filename = NULL;
157 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159 int32_t sample_rate_hz = 16000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000160
161 int num_capture_input_channels = 1;
162 int num_capture_output_channels = 1;
163 int num_render_channels = 1;
164
165 int samples_per_channel = sample_rate_hz / 100;
166
167 bool simulating = false;
168 bool perf_testing = false;
169 bool verbose = true;
170 bool progress = true;
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000171 bool raw_output = false;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000172 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000173 int override_delay_ms = 0;
Bjorn Volckerbeb97982015-04-28 13:52:50 +0200174 Config config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000175
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000176 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000178 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000179 i++;
180 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
181 pb_filename = argv[i];
182
183 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 i++;
185 ASSERT_LT(i, argc) << "Specify filename after -ir";
186 far_filename = argv[i];
187 simulating = true;
188
189 } else if (strcmp(argv[i], "-i") == 0) {
190 i++;
191 ASSERT_LT(i, argc) << "Specify filename after -i";
192 near_filename = argv[i];
193 simulating = true;
194
195 } else if (strcmp(argv[i], "-o") == 0) {
196 i++;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000197 ASSERT_LT(i, argc) << "Specify filename without extension after -o";
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 out_filename = argv[i];
199
200 } else if (strcmp(argv[i], "-fs") == 0) {
201 i++;
202 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
203 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
204 samples_per_channel = sample_rate_hz / 100;
205
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 } else if (strcmp(argv[i], "-ch") == 0) {
207 i++;
208 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
209 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
210 i++;
211 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
212
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 } else if (strcmp(argv[i], "-rch") == 0) {
214 i++;
215 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
216 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
217
niklase@google.com470e71d2011-07-07 08:21:25 +0000218 } else if (strcmp(argv[i], "-aec") == 0) {
219 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000220 ASSERT_EQ(apm->kNoError,
221 apm->echo_cancellation()->enable_metrics(true));
222 ASSERT_EQ(apm->kNoError,
223 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000224
niklase@google.com470e71d2011-07-07 08:21:25 +0000225 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
226 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
227 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
228 // why it can give better performance despite passing zeros.
229 ASSERT_EQ(apm->kNoError,
230 apm->echo_cancellation()->enable_drift_compensation(true));
231 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
232 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
233 ASSERT_EQ(apm->kNoError,
234 apm->echo_cancellation()->enable_drift_compensation(false));
235
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000236 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
237 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
238 ASSERT_EQ(apm->kNoError,
239 apm->echo_cancellation()->enable_metrics(false));
240
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000241 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
242 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
243 ASSERT_EQ(apm->kNoError,
244 apm->echo_cancellation()->enable_delay_logging(false));
245
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000246 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
247 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
248
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000249 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
250 i++;
251 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
252 int suppression_level;
253 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
254 ASSERT_EQ(apm->kNoError,
255 apm->echo_cancellation()->set_suppression_level(
256 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
257 suppression_level)));
258
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000259 } else if (strcmp(argv[i], "--extended_filter") == 0) {
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000260 config.Set<DelayCorrection>(new DelayCorrection(true));
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000261
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000262 } else if (strcmp(argv[i], "--no_reported_delay") == 0) {
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000263 config.Set<ReportedDelay>(new ReportedDelay(false));
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000264
niklase@google.com470e71d2011-07-07 08:21:25 +0000265 } else if (strcmp(argv[i], "-aecm") == 0) {
266 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
267
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000268 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
269 i++;
270 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
271 aecm_echo_path_in_filename = argv[i];
272
273 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
274 i++;
275 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
276 aecm_echo_path_out_filename = argv[i];
277
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000278 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
279 ASSERT_EQ(apm->kNoError,
280 apm->echo_control_mobile()->enable_comfort_noise(false));
281
282 } else if (strcmp(argv[i], "--routing_mode") == 0) {
283 i++;
284 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
285 int routing_mode;
286 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
287 ASSERT_EQ(apm->kNoError,
288 apm->echo_control_mobile()->set_routing_mode(
289 static_cast<webrtc::EchoControlMobile::RoutingMode>(
290 routing_mode)));
291
niklase@google.com470e71d2011-07-07 08:21:25 +0000292 } else if (strcmp(argv[i], "-agc") == 0) {
293 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
294
295 } else if (strcmp(argv[i], "--analog") == 0) {
296 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
297 ASSERT_EQ(apm->kNoError,
298 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
299
300 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
301 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
302 ASSERT_EQ(apm->kNoError,
303 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
304
305 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
306 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
307 ASSERT_EQ(apm->kNoError,
308 apm->gain_control()->set_mode(GainControl::kFixedDigital));
309
310 } else if (strcmp(argv[i], "--target_level") == 0) {
311 i++;
312 int level;
313 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
314
315 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
316 ASSERT_EQ(apm->kNoError,
317 apm->gain_control()->set_target_level_dbfs(level));
318
319 } else if (strcmp(argv[i], "--compression_gain") == 0) {
320 i++;
321 int gain;
322 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
323
324 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
325 ASSERT_EQ(apm->kNoError,
326 apm->gain_control()->set_compression_gain_db(gain));
327
328 } else if (strcmp(argv[i], "--limiter") == 0) {
329 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
330 ASSERT_EQ(apm->kNoError,
331 apm->gain_control()->enable_limiter(true));
332
333 } else if (strcmp(argv[i], "--no_limiter") == 0) {
334 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
335 ASSERT_EQ(apm->kNoError,
336 apm->gain_control()->enable_limiter(false));
337
338 } else if (strcmp(argv[i], "-hpf") == 0) {
339 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
340
341 } else if (strcmp(argv[i], "-ns") == 0) {
342 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
343
344 } else if (strcmp(argv[i], "--ns_low") == 0) {
345 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
346 ASSERT_EQ(apm->kNoError,
347 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
348
349 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
350 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
351 ASSERT_EQ(apm->kNoError,
352 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
353
354 } else if (strcmp(argv[i], "--ns_high") == 0) {
355 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
356 ASSERT_EQ(apm->kNoError,
357 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
358
359 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
360 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
361 ASSERT_EQ(apm->kNoError,
362 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
363
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000364 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
365 i++;
366 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
367 ns_prob_filename = argv[i];
368
niklase@google.com470e71d2011-07-07 08:21:25 +0000369 } else if (strcmp(argv[i], "-vad") == 0) {
370 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
371
andrew@webrtc.org89752612012-10-12 16:41:45 +0000372 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
373 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
374 ASSERT_EQ(apm->kNoError,
375 apm->voice_detection()->set_likelihood(
376 VoiceDetection::kVeryLowLikelihood));
377
378 } else if (strcmp(argv[i], "--vad_low") == 0) {
379 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
380 ASSERT_EQ(apm->kNoError,
381 apm->voice_detection()->set_likelihood(
382 VoiceDetection::kLowLikelihood));
383
384 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
385 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
386 ASSERT_EQ(apm->kNoError,
387 apm->voice_detection()->set_likelihood(
388 VoiceDetection::kModerateLikelihood));
389
390 } else if (strcmp(argv[i], "--vad_high") == 0) {
391 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
392 ASSERT_EQ(apm->kNoError,
393 apm->voice_detection()->set_likelihood(
394 VoiceDetection::kHighLikelihood));
395
niklase@google.com470e71d2011-07-07 08:21:25 +0000396 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
397 i++;
398 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
399 vad_out_filename = argv[i];
400
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000401 } else if (strcmp(argv[i], "-expns") == 0) {
aluebs@webrtc.org9825afc2014-06-30 17:39:53 +0000402 config.Set<ExperimentalNs>(new ExperimentalNs(true));
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000403
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000404 } else if (strcmp(argv[i], "--noasm") == 0) {
405 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
406 // We need to reinitialize here if components have already been enabled.
407 ASSERT_EQ(apm->kNoError, apm->Initialize());
408
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000409 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000410 i++;
411 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
412
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000413 } else if (strcmp(argv[i], "--delay") == 0) {
414 i++;
415 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
416
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 } else if (strcmp(argv[i], "--perf") == 0) {
418 perf_testing = true;
419
420 } else if (strcmp(argv[i], "--quiet") == 0) {
421 verbose = false;
422 progress = false;
423
424 } else if (strcmp(argv[i], "--no_progress") == 0) {
425 progress = false;
426
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000427 } else if (strcmp(argv[i], "--raw_output") == 0) {
428 raw_output = true;
429
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000430 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000431 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000432 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000433 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 } else {
435 FAIL() << "Unrecognized argument " << argv[i];
436 }
437 }
Bjorn Volckerbeb97982015-04-28 13:52:50 +0200438 apm->SetExtraOptions(config);
439
ajm@google.com808e0e02011-08-03 21:08:51 +0000440 // If we're reading a protobuf file, ensure a simulation hasn't also
441 // been requested (which makes no sense...)
442 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000443
444 if (verbose) {
445 printf("Sample rate: %d Hz\n", sample_rate_hz);
446 printf("Primary channels: %d (in), %d (out)\n",
447 num_capture_input_channels,
448 num_capture_output_channels);
449 printf("Reverse channels: %d \n", num_render_channels);
450 }
451
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000452 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000453 const char far_file_default[] = "apm_far.pcm";
454 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000455 const char event_filename[] = "apm_event.dat";
456 const char delay_filename[] = "apm_delay.dat";
457 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000458 const std::string vad_file_default = out_path + "vad_out.dat";
459 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000460
461 if (!simulating) {
462 far_filename = far_file_default;
463 near_filename = near_file_default;
464 }
465
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000466 if (out_filename.size() == 0) {
467 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 }
469
ajm@google.com808e0e02011-08-03 21:08:51 +0000470 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000471 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 }
473
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000474 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000475 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000476 }
477
ajm@google.com808e0e02011-08-03 21:08:51 +0000478 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 FILE* far_file = NULL;
480 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000481 FILE* event_file = NULL;
482 FILE* delay_file = NULL;
483 FILE* drift_file = NULL;
484 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000485 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000486 FILE* aecm_echo_path_in_file = NULL;
487 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000488
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000489 rtc::scoped_ptr<WavWriter> output_wav_file;
490 rtc::scoped_ptr<RawFile> output_raw_file;
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000491
ajm@google.com808e0e02011-08-03 21:08:51 +0000492 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000493 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000494 } else {
495 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000496 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000497 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000498
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000499 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000500 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000501 event_file = OpenFile(event_filename, "rb");
502 delay_file = OpenFile(delay_filename, "rb");
503 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000504 }
505 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000506
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000507 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000508 if (pb_file) {
509 struct stat st;
510 stat(pb_filename, &st);
511 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000512 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000513 } else {
514 struct stat st;
515 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000516 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000517 }
518
519 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000520 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 }
522
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000523 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000524 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000525 }
526
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000527 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000528 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000529
ajm@google.com22e65152011-07-18 18:03:01 +0000530 const size_t path_size =
531 apm->echo_control_mobile()->echo_path_size_bytes();
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000532 rtc::scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000533 ASSERT_EQ(path_size, fread(echo_path.get(),
534 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000535 path_size,
536 aecm_echo_path_in_file));
537 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000538 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
539 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000540 fclose(aecm_echo_path_in_file);
541 aecm_echo_path_in_file = NULL;
542 }
543
544 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000545 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000546 }
547
niklase@google.com470e71d2011-07-07 08:21:25 +0000548 size_t read_count = 0;
549 int reverse_count = 0;
550 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000551 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552 TickInterval acc_ticks;
553
554 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000556
557 int delay_ms = 0;
558 int drift_samples = 0;
559 int capture_level = 127;
560 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000561 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000562
563 TickTime t0 = TickTime::Now();
564 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000565 int64_t max_time_us = 0;
566 int64_t max_time_reverse_us = 0;
567 int64_t min_time_us = 1e6;
568 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000569
ajm@google.com808e0e02011-08-03 21:08:51 +0000570 // TODO(ajm): Ideally we would refactor this block into separate functions,
571 // but for now we want to share the variables.
572 if (pb_file) {
573 Event event_msg;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000574 rtc::scoped_ptr<ChannelBuffer<float> > reverse_cb;
575 rtc::scoped_ptr<ChannelBuffer<float> > primary_cb;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000576 int output_sample_rate = 32000;
577 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
ajm@google.com808e0e02011-08-03 21:08:51 +0000578 while (ReadMessageFromFile(pb_file, &event_msg)) {
579 std::ostringstream trace_stream;
580 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
581 << primary_count << " (primary)";
582 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000583
ajm@google.com808e0e02011-08-03 21:08:51 +0000584 if (event_msg.type() == Event::INIT) {
585 ASSERT_TRUE(event_msg.has_init());
586 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000587
ajm@google.com808e0e02011-08-03 21:08:51 +0000588 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000589 ASSERT_TRUE(msg.has_num_input_channels());
590 ASSERT_TRUE(msg.has_num_output_channels());
591 ASSERT_TRUE(msg.has_num_reverse_channels());
592 int reverse_sample_rate = msg.sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000593 if (msg.has_reverse_sample_rate()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000594 reverse_sample_rate = msg.reverse_sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000595 }
596 output_sample_rate = msg.sample_rate();
597 if (msg.has_output_sample_rate()) {
598 output_sample_rate = msg.output_sample_rate();
599 }
600 output_layout = LayoutFromChannels(msg.num_output_channels());
601 ASSERT_EQ(kNoErr, apm->Initialize(
602 msg.sample_rate(),
603 output_sample_rate,
604 reverse_sample_rate,
605 LayoutFromChannels(msg.num_input_channels()),
606 output_layout,
607 LayoutFromChannels(msg.num_reverse_channels())));
ajm@google.com808e0e02011-08-03 21:08:51 +0000608
609 samples_per_channel = msg.sample_rate() / 100;
bjornv@webrtc.orgee300822014-11-13 11:00:10 +0000610 far_frame.sample_rate_hz_ = reverse_sample_rate;
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000611 far_frame.samples_per_channel_ = reverse_sample_rate / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000612 far_frame.num_channels_ = msg.num_reverse_channels();
613 near_frame.sample_rate_hz_ = msg.sample_rate();
614 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000615 near_frame.num_channels_ = msg.num_input_channels();
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000616 reverse_cb.reset(new ChannelBuffer<float>(
617 far_frame.samples_per_channel_,
618 msg.num_reverse_channels()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000619 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
620 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000621
622 if (verbose) {
623 printf("Init at frame: %d (primary), %d (reverse)\n",
624 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000625 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
626 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000627 printf(" Primary channels: %d (in), %d (out)\n",
628 msg.num_input_channels(),
629 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000630 printf(" Reverse rate: %d\n", reverse_sample_rate);
631 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000632 }
633
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000634 if (!raw_output) {
635 // The WAV file needs to be reset every time, because it cant change
636 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000637 output_wav_file.reset(new WavWriter(out_filename + ".wav",
638 output_sample_rate,
639 msg.num_output_channels()));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000640 }
641
ajm@google.com808e0e02011-08-03 21:08:51 +0000642 } else if (event_msg.type() == Event::REVERSE_STREAM) {
643 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000644 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000645 reverse_count++;
646
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000647 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
648 if (msg.has_data()) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000649 ASSERT_EQ(sizeof(int16_t) * far_frame.samples_per_channel_ *
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000650 far_frame.num_channels_, msg.data().size());
651 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
652 } else {
653 for (int i = 0; i < msg.channel_size(); ++i) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000654 memcpy(reverse_cb->channels()[i],
655 msg.channel(i).data(),
656 reverse_cb->num_frames() *
657 sizeof(reverse_cb->channels()[i][0]));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000658 }
659 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000660
661 if (perf_testing) {
662 t0 = TickTime::Now();
663 }
664
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000665 if (msg.has_data()) {
666 ASSERT_EQ(apm->kNoError,
667 apm->AnalyzeReverseStream(&far_frame));
668 } else {
669 ASSERT_EQ(apm->kNoError,
670 apm->AnalyzeReverseStream(
671 reverse_cb->channels(),
672 far_frame.samples_per_channel_,
673 far_frame.sample_rate_hz_,
674 LayoutFromChannels(far_frame.num_channels_)));
675 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000676
677 if (perf_testing) {
678 t1 = TickTime::Now();
679 TickInterval tick_diff = t1 - t0;
680 acc_ticks += tick_diff;
681 if (tick_diff.Microseconds() > max_time_reverse_us) {
682 max_time_reverse_us = tick_diff.Microseconds();
683 }
684 if (tick_diff.Microseconds() < min_time_reverse_us) {
685 min_time_reverse_us = tick_diff.Microseconds();
686 }
687 }
688
689 } else if (event_msg.type() == Event::STREAM) {
690 ASSERT_TRUE(event_msg.has_stream());
691 const Stream msg = event_msg.stream();
692 primary_count++;
693
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000694 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000695 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000696
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000697 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
698 if (msg.has_input_data()) {
699 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
700 near_frame.num_channels_, msg.input_data().size());
701 memcpy(near_frame.data_,
702 msg.input_data().data(),
703 msg.input_data().size());
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000704 near_read_bytes += msg.input_data().size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000705 } else {
706 for (int i = 0; i < msg.input_channel_size(); ++i) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000707 memcpy(primary_cb->channels()[i],
708 msg.input_channel(i).data(),
709 primary_cb->num_frames() *
710 sizeof(primary_cb->channels()[i][0]));
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000711 near_read_bytes += msg.input_channel(i).size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000712 }
713 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000714
ajm@google.com808e0e02011-08-03 21:08:51 +0000715 if (progress && primary_count % 100 == 0) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000716 near_read_bytes = std::min(near_read_bytes, near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000717 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000718 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000719 fflush(stdout);
720 }
721
722 if (perf_testing) {
723 t0 = TickTime::Now();
724 }
725
726 ASSERT_EQ(apm->kNoError,
727 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000728 delay_ms = msg.delay() + extra_delay_ms;
729 if (override_delay_ms) {
730 delay_ms = override_delay_ms;
731 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000732 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000733 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000734 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000735
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000736 if (msg.has_keypress()) {
737 apm->set_stream_key_pressed(msg.keypress());
738 } else {
739 apm->set_stream_key_pressed(true);
740 }
741
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000742 int err = apm->kNoError;
743 if (msg.has_input_data()) {
744 err = apm->ProcessStream(&near_frame);
745 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
746 } else {
747 err = apm->ProcessStream(
748 primary_cb->channels(),
749 near_frame.samples_per_channel_,
750 near_frame.sample_rate_hz_,
751 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000752 output_sample_rate,
753 output_layout,
754 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000755 }
756
ajm@google.com808e0e02011-08-03 21:08:51 +0000757 if (err == apm->kBadStreamParameterWarning) {
758 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
759 }
760 ASSERT_TRUE(err == apm->kNoError ||
761 err == apm->kBadStreamParameterWarning);
762
ajm@google.com808e0e02011-08-03 21:08:51 +0000763 stream_has_voice =
764 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
765 if (vad_out_file != NULL) {
766 ASSERT_EQ(1u, fwrite(&stream_has_voice,
767 sizeof(stream_has_voice),
768 1,
769 vad_out_file));
770 }
771
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000772 if (ns_prob_file != NULL) {
773 ns_speech_prob = apm->noise_suppression()->speech_probability();
774 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
775 sizeof(ns_speech_prob),
776 1,
777 ns_prob_file));
778 }
779
ajm@google.com808e0e02011-08-03 21:08:51 +0000780 if (perf_testing) {
781 t1 = TickTime::Now();
782 TickInterval tick_diff = t1 - t0;
783 acc_ticks += tick_diff;
784 if (tick_diff.Microseconds() > max_time_us) {
785 max_time_us = tick_diff.Microseconds();
786 }
787 if (tick_diff.Microseconds() < min_time_us) {
788 min_time_us = tick_diff.Microseconds();
789 }
790 }
791
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000792 const size_t samples_per_channel = output_sample_rate / 100;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000793 if (msg.has_input_data()) {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000794 if (raw_output && !output_raw_file) {
795 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
796 }
797 WriteIntData(near_frame.data_,
798 apm->num_output_channels() * samples_per_channel,
799 output_wav_file.get(),
800 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000801 } else {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000802 if (raw_output && !output_raw_file) {
803 output_raw_file.reset(new RawFile(out_filename + ".float"));
804 }
805 WriteFloatData(primary_cb->channels(),
806 samples_per_channel,
807 apm->num_output_channels(),
808 output_wav_file.get(),
809 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000810 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000811 }
812 }
813
814 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000815
816 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000817 enum Events {
818 kInitializeEvent,
819 kRenderEvent,
820 kCaptureEvent,
821 kResetEventDeprecated
822 };
823 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000824 while (simulating || feof(event_file) == 0) {
825 std::ostringstream trace_stream;
826 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
827 << primary_count << " (primary)";
828 SCOPED_TRACE(trace_stream.str());
829
830 if (simulating) {
831 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000832 event = kCaptureEvent;
833 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000834 if (event == kRenderEvent) {
835 event = kCaptureEvent;
836 } else {
837 event = kRenderEvent;
838 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000839 }
840 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000841 read_count = fread(&event, sizeof(event), 1, event_file);
842 if (read_count != 1) {
843 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000844 }
845 }
846
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000847 far_frame.sample_rate_hz_ = sample_rate_hz;
848 far_frame.samples_per_channel_ = samples_per_channel;
849 far_frame.num_channels_ = num_render_channels;
850 near_frame.sample_rate_hz_ = sample_rate_hz;
851 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000852
ajm@google.com808e0e02011-08-03 21:08:51 +0000853 if (event == kInitializeEvent || event == kResetEventDeprecated) {
854 ASSERT_EQ(1u,
855 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
856 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000857
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000858 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000859 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000860 fread(&unused_device_sample_rate_hz,
861 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000862 1,
863 event_file));
864
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000865 ASSERT_EQ(kNoErr, apm->Initialize(
866 sample_rate_hz,
867 sample_rate_hz,
868 sample_rate_hz,
869 LayoutFromChannels(num_capture_input_channels),
870 LayoutFromChannels(num_capture_output_channels),
871 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000872
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000873 far_frame.sample_rate_hz_ = sample_rate_hz;
874 far_frame.samples_per_channel_ = samples_per_channel;
875 far_frame.num_channels_ = num_render_channels;
876 near_frame.sample_rate_hz_ = sample_rate_hz;
877 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000878
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000879 if (!raw_output) {
bjornv@webrtc.org634c9262014-09-24 12:21:51 +0000880 // The WAV file needs to be reset every time, because it can't change
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000881 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000882 output_wav_file.reset(new WavWriter(out_filename + ".wav",
883 sample_rate_hz,
884 num_capture_output_channels));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000885 }
886
ajm@google.com808e0e02011-08-03 21:08:51 +0000887 if (verbose) {
888 printf("Init at frame: %d (primary), %d (reverse)\n",
889 primary_count, reverse_count);
890 printf(" Sample rate: %d Hz\n", sample_rate_hz);
891 }
892
893 } else if (event == kRenderEvent) {
894 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000895
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000896 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000897 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000898 sizeof(int16_t),
899 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000900 far_file);
901
902 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000903 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000904 // Read an equal amount from the near file to avoid errors due to
905 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000906 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000907 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000908 break; // This is expected.
909 }
910 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000911 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000912 }
913
914 if (perf_testing) {
915 t0 = TickTime::Now();
916 }
917
918 ASSERT_EQ(apm->kNoError,
919 apm->AnalyzeReverseStream(&far_frame));
920
921 if (perf_testing) {
922 t1 = TickTime::Now();
923 TickInterval tick_diff = t1 - t0;
924 acc_ticks += tick_diff;
925 if (tick_diff.Microseconds() > max_time_reverse_us) {
926 max_time_reverse_us = tick_diff.Microseconds();
927 }
928 if (tick_diff.Microseconds() < min_time_reverse_us) {
929 min_time_reverse_us = tick_diff.Microseconds();
930 }
931 }
932
933 } else if (event == kCaptureEvent) {
934 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000935 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000936
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000937 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000938 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000939 sizeof(int16_t),
940 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000941 near_file);
942
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000943 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000944 if (progress && primary_count % 100 == 0) {
945 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000946 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000947 fflush(stdout);
948 }
949 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000950 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000951 break; // This is expected.
952 }
953
954 delay_ms = 0;
955 drift_samples = 0;
956 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000957 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000958
959 // TODO(ajm): sizeof(delay_ms) for current files?
960 ASSERT_EQ(1u,
961 fread(&delay_ms, 2, 1, delay_file));
962 ASSERT_EQ(1u,
963 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
964 }
965
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000966 if (apm->gain_control()->is_enabled() &&
967 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000968 SimulateMic(capture_level, &near_frame);
969 }
970
ajm@google.com808e0e02011-08-03 21:08:51 +0000971 if (perf_testing) {
972 t0 = TickTime::Now();
973 }
974
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000975 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000976 ASSERT_EQ(apm->kNoError,
977 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000978 delay_ms += extra_delay_ms;
979 if (override_delay_ms) {
980 delay_ms = override_delay_ms;
981 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000982 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000983 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000984 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000985
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000986 apm->set_stream_key_pressed(true);
987
ajm@google.com808e0e02011-08-03 21:08:51 +0000988 int err = apm->ProcessStream(&near_frame);
989 if (err == apm->kBadStreamParameterWarning) {
990 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
991 }
992 ASSERT_TRUE(err == apm->kNoError ||
993 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000994 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000995
996 capture_level = apm->gain_control()->stream_analog_level();
997
998 stream_has_voice =
999 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
1000 if (vad_out_file != NULL) {
1001 ASSERT_EQ(1u, fwrite(&stream_has_voice,
1002 sizeof(stream_has_voice),
1003 1,
1004 vad_out_file));
1005 }
1006
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001007 if (ns_prob_file != NULL) {
1008 ns_speech_prob = apm->noise_suppression()->speech_probability();
1009 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
1010 sizeof(ns_speech_prob),
1011 1,
1012 ns_prob_file));
1013 }
1014
ajm@google.com808e0e02011-08-03 21:08:51 +00001015 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
1016 ASSERT_EQ(capture_level_in, capture_level);
1017 }
1018
1019 if (perf_testing) {
1020 t1 = TickTime::Now();
1021 TickInterval tick_diff = t1 - t0;
1022 acc_ticks += tick_diff;
1023 if (tick_diff.Microseconds() > max_time_us) {
1024 max_time_us = tick_diff.Microseconds();
1025 }
1026 if (tick_diff.Microseconds() < min_time_us) {
1027 min_time_us = tick_diff.Microseconds();
1028 }
1029 }
1030
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001031 if (raw_output && !output_raw_file) {
1032 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
1033 }
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001034 if (!raw_output && !output_wav_file) {
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +00001035 output_wav_file.reset(new WavWriter(out_filename + ".wav",
1036 sample_rate_hz,
1037 num_capture_output_channels));
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001038 }
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001039 WriteIntData(near_frame.data_,
1040 size,
1041 output_wav_file.get(),
1042 output_raw_file.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 }
ajm@google.com808e0e02011-08-03 21:08:51 +00001044 else {
1045 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
1139int main(int argc, char* argv[])
1140{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001141 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001142
andrew@webrtc.org64235092011-08-19 21:22:08 +00001143 // Optional, but removes memory leak noise from Valgrind.
1144 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001145 return 0;
1146}