blob: d32dcb89a7b77451c38a60fc2d628ec3231b8a70 [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;
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
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000492 rtc::scoped_ptr<WavWriter> output_wav_file;
493 rtc::scoped_ptr<RawFile> output_raw_file;
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000494
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();
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000535 rtc::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;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000577 rtc::scoped_ptr<ChannelBuffer<float> > reverse_cb;
578 rtc::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) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000657 memcpy(reverse_cb->channels()[i],
658 msg.channel(i).data(),
659 reverse_cb->num_frames() *
660 sizeof(reverse_cb->channels()[i][0]));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000661 }
662 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000663
664 if (perf_testing) {
665 t0 = TickTime::Now();
666 }
667
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000668 if (msg.has_data()) {
669 ASSERT_EQ(apm->kNoError,
670 apm->AnalyzeReverseStream(&far_frame));
671 } else {
672 ASSERT_EQ(apm->kNoError,
673 apm->AnalyzeReverseStream(
674 reverse_cb->channels(),
675 far_frame.samples_per_channel_,
676 far_frame.sample_rate_hz_,
677 LayoutFromChannels(far_frame.num_channels_)));
678 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000679
680 if (perf_testing) {
681 t1 = TickTime::Now();
682 TickInterval tick_diff = t1 - t0;
683 acc_ticks += tick_diff;
684 if (tick_diff.Microseconds() > max_time_reverse_us) {
685 max_time_reverse_us = tick_diff.Microseconds();
686 }
687 if (tick_diff.Microseconds() < min_time_reverse_us) {
688 min_time_reverse_us = tick_diff.Microseconds();
689 }
690 }
691
692 } else if (event_msg.type() == Event::STREAM) {
693 ASSERT_TRUE(event_msg.has_stream());
694 const Stream msg = event_msg.stream();
695 primary_count++;
696
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000697 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000698 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000699
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000700 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
701 if (msg.has_input_data()) {
702 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
703 near_frame.num_channels_, msg.input_data().size());
704 memcpy(near_frame.data_,
705 msg.input_data().data(),
706 msg.input_data().size());
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000707 near_read_bytes += msg.input_data().size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000708 } else {
709 for (int i = 0; i < msg.input_channel_size(); ++i) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000710 memcpy(primary_cb->channels()[i],
711 msg.input_channel(i).data(),
712 primary_cb->num_frames() *
713 sizeof(primary_cb->channels()[i][0]));
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000714 near_read_bytes += msg.input_channel(i).size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000715 }
716 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000717
ajm@google.com808e0e02011-08-03 21:08:51 +0000718 if (progress && primary_count % 100 == 0) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000719 near_read_bytes = std::min(near_read_bytes, near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000720 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000721 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000722 fflush(stdout);
723 }
724
725 if (perf_testing) {
726 t0 = TickTime::Now();
727 }
728
729 ASSERT_EQ(apm->kNoError,
730 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000731 delay_ms = msg.delay() + extra_delay_ms;
732 if (override_delay_ms) {
733 delay_ms = override_delay_ms;
734 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000735 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000736 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000737 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000738
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000739 if (msg.has_keypress()) {
740 apm->set_stream_key_pressed(msg.keypress());
741 } else {
742 apm->set_stream_key_pressed(true);
743 }
744
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000745 int err = apm->kNoError;
746 if (msg.has_input_data()) {
747 err = apm->ProcessStream(&near_frame);
748 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
749 } else {
750 err = apm->ProcessStream(
751 primary_cb->channels(),
752 near_frame.samples_per_channel_,
753 near_frame.sample_rate_hz_,
754 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000755 output_sample_rate,
756 output_layout,
757 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000758 }
759
ajm@google.com808e0e02011-08-03 21:08:51 +0000760 if (err == apm->kBadStreamParameterWarning) {
761 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
762 }
763 ASSERT_TRUE(err == apm->kNoError ||
764 err == apm->kBadStreamParameterWarning);
765
ajm@google.com808e0e02011-08-03 21:08:51 +0000766 stream_has_voice =
767 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
768 if (vad_out_file != NULL) {
769 ASSERT_EQ(1u, fwrite(&stream_has_voice,
770 sizeof(stream_has_voice),
771 1,
772 vad_out_file));
773 }
774
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000775 if (ns_prob_file != NULL) {
776 ns_speech_prob = apm->noise_suppression()->speech_probability();
777 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
778 sizeof(ns_speech_prob),
779 1,
780 ns_prob_file));
781 }
782
ajm@google.com808e0e02011-08-03 21:08:51 +0000783 if (perf_testing) {
784 t1 = TickTime::Now();
785 TickInterval tick_diff = t1 - t0;
786 acc_ticks += tick_diff;
787 if (tick_diff.Microseconds() > max_time_us) {
788 max_time_us = tick_diff.Microseconds();
789 }
790 if (tick_diff.Microseconds() < min_time_us) {
791 min_time_us = tick_diff.Microseconds();
792 }
793 }
794
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000795 const size_t samples_per_channel = output_sample_rate / 100;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000796 if (msg.has_input_data()) {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000797 if (raw_output && !output_raw_file) {
798 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
799 }
800 WriteIntData(near_frame.data_,
801 apm->num_output_channels() * samples_per_channel,
802 output_wav_file.get(),
803 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000804 } else {
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000805 if (raw_output && !output_raw_file) {
806 output_raw_file.reset(new RawFile(out_filename + ".float"));
807 }
808 WriteFloatData(primary_cb->channels(),
809 samples_per_channel,
810 apm->num_output_channels(),
811 output_wav_file.get(),
812 output_raw_file.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000813 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000814 }
815 }
816
817 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000818
819 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000820 enum Events {
821 kInitializeEvent,
822 kRenderEvent,
823 kCaptureEvent,
824 kResetEventDeprecated
825 };
826 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000827 while (simulating || feof(event_file) == 0) {
828 std::ostringstream trace_stream;
829 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
830 << primary_count << " (primary)";
831 SCOPED_TRACE(trace_stream.str());
832
833 if (simulating) {
834 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000835 event = kCaptureEvent;
836 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000837 if (event == kRenderEvent) {
838 event = kCaptureEvent;
839 } else {
840 event = kRenderEvent;
841 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000842 }
843 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000844 read_count = fread(&event, sizeof(event), 1, event_file);
845 if (read_count != 1) {
846 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000847 }
848 }
849
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000850 far_frame.sample_rate_hz_ = sample_rate_hz;
851 far_frame.samples_per_channel_ = samples_per_channel;
852 far_frame.num_channels_ = num_render_channels;
853 near_frame.sample_rate_hz_ = sample_rate_hz;
854 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000855
ajm@google.com808e0e02011-08-03 21:08:51 +0000856 if (event == kInitializeEvent || event == kResetEventDeprecated) {
857 ASSERT_EQ(1u,
858 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
859 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000860
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000861 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000862 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000863 fread(&unused_device_sample_rate_hz,
864 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000865 1,
866 event_file));
867
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000868 ASSERT_EQ(kNoErr, apm->Initialize(
869 sample_rate_hz,
870 sample_rate_hz,
871 sample_rate_hz,
872 LayoutFromChannels(num_capture_input_channels),
873 LayoutFromChannels(num_capture_output_channels),
874 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000875
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000876 far_frame.sample_rate_hz_ = sample_rate_hz;
877 far_frame.samples_per_channel_ = samples_per_channel;
878 far_frame.num_channels_ = num_render_channels;
879 near_frame.sample_rate_hz_ = sample_rate_hz;
880 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000881
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000882 if (!raw_output) {
bjornv@webrtc.org634c9262014-09-24 12:21:51 +0000883 // The WAV file needs to be reset every time, because it can't change
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000884 // it's sample rate or number of channels.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000885 output_wav_file.reset(new WavWriter(out_filename + ".wav",
886 sample_rate_hz,
887 num_capture_output_channels));
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +0000888 }
889
ajm@google.com808e0e02011-08-03 21:08:51 +0000890 if (verbose) {
891 printf("Init at frame: %d (primary), %d (reverse)\n",
892 primary_count, reverse_count);
893 printf(" Sample rate: %d Hz\n", sample_rate_hz);
894 }
895
896 } else if (event == kRenderEvent) {
897 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000898
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000899 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000900 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000901 sizeof(int16_t),
902 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000903 far_file);
904
905 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000906 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000907 // Read an equal amount from the near file to avoid errors due to
908 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000909 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000910 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000911 break; // This is expected.
912 }
913 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000914 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000915 }
916
917 if (perf_testing) {
918 t0 = TickTime::Now();
919 }
920
921 ASSERT_EQ(apm->kNoError,
922 apm->AnalyzeReverseStream(&far_frame));
923
924 if (perf_testing) {
925 t1 = TickTime::Now();
926 TickInterval tick_diff = t1 - t0;
927 acc_ticks += tick_diff;
928 if (tick_diff.Microseconds() > max_time_reverse_us) {
929 max_time_reverse_us = tick_diff.Microseconds();
930 }
931 if (tick_diff.Microseconds() < min_time_reverse_us) {
932 min_time_reverse_us = tick_diff.Microseconds();
933 }
934 }
935
936 } else if (event == kCaptureEvent) {
937 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000938 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000939
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000940 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000941 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000942 sizeof(int16_t),
943 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000944 near_file);
945
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000946 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000947 if (progress && primary_count % 100 == 0) {
948 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000949 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000950 fflush(stdout);
951 }
952 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000953 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000954 break; // This is expected.
955 }
956
957 delay_ms = 0;
958 drift_samples = 0;
959 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000960 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000961
962 // TODO(ajm): sizeof(delay_ms) for current files?
963 ASSERT_EQ(1u,
964 fread(&delay_ms, 2, 1, delay_file));
965 ASSERT_EQ(1u,
966 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
967 }
968
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000969 if (apm->gain_control()->is_enabled() &&
970 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000971 SimulateMic(capture_level, &near_frame);
972 }
973
ajm@google.com808e0e02011-08-03 21:08:51 +0000974 if (perf_testing) {
975 t0 = TickTime::Now();
976 }
977
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000978 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000979 ASSERT_EQ(apm->kNoError,
980 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000981 delay_ms += extra_delay_ms;
982 if (override_delay_ms) {
983 delay_ms = override_delay_ms;
984 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000985 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000986 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000987 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000988
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000989 apm->set_stream_key_pressed(true);
990
ajm@google.com808e0e02011-08-03 21:08:51 +0000991 int err = apm->ProcessStream(&near_frame);
992 if (err == apm->kBadStreamParameterWarning) {
993 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
994 }
995 ASSERT_TRUE(err == apm->kNoError ||
996 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000997 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000998
999 capture_level = apm->gain_control()->stream_analog_level();
1000
1001 stream_has_voice =
1002 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
1003 if (vad_out_file != NULL) {
1004 ASSERT_EQ(1u, fwrite(&stream_has_voice,
1005 sizeof(stream_has_voice),
1006 1,
1007 vad_out_file));
1008 }
1009
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001010 if (ns_prob_file != NULL) {
1011 ns_speech_prob = apm->noise_suppression()->speech_probability();
1012 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
1013 sizeof(ns_speech_prob),
1014 1,
1015 ns_prob_file));
1016 }
1017
ajm@google.com808e0e02011-08-03 21:08:51 +00001018 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
1019 ASSERT_EQ(capture_level_in, capture_level);
1020 }
1021
1022 if (perf_testing) {
1023 t1 = TickTime::Now();
1024 TickInterval tick_diff = t1 - t0;
1025 acc_ticks += tick_diff;
1026 if (tick_diff.Microseconds() > max_time_us) {
1027 max_time_us = tick_diff.Microseconds();
1028 }
1029 if (tick_diff.Microseconds() < min_time_us) {
1030 min_time_us = tick_diff.Microseconds();
1031 }
1032 }
1033
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001034 if (raw_output && !output_raw_file) {
1035 output_raw_file.reset(new RawFile(out_filename + ".pcm"));
1036 }
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001037 if (!raw_output && !output_wav_file) {
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +00001038 output_wav_file.reset(new WavWriter(out_filename + ".wav",
1039 sample_rate_hz,
1040 num_capture_output_channels));
bjornv@webrtc.org634c9262014-09-24 12:21:51 +00001041 }
aluebs@webrtc.org021e76f2014-09-04 18:12:00 +00001042 WriteIntData(near_frame.data_,
1043 size,
1044 output_wav_file.get(),
1045 output_raw_file.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001046 }
ajm@google.com808e0e02011-08-03 21:08:51 +00001047 else {
1048 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 }
1051 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001052 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001053
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001054 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001055 const size_t path_size =
1056 apm->echo_control_mobile()->echo_path_size_bytes();
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00001057 rtc::scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001058 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1059 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1060 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001061 path_size,
1062 aecm_echo_path_out_file));
1063 fclose(aecm_echo_path_out_file);
1064 aecm_echo_path_out_file = NULL;
1065 }
1066
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 if (verbose) {
1068 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1069 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001070
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001071 if (apm->level_estimator()->is_enabled()) {
1072 printf("\n--Level metrics--\n");
1073 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1074 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001075 if (apm->echo_cancellation()->are_metrics_enabled()) {
1076 EchoCancellation::Metrics metrics;
1077 apm->echo_cancellation()->GetMetrics(&metrics);
1078 printf("\n--Echo metrics--\n");
1079 printf("(avg, max, min)\n");
1080 printf("ERL: ");
1081 PrintStat(metrics.echo_return_loss);
1082 printf("ERLE: ");
1083 PrintStat(metrics.echo_return_loss_enhancement);
1084 printf("ANLP: ");
1085 PrintStat(metrics.a_nlp);
1086 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001087 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1088 int median = 0;
1089 int std = 0;
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001090 float fraction_poor_delays = 0;
1091 apm->echo_cancellation()->GetDelayMetrics(&median, &std,
1092 &fraction_poor_delays);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001093 printf("\n--Delay metrics--\n");
1094 printf("Median: %3d\n", median);
1095 printf("Standard deviation: %3d\n", std);
bjornv@webrtc.orgb1786db2015-02-03 06:06:26 +00001096 printf("Poor delay values: %3.1f%%\n", fraction_poor_delays * 100);
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001097 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001098 }
1099
ajm@google.com808e0e02011-08-03 21:08:51 +00001100 if (!pb_file) {
1101 int8_t temp_int8;
1102 if (far_file) {
1103 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1104 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1105 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001106
ajm@google.com808e0e02011-08-03 21:08:51 +00001107 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1108 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1109
1110 if (!simulating) {
1111 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1112 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1113 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1114 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1115 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1116 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1117 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001118 }
1119
1120 if (perf_testing) {
1121 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001122 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001123 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1124 exec_time * 0.001, primary_count * 0.01);
1125 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1126 " %.3f ms (min)\n",
1127 (exec_time * 1.0) / primary_count,
1128 (max_time_us + max_time_reverse_us) / 1000.0,
1129 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001130 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001131 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001132 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001133 } else {
1134 printf("Warning: no capture frames\n");
1135 }
1136 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001137}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001138
ajm@google.com808e0e02011-08-03 21:08:51 +00001139} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001140} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001141
1142int main(int argc, char* argv[])
1143{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001144 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001145
andrew@webrtc.org64235092011-08-19 21:22:08 +00001146 // Optional, but removes memory leak noise from Valgrind.
1147 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001148 return 0;
1149}