blob: a36a072c910487971b55bd96b510fd1fc41e7bdc [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) {
403 ASSERT_EQ(apm->kNoError, apm->EnableExperimentalNs(true));
404
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000405 } else if (strcmp(argv[i], "--noasm") == 0) {
406 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
407 // We need to reinitialize here if components have already been enabled.
408 ASSERT_EQ(apm->kNoError, apm->Initialize());
409
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000410 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000411 i++;
412 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
413
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000414 } else if (strcmp(argv[i], "--delay") == 0) {
415 i++;
416 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
417
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 } else if (strcmp(argv[i], "--perf") == 0) {
419 perf_testing = true;
420
421 } else if (strcmp(argv[i], "--quiet") == 0) {
422 verbose = false;
423 progress = false;
424
425 } else if (strcmp(argv[i], "--no_progress") == 0) {
426 progress = false;
427
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000428 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000429 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000430 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000431 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 } else {
433 FAIL() << "Unrecognized argument " << argv[i];
434 }
435 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000436 // If we're reading a protobuf file, ensure a simulation hasn't also
437 // been requested (which makes no sense...)
438 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000439
440 if (verbose) {
441 printf("Sample rate: %d Hz\n", sample_rate_hz);
442 printf("Primary channels: %d (in), %d (out)\n",
443 num_capture_input_channels,
444 num_capture_output_channels);
445 printf("Reverse channels: %d \n", num_render_channels);
446 }
447
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000448 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 const char far_file_default[] = "apm_far.pcm";
450 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 const char event_filename[] = "apm_event.dat";
452 const char delay_filename[] = "apm_delay.dat";
453 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000454 const std::string vad_file_default = out_path + "vad_out.dat";
455 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000456
457 if (!simulating) {
458 far_filename = far_file_default;
459 near_filename = near_file_default;
460 }
461
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000462 if (out_filename.size() == 0) {
463 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000464 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000465 std::string out_float_filename = out_filename + ".float";
466 out_filename += ".pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000467
ajm@google.com808e0e02011-08-03 21:08:51 +0000468 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000469 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 }
471
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000472 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000473 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000474 }
475
ajm@google.com808e0e02011-08-03 21:08:51 +0000476 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 FILE* far_file = NULL;
478 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 FILE* event_file = NULL;
480 FILE* delay_file = NULL;
481 FILE* drift_file = NULL;
482 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000483 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000484 FILE* aecm_echo_path_in_file = NULL;
485 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000486
ajm@google.com808e0e02011-08-03 21:08:51 +0000487 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000488 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000489 } else {
490 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000491 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000492 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000493
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000494 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000495 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000496 event_file = OpenFile(event_filename, "rb");
497 delay_file = OpenFile(delay_filename, "rb");
498 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000499 }
500 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000501
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000502 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000503 if (pb_file) {
504 struct stat st;
505 stat(pb_filename, &st);
506 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000507 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000508 } else {
509 struct stat st;
510 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000511 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000512 }
513
514 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000515 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000516 }
517
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000518 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000519 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000520 }
521
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000522 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000523 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000524
ajm@google.com22e65152011-07-18 18:03:01 +0000525 const size_t path_size =
526 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +0000527 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000528 ASSERT_EQ(path_size, fread(echo_path.get(),
529 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000530 path_size,
531 aecm_echo_path_in_file));
532 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000533 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
534 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000535 fclose(aecm_echo_path_in_file);
536 aecm_echo_path_in_file = NULL;
537 }
538
539 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000540 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000541 }
542
niklase@google.com470e71d2011-07-07 08:21:25 +0000543 size_t read_count = 0;
544 int reverse_count = 0;
545 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000546 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000547 TickInterval acc_ticks;
548
549 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000551
552 int delay_ms = 0;
553 int drift_samples = 0;
554 int capture_level = 127;
555 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000556 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000557
558 TickTime t0 = TickTime::Now();
559 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000560 int64_t max_time_us = 0;
561 int64_t max_time_reverse_us = 0;
562 int64_t min_time_us = 1e6;
563 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000564
ajm@google.com808e0e02011-08-03 21:08:51 +0000565 // TODO(ajm): Ideally we would refactor this block into separate functions,
566 // but for now we want to share the variables.
567 if (pb_file) {
568 Event event_msg;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000569 scoped_ptr<ChannelBuffer<float> > reverse_cb;
570 scoped_ptr<ChannelBuffer<float> > primary_cb;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000571 int output_sample_rate = 32000;
572 AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono;
ajm@google.com808e0e02011-08-03 21:08:51 +0000573 while (ReadMessageFromFile(pb_file, &event_msg)) {
574 std::ostringstream trace_stream;
575 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
576 << primary_count << " (primary)";
577 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000578
ajm@google.com808e0e02011-08-03 21:08:51 +0000579 if (event_msg.type() == Event::INIT) {
580 ASSERT_TRUE(event_msg.has_init());
581 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000582
ajm@google.com808e0e02011-08-03 21:08:51 +0000583 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000584 ASSERT_TRUE(msg.has_num_input_channels());
585 ASSERT_TRUE(msg.has_num_output_channels());
586 ASSERT_TRUE(msg.has_num_reverse_channels());
587 int reverse_sample_rate = msg.sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000588 if (msg.has_reverse_sample_rate()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000589 reverse_sample_rate = msg.reverse_sample_rate();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000590 }
591 output_sample_rate = msg.sample_rate();
592 if (msg.has_output_sample_rate()) {
593 output_sample_rate = msg.output_sample_rate();
594 }
595 output_layout = LayoutFromChannels(msg.num_output_channels());
596 ASSERT_EQ(kNoErr, apm->Initialize(
597 msg.sample_rate(),
598 output_sample_rate,
599 reverse_sample_rate,
600 LayoutFromChannels(msg.num_input_channels()),
601 output_layout,
602 LayoutFromChannels(msg.num_reverse_channels())));
ajm@google.com808e0e02011-08-03 21:08:51 +0000603
604 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000605 far_frame.sample_rate_hz_ = msg.sample_rate();
606 far_frame.samples_per_channel_ = samples_per_channel;
607 far_frame.num_channels_ = msg.num_reverse_channels();
608 near_frame.sample_rate_hz_ = msg.sample_rate();
609 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000610 near_frame.num_channels_ = msg.num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000611 reverse_cb.reset(new ChannelBuffer<float>(samples_per_channel,
612 msg.num_reverse_channels()));
613 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
614 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000615
616 if (verbose) {
617 printf("Init at frame: %d (primary), %d (reverse)\n",
618 primary_count, reverse_count);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000619 printf(" Primary rates: %d Hz (in), %d Hz (out)\n",
620 msg.sample_rate(), output_sample_rate);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000621 printf(" Primary channels: %d (in), %d (out)\n",
622 msg.num_input_channels(),
623 msg.num_output_channels());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000624 printf(" Reverse rate: %d\n", reverse_sample_rate);
625 printf(" Reverse channels: %d\n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000626 }
627
628 } else if (event_msg.type() == Event::REVERSE_STREAM) {
629 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000630 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000631 reverse_count++;
632
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000633 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
634 if (msg.has_data()) {
635 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
636 far_frame.num_channels_, msg.data().size());
637 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
638 } else {
639 for (int i = 0; i < msg.channel_size(); ++i) {
640 reverse_cb->CopyFrom(msg.channel(i).data(), i);
641 }
642 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000643
644 if (perf_testing) {
645 t0 = TickTime::Now();
646 }
647
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000648 if (msg.has_data()) {
649 ASSERT_EQ(apm->kNoError,
650 apm->AnalyzeReverseStream(&far_frame));
651 } else {
652 ASSERT_EQ(apm->kNoError,
653 apm->AnalyzeReverseStream(
654 reverse_cb->channels(),
655 far_frame.samples_per_channel_,
656 far_frame.sample_rate_hz_,
657 LayoutFromChannels(far_frame.num_channels_)));
658 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000659
660 if (perf_testing) {
661 t1 = TickTime::Now();
662 TickInterval tick_diff = t1 - t0;
663 acc_ticks += tick_diff;
664 if (tick_diff.Microseconds() > max_time_reverse_us) {
665 max_time_reverse_us = tick_diff.Microseconds();
666 }
667 if (tick_diff.Microseconds() < min_time_reverse_us) {
668 min_time_reverse_us = tick_diff.Microseconds();
669 }
670 }
671
672 } else if (event_msg.type() == Event::STREAM) {
673 ASSERT_TRUE(event_msg.has_stream());
674 const Stream msg = event_msg.stream();
675 primary_count++;
676
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000677 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000678 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000679
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000680 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
681 if (msg.has_input_data()) {
682 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
683 near_frame.num_channels_, msg.input_data().size());
684 memcpy(near_frame.data_,
685 msg.input_data().data(),
686 msg.input_data().size());
687 } else {
688 for (int i = 0; i < msg.input_channel_size(); ++i) {
689 primary_cb->CopyFrom(msg.input_channel(i).data(), i);
690 }
691 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000692
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000693 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000694 if (progress && primary_count % 100 == 0) {
695 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000696 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000697 fflush(stdout);
698 }
699
700 if (perf_testing) {
701 t0 = TickTime::Now();
702 }
703
704 ASSERT_EQ(apm->kNoError,
705 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000706 delay_ms = msg.delay() + extra_delay_ms;
707 if (override_delay_ms) {
708 delay_ms = override_delay_ms;
709 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000710 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000711 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000712 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000713
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000714 if (msg.has_keypress()) {
715 apm->set_stream_key_pressed(msg.keypress());
716 } else {
717 apm->set_stream_key_pressed(true);
718 }
719
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000720 int err = apm->kNoError;
721 if (msg.has_input_data()) {
722 err = apm->ProcessStream(&near_frame);
723 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
724 } else {
725 err = apm->ProcessStream(
726 primary_cb->channels(),
727 near_frame.samples_per_channel_,
728 near_frame.sample_rate_hz_,
729 LayoutFromChannels(near_frame.num_channels_),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000730 output_sample_rate,
731 output_layout,
732 primary_cb->channels());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000733 }
734
ajm@google.com808e0e02011-08-03 21:08:51 +0000735 if (err == apm->kBadStreamParameterWarning) {
736 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
737 }
738 ASSERT_TRUE(err == apm->kNoError ||
739 err == apm->kBadStreamParameterWarning);
740
ajm@google.com808e0e02011-08-03 21:08:51 +0000741 stream_has_voice =
742 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
743 if (vad_out_file != NULL) {
744 ASSERT_EQ(1u, fwrite(&stream_has_voice,
745 sizeof(stream_has_voice),
746 1,
747 vad_out_file));
748 }
749
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000750 if (ns_prob_file != NULL) {
751 ns_speech_prob = apm->noise_suppression()->speech_probability();
752 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
753 sizeof(ns_speech_prob),
754 1,
755 ns_prob_file));
756 }
757
ajm@google.com808e0e02011-08-03 21:08:51 +0000758 if (perf_testing) {
759 t1 = TickTime::Now();
760 TickInterval tick_diff = t1 - t0;
761 acc_ticks += tick_diff;
762 if (tick_diff.Microseconds() > max_time_us) {
763 max_time_us = tick_diff.Microseconds();
764 }
765 if (tick_diff.Microseconds() < min_time_us) {
766 min_time_us = tick_diff.Microseconds();
767 }
768 }
769
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000770 size_t num_samples = samples_per_channel * apm->num_output_channels();
771 if (msg.has_input_data()) {
772 static FILE* out_file = OpenFile(out_filename, "wb");
773 ASSERT_EQ(num_samples, fwrite(near_frame.data_,
774 sizeof(*near_frame.data_),
775 num_samples,
776 out_file));
777 } else {
778 static FILE* out_float_file = OpenFile(out_float_filename, "wb");
779 ASSERT_EQ(num_samples, fwrite(primary_cb->data(),
780 sizeof(*primary_cb->data()),
781 num_samples,
782 out_float_file));
783 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000784 }
785 }
786
787 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000788
789 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000790 enum Events {
791 kInitializeEvent,
792 kRenderEvent,
793 kCaptureEvent,
794 kResetEventDeprecated
795 };
796 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000797 while (simulating || feof(event_file) == 0) {
798 std::ostringstream trace_stream;
799 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
800 << primary_count << " (primary)";
801 SCOPED_TRACE(trace_stream.str());
802
803 if (simulating) {
804 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000805 event = kCaptureEvent;
806 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000807 if (event == kRenderEvent) {
808 event = kCaptureEvent;
809 } else {
810 event = kRenderEvent;
811 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000812 }
813 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000814 read_count = fread(&event, sizeof(event), 1, event_file);
815 if (read_count != 1) {
816 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000817 }
818 }
819
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000820 far_frame.sample_rate_hz_ = sample_rate_hz;
821 far_frame.samples_per_channel_ = samples_per_channel;
822 far_frame.num_channels_ = num_render_channels;
823 near_frame.sample_rate_hz_ = sample_rate_hz;
824 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000825
ajm@google.com808e0e02011-08-03 21:08:51 +0000826 if (event == kInitializeEvent || event == kResetEventDeprecated) {
827 ASSERT_EQ(1u,
828 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
829 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000830
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000831 int32_t unused_device_sample_rate_hz;
ajm@google.com808e0e02011-08-03 21:08:51 +0000832 ASSERT_EQ(1u,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000833 fread(&unused_device_sample_rate_hz,
834 sizeof(unused_device_sample_rate_hz),
ajm@google.com808e0e02011-08-03 21:08:51 +0000835 1,
836 event_file));
837
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000838 ASSERT_EQ(kNoErr, apm->Initialize(
839 sample_rate_hz,
840 sample_rate_hz,
841 sample_rate_hz,
842 LayoutFromChannels(num_capture_input_channels),
843 LayoutFromChannels(num_capture_output_channels),
844 LayoutFromChannels(num_render_channels)));
ajm@google.com808e0e02011-08-03 21:08:51 +0000845
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000846 far_frame.sample_rate_hz_ = sample_rate_hz;
847 far_frame.samples_per_channel_ = samples_per_channel;
848 far_frame.num_channels_ = num_render_channels;
849 near_frame.sample_rate_hz_ = sample_rate_hz;
850 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000851
852 if (verbose) {
853 printf("Init at frame: %d (primary), %d (reverse)\n",
854 primary_count, reverse_count);
855 printf(" Sample rate: %d Hz\n", sample_rate_hz);
856 }
857
858 } else if (event == kRenderEvent) {
859 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000860
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000861 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000862 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000863 sizeof(int16_t),
864 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000865 far_file);
866
867 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000868 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000869 // Read an equal amount from the near file to avoid errors due to
870 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000871 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000872 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000873 break; // This is expected.
874 }
875 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000876 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000877 }
878
879 if (perf_testing) {
880 t0 = TickTime::Now();
881 }
882
883 ASSERT_EQ(apm->kNoError,
884 apm->AnalyzeReverseStream(&far_frame));
885
886 if (perf_testing) {
887 t1 = TickTime::Now();
888 TickInterval tick_diff = t1 - t0;
889 acc_ticks += tick_diff;
890 if (tick_diff.Microseconds() > max_time_reverse_us) {
891 max_time_reverse_us = tick_diff.Microseconds();
892 }
893 if (tick_diff.Microseconds() < min_time_reverse_us) {
894 min_time_reverse_us = tick_diff.Microseconds();
895 }
896 }
897
898 } else if (event == kCaptureEvent) {
899 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000900 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000901
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000902 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000903 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000904 sizeof(int16_t),
905 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000906 near_file);
907
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000908 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000909 if (progress && primary_count % 100 == 0) {
910 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000911 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000912 fflush(stdout);
913 }
914 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000915 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000916 break; // This is expected.
917 }
918
919 delay_ms = 0;
920 drift_samples = 0;
921 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000922 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000923
924 // TODO(ajm): sizeof(delay_ms) for current files?
925 ASSERT_EQ(1u,
926 fread(&delay_ms, 2, 1, delay_file));
927 ASSERT_EQ(1u,
928 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
929 }
930
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000931 if (apm->gain_control()->is_enabled() &&
932 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000933 SimulateMic(capture_level, &near_frame);
934 }
935
ajm@google.com808e0e02011-08-03 21:08:51 +0000936 if (perf_testing) {
937 t0 = TickTime::Now();
938 }
939
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000940 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000941 ASSERT_EQ(apm->kNoError,
942 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000943 delay_ms += extra_delay_ms;
944 if (override_delay_ms) {
945 delay_ms = override_delay_ms;
946 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000947 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000948 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000949 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000950
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000951 apm->set_stream_key_pressed(true);
952
ajm@google.com808e0e02011-08-03 21:08:51 +0000953 int err = apm->ProcessStream(&near_frame);
954 if (err == apm->kBadStreamParameterWarning) {
955 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
956 }
957 ASSERT_TRUE(err == apm->kNoError ||
958 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000959 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000960
961 capture_level = apm->gain_control()->stream_analog_level();
962
963 stream_has_voice =
964 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
965 if (vad_out_file != NULL) {
966 ASSERT_EQ(1u, fwrite(&stream_has_voice,
967 sizeof(stream_has_voice),
968 1,
969 vad_out_file));
970 }
971
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000972 if (ns_prob_file != NULL) {
973 ns_speech_prob = apm->noise_suppression()->speech_probability();
974 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
975 sizeof(ns_speech_prob),
976 1,
977 ns_prob_file));
978 }
979
ajm@google.com808e0e02011-08-03 21:08:51 +0000980 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
981 ASSERT_EQ(capture_level_in, capture_level);
982 }
983
984 if (perf_testing) {
985 t1 = TickTime::Now();
986 TickInterval tick_diff = t1 - t0;
987 acc_ticks += tick_diff;
988 if (tick_diff.Microseconds() > max_time_us) {
989 max_time_us = tick_diff.Microseconds();
990 }
991 if (tick_diff.Microseconds() < min_time_us) {
992 min_time_us = tick_diff.Microseconds();
993 }
994 }
995
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000996 size = samples_per_channel * near_frame.num_channels_;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000997 static FILE* out_file = OpenFile(out_filename, "wb");
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000998 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000999 sizeof(int16_t),
1000 size,
1001 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 }
ajm@google.com808e0e02011-08-03 21:08:51 +00001003 else {
1004 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 }
1007 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001008 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001009
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001010 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001011 const size_t path_size =
1012 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org8f693302014-04-25 23:10:28 +00001013 scoped_ptr<char[]> echo_path(new char[path_size]);
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001014 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1015 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1016 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001017 path_size,
1018 aecm_echo_path_out_file));
1019 fclose(aecm_echo_path_out_file);
1020 aecm_echo_path_out_file = NULL;
1021 }
1022
niklase@google.com470e71d2011-07-07 08:21:25 +00001023 if (verbose) {
1024 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1025 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001026
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001027 if (apm->level_estimator()->is_enabled()) {
1028 printf("\n--Level metrics--\n");
1029 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1030 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001031 if (apm->echo_cancellation()->are_metrics_enabled()) {
1032 EchoCancellation::Metrics metrics;
1033 apm->echo_cancellation()->GetMetrics(&metrics);
1034 printf("\n--Echo metrics--\n");
1035 printf("(avg, max, min)\n");
1036 printf("ERL: ");
1037 PrintStat(metrics.echo_return_loss);
1038 printf("ERLE: ");
1039 PrintStat(metrics.echo_return_loss_enhancement);
1040 printf("ANLP: ");
1041 PrintStat(metrics.a_nlp);
1042 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001043 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1044 int median = 0;
1045 int std = 0;
1046 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1047 printf("\n--Delay metrics--\n");
1048 printf("Median: %3d\n", median);
1049 printf("Standard deviation: %3d\n", std);
1050 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 }
1052
ajm@google.com808e0e02011-08-03 21:08:51 +00001053 if (!pb_file) {
1054 int8_t temp_int8;
1055 if (far_file) {
1056 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1057 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1058 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001059
ajm@google.com808e0e02011-08-03 21:08:51 +00001060 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1061 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1062
1063 if (!simulating) {
1064 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1065 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1066 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1067 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1068 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1069 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1070 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 }
1072
1073 if (perf_testing) {
1074 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001075 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001076 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1077 exec_time * 0.001, primary_count * 0.01);
1078 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1079 " %.3f ms (min)\n",
1080 (exec_time * 1.0) / primary_count,
1081 (max_time_us + max_time_reverse_us) / 1000.0,
1082 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001083 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001084 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001085 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 } else {
1087 printf("Warning: no capture frames\n");
1088 }
1089 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001090}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001091
ajm@google.com808e0e02011-08-03 21:08:51 +00001092} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001093} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001094
1095int main(int argc, char* argv[])
1096{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001097 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001098
andrew@webrtc.org64235092011-08-19 21:22:08 +00001099 // Optional, but removes memory leak noise from Valgrind.
1100 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001101 return 0;
1102}