blob: 3af495c19b56e059cd6fdd356c4930bc6f99969a [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
leozwang@webrtc.org9a85d8e2012-03-16 18:03:18 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
andrew@webrtc.org81865342012-10-27 00:28:27 +000011#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000012#include <stdio.h>
13#include <string.h>
14#ifdef WEBRTC_ANDROID
15#include <sys/stat.h>
16#endif
17
andrew@webrtc.org81865342012-10-27 00:28:27 +000018#include <algorithm>
19
andrew@webrtc.org22858d42013-10-23 14:07:17 +000020#include "webrtc/common.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000021#include "webrtc/modules/audio_processing/include/audio_processing.h"
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000022#include "webrtc/modules/audio_processing/test/test_utils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000023#include "webrtc/modules/interface/module_common_types.h"
24#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
25#include "webrtc/system_wrappers/interface/scoped_ptr.h"
26#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
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000147 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;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000175 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000177 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000178 i++;
179 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
180 pb_filename = argv[i];
181
182 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 i++;
184 ASSERT_LT(i, argc) << "Specify filename after -ir";
185 far_filename = argv[i];
186 simulating = true;
187
188 } else if (strcmp(argv[i], "-i") == 0) {
189 i++;
190 ASSERT_LT(i, argc) << "Specify filename after -i";
191 near_filename = argv[i];
192 simulating = true;
193
194 } else if (strcmp(argv[i], "-o") == 0) {
195 i++;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000196 ASSERT_LT(i, argc) << "Specify filename without extension after -o";
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 out_filename = argv[i];
198
199 } else if (strcmp(argv[i], "-fs") == 0) {
200 i++;
201 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
202 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
203 samples_per_channel = sample_rate_hz / 100;
204
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 } else if (strcmp(argv[i], "-ch") == 0) {
206 i++;
207 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
208 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
209 i++;
210 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
211
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 } else if (strcmp(argv[i], "-rch") == 0) {
213 i++;
214 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
215 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
216
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 } else if (strcmp(argv[i], "-aec") == 0) {
218 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000219 ASSERT_EQ(apm->kNoError,
220 apm->echo_cancellation()->enable_metrics(true));
221 ASSERT_EQ(apm->kNoError,
222 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000223
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
225 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
226 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
227 // why it can give better performance despite passing zeros.
228 ASSERT_EQ(apm->kNoError,
229 apm->echo_cancellation()->enable_drift_compensation(true));
230 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
231 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
232 ASSERT_EQ(apm->kNoError,
233 apm->echo_cancellation()->enable_drift_compensation(false));
234
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000235 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
236 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
237 ASSERT_EQ(apm->kNoError,
238 apm->echo_cancellation()->enable_metrics(false));
239
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000240 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
241 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
242 ASSERT_EQ(apm->kNoError,
243 apm->echo_cancellation()->enable_delay_logging(false));
244
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000245 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
246 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
247
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000248 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
249 i++;
250 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
251 int suppression_level;
252 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
253 ASSERT_EQ(apm->kNoError,
254 apm->echo_cancellation()->set_suppression_level(
255 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
256 suppression_level)));
257
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000258 } else if (strcmp(argv[i], "--extended_filter") == 0) {
259 Config config;
260 config.Set<DelayCorrection>(new DelayCorrection(true));
261 apm->SetExtraOptions(config);
262
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000263 } else if (strcmp(argv[i], "--no_reported_delay") == 0) {
264 Config config;
265 config.Set<ReportedDelay>(new ReportedDelay(false));
266 apm->SetExtraOptions(config);
267
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 } else if (strcmp(argv[i], "-aecm") == 0) {
269 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
270
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000271 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
272 i++;
273 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
274 aecm_echo_path_in_filename = argv[i];
275
276 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
277 i++;
278 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
279 aecm_echo_path_out_filename = argv[i];
280
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000281 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
282 ASSERT_EQ(apm->kNoError,
283 apm->echo_control_mobile()->enable_comfort_noise(false));
284
285 } else if (strcmp(argv[i], "--routing_mode") == 0) {
286 i++;
287 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
288 int routing_mode;
289 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
290 ASSERT_EQ(apm->kNoError,
291 apm->echo_control_mobile()->set_routing_mode(
292 static_cast<webrtc::EchoControlMobile::RoutingMode>(
293 routing_mode)));
294
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 } else if (strcmp(argv[i], "-agc") == 0) {
296 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
297
298 } else if (strcmp(argv[i], "--analog") == 0) {
299 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
300 ASSERT_EQ(apm->kNoError,
301 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
302
303 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
304 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
305 ASSERT_EQ(apm->kNoError,
306 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
307
308 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
309 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
310 ASSERT_EQ(apm->kNoError,
311 apm->gain_control()->set_mode(GainControl::kFixedDigital));
312
313 } else if (strcmp(argv[i], "--target_level") == 0) {
314 i++;
315 int level;
316 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
317
318 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
319 ASSERT_EQ(apm->kNoError,
320 apm->gain_control()->set_target_level_dbfs(level));
321
322 } else if (strcmp(argv[i], "--compression_gain") == 0) {
323 i++;
324 int gain;
325 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
326
327 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
328 ASSERT_EQ(apm->kNoError,
329 apm->gain_control()->set_compression_gain_db(gain));
330
331 } else if (strcmp(argv[i], "--limiter") == 0) {
332 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
333 ASSERT_EQ(apm->kNoError,
334 apm->gain_control()->enable_limiter(true));
335
336 } else if (strcmp(argv[i], "--no_limiter") == 0) {
337 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
338 ASSERT_EQ(apm->kNoError,
339 apm->gain_control()->enable_limiter(false));
340
341 } else if (strcmp(argv[i], "-hpf") == 0) {
342 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
343
344 } else if (strcmp(argv[i], "-ns") == 0) {
345 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
346
347 } else if (strcmp(argv[i], "--ns_low") == 0) {
348 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
349 ASSERT_EQ(apm->kNoError,
350 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
351
352 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
353 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
354 ASSERT_EQ(apm->kNoError,
355 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
356
357 } else if (strcmp(argv[i], "--ns_high") == 0) {
358 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
359 ASSERT_EQ(apm->kNoError,
360 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
361
362 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
363 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
364 ASSERT_EQ(apm->kNoError,
365 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
366
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000367 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
368 i++;
369 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
370 ns_prob_filename = argv[i];
371
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 } else if (strcmp(argv[i], "-vad") == 0) {
373 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
374
andrew@webrtc.org89752612012-10-12 16:41:45 +0000375 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
376 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
377 ASSERT_EQ(apm->kNoError,
378 apm->voice_detection()->set_likelihood(
379 VoiceDetection::kVeryLowLikelihood));
380
381 } else if (strcmp(argv[i], "--vad_low") == 0) {
382 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
383 ASSERT_EQ(apm->kNoError,
384 apm->voice_detection()->set_likelihood(
385 VoiceDetection::kLowLikelihood));
386
387 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
388 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
389 ASSERT_EQ(apm->kNoError,
390 apm->voice_detection()->set_likelihood(
391 VoiceDetection::kModerateLikelihood));
392
393 } else if (strcmp(argv[i], "--vad_high") == 0) {
394 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
395 ASSERT_EQ(apm->kNoError,
396 apm->voice_detection()->set_likelihood(
397 VoiceDetection::kHighLikelihood));
398
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
400 i++;
401 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
402 vad_out_filename = argv[i];
403
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000404 } else if (strcmp(argv[i], "-expns") == 0) {
aluebs@webrtc.org9825afc2014-06-30 17:39:53 +0000405 Config config;
406 config.Set<ExperimentalNs>(new ExperimentalNs(true));
407 apm->SetExtraOptions(config);
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000408
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000409 } else if (strcmp(argv[i], "--noasm") == 0) {
410 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
411 // We need to reinitialize here if components have already been enabled.
412 ASSERT_EQ(apm->kNoError, apm->Initialize());
413
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000414 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000415 i++;
416 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
417
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000418 } else if (strcmp(argv[i], "--delay") == 0) {
419 i++;
420 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
421
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 } else if (strcmp(argv[i], "--perf") == 0) {
423 perf_testing = true;
424
425 } else if (strcmp(argv[i], "--quiet") == 0) {
426 verbose = false;
427 progress = false;
428
429 } else if (strcmp(argv[i], "--no_progress") == 0) {
430 progress = false;
431
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000432 } else if (strcmp(argv[i], "--raw_output") == 0) {
433 raw_output = true;
434
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000435 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000436 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000437 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000438 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 } else {
440 FAIL() << "Unrecognized argument " << argv[i];
441 }
442 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000443 // If we're reading a protobuf file, ensure a simulation hasn't also
444 // been requested (which makes no sense...)
445 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000446
447 if (verbose) {
448 printf("Sample rate: %d Hz\n", sample_rate_hz);
449 printf("Primary channels: %d (in), %d (out)\n",
450 num_capture_input_channels,
451 num_capture_output_channels);
452 printf("Reverse channels: %d \n", num_render_channels);
453 }
454
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000455 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000456 const char far_file_default[] = "apm_far.pcm";
457 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000458 const char event_filename[] = "apm_event.dat";
459 const char delay_filename[] = "apm_delay.dat";
460 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000461 const std::string vad_file_default = out_path + "vad_out.dat";
462 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
464 if (!simulating) {
465 far_filename = far_file_default;
466 near_filename = near_file_default;
467 }
468
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000469 if (out_filename.size() == 0) {
470 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 }
472
ajm@google.com808e0e02011-08-03 21:08:51 +0000473 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000474 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 }
476
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000477 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000478 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000479 }
480
ajm@google.com808e0e02011-08-03 21:08:51 +0000481 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 FILE* far_file = NULL;
483 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000484 FILE* event_file = NULL;
485 FILE* delay_file = NULL;
486 FILE* drift_file = NULL;
487 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000488 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000489 FILE* aecm_echo_path_in_file = NULL;
490 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000491
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000492 scoped_ptr<WavWriter> output_wav_file;
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000493 scoped_ptr<RawFile> output_raw_file;
494
ajm@google.com808e0e02011-08-03 21:08:51 +0000495 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000496 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000497 } else {
498 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000499 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000500 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000501
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000502 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000503 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000504 event_file = OpenFile(event_filename, "rb");
505 delay_file = OpenFile(delay_filename, "rb");
506 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000507 }
508 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000509
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000510 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000511 if (pb_file) {
512 struct stat st;
513 stat(pb_filename, &st);
514 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000515 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000516 } else {
517 struct stat st;
518 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000519 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000520 }
521
522 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000523 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000524 }
525
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000526 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000527 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000528 }
529
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000530 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000531 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000532
ajm@google.com22e65152011-07-18 18:03:01 +0000533 const size_t path_size =
534 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +0000535 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000536 ASSERT_EQ(path_size, fread(echo_path.get(),
537 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000538 path_size,
539 aecm_echo_path_in_file));
540 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000541 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
542 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000543 fclose(aecm_echo_path_in_file);
544 aecm_echo_path_in_file = NULL;
545 }
546
547 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000548 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000549 }
550
niklase@google.com470e71d2011-07-07 08:21:25 +0000551 size_t read_count = 0;
552 int reverse_count = 0;
553 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000554 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 TickInterval acc_ticks;
556
557 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559
560 int delay_ms = 0;
561 int drift_samples = 0;
562 int capture_level = 127;
563 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000564 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000565
566 TickTime t0 = TickTime::Now();
567 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000568 int64_t max_time_us = 0;
569 int64_t max_time_reverse_us = 0;
570 int64_t min_time_us = 1e6;
571 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000572
ajm@google.com808e0e02011-08-03 21:08:51 +0000573 // TODO(ajm): Ideally we would refactor this block into separate functions,
574 // but for now we want to share the variables.
575 if (pb_file) {
576 Event event_msg;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000577 scoped_ptr<ChannelBuffer<float> > reverse_cb;
578 scoped_ptr<ChannelBuffer<float> > primary_cb;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000579 int output_sample_rate = 32000;
580 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
ajm@google.com808e0e02011-08-03 21:08:51 +0000581 while (ReadMessageFromFile(pb_file, &event_msg)) {
582 std::ostringstream trace_stream;
583 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
584 << primary_count << " (primary)";
585 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000586
ajm@google.com808e0e02011-08-03 21:08:51 +0000587 if (event_msg.type() == Event::INIT) {
588 ASSERT_TRUE(event_msg.has_init());
589 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000590
ajm@google.com808e0e02011-08-03 21:08:51 +0000591 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000592 ASSERT_TRUE(msg.has_num_input_channels());
593 ASSERT_TRUE(msg.has_num_output_channels());
594 ASSERT_TRUE(msg.has_num_reverse_channels());
595 int reverse_sample_rate = msg.sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000596 if (msg.has_reverse_sample_rate()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000597 reverse_sample_rate = msg.reverse_sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000598 }
599 output_sample_rate = msg.sample_rate();
600 if (msg.has_output_sample_rate()) {
601 output_sample_rate = msg.output_sample_rate();
602 }
603 output_layout = LayoutFromChannels(msg.num_output_channels());
604 ASSERT_EQ(kNoErr, apm->Initialize(
605 msg.sample_rate(),
606 output_sample_rate,
607 reverse_sample_rate,
608 LayoutFromChannels(msg.num_input_channels()),
609 output_layout,
610 LayoutFromChannels(msg.num_reverse_channels())));
ajm@google.com808e0e02011-08-03 21:08:51 +0000611
612 samples_per_channel = msg.sample_rate() / 100;
bjornv@webrtc.orgee300822014-11-13 11:00:10 +0000613 far_frame.sample_rate_hz_ = reverse_sample_rate;
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000614 far_frame.samples_per_channel_ = reverse_sample_rate / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000615 far_frame.num_channels_ = msg.num_reverse_channels();
616 near_frame.sample_rate_hz_ = msg.sample_rate();
617 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000618 near_frame.num_channels_ = msg.num_input_channels();
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000619 reverse_cb.reset(new ChannelBuffer<float>(
620 far_frame.samples_per_channel_,
621 msg.num_reverse_channels()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000622 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
623 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000624
625 if (verbose) {
626 printf("Init at frame: %d (primary), %d (reverse)\n",
627 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000628 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
629 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000630 printf(" Primary channels: %d (in), %d (out)\n",
631 msg.num_input_channels(),
632 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000633 printf(" Reverse rate: %d\n", reverse_sample_rate);
634 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000635 }
636
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000637 if (!raw_output) {
638 // The WAV file needs to be reset every time, because it cant change
639 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000640 output_wav_file.reset(new WavWriter(out_filename + ".wav",
641 output_sample_rate,
642 msg.num_output_channels()));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000643 }
644
ajm@google.com808e0e02011-08-03 21:08:51 +0000645 } else if (event_msg.type() == Event::REVERSE_STREAM) {
646 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000647 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000648 reverse_count++;
649
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000650 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
651 if (msg.has_data()) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000652 ASSERT_EQ(sizeof(int16_t) * far_frame.samples_per_channel_ *
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000653 far_frame.num_channels_, msg.data().size());
654 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
655 } else {
656 for (int i = 0; i < msg.channel_size(); ++i) {
657 reverse_cb->CopyFrom(msg.channel(i).data(), i);
658 }
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) {
707 primary_cb->CopyFrom(msg.input_channel(i).data(), i);
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000708 near_read_bytes += msg.input_channel(i).size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000709 }
710 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000711
ajm@google.com808e0e02011-08-03 21:08:51 +0000712 if (progress && primary_count % 100 == 0) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000713 near_read_bytes = std::min(near_read_bytes, near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000714 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000715 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000716 fflush(stdout);
717 }
718
719 if (perf_testing) {
720 t0 = TickTime::Now();
721 }
722
723 ASSERT_EQ(apm->kNoError,
724 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000725 delay_ms = msg.delay() + extra_delay_ms;
726 if (override_delay_ms) {
727 delay_ms = override_delay_ms;
728 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000729 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000730 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000731 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000732
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000733 if (msg.has_keypress()) {
734 apm->set_stream_key_pressed(msg.keypress());
735 } else {
736 apm->set_stream_key_pressed(true);
737 }
738
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000739 int err = apm->kNoError;
740 if (msg.has_input_data()) {
741 err = apm->ProcessStream(&near_frame);
742 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
743 } else {
744 err = apm->ProcessStream(
745 primary_cb->channels(),
746 near_frame.samples_per_channel_,
747 near_frame.sample_rate_hz_,
748 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000749 output_sample_rate,
750 output_layout,
751 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000752 }
753
ajm@google.com808e0e02011-08-03 21:08:51 +0000754 if (err == apm->kBadStreamParameterWarning) {
755 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
756 }
757 ASSERT_TRUE(err == apm->kNoError ||
758 err == apm->kBadStreamParameterWarning);
759
ajm@google.com808e0e02011-08-03 21:08:51 +0000760 stream_has_voice =
761 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
762 if (vad_out_file != NULL) {
763 ASSERT_EQ(1u, fwrite(&stream_has_voice,
764 sizeof(stream_has_voice),
765 1,
766 vad_out_file));
767 }
768
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000769 if (ns_prob_file != NULL) {
770 ns_speech_prob = apm->noise_suppression()->speech_probability();
771 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
772 sizeof(ns_speech_prob),
773 1,
774 ns_prob_file));
775 }
776
ajm@google.com808e0e02011-08-03 21:08:51 +0000777 if (perf_testing) {
778 t1 = TickTime::Now();
779 TickInterval tick_diff = t1 - t0;
780 acc_ticks += tick_diff;
781 if (tick_diff.Microseconds() > max_time_us) {
782 max_time_us = tick_diff.Microseconds();
783 }
784 if (tick_diff.Microseconds() < min_time_us) {
785 min_time_us = tick_diff.Microseconds();
786 }
787 }
788
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000789 const size_t samples_per_channel = output_sample_rate / 100;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000790 if (msg.has_input_data()) {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000791 if (raw_output && !output_raw_file) {
792 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
793 }
794 WriteIntData(near_frame.data_,
795 apm->num_output_channels() * samples_per_channel,
796 output_wav_file.get(),
797 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000798 } else {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000799 if (raw_output && !output_raw_file) {
800 output_raw_file.reset(new RawFile(out_filename + ".float"));
801 }
802 WriteFloatData(primary_cb->channels(),
803 samples_per_channel,
804 apm->num_output_channels(),
805 output_wav_file.get(),
806 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000807 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000808 }
809 }
810
811 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000812
813 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000814 enum Events {
815 kInitializeEvent,
816 kRenderEvent,
817 kCaptureEvent,
818 kResetEventDeprecated
819 };
820 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000821 while (simulating || feof(event_file) == 0) {
822 std::ostringstream trace_stream;
823 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
824 << primary_count << " (primary)";
825 SCOPED_TRACE(trace_stream.str());
826
827 if (simulating) {
828 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000829 event = kCaptureEvent;
830 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000831 if (event == kRenderEvent) {
832 event = kCaptureEvent;
833 } else {
834 event = kRenderEvent;
835 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000836 }
837 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000838 read_count = fread(&event, sizeof(event), 1, event_file);
839 if (read_count != 1) {
840 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000841 }
842 }
843
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000844 far_frame.sample_rate_hz_ = sample_rate_hz;
845 far_frame.samples_per_channel_ = samples_per_channel;
846 far_frame.num_channels_ = num_render_channels;
847 near_frame.sample_rate_hz_ = sample_rate_hz;
848 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000849
ajm@google.com808e0e02011-08-03 21:08:51 +0000850 if (event == kInitializeEvent || event == kResetEventDeprecated) {
851 ASSERT_EQ(1u,
852 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
853 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000854
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000855 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000856 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000857 fread(&unused_device_sample_rate_hz,
858 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000859 1,
860 event_file));
861
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000862 ASSERT_EQ(kNoErr, apm->Initialize(
863 sample_rate_hz,
864 sample_rate_hz,
865 sample_rate_hz,
866 LayoutFromChannels(num_capture_input_channels),
867 LayoutFromChannels(num_capture_output_channels),
868 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000869
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000870 far_frame.sample_rate_hz_ = sample_rate_hz;
871 far_frame.samples_per_channel_ = samples_per_channel;
872 far_frame.num_channels_ = num_render_channels;
873 near_frame.sample_rate_hz_ = sample_rate_hz;
874 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000875
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000876 if (!raw_output) {
bjornv@webrtc.org634c9262014-09-24 12:21:51 +0000877 // The WAV file needs to be reset every time, because it can't change
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000878 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000879 output_wav_file.reset(new WavWriter(out_filename + ".wav",
880 sample_rate_hz,
881 num_capture_output_channels));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000882 }
883
ajm@google.com808e0e02011-08-03 21:08:51 +0000884 if (verbose) {
885 printf("Init at frame: %d (primary), %d (reverse)\n",
886 primary_count, reverse_count);
887 printf(" Sample rate: %d Hz\n", sample_rate_hz);
888 }
889
890 } else if (event == kRenderEvent) {
891 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000892
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000893 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000894 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000895 sizeof(int16_t),
896 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000897 far_file);
898
899 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000900 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000901 // Read an equal amount from the near file to avoid errors due to
902 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000903 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000904 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000905 break; // This is expected.
906 }
907 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000908 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000909 }
910
911 if (perf_testing) {
912 t0 = TickTime::Now();
913 }
914
915 ASSERT_EQ(apm->kNoError,
916 apm->AnalyzeReverseStream(&far_frame));
917
918 if (perf_testing) {
919 t1 = TickTime::Now();
920 TickInterval tick_diff = t1 - t0;
921 acc_ticks += tick_diff;
922 if (tick_diff.Microseconds() > max_time_reverse_us) {
923 max_time_reverse_us = tick_diff.Microseconds();
924 }
925 if (tick_diff.Microseconds() < min_time_reverse_us) {
926 min_time_reverse_us = tick_diff.Microseconds();
927 }
928 }
929
930 } else if (event == kCaptureEvent) {
931 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000932 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000933
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000934 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000935 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000936 sizeof(int16_t),
937 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000938 near_file);
939
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000940 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000941 if (progress && primary_count % 100 == 0) {
942 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000943 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000944 fflush(stdout);
945 }
946 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000947 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000948 break; // This is expected.
949 }
950
951 delay_ms = 0;
952 drift_samples = 0;
953 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000954 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000955
956 // TODO(ajm): sizeof(delay_ms) for current files?
957 ASSERT_EQ(1u,
958 fread(&delay_ms, 2, 1, delay_file));
959 ASSERT_EQ(1u,
960 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
961 }
962
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000963 if (apm->gain_control()->is_enabled() &&
964 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000965 SimulateMic(capture_level, &near_frame);
966 }
967
ajm@google.com808e0e02011-08-03 21:08:51 +0000968 if (perf_testing) {
969 t0 = TickTime::Now();
970 }
971
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000972 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000973 ASSERT_EQ(apm->kNoError,
974 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000975 delay_ms += extra_delay_ms;
976 if (override_delay_ms) {
977 delay_ms = override_delay_ms;
978 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000979 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000980 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000981 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000982
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000983 apm->set_stream_key_pressed(true);
984
ajm@google.com808e0e02011-08-03 21:08:51 +0000985 int err = apm->ProcessStream(&near_frame);
986 if (err == apm->kBadStreamParameterWarning) {
987 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
988 }
989 ASSERT_TRUE(err == apm->kNoError ||
990 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000991 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000992
993 capture_level = apm->gain_control()->stream_analog_level();
994
995 stream_has_voice =
996 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
997 if (vad_out_file != NULL) {
998 ASSERT_EQ(1u, fwrite(&stream_has_voice,
999 sizeof(stream_has_voice),
1000 1,
1001 vad_out_file));
1002 }
1003
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001004 if (ns_prob_file != NULL) {
1005 ns_speech_prob = apm->noise_suppression()->speech_probability();
1006 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
1007 sizeof(ns_speech_prob),
1008 1,
1009 ns_prob_file));
1010 }
1011
ajm@google.com808e0e02011-08-03 21:08:51 +00001012 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
1013 ASSERT_EQ(capture_level_in, capture_level);
1014 }
1015
1016 if (perf_testing) {
1017 t1 = TickTime::Now();
1018 TickInterval tick_diff = t1 - t0;
1019 acc_ticks += tick_diff;
1020 if (tick_diff.Microseconds() > max_time_us) {
1021 max_time_us = tick_diff.Microseconds();
1022 }
1023 if (tick_diff.Microseconds() < min_time_us) {
1024 min_time_us = tick_diff.Microseconds();
1025 }
1026 }
1027
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001028 if (raw_output && !output_raw_file) {
1029 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
1030 }
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001031 if (!raw_output && !output_wav_file) {
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +00001032 output_wav_file.reset(new WavWriter(out_filename + ".wav",
1033 sample_rate_hz,
1034 num_capture_output_channels));
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001035 }
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001036 WriteIntData(near_frame.data_,
1037 size,
1038 output_wav_file.get(),
1039 output_raw_file.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 }
ajm@google.com808e0e02011-08-03 21:08:51 +00001041 else {
1042 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001044 }
1045 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001046 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001047
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001048 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001049 const size_t path_size =
1050 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +00001051 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001052 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1053 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1054 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001055 path_size,
1056 aecm_echo_path_out_file));
1057 fclose(aecm_echo_path_out_file);
1058 aecm_echo_path_out_file = NULL;
1059 }
1060
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 if (verbose) {
1062 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1063 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001064
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001065 if (apm->level_estimator()->is_enabled()) {
1066 printf("\n--Level metrics--\n");
1067 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1068 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001069 if (apm->echo_cancellation()->are_metrics_enabled()) {
1070 EchoCancellation::Metrics metrics;
1071 apm->echo_cancellation()->GetMetrics(&metrics);
1072 printf("\n--Echo metrics--\n");
1073 printf("(avg, max, min)\n");
1074 printf("ERL: ");
1075 PrintStat(metrics.echo_return_loss);
1076 printf("ERLE: ");
1077 PrintStat(metrics.echo_return_loss_enhancement);
1078 printf("ANLP: ");
1079 PrintStat(metrics.a_nlp);
1080 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001081 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1082 int median = 0;
1083 int std = 0;
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001084 float fraction_poor_delays = 0;
1085 apm->echo_cancellation()->GetDelayMetrics(&median, &std,
1086 &fraction_poor_delays);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001087 printf("\n--Delay metrics--\n");
1088 printf("Median: %3d\n", median);
1089 printf("Standard deviation: %3d\n", std);
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001090 printf("Poor delay values: %3.1f%%\n", fraction_poor_delays * 100);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001091 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 }
1093
ajm@google.com808e0e02011-08-03 21:08:51 +00001094 if (!pb_file) {
1095 int8_t temp_int8;
1096 if (far_file) {
1097 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1098 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1099 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001100
ajm@google.com808e0e02011-08-03 21:08:51 +00001101 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1102 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1103
1104 if (!simulating) {
1105 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1106 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1107 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1108 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1109 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1110 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1111 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001112 }
1113
1114 if (perf_testing) {
1115 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001116 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001117 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1118 exec_time * 0.001, primary_count * 0.01);
1119 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1120 " %.3f ms (min)\n",
1121 (exec_time * 1.0) / primary_count,
1122 (max_time_us + max_time_reverse_us) / 1000.0,
1123 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001124 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001125 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001126 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001127 } else {
1128 printf("Warning: no capture frames\n");
1129 }
1130 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001131}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001132
ajm@google.com808e0e02011-08-03 21:08:51 +00001133} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001134} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001135
1136int main(int argc, char* argv[])
1137{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001138 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001139
andrew@webrtc.org64235092011-08-19 21:22:08 +00001140 // Optional, but removes memory leak noise from Valgrind.
1141 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 return 0;
1143}