blob: 01f9dcecb74096833e2b74dc1cc677bd65d2d760 [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");
niklase@google.com470e71d2011-07-07 08:21:25 +000081 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +000082 printf(" --aecm_echo_path_in_file FILE\n");
83 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +000084 printf(" --no_comfort_noise\n");
85 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000086 printf("\n -agc Gain control\n");
87 printf(" --analog\n");
88 printf(" --adaptive_digital\n");
89 printf(" --fixed_digital\n");
90 printf(" --target_level LEVEL\n");
91 printf(" --compression_gain GAIN\n");
92 printf(" --limiter\n");
93 printf(" --no_limiter\n");
94 printf("\n -hpf High pass filter\n");
95 printf("\n -ns Noise suppression\n");
96 printf(" --ns_low\n");
97 printf(" --ns_moderate\n");
98 printf(" --ns_high\n");
99 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000100 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000102 printf(" --vad_out_file FILE\n");
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000103 printf("\n -expns Experimental noise suppression\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000104 printf("\n Level metrics (enabled by default)\n");
105 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000106 printf("\n");
107 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000108 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000109 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
110 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000111 printf(" --perf Measure performance.\n");
112 printf(" --quiet Suppress text output.\n");
113 printf(" --no_progress Suppress progress.\n");
114 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000115}
116
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000117static float MicLevel2Gain(int level) {
118 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000119}
120
121static void SimulateMic(int mic_level, AudioFrame* frame) {
122 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000123 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000124 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000125 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000126 for (int n = 0; n < num_samples; n++) {
127 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000128 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000129 frame->data_[n] = static_cast<int16_t>(v);
130 }
131}
132
niklase@google.com470e71d2011-07-07 08:21:25 +0000133// void function for gtest.
134void void_main(int argc, char* argv[]) {
135 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
136 usage();
137 return;
138 }
139
140 if (argc < 2) {
141 printf("Did you mean to run without arguments?\n");
142 printf("Try `process_test --help' for more information.\n\n");
143 }
144
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000145 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create());
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000146 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
ajm@google.com808e0e02011-08-03 21:08:51 +0000148 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 const char* far_filename = NULL;
150 const char* near_filename = NULL;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000151 std::string out_filename;
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000153 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000154 const char* aecm_echo_path_in_filename = NULL;
155 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000156
157 int32_t sample_rate_hz = 16000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159 int num_capture_input_channels = 1;
160 int num_capture_output_channels = 1;
161 int num_render_channels = 1;
162
163 int samples_per_channel = sample_rate_hz / 100;
164
165 bool simulating = false;
166 bool perf_testing = false;
167 bool verbose = true;
168 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000169 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000170 int override_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000171
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000172 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000173 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000174 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000175 i++;
176 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
177 pb_filename = argv[i];
178
179 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 i++;
181 ASSERT_LT(i, argc) << "Specify filename after -ir";
182 far_filename = argv[i];
183 simulating = true;
184
185 } else if (strcmp(argv[i], "-i") == 0) {
186 i++;
187 ASSERT_LT(i, argc) << "Specify filename after -i";
188 near_filename = argv[i];
189 simulating = true;
190
191 } else if (strcmp(argv[i], "-o") == 0) {
192 i++;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000193 ASSERT_LT(i, argc) << "Specify filename without extension after -o";
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 out_filename = argv[i];
195
196 } else if (strcmp(argv[i], "-fs") == 0) {
197 i++;
198 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
199 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
200 samples_per_channel = sample_rate_hz / 100;
201
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 } else if (strcmp(argv[i], "-ch") == 0) {
203 i++;
204 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
205 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
206 i++;
207 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
208
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 } else if (strcmp(argv[i], "-rch") == 0) {
210 i++;
211 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
212 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
213
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 } else if (strcmp(argv[i], "-aec") == 0) {
215 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000216 ASSERT_EQ(apm->kNoError,
217 apm->echo_cancellation()->enable_metrics(true));
218 ASSERT_EQ(apm->kNoError,
219 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000220
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
222 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
223 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
224 // why it can give better performance despite passing zeros.
225 ASSERT_EQ(apm->kNoError,
226 apm->echo_cancellation()->enable_drift_compensation(true));
227 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
228 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
229 ASSERT_EQ(apm->kNoError,
230 apm->echo_cancellation()->enable_drift_compensation(false));
231
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000232 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
233 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
234 ASSERT_EQ(apm->kNoError,
235 apm->echo_cancellation()->enable_metrics(false));
236
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000237 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
238 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
239 ASSERT_EQ(apm->kNoError,
240 apm->echo_cancellation()->enable_delay_logging(false));
241
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000242 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
243 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
244
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000245 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
246 i++;
247 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
248 int suppression_level;
249 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
250 ASSERT_EQ(apm->kNoError,
251 apm->echo_cancellation()->set_suppression_level(
252 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
253 suppression_level)));
254
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000255 } else if (strcmp(argv[i], "--extended_filter") == 0) {
256 Config config;
257 config.Set<DelayCorrection>(new DelayCorrection(true));
258 apm->SetExtraOptions(config);
259
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 } else if (strcmp(argv[i], "-aecm") == 0) {
261 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
262
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000263 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
264 i++;
265 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
266 aecm_echo_path_in_filename = argv[i];
267
268 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
269 i++;
270 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
271 aecm_echo_path_out_filename = argv[i];
272
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000273 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
274 ASSERT_EQ(apm->kNoError,
275 apm->echo_control_mobile()->enable_comfort_noise(false));
276
277 } else if (strcmp(argv[i], "--routing_mode") == 0) {
278 i++;
279 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
280 int routing_mode;
281 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
282 ASSERT_EQ(apm->kNoError,
283 apm->echo_control_mobile()->set_routing_mode(
284 static_cast<webrtc::EchoControlMobile::RoutingMode>(
285 routing_mode)));
286
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 } else if (strcmp(argv[i], "-agc") == 0) {
288 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
289
290 } else if (strcmp(argv[i], "--analog") == 0) {
291 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
292 ASSERT_EQ(apm->kNoError,
293 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
294
295 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
296 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
297 ASSERT_EQ(apm->kNoError,
298 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
299
300 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
301 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
302 ASSERT_EQ(apm->kNoError,
303 apm->gain_control()->set_mode(GainControl::kFixedDigital));
304
305 } else if (strcmp(argv[i], "--target_level") == 0) {
306 i++;
307 int level;
308 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
309
310 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
311 ASSERT_EQ(apm->kNoError,
312 apm->gain_control()->set_target_level_dbfs(level));
313
314 } else if (strcmp(argv[i], "--compression_gain") == 0) {
315 i++;
316 int gain;
317 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
318
319 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
320 ASSERT_EQ(apm->kNoError,
321 apm->gain_control()->set_compression_gain_db(gain));
322
323 } else if (strcmp(argv[i], "--limiter") == 0) {
324 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
325 ASSERT_EQ(apm->kNoError,
326 apm->gain_control()->enable_limiter(true));
327
328 } else if (strcmp(argv[i], "--no_limiter") == 0) {
329 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
330 ASSERT_EQ(apm->kNoError,
331 apm->gain_control()->enable_limiter(false));
332
333 } else if (strcmp(argv[i], "-hpf") == 0) {
334 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
335
336 } else if (strcmp(argv[i], "-ns") == 0) {
337 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
338
339 } else if (strcmp(argv[i], "--ns_low") == 0) {
340 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
341 ASSERT_EQ(apm->kNoError,
342 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
343
344 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
345 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
346 ASSERT_EQ(apm->kNoError,
347 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
348
349 } else if (strcmp(argv[i], "--ns_high") == 0) {
350 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
351 ASSERT_EQ(apm->kNoError,
352 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
353
354 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
355 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
356 ASSERT_EQ(apm->kNoError,
357 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
358
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000359 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
360 i++;
361 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
362 ns_prob_filename = argv[i];
363
niklase@google.com470e71d2011-07-07 08:21:25 +0000364 } else if (strcmp(argv[i], "-vad") == 0) {
365 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
366
andrew@webrtc.org89752612012-10-12 16:41:45 +0000367 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
368 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
369 ASSERT_EQ(apm->kNoError,
370 apm->voice_detection()->set_likelihood(
371 VoiceDetection::kVeryLowLikelihood));
372
373 } else if (strcmp(argv[i], "--vad_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::kLowLikelihood));
378
379 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
380 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
381 ASSERT_EQ(apm->kNoError,
382 apm->voice_detection()->set_likelihood(
383 VoiceDetection::kModerateLikelihood));
384
385 } else if (strcmp(argv[i], "--vad_high") == 0) {
386 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
387 ASSERT_EQ(apm->kNoError,
388 apm->voice_detection()->set_likelihood(
389 VoiceDetection::kHighLikelihood));
390
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
392 i++;
393 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
394 vad_out_filename = argv[i];
395
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000396 } else if (strcmp(argv[i], "-expns") == 0) {
397 ASSERT_EQ(apm->kNoError, apm->EnableExperimentalNs(true));
398
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000399 } else if (strcmp(argv[i], "--noasm") == 0) {
400 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
401 // We need to reinitialize here if components have already been enabled.
402 ASSERT_EQ(apm->kNoError, apm->Initialize());
403
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000404 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000405 i++;
406 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
407
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000408 } else if (strcmp(argv[i], "--delay") == 0) {
409 i++;
410 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
411
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 } else if (strcmp(argv[i], "--perf") == 0) {
413 perf_testing = true;
414
415 } else if (strcmp(argv[i], "--quiet") == 0) {
416 verbose = false;
417 progress = false;
418
419 } else if (strcmp(argv[i], "--no_progress") == 0) {
420 progress = false;
421
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000422 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000423 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000424 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000425 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 } else {
427 FAIL() << "Unrecognized argument " << argv[i];
428 }
429 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000430 // If we're reading a protobuf file, ensure a simulation hasn't also
431 // been requested (which makes no sense...)
432 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000433
434 if (verbose) {
435 printf("Sample rate: %d Hz\n", sample_rate_hz);
436 printf("Primary channels: %d (in), %d (out)\n",
437 num_capture_input_channels,
438 num_capture_output_channels);
439 printf("Reverse channels: %d \n", num_render_channels);
440 }
441
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000442 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 const char far_file_default[] = "apm_far.pcm";
444 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 const char event_filename[] = "apm_event.dat";
446 const char delay_filename[] = "apm_delay.dat";
447 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000448 const std::string vad_file_default = out_path + "vad_out.dat";
449 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000450
451 if (!simulating) {
452 far_filename = far_file_default;
453 near_filename = near_file_default;
454 }
455
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000456 if (out_filename.size() == 0) {
457 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000458 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000459 std::string out_float_filename = out_filename + ".float";
460 out_filename += ".pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000461
ajm@google.com808e0e02011-08-03 21:08:51 +0000462 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000463 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000464 }
465
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000466 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000467 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000468 }
469
ajm@google.com808e0e02011-08-03 21:08:51 +0000470 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 FILE* far_file = NULL;
472 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 FILE* event_file = NULL;
474 FILE* delay_file = NULL;
475 FILE* drift_file = NULL;
476 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000477 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000478 FILE* aecm_echo_path_in_file = NULL;
479 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000480
ajm@google.com808e0e02011-08-03 21:08:51 +0000481 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000482 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000483 } else {
484 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000485 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000486 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000487
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000488 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000489 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000490 event_file = OpenFile(event_filename, "rb");
491 delay_file = OpenFile(delay_filename, "rb");
492 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000493 }
494 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000495
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000496 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000497 if (pb_file) {
498 struct stat st;
499 stat(pb_filename, &st);
500 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000501 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000502 } else {
503 struct stat st;
504 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000505 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000506 }
507
508 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000509 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 }
511
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000512 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000513 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000514 }
515
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000516 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000517 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000518
ajm@google.com22e65152011-07-18 18:03:01 +0000519 const size_t path_size =
520 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +0000521 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000522 ASSERT_EQ(path_size, fread(echo_path.get(),
523 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000524 path_size,
525 aecm_echo_path_in_file));
526 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000527 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
528 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000529 fclose(aecm_echo_path_in_file);
530 aecm_echo_path_in_file = NULL;
531 }
532
533 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000534 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000535 }
536
niklase@google.com470e71d2011-07-07 08:21:25 +0000537 size_t read_count = 0;
538 int reverse_count = 0;
539 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000540 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000541 TickInterval acc_ticks;
542
543 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000545
546 int delay_ms = 0;
547 int drift_samples = 0;
548 int capture_level = 127;
549 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000550 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000551
552 TickTime t0 = TickTime::Now();
553 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000554 int64_t max_time_us = 0;
555 int64_t max_time_reverse_us = 0;
556 int64_t min_time_us = 1e6;
557 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000558
ajm@google.com808e0e02011-08-03 21:08:51 +0000559 // TODO(ajm): Ideally we would refactor this block into separate functions,
560 // but for now we want to share the variables.
561 if (pb_file) {
562 Event event_msg;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000563 scoped_ptr<ChannelBuffer<float> > reverse_cb;
564 scoped_ptr<ChannelBuffer<float> > primary_cb;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000565 int output_sample_rate = 32000;
566 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
ajm@google.com808e0e02011-08-03 21:08:51 +0000567 while (ReadMessageFromFile(pb_file, &event_msg)) {
568 std::ostringstream trace_stream;
569 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
570 << primary_count << " (primary)";
571 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000572
ajm@google.com808e0e02011-08-03 21:08:51 +0000573 if (event_msg.type() == Event::INIT) {
574 ASSERT_TRUE(event_msg.has_init());
575 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000576
ajm@google.com808e0e02011-08-03 21:08:51 +0000577 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000578 ASSERT_TRUE(msg.has_num_input_channels());
579 ASSERT_TRUE(msg.has_num_output_channels());
580 ASSERT_TRUE(msg.has_num_reverse_channels());
581 int reverse_sample_rate = msg.sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000582 if (msg.has_reverse_sample_rate()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000583 reverse_sample_rate = msg.reverse_sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000584 }
585 output_sample_rate = msg.sample_rate();
586 if (msg.has_output_sample_rate()) {
587 output_sample_rate = msg.output_sample_rate();
588 }
589 output_layout = LayoutFromChannels(msg.num_output_channels());
590 ASSERT_EQ(kNoErr, apm->Initialize(
591 msg.sample_rate(),
592 output_sample_rate,
593 reverse_sample_rate,
594 LayoutFromChannels(msg.num_input_channels()),
595 output_layout,
596 LayoutFromChannels(msg.num_reverse_channels())));
ajm@google.com808e0e02011-08-03 21:08:51 +0000597
598 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000599 far_frame.sample_rate_hz_ = msg.sample_rate();
600 far_frame.samples_per_channel_ = samples_per_channel;
601 far_frame.num_channels_ = msg.num_reverse_channels();
602 near_frame.sample_rate_hz_ = msg.sample_rate();
603 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000604 near_frame.num_channels_ = msg.num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000605 reverse_cb.reset(new ChannelBuffer<float>(samples_per_channel,
606 msg.num_reverse_channels()));
607 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
608 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000609
610 if (verbose) {
611 printf("Init at frame: %d (primary), %d (reverse)\n",
612 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000613 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
614 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000615 printf(" Primary channels: %d (in), %d (out)\n",
616 msg.num_input_channels(),
617 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000618 printf(" Reverse rate: %d\n", reverse_sample_rate);
619 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000620 }
621
622 } else if (event_msg.type() == Event::REVERSE_STREAM) {
623 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000624 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000625 reverse_count++;
626
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000627 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
628 if (msg.has_data()) {
629 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
630 far_frame.num_channels_, msg.data().size());
631 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
632 } else {
633 for (int i = 0; i < msg.channel_size(); ++i) {
634 reverse_cb->CopyFrom(msg.channel(i).data(), i);
635 }
636 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000637
638 if (perf_testing) {
639 t0 = TickTime::Now();
640 }
641
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000642 if (msg.has_data()) {
643 ASSERT_EQ(apm->kNoError,
644 apm->AnalyzeReverseStream(&far_frame));
645 } else {
646 ASSERT_EQ(apm->kNoError,
647 apm->AnalyzeReverseStream(
648 reverse_cb->channels(),
649 far_frame.samples_per_channel_,
650 far_frame.sample_rate_hz_,
651 LayoutFromChannels(far_frame.num_channels_)));
652 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000653
654 if (perf_testing) {
655 t1 = TickTime::Now();
656 TickInterval tick_diff = t1 - t0;
657 acc_ticks += tick_diff;
658 if (tick_diff.Microseconds() > max_time_reverse_us) {
659 max_time_reverse_us = tick_diff.Microseconds();
660 }
661 if (tick_diff.Microseconds() < min_time_reverse_us) {
662 min_time_reverse_us = tick_diff.Microseconds();
663 }
664 }
665
666 } else if (event_msg.type() == Event::STREAM) {
667 ASSERT_TRUE(event_msg.has_stream());
668 const Stream msg = event_msg.stream();
669 primary_count++;
670
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000671 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000672 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000673
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000674 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
675 if (msg.has_input_data()) {
676 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
677 near_frame.num_channels_, msg.input_data().size());
678 memcpy(near_frame.data_,
679 msg.input_data().data(),
680 msg.input_data().size());
681 } else {
682 for (int i = 0; i < msg.input_channel_size(); ++i) {
683 primary_cb->CopyFrom(msg.input_channel(i).data(), i);
684 }
685 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000686
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000687 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000688 if (progress && primary_count % 100 == 0) {
689 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000690 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000691 fflush(stdout);
692 }
693
694 if (perf_testing) {
695 t0 = TickTime::Now();
696 }
697
698 ASSERT_EQ(apm->kNoError,
699 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000700 delay_ms = msg.delay() + extra_delay_ms;
701 if (override_delay_ms) {
702 delay_ms = override_delay_ms;
703 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000704 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000705 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000706 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000707
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000708 if (msg.has_keypress()) {
709 apm->set_stream_key_pressed(msg.keypress());
710 } else {
711 apm->set_stream_key_pressed(true);
712 }
713
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000714 int err = apm->kNoError;
715 if (msg.has_input_data()) {
716 err = apm->ProcessStream(&near_frame);
717 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
718 } else {
719 err = apm->ProcessStream(
720 primary_cb->channels(),
721 near_frame.samples_per_channel_,
722 near_frame.sample_rate_hz_,
723 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000724 output_sample_rate,
725 output_layout,
726 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000727 }
728
ajm@google.com808e0e02011-08-03 21:08:51 +0000729 if (err == apm->kBadStreamParameterWarning) {
730 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
731 }
732 ASSERT_TRUE(err == apm->kNoError ||
733 err == apm->kBadStreamParameterWarning);
734
ajm@google.com808e0e02011-08-03 21:08:51 +0000735 stream_has_voice =
736 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
737 if (vad_out_file != NULL) {
738 ASSERT_EQ(1u, fwrite(&stream_has_voice,
739 sizeof(stream_has_voice),
740 1,
741 vad_out_file));
742 }
743
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000744 if (ns_prob_file != NULL) {
745 ns_speech_prob = apm->noise_suppression()->speech_probability();
746 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
747 sizeof(ns_speech_prob),
748 1,
749 ns_prob_file));
750 }
751
ajm@google.com808e0e02011-08-03 21:08:51 +0000752 if (perf_testing) {
753 t1 = TickTime::Now();
754 TickInterval tick_diff = t1 - t0;
755 acc_ticks += tick_diff;
756 if (tick_diff.Microseconds() > max_time_us) {
757 max_time_us = tick_diff.Microseconds();
758 }
759 if (tick_diff.Microseconds() < min_time_us) {
760 min_time_us = tick_diff.Microseconds();
761 }
762 }
763
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000764 size_t num_samples = samples_per_channel * apm->num_output_channels();
765 if (msg.has_input_data()) {
766 static FILE* out_file = OpenFile(out_filename, "wb");
767 ASSERT_EQ(num_samples, fwrite(near_frame.data_,
768 sizeof(*near_frame.data_),
769 num_samples,
770 out_file));
771 } else {
772 static FILE* out_float_file = OpenFile(out_float_filename, "wb");
773 ASSERT_EQ(num_samples, fwrite(primary_cb->data(),
774 sizeof(*primary_cb->data()),
775 num_samples,
776 out_float_file));
777 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000778 }
779 }
780
781 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000782
783 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000784 enum Events {
785 kInitializeEvent,
786 kRenderEvent,
787 kCaptureEvent,
788 kResetEventDeprecated
789 };
790 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000791 while (simulating || feof(event_file) == 0) {
792 std::ostringstream trace_stream;
793 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
794 << primary_count << " (primary)";
795 SCOPED_TRACE(trace_stream.str());
796
797 if (simulating) {
798 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 event = kCaptureEvent;
800 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000801 if (event == kRenderEvent) {
802 event = kCaptureEvent;
803 } else {
804 event = kRenderEvent;
805 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000806 }
807 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000808 read_count = fread(&event, sizeof(event), 1, event_file);
809 if (read_count != 1) {
810 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000811 }
812 }
813
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000814 far_frame.sample_rate_hz_ = sample_rate_hz;
815 far_frame.samples_per_channel_ = samples_per_channel;
816 far_frame.num_channels_ = num_render_channels;
817 near_frame.sample_rate_hz_ = sample_rate_hz;
818 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000819
ajm@google.com808e0e02011-08-03 21:08:51 +0000820 if (event == kInitializeEvent || event == kResetEventDeprecated) {
821 ASSERT_EQ(1u,
822 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
823 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000824
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000825 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000826 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000827 fread(&unused_device_sample_rate_hz,
828 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000829 1,
830 event_file));
831
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000832 ASSERT_EQ(kNoErr, apm->Initialize(
833 sample_rate_hz,
834 sample_rate_hz,
835 sample_rate_hz,
836 LayoutFromChannels(num_capture_input_channels),
837 LayoutFromChannels(num_capture_output_channels),
838 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000839
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000840 far_frame.sample_rate_hz_ = sample_rate_hz;
841 far_frame.samples_per_channel_ = samples_per_channel;
842 far_frame.num_channels_ = num_render_channels;
843 near_frame.sample_rate_hz_ = sample_rate_hz;
844 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000845
846 if (verbose) {
847 printf("Init at frame: %d (primary), %d (reverse)\n",
848 primary_count, reverse_count);
849 printf(" Sample rate: %d Hz\n", sample_rate_hz);
850 }
851
852 } else if (event == kRenderEvent) {
853 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000854
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000855 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000856 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000857 sizeof(int16_t),
858 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000859 far_file);
860
861 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000862 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000863 // Read an equal amount from the near file to avoid errors due to
864 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000865 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000866 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000867 break; // This is expected.
868 }
869 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000870 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000871 }
872
873 if (perf_testing) {
874 t0 = TickTime::Now();
875 }
876
877 ASSERT_EQ(apm->kNoError,
878 apm->AnalyzeReverseStream(&far_frame));
879
880 if (perf_testing) {
881 t1 = TickTime::Now();
882 TickInterval tick_diff = t1 - t0;
883 acc_ticks += tick_diff;
884 if (tick_diff.Microseconds() > max_time_reverse_us) {
885 max_time_reverse_us = tick_diff.Microseconds();
886 }
887 if (tick_diff.Microseconds() < min_time_reverse_us) {
888 min_time_reverse_us = tick_diff.Microseconds();
889 }
890 }
891
892 } else if (event == kCaptureEvent) {
893 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000894 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000895
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000896 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000897 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000898 sizeof(int16_t),
899 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000900 near_file);
901
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000902 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000903 if (progress && primary_count % 100 == 0) {
904 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000905 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000906 fflush(stdout);
907 }
908 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000909 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000910 break; // This is expected.
911 }
912
913 delay_ms = 0;
914 drift_samples = 0;
915 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000916 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000917
918 // TODO(ajm): sizeof(delay_ms) for current files?
919 ASSERT_EQ(1u,
920 fread(&delay_ms, 2, 1, delay_file));
921 ASSERT_EQ(1u,
922 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
923 }
924
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000925 if (apm->gain_control()->is_enabled() &&
926 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000927 SimulateMic(capture_level, &near_frame);
928 }
929
ajm@google.com808e0e02011-08-03 21:08:51 +0000930 if (perf_testing) {
931 t0 = TickTime::Now();
932 }
933
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000934 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000935 ASSERT_EQ(apm->kNoError,
936 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000937 delay_ms += extra_delay_ms;
938 if (override_delay_ms) {
939 delay_ms = override_delay_ms;
940 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000941 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000942 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000943 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000944
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000945 apm->set_stream_key_pressed(true);
946
ajm@google.com808e0e02011-08-03 21:08:51 +0000947 int err = apm->ProcessStream(&near_frame);
948 if (err == apm->kBadStreamParameterWarning) {
949 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
950 }
951 ASSERT_TRUE(err == apm->kNoError ||
952 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000953 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000954
955 capture_level = apm->gain_control()->stream_analog_level();
956
957 stream_has_voice =
958 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
959 if (vad_out_file != NULL) {
960 ASSERT_EQ(1u, fwrite(&stream_has_voice,
961 sizeof(stream_has_voice),
962 1,
963 vad_out_file));
964 }
965
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000966 if (ns_prob_file != NULL) {
967 ns_speech_prob = apm->noise_suppression()->speech_probability();
968 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
969 sizeof(ns_speech_prob),
970 1,
971 ns_prob_file));
972 }
973
ajm@google.com808e0e02011-08-03 21:08:51 +0000974 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
975 ASSERT_EQ(capture_level_in, capture_level);
976 }
977
978 if (perf_testing) {
979 t1 = TickTime::Now();
980 TickInterval tick_diff = t1 - t0;
981 acc_ticks += tick_diff;
982 if (tick_diff.Microseconds() > max_time_us) {
983 max_time_us = tick_diff.Microseconds();
984 }
985 if (tick_diff.Microseconds() < min_time_us) {
986 min_time_us = tick_diff.Microseconds();
987 }
988 }
989
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000990 size = samples_per_channel * near_frame.num_channels_;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000991 static FILE* out_file = OpenFile(out_filename, "wb");
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000992 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000993 sizeof(int16_t),
994 size,
995 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000997 else {
998 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000999 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 }
1001 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001002 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001003
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001004 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001005 const size_t path_size =
1006 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +00001007 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001008 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1009 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1010 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001011 path_size,
1012 aecm_echo_path_out_file));
1013 fclose(aecm_echo_path_out_file);
1014 aecm_echo_path_out_file = NULL;
1015 }
1016
niklase@google.com470e71d2011-07-07 08:21:25 +00001017 if (verbose) {
1018 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1019 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001020
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001021 if (apm->level_estimator()->is_enabled()) {
1022 printf("\n--Level metrics--\n");
1023 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1024 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001025 if (apm->echo_cancellation()->are_metrics_enabled()) {
1026 EchoCancellation::Metrics metrics;
1027 apm->echo_cancellation()->GetMetrics(&metrics);
1028 printf("\n--Echo metrics--\n");
1029 printf("(avg, max, min)\n");
1030 printf("ERL: ");
1031 PrintStat(metrics.echo_return_loss);
1032 printf("ERLE: ");
1033 PrintStat(metrics.echo_return_loss_enhancement);
1034 printf("ANLP: ");
1035 PrintStat(metrics.a_nlp);
1036 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001037 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1038 int median = 0;
1039 int std = 0;
1040 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1041 printf("\n--Delay metrics--\n");
1042 printf("Median: %3d\n", median);
1043 printf("Standard deviation: %3d\n", std);
1044 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 }
1046
ajm@google.com808e0e02011-08-03 21:08:51 +00001047 if (!pb_file) {
1048 int8_t temp_int8;
1049 if (far_file) {
1050 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1051 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1052 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001053
ajm@google.com808e0e02011-08-03 21:08:51 +00001054 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1055 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1056
1057 if (!simulating) {
1058 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1059 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1060 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1061 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1062 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1063 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1064 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 }
1066
1067 if (perf_testing) {
1068 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001069 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1071 exec_time * 0.001, primary_count * 0.01);
1072 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1073 " %.3f ms (min)\n",
1074 (exec_time * 1.0) / primary_count,
1075 (max_time_us + max_time_reverse_us) / 1000.0,
1076 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001077 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001078 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001079 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 } else {
1081 printf("Warning: no capture frames\n");
1082 }
1083 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001084}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001085
ajm@google.com808e0e02011-08-03 21:08:51 +00001086} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001087} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001088
1089int main(int argc, char* argv[])
1090{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001091 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001092
andrew@webrtc.org64235092011-08-19 21:22:08 +00001093 // Optional, but removes memory leak noise from Valgrind.
1094 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001095 return 0;
1096}