blob: 05f4b77b6cdad70af9bd3f2100b8c24946af66d2 [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"
62 "without extension to support both int and float 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");
115 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000118static float MicLevel2Gain(int level) {
119 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000120}
121
122static void SimulateMic(int mic_level, AudioFrame* frame) {
123 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000124 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000125 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000126 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000127 for (int n = 0; n < num_samples; n++) {
128 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000129 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000130 frame->data_[n] = static_cast<int16_t>(v);
131 }
132}
133
niklase@google.com470e71d2011-07-07 08:21:25 +0000134// void function for gtest.
135void void_main(int argc, char* argv[]) {
136 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
137 usage();
138 return;
139 }
140
141 if (argc < 2) {
142 printf("Did you mean to run without arguments?\n");
143 printf("Try `process_test --help' for more information.\n\n");
144 }
145
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000146 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create());
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000147 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
ajm@google.com808e0e02011-08-03 21:08:51 +0000149 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 const char* far_filename = NULL;
151 const char* near_filename = NULL;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000152 std::string out_filename;
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000154 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000155 const char* aecm_echo_path_in_filename = NULL;
156 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157
158 int32_t sample_rate_hz = 16000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000159
160 int num_capture_input_channels = 1;
161 int num_capture_output_channels = 1;
162 int num_render_channels = 1;
163
164 int samples_per_channel = sample_rate_hz / 100;
165
166 bool simulating = false;
167 bool perf_testing = false;
168 bool verbose = true;
169 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000170 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000171 int override_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000172
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000173 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000175 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000176 i++;
177 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
178 pb_filename = argv[i];
179
180 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000181 i++;
182 ASSERT_LT(i, argc) << "Specify filename after -ir";
183 far_filename = argv[i];
184 simulating = true;
185
186 } else if (strcmp(argv[i], "-i") == 0) {
187 i++;
188 ASSERT_LT(i, argc) << "Specify filename after -i";
189 near_filename = argv[i];
190 simulating = true;
191
192 } else if (strcmp(argv[i], "-o") == 0) {
193 i++;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000194 ASSERT_LT(i, argc) << "Specify filename without extension after -o";
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 out_filename = argv[i];
196
197 } else if (strcmp(argv[i], "-fs") == 0) {
198 i++;
199 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
200 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
201 samples_per_channel = sample_rate_hz / 100;
202
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 } else if (strcmp(argv[i], "-ch") == 0) {
204 i++;
205 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
206 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
207 i++;
208 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
209
niklase@google.com470e71d2011-07-07 08:21:25 +0000210 } else if (strcmp(argv[i], "-rch") == 0) {
211 i++;
212 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
213 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
214
niklase@google.com470e71d2011-07-07 08:21:25 +0000215 } else if (strcmp(argv[i], "-aec") == 0) {
216 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000217 ASSERT_EQ(apm->kNoError,
218 apm->echo_cancellation()->enable_metrics(true));
219 ASSERT_EQ(apm->kNoError,
220 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000221
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
223 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
224 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
225 // why it can give better performance despite passing zeros.
226 ASSERT_EQ(apm->kNoError,
227 apm->echo_cancellation()->enable_drift_compensation(true));
228 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
229 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
230 ASSERT_EQ(apm->kNoError,
231 apm->echo_cancellation()->enable_drift_compensation(false));
232
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000233 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
234 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
235 ASSERT_EQ(apm->kNoError,
236 apm->echo_cancellation()->enable_metrics(false));
237
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000238 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
239 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
240 ASSERT_EQ(apm->kNoError,
241 apm->echo_cancellation()->enable_delay_logging(false));
242
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000243 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
244 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
245
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000246 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
247 i++;
248 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
249 int suppression_level;
250 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
251 ASSERT_EQ(apm->kNoError,
252 apm->echo_cancellation()->set_suppression_level(
253 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
254 suppression_level)));
255
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000256 } else if (strcmp(argv[i], "--extended_filter") == 0) {
257 Config config;
258 config.Set<DelayCorrection>(new DelayCorrection(true));
259 apm->SetExtraOptions(config);
260
bjornv@webrtc.org84f8ec12014-06-19 12:14:33 +0000261 } else if (strcmp(argv[i], "--no_reported_delay") == 0) {
262 Config config;
263 config.Set<ReportedDelay>(new ReportedDelay(false));
264 apm->SetExtraOptions(config);
265
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 } else if (strcmp(argv[i], "-aecm") == 0) {
267 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
268
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000269 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
270 i++;
271 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
272 aecm_echo_path_in_filename = argv[i];
273
274 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
275 i++;
276 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
277 aecm_echo_path_out_filename = argv[i];
278
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000279 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
280 ASSERT_EQ(apm->kNoError,
281 apm->echo_control_mobile()->enable_comfort_noise(false));
282
283 } else if (strcmp(argv[i], "--routing_mode") == 0) {
284 i++;
285 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
286 int routing_mode;
287 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
288 ASSERT_EQ(apm->kNoError,
289 apm->echo_control_mobile()->set_routing_mode(
290 static_cast<webrtc::EchoControlMobile::RoutingMode>(
291 routing_mode)));
292
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 } else if (strcmp(argv[i], "-agc") == 0) {
294 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
295
296 } else if (strcmp(argv[i], "--analog") == 0) {
297 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
298 ASSERT_EQ(apm->kNoError,
299 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
300
301 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
302 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
303 ASSERT_EQ(apm->kNoError,
304 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
305
306 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
307 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
308 ASSERT_EQ(apm->kNoError,
309 apm->gain_control()->set_mode(GainControl::kFixedDigital));
310
311 } else if (strcmp(argv[i], "--target_level") == 0) {
312 i++;
313 int level;
314 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
315
316 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
317 ASSERT_EQ(apm->kNoError,
318 apm->gain_control()->set_target_level_dbfs(level));
319
320 } else if (strcmp(argv[i], "--compression_gain") == 0) {
321 i++;
322 int gain;
323 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
324
325 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
326 ASSERT_EQ(apm->kNoError,
327 apm->gain_control()->set_compression_gain_db(gain));
328
329 } else if (strcmp(argv[i], "--limiter") == 0) {
330 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
331 ASSERT_EQ(apm->kNoError,
332 apm->gain_control()->enable_limiter(true));
333
334 } else if (strcmp(argv[i], "--no_limiter") == 0) {
335 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
336 ASSERT_EQ(apm->kNoError,
337 apm->gain_control()->enable_limiter(false));
338
339 } else if (strcmp(argv[i], "-hpf") == 0) {
340 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
341
342 } else if (strcmp(argv[i], "-ns") == 0) {
343 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
344
345 } else if (strcmp(argv[i], "--ns_low") == 0) {
346 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
347 ASSERT_EQ(apm->kNoError,
348 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
349
350 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
351 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
352 ASSERT_EQ(apm->kNoError,
353 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
354
355 } else if (strcmp(argv[i], "--ns_high") == 0) {
356 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
357 ASSERT_EQ(apm->kNoError,
358 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
359
360 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
361 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
362 ASSERT_EQ(apm->kNoError,
363 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
364
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000365 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
366 i++;
367 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
368 ns_prob_filename = argv[i];
369
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 } else if (strcmp(argv[i], "-vad") == 0) {
371 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
372
andrew@webrtc.org89752612012-10-12 16:41:45 +0000373 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
374 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
375 ASSERT_EQ(apm->kNoError,
376 apm->voice_detection()->set_likelihood(
377 VoiceDetection::kVeryLowLikelihood));
378
379 } else if (strcmp(argv[i], "--vad_low") == 0) {
380 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
381 ASSERT_EQ(apm->kNoError,
382 apm->voice_detection()->set_likelihood(
383 VoiceDetection::kLowLikelihood));
384
385 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
386 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
387 ASSERT_EQ(apm->kNoError,
388 apm->voice_detection()->set_likelihood(
389 VoiceDetection::kModerateLikelihood));
390
391 } else if (strcmp(argv[i], "--vad_high") == 0) {
392 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
393 ASSERT_EQ(apm->kNoError,
394 apm->voice_detection()->set_likelihood(
395 VoiceDetection::kHighLikelihood));
396
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
398 i++;
399 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
400 vad_out_filename = argv[i];
401
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000402 } else if (strcmp(argv[i], "-expns") == 0) {
aluebs@webrtc.org9825afc2014-06-30 17:39:53 +0000403 Config config;
404 config.Set<ExperimentalNs>(new ExperimentalNs(true));
405 apm->SetExtraOptions(config);
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000406
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000407 } else if (strcmp(argv[i], "--noasm") == 0) {
408 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
409 // We need to reinitialize here if components have already been enabled.
410 ASSERT_EQ(apm->kNoError, apm->Initialize());
411
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000412 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000413 i++;
414 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
415
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000416 } else if (strcmp(argv[i], "--delay") == 0) {
417 i++;
418 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
419
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 } else if (strcmp(argv[i], "--perf") == 0) {
421 perf_testing = true;
422
423 } else if (strcmp(argv[i], "--quiet") == 0) {
424 verbose = false;
425 progress = false;
426
427 } else if (strcmp(argv[i], "--no_progress") == 0) {
428 progress = false;
429
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000430 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000431 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000432 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000433 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 } else {
435 FAIL() << "Unrecognized argument " << argv[i];
436 }
437 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000438 // If we're reading a protobuf file, ensure a simulation hasn't also
439 // been requested (which makes no sense...)
440 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000441
442 if (verbose) {
443 printf("Sample rate: %d Hz\n", sample_rate_hz);
444 printf("Primary channels: %d (in), %d (out)\n",
445 num_capture_input_channels,
446 num_capture_output_channels);
447 printf("Reverse channels: %d \n", num_render_channels);
448 }
449
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000450 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 const char far_file_default[] = "apm_far.pcm";
452 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000453 const char event_filename[] = "apm_event.dat";
454 const char delay_filename[] = "apm_delay.dat";
455 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000456 const std::string vad_file_default = out_path + "vad_out.dat";
457 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000458
459 if (!simulating) {
460 far_filename = far_file_default;
461 near_filename = near_file_default;
462 }
463
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000464 if (out_filename.size() == 0) {
465 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000466 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000467 std::string out_float_filename = out_filename + ".float";
468 out_filename += ".pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000469
ajm@google.com808e0e02011-08-03 21:08:51 +0000470 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000471 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 }
473
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000474 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000475 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000476 }
477
ajm@google.com808e0e02011-08-03 21:08:51 +0000478 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 FILE* far_file = NULL;
480 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000481 FILE* event_file = NULL;
482 FILE* delay_file = NULL;
483 FILE* drift_file = NULL;
484 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000485 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000486 FILE* aecm_echo_path_in_file = NULL;
487 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000488
ajm@google.com808e0e02011-08-03 21:08:51 +0000489 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000490 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000491 } else {
492 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000493 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000494 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000495
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000496 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000497 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000498 event_file = OpenFile(event_filename, "rb");
499 delay_file = OpenFile(delay_filename, "rb");
500 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000501 }
502 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000503
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000504 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000505 if (pb_file) {
506 struct stat st;
507 stat(pb_filename, &st);
508 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000509 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000510 } else {
511 struct stat st;
512 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000513 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000514 }
515
516 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000517 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 }
519
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000520 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000521 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000522 }
523
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000524 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000525 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000526
ajm@google.com22e65152011-07-18 18:03:01 +0000527 const size_t path_size =
528 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +0000529 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000530 ASSERT_EQ(path_size, fread(echo_path.get(),
531 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000532 path_size,
533 aecm_echo_path_in_file));
534 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000535 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
536 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000537 fclose(aecm_echo_path_in_file);
538 aecm_echo_path_in_file = NULL;
539 }
540
541 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000542 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000543 }
544
niklase@google.com470e71d2011-07-07 08:21:25 +0000545 size_t read_count = 0;
546 int reverse_count = 0;
547 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000548 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000549 TickInterval acc_ticks;
550
551 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000553
554 int delay_ms = 0;
555 int drift_samples = 0;
556 int capture_level = 127;
557 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000558 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559
560 TickTime t0 = TickTime::Now();
561 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000562 int64_t max_time_us = 0;
563 int64_t max_time_reverse_us = 0;
564 int64_t min_time_us = 1e6;
565 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000566
ajm@google.com808e0e02011-08-03 21:08:51 +0000567 // TODO(ajm): Ideally we would refactor this block into separate functions,
568 // but for now we want to share the variables.
569 if (pb_file) {
570 Event event_msg;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000571 scoped_ptr<ChannelBuffer<float> > reverse_cb;
572 scoped_ptr<ChannelBuffer<float> > primary_cb;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000573 int output_sample_rate = 32000;
574 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
ajm@google.com808e0e02011-08-03 21:08:51 +0000575 while (ReadMessageFromFile(pb_file, &event_msg)) {
576 std::ostringstream trace_stream;
577 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
578 << primary_count << " (primary)";
579 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000580
ajm@google.com808e0e02011-08-03 21:08:51 +0000581 if (event_msg.type() == Event::INIT) {
582 ASSERT_TRUE(event_msg.has_init());
583 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
ajm@google.com808e0e02011-08-03 21:08:51 +0000585 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000586 ASSERT_TRUE(msg.has_num_input_channels());
587 ASSERT_TRUE(msg.has_num_output_channels());
588 ASSERT_TRUE(msg.has_num_reverse_channels());
589 int reverse_sample_rate = msg.sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000590 if (msg.has_reverse_sample_rate()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000591 reverse_sample_rate = msg.reverse_sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000592 }
593 output_sample_rate = msg.sample_rate();
594 if (msg.has_output_sample_rate()) {
595 output_sample_rate = msg.output_sample_rate();
596 }
597 output_layout = LayoutFromChannels(msg.num_output_channels());
598 ASSERT_EQ(kNoErr, apm->Initialize(
599 msg.sample_rate(),
600 output_sample_rate,
601 reverse_sample_rate,
602 LayoutFromChannels(msg.num_input_channels()),
603 output_layout,
604 LayoutFromChannels(msg.num_reverse_channels())));
ajm@google.com808e0e02011-08-03 21:08:51 +0000605
606 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000607 far_frame.sample_rate_hz_ = msg.sample_rate();
608 far_frame.samples_per_channel_ = samples_per_channel;
609 far_frame.num_channels_ = msg.num_reverse_channels();
610 near_frame.sample_rate_hz_ = msg.sample_rate();
611 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000612 near_frame.num_channels_ = msg.num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000613 reverse_cb.reset(new ChannelBuffer<float>(samples_per_channel,
614 msg.num_reverse_channels()));
615 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
616 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000617
618 if (verbose) {
619 printf("Init at frame: %d (primary), %d (reverse)\n",
620 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000621 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
622 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000623 printf(" Primary channels: %d (in), %d (out)\n",
624 msg.num_input_channels(),
625 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000626 printf(" Reverse rate: %d\n", reverse_sample_rate);
627 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000628 }
629
630 } else if (event_msg.type() == Event::REVERSE_STREAM) {
631 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000632 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000633 reverse_count++;
634
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000635 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
636 if (msg.has_data()) {
637 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
638 far_frame.num_channels_, msg.data().size());
639 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
640 } else {
641 for (int i = 0; i < msg.channel_size(); ++i) {
642 reverse_cb->CopyFrom(msg.channel(i).data(), i);
643 }
644 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000645
646 if (perf_testing) {
647 t0 = TickTime::Now();
648 }
649
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000650 if (msg.has_data()) {
651 ASSERT_EQ(apm->kNoError,
652 apm->AnalyzeReverseStream(&far_frame));
653 } else {
654 ASSERT_EQ(apm->kNoError,
655 apm->AnalyzeReverseStream(
656 reverse_cb->channels(),
657 far_frame.samples_per_channel_,
658 far_frame.sample_rate_hz_,
659 LayoutFromChannels(far_frame.num_channels_)));
660 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000661
662 if (perf_testing) {
663 t1 = TickTime::Now();
664 TickInterval tick_diff = t1 - t0;
665 acc_ticks += tick_diff;
666 if (tick_diff.Microseconds() > max_time_reverse_us) {
667 max_time_reverse_us = tick_diff.Microseconds();
668 }
669 if (tick_diff.Microseconds() < min_time_reverse_us) {
670 min_time_reverse_us = tick_diff.Microseconds();
671 }
672 }
673
674 } else if (event_msg.type() == Event::STREAM) {
675 ASSERT_TRUE(event_msg.has_stream());
676 const Stream msg = event_msg.stream();
677 primary_count++;
678
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000679 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000680 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000681
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000682 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
683 if (msg.has_input_data()) {
684 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
685 near_frame.num_channels_, msg.input_data().size());
686 memcpy(near_frame.data_,
687 msg.input_data().data(),
688 msg.input_data().size());
689 } else {
690 for (int i = 0; i < msg.input_channel_size(); ++i) {
691 primary_cb->CopyFrom(msg.input_channel(i).data(), i);
692 }
693 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000694
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000695 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000696 if (progress && primary_count % 100 == 0) {
697 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000698 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000699 fflush(stdout);
700 }
701
702 if (perf_testing) {
703 t0 = TickTime::Now();
704 }
705
706 ASSERT_EQ(apm->kNoError,
707 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000708 delay_ms = msg.delay() + extra_delay_ms;
709 if (override_delay_ms) {
710 delay_ms = override_delay_ms;
711 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000712 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000713 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000714 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000715
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000716 if (msg.has_keypress()) {
717 apm->set_stream_key_pressed(msg.keypress());
718 } else {
719 apm->set_stream_key_pressed(true);
720 }
721
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000722 int err = apm->kNoError;
723 if (msg.has_input_data()) {
724 err = apm->ProcessStream(&near_frame);
725 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
726 } else {
727 err = apm->ProcessStream(
728 primary_cb->channels(),
729 near_frame.samples_per_channel_,
730 near_frame.sample_rate_hz_,
731 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000732 output_sample_rate,
733 output_layout,
734 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000735 }
736
ajm@google.com808e0e02011-08-03 21:08:51 +0000737 if (err == apm->kBadStreamParameterWarning) {
738 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
739 }
740 ASSERT_TRUE(err == apm->kNoError ||
741 err == apm->kBadStreamParameterWarning);
742
ajm@google.com808e0e02011-08-03 21:08:51 +0000743 stream_has_voice =
744 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
745 if (vad_out_file != NULL) {
746 ASSERT_EQ(1u, fwrite(&stream_has_voice,
747 sizeof(stream_has_voice),
748 1,
749 vad_out_file));
750 }
751
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000752 if (ns_prob_file != NULL) {
753 ns_speech_prob = apm->noise_suppression()->speech_probability();
754 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
755 sizeof(ns_speech_prob),
756 1,
757 ns_prob_file));
758 }
759
ajm@google.com808e0e02011-08-03 21:08:51 +0000760 if (perf_testing) {
761 t1 = TickTime::Now();
762 TickInterval tick_diff = t1 - t0;
763 acc_ticks += tick_diff;
764 if (tick_diff.Microseconds() > max_time_us) {
765 max_time_us = tick_diff.Microseconds();
766 }
767 if (tick_diff.Microseconds() < min_time_us) {
768 min_time_us = tick_diff.Microseconds();
769 }
770 }
771
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000772 size_t num_samples = samples_per_channel * apm->num_output_channels();
773 if (msg.has_input_data()) {
774 static FILE* out_file = OpenFile(out_filename, "wb");
775 ASSERT_EQ(num_samples, fwrite(near_frame.data_,
776 sizeof(*near_frame.data_),
777 num_samples,
778 out_file));
779 } else {
780 static FILE* out_float_file = OpenFile(out_float_filename, "wb");
781 ASSERT_EQ(num_samples, fwrite(primary_cb->data(),
782 sizeof(*primary_cb->data()),
783 num_samples,
784 out_float_file));
785 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000786 }
787 }
788
789 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000790
791 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000792 enum Events {
793 kInitializeEvent,
794 kRenderEvent,
795 kCaptureEvent,
796 kResetEventDeprecated
797 };
798 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000799 while (simulating || feof(event_file) == 0) {
800 std::ostringstream trace_stream;
801 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
802 << primary_count << " (primary)";
803 SCOPED_TRACE(trace_stream.str());
804
805 if (simulating) {
806 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 event = kCaptureEvent;
808 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000809 if (event == kRenderEvent) {
810 event = kCaptureEvent;
811 } else {
812 event = kRenderEvent;
813 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000814 }
815 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000816 read_count = fread(&event, sizeof(event), 1, event_file);
817 if (read_count != 1) {
818 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000819 }
820 }
821
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000822 far_frame.sample_rate_hz_ = sample_rate_hz;
823 far_frame.samples_per_channel_ = samples_per_channel;
824 far_frame.num_channels_ = num_render_channels;
825 near_frame.sample_rate_hz_ = sample_rate_hz;
826 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000827
ajm@google.com808e0e02011-08-03 21:08:51 +0000828 if (event == kInitializeEvent || event == kResetEventDeprecated) {
829 ASSERT_EQ(1u,
830 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
831 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000832
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000833 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000834 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000835 fread(&unused_device_sample_rate_hz,
836 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000837 1,
838 event_file));
839
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000840 ASSERT_EQ(kNoErr, apm->Initialize(
841 sample_rate_hz,
842 sample_rate_hz,
843 sample_rate_hz,
844 LayoutFromChannels(num_capture_input_channels),
845 LayoutFromChannels(num_capture_output_channels),
846 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000847
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000848 far_frame.sample_rate_hz_ = sample_rate_hz;
849 far_frame.samples_per_channel_ = samples_per_channel;
850 far_frame.num_channels_ = num_render_channels;
851 near_frame.sample_rate_hz_ = sample_rate_hz;
852 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000853
854 if (verbose) {
855 printf("Init at frame: %d (primary), %d (reverse)\n",
856 primary_count, reverse_count);
857 printf(" Sample rate: %d Hz\n", sample_rate_hz);
858 }
859
860 } else if (event == kRenderEvent) {
861 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000862
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000863 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000864 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000865 sizeof(int16_t),
866 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000867 far_file);
868
869 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000870 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000871 // Read an equal amount from the near file to avoid errors due to
872 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000873 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000874 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000875 break; // This is expected.
876 }
877 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000878 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000879 }
880
881 if (perf_testing) {
882 t0 = TickTime::Now();
883 }
884
885 ASSERT_EQ(apm->kNoError,
886 apm->AnalyzeReverseStream(&far_frame));
887
888 if (perf_testing) {
889 t1 = TickTime::Now();
890 TickInterval tick_diff = t1 - t0;
891 acc_ticks += tick_diff;
892 if (tick_diff.Microseconds() > max_time_reverse_us) {
893 max_time_reverse_us = tick_diff.Microseconds();
894 }
895 if (tick_diff.Microseconds() < min_time_reverse_us) {
896 min_time_reverse_us = tick_diff.Microseconds();
897 }
898 }
899
900 } else if (event == kCaptureEvent) {
901 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000902 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000903
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000904 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000905 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000906 sizeof(int16_t),
907 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000908 near_file);
909
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000910 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000911 if (progress && primary_count % 100 == 0) {
912 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000913 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000914 fflush(stdout);
915 }
916 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000917 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000918 break; // This is expected.
919 }
920
921 delay_ms = 0;
922 drift_samples = 0;
923 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000924 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000925
926 // TODO(ajm): sizeof(delay_ms) for current files?
927 ASSERT_EQ(1u,
928 fread(&delay_ms, 2, 1, delay_file));
929 ASSERT_EQ(1u,
930 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
931 }
932
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000933 if (apm->gain_control()->is_enabled() &&
934 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000935 SimulateMic(capture_level, &near_frame);
936 }
937
ajm@google.com808e0e02011-08-03 21:08:51 +0000938 if (perf_testing) {
939 t0 = TickTime::Now();
940 }
941
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000942 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000943 ASSERT_EQ(apm->kNoError,
944 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000945 delay_ms += extra_delay_ms;
946 if (override_delay_ms) {
947 delay_ms = override_delay_ms;
948 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000949 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000950 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000951 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000952
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000953 apm->set_stream_key_pressed(true);
954
ajm@google.com808e0e02011-08-03 21:08:51 +0000955 int err = apm->ProcessStream(&near_frame);
956 if (err == apm->kBadStreamParameterWarning) {
957 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
958 }
959 ASSERT_TRUE(err == apm->kNoError ||
960 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000961 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000962
963 capture_level = apm->gain_control()->stream_analog_level();
964
965 stream_has_voice =
966 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
967 if (vad_out_file != NULL) {
968 ASSERT_EQ(1u, fwrite(&stream_has_voice,
969 sizeof(stream_has_voice),
970 1,
971 vad_out_file));
972 }
973
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000974 if (ns_prob_file != NULL) {
975 ns_speech_prob = apm->noise_suppression()->speech_probability();
976 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
977 sizeof(ns_speech_prob),
978 1,
979 ns_prob_file));
980 }
981
ajm@google.com808e0e02011-08-03 21:08:51 +0000982 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
983 ASSERT_EQ(capture_level_in, capture_level);
984 }
985
986 if (perf_testing) {
987 t1 = TickTime::Now();
988 TickInterval tick_diff = t1 - t0;
989 acc_ticks += tick_diff;
990 if (tick_diff.Microseconds() > max_time_us) {
991 max_time_us = tick_diff.Microseconds();
992 }
993 if (tick_diff.Microseconds() < min_time_us) {
994 min_time_us = tick_diff.Microseconds();
995 }
996 }
997
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000998 size = samples_per_channel * near_frame.num_channels_;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000999 static FILE* out_file = OpenFile(out_filename, "wb");
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001000 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001001 sizeof(int16_t),
1002 size,
1003 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 }
ajm@google.com808e0e02011-08-03 21:08:51 +00001005 else {
1006 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 }
1009 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001010 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001011
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001012 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001013 const size_t path_size =
1014 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +00001015 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001016 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1017 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1018 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001019 path_size,
1020 aecm_echo_path_out_file));
1021 fclose(aecm_echo_path_out_file);
1022 aecm_echo_path_out_file = NULL;
1023 }
1024
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 if (verbose) {
1026 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1027 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001028
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001029 if (apm->level_estimator()->is_enabled()) {
1030 printf("\n--Level metrics--\n");
1031 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1032 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001033 if (apm->echo_cancellation()->are_metrics_enabled()) {
1034 EchoCancellation::Metrics metrics;
1035 apm->echo_cancellation()->GetMetrics(&metrics);
1036 printf("\n--Echo metrics--\n");
1037 printf("(avg, max, min)\n");
1038 printf("ERL: ");
1039 PrintStat(metrics.echo_return_loss);
1040 printf("ERLE: ");
1041 PrintStat(metrics.echo_return_loss_enhancement);
1042 printf("ANLP: ");
1043 PrintStat(metrics.a_nlp);
1044 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001045 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1046 int median = 0;
1047 int std = 0;
1048 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1049 printf("\n--Delay metrics--\n");
1050 printf("Median: %3d\n", median);
1051 printf("Standard deviation: %3d\n", std);
1052 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 }
1054
ajm@google.com808e0e02011-08-03 21:08:51 +00001055 if (!pb_file) {
1056 int8_t temp_int8;
1057 if (far_file) {
1058 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1059 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1060 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001061
ajm@google.com808e0e02011-08-03 21:08:51 +00001062 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1063 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1064
1065 if (!simulating) {
1066 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1067 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1068 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1069 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1070 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1071 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1072 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 }
1074
1075 if (perf_testing) {
1076 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001077 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001078 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1079 exec_time * 0.001, primary_count * 0.01);
1080 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1081 " %.3f ms (min)\n",
1082 (exec_time * 1.0) / primary_count,
1083 (max_time_us + max_time_reverse_us) / 1000.0,
1084 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001085 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001086 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001087 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 } else {
1089 printf("Warning: no capture frames\n");
1090 }
1091 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001092}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001093
ajm@google.com808e0e02011-08-03 21:08:51 +00001094} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001095} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001096
1097int main(int argc, char* argv[])
1098{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001099 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001100
andrew@webrtc.org64235092011-08-19 21:22:08 +00001101 // Optional, but removes memory leak noise from Valgrind.
1102 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 return 0;
1104}