blob: f0dc2cb6f9cb8eac7b337cbb46de1a736839f031 [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();
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000608 far_frame.samples_per_channel_ = reverse_sample_rate / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000609 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();
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000613 reverse_cb.reset(new ChannelBuffer<float>(
614 far_frame.samples_per_channel_,
615 msg.num_reverse_channels()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000616 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
617 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000618
619 if (verbose) {
620 printf("Init at frame: %d (primary), %d (reverse)\n",
621 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000622 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
623 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000624 printf(" Primary channels: %d (in), %d (out)\n",
625 msg.num_input_channels(),
626 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000627 printf(" Reverse rate: %d\n", reverse_sample_rate);
628 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000629 }
630
631 } else if (event_msg.type() == Event::REVERSE_STREAM) {
632 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000633 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000634 reverse_count++;
635
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000636 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
637 if (msg.has_data()) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000638 ASSERT_EQ(sizeof(int16_t) * far_frame.samples_per_channel_ *
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000639 far_frame.num_channels_, msg.data().size());
640 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
641 } else {
642 for (int i = 0; i < msg.channel_size(); ++i) {
643 reverse_cb->CopyFrom(msg.channel(i).data(), i);
644 }
645 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000646
647 if (perf_testing) {
648 t0 = TickTime::Now();
649 }
650
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000651 if (msg.has_data()) {
652 ASSERT_EQ(apm->kNoError,
653 apm->AnalyzeReverseStream(&far_frame));
654 } else {
655 ASSERT_EQ(apm->kNoError,
656 apm->AnalyzeReverseStream(
657 reverse_cb->channels(),
658 far_frame.samples_per_channel_,
659 far_frame.sample_rate_hz_,
660 LayoutFromChannels(far_frame.num_channels_)));
661 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000662
663 if (perf_testing) {
664 t1 = TickTime::Now();
665 TickInterval tick_diff = t1 - t0;
666 acc_ticks += tick_diff;
667 if (tick_diff.Microseconds() > max_time_reverse_us) {
668 max_time_reverse_us = tick_diff.Microseconds();
669 }
670 if (tick_diff.Microseconds() < min_time_reverse_us) {
671 min_time_reverse_us = tick_diff.Microseconds();
672 }
673 }
674
675 } else if (event_msg.type() == Event::STREAM) {
676 ASSERT_TRUE(event_msg.has_stream());
677 const Stream msg = event_msg.stream();
678 primary_count++;
679
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000680 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000681 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000682
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000683 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
684 if (msg.has_input_data()) {
685 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
686 near_frame.num_channels_, msg.input_data().size());
687 memcpy(near_frame.data_,
688 msg.input_data().data(),
689 msg.input_data().size());
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000690 near_read_bytes += msg.input_data().size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000691 } else {
692 for (int i = 0; i < msg.input_channel_size(); ++i) {
693 primary_cb->CopyFrom(msg.input_channel(i).data(), i);
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000694 near_read_bytes += msg.input_channel(i).size();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000695 }
696 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000697
ajm@google.com808e0e02011-08-03 21:08:51 +0000698 if (progress && primary_count % 100 == 0) {
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000699 near_read_bytes = std::min(near_read_bytes, near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000700 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000701 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000702 fflush(stdout);
703 }
704
705 if (perf_testing) {
706 t0 = TickTime::Now();
707 }
708
709 ASSERT_EQ(apm->kNoError,
710 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000711 delay_ms = msg.delay() + extra_delay_ms;
712 if (override_delay_ms) {
713 delay_ms = override_delay_ms;
714 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000715 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000716 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000717 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000718
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000719 if (msg.has_keypress()) {
720 apm->set_stream_key_pressed(msg.keypress());
721 } else {
722 apm->set_stream_key_pressed(true);
723 }
724
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000725 int err = apm->kNoError;
726 if (msg.has_input_data()) {
727 err = apm->ProcessStream(&near_frame);
728 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
729 } else {
730 err = apm->ProcessStream(
731 primary_cb->channels(),
732 near_frame.samples_per_channel_,
733 near_frame.sample_rate_hz_,
734 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000735 output_sample_rate,
736 output_layout,
737 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000738 }
739
ajm@google.com808e0e02011-08-03 21:08:51 +0000740 if (err == apm->kBadStreamParameterWarning) {
741 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
742 }
743 ASSERT_TRUE(err == apm->kNoError ||
744 err == apm->kBadStreamParameterWarning);
745
ajm@google.com808e0e02011-08-03 21:08:51 +0000746 stream_has_voice =
747 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
748 if (vad_out_file != NULL) {
749 ASSERT_EQ(1u, fwrite(&stream_has_voice,
750 sizeof(stream_has_voice),
751 1,
752 vad_out_file));
753 }
754
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000755 if (ns_prob_file != NULL) {
756 ns_speech_prob = apm->noise_suppression()->speech_probability();
757 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
758 sizeof(ns_speech_prob),
759 1,
760 ns_prob_file));
761 }
762
ajm@google.com808e0e02011-08-03 21:08:51 +0000763 if (perf_testing) {
764 t1 = TickTime::Now();
765 TickInterval tick_diff = t1 - t0;
766 acc_ticks += tick_diff;
767 if (tick_diff.Microseconds() > max_time_us) {
768 max_time_us = tick_diff.Microseconds();
769 }
770 if (tick_diff.Microseconds() < min_time_us) {
771 min_time_us = tick_diff.Microseconds();
772 }
773 }
774
aluebs@webrtc.org74cf9162014-09-03 11:05:01 +0000775 size_t num_samples =
776 apm->num_output_channels() * output_sample_rate / 100;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000777 if (msg.has_input_data()) {
778 static FILE* out_file = OpenFile(out_filename, "wb");
779 ASSERT_EQ(num_samples, fwrite(near_frame.data_,
780 sizeof(*near_frame.data_),
781 num_samples,
782 out_file));
783 } else {
784 static FILE* out_float_file = OpenFile(out_float_filename, "wb");
785 ASSERT_EQ(num_samples, fwrite(primary_cb->data(),
786 sizeof(*primary_cb->data()),
787 num_samples,
788 out_float_file));
789 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000790 }
791 }
792
793 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000794
795 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000796 enum Events {
797 kInitializeEvent,
798 kRenderEvent,
799 kCaptureEvent,
800 kResetEventDeprecated
801 };
802 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000803 while (simulating || feof(event_file) == 0) {
804 std::ostringstream trace_stream;
805 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
806 << primary_count << " (primary)";
807 SCOPED_TRACE(trace_stream.str());
808
809 if (simulating) {
810 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000811 event = kCaptureEvent;
812 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000813 if (event == kRenderEvent) {
814 event = kCaptureEvent;
815 } else {
816 event = kRenderEvent;
817 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000818 }
819 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000820 read_count = fread(&event, sizeof(event), 1, event_file);
821 if (read_count != 1) {
822 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000823 }
824 }
825
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000826 far_frame.sample_rate_hz_ = sample_rate_hz;
827 far_frame.samples_per_channel_ = samples_per_channel;
828 far_frame.num_channels_ = num_render_channels;
829 near_frame.sample_rate_hz_ = sample_rate_hz;
830 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000831
ajm@google.com808e0e02011-08-03 21:08:51 +0000832 if (event == kInitializeEvent || event == kResetEventDeprecated) {
833 ASSERT_EQ(1u,
834 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
835 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000836
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000837 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000838 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000839 fread(&unused_device_sample_rate_hz,
840 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000841 1,
842 event_file));
843
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000844 ASSERT_EQ(kNoErr, apm->Initialize(
845 sample_rate_hz,
846 sample_rate_hz,
847 sample_rate_hz,
848 LayoutFromChannels(num_capture_input_channels),
849 LayoutFromChannels(num_capture_output_channels),
850 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000851
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000852 far_frame.sample_rate_hz_ = sample_rate_hz;
853 far_frame.samples_per_channel_ = samples_per_channel;
854 far_frame.num_channels_ = num_render_channels;
855 near_frame.sample_rate_hz_ = sample_rate_hz;
856 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000857
858 if (verbose) {
859 printf("Init at frame: %d (primary), %d (reverse)\n",
860 primary_count, reverse_count);
861 printf(" Sample rate: %d Hz\n", sample_rate_hz);
862 }
863
864 } else if (event == kRenderEvent) {
865 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000866
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000867 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000868 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000869 sizeof(int16_t),
870 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000871 far_file);
872
873 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000874 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000875 // Read an equal amount from the near file to avoid errors due to
876 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000877 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000878 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000879 break; // This is expected.
880 }
881 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000882 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000883 }
884
885 if (perf_testing) {
886 t0 = TickTime::Now();
887 }
888
889 ASSERT_EQ(apm->kNoError,
890 apm->AnalyzeReverseStream(&far_frame));
891
892 if (perf_testing) {
893 t1 = TickTime::Now();
894 TickInterval tick_diff = t1 - t0;
895 acc_ticks += tick_diff;
896 if (tick_diff.Microseconds() > max_time_reverse_us) {
897 max_time_reverse_us = tick_diff.Microseconds();
898 }
899 if (tick_diff.Microseconds() < min_time_reverse_us) {
900 min_time_reverse_us = tick_diff.Microseconds();
901 }
902 }
903
904 } else if (event == kCaptureEvent) {
905 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000906 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000907
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000908 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000909 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000910 sizeof(int16_t),
911 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000912 near_file);
913
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000914 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000915 if (progress && primary_count % 100 == 0) {
916 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000917 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000918 fflush(stdout);
919 }
920 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000921 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000922 break; // This is expected.
923 }
924
925 delay_ms = 0;
926 drift_samples = 0;
927 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000928 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000929
930 // TODO(ajm): sizeof(delay_ms) for current files?
931 ASSERT_EQ(1u,
932 fread(&delay_ms, 2, 1, delay_file));
933 ASSERT_EQ(1u,
934 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
935 }
936
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000937 if (apm->gain_control()->is_enabled() &&
938 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000939 SimulateMic(capture_level, &near_frame);
940 }
941
ajm@google.com808e0e02011-08-03 21:08:51 +0000942 if (perf_testing) {
943 t0 = TickTime::Now();
944 }
945
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000946 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000947 ASSERT_EQ(apm->kNoError,
948 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000949 delay_ms += extra_delay_ms;
950 if (override_delay_ms) {
951 delay_ms = override_delay_ms;
952 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000953 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000954 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000955 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000956
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000957 apm->set_stream_key_pressed(true);
958
ajm@google.com808e0e02011-08-03 21:08:51 +0000959 int err = apm->ProcessStream(&near_frame);
960 if (err == apm->kBadStreamParameterWarning) {
961 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
962 }
963 ASSERT_TRUE(err == apm->kNoError ||
964 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000965 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000966
967 capture_level = apm->gain_control()->stream_analog_level();
968
969 stream_has_voice =
970 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
971 if (vad_out_file != NULL) {
972 ASSERT_EQ(1u, fwrite(&stream_has_voice,
973 sizeof(stream_has_voice),
974 1,
975 vad_out_file));
976 }
977
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000978 if (ns_prob_file != NULL) {
979 ns_speech_prob = apm->noise_suppression()->speech_probability();
980 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
981 sizeof(ns_speech_prob),
982 1,
983 ns_prob_file));
984 }
985
ajm@google.com808e0e02011-08-03 21:08:51 +0000986 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
987 ASSERT_EQ(capture_level_in, capture_level);
988 }
989
990 if (perf_testing) {
991 t1 = TickTime::Now();
992 TickInterval tick_diff = t1 - t0;
993 acc_ticks += tick_diff;
994 if (tick_diff.Microseconds() > max_time_us) {
995 max_time_us = tick_diff.Microseconds();
996 }
997 if (tick_diff.Microseconds() < min_time_us) {
998 min_time_us = tick_diff.Microseconds();
999 }
1000 }
1001
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001002 size = samples_per_channel * near_frame.num_channels_;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001003 static FILE* out_file = OpenFile(out_filename, "wb");
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001004 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001005 sizeof(int16_t),
1006 size,
1007 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 }
ajm@google.com808e0e02011-08-03 21:08:51 +00001009 else {
1010 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +00001011 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 }
1013 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001014 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001015
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001016 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001017 const size_t path_size =
1018 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +00001019 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001020 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1021 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1022 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001023 path_size,
1024 aecm_echo_path_out_file));
1025 fclose(aecm_echo_path_out_file);
1026 aecm_echo_path_out_file = NULL;
1027 }
1028
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 if (verbose) {
1030 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1031 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001032
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001033 if (apm->level_estimator()->is_enabled()) {
1034 printf("\n--Level metrics--\n");
1035 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1036 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001037 if (apm->echo_cancellation()->are_metrics_enabled()) {
1038 EchoCancellation::Metrics metrics;
1039 apm->echo_cancellation()->GetMetrics(&metrics);
1040 printf("\n--Echo metrics--\n");
1041 printf("(avg, max, min)\n");
1042 printf("ERL: ");
1043 PrintStat(metrics.echo_return_loss);
1044 printf("ERLE: ");
1045 PrintStat(metrics.echo_return_loss_enhancement);
1046 printf("ANLP: ");
1047 PrintStat(metrics.a_nlp);
1048 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001049 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1050 int median = 0;
1051 int std = 0;
1052 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1053 printf("\n--Delay metrics--\n");
1054 printf("Median: %3d\n", median);
1055 printf("Standard deviation: %3d\n", std);
1056 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 }
1058
ajm@google.com808e0e02011-08-03 21:08:51 +00001059 if (!pb_file) {
1060 int8_t temp_int8;
1061 if (far_file) {
1062 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1063 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1064 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001065
ajm@google.com808e0e02011-08-03 21:08:51 +00001066 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1067 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1068
1069 if (!simulating) {
1070 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1071 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1072 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1073 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1074 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1075 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1076 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001077 }
1078
1079 if (perf_testing) {
1080 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001081 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001082 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1083 exec_time * 0.001, primary_count * 0.01);
1084 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1085 " %.3f ms (min)\n",
1086 (exec_time * 1.0) / primary_count,
1087 (max_time_us + max_time_reverse_us) / 1000.0,
1088 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001089 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001090 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001091 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 } else {
1093 printf("Warning: no capture frames\n");
1094 }
1095 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001096}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001097
ajm@google.com808e0e02011-08-03 21:08:51 +00001098} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001099} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001100
1101int main(int argc, char* argv[])
1102{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001103 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001104
andrew@webrtc.org64235092011-08-19 21:22:08 +00001105 // Optional, but removes memory leak noise from Valgrind.
1106 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001107 return 0;
1108}