blob: 2f02727f8e78141ee2afcb69afe37366d8382934 [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");
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +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.orga8b97372014-03-10 22:26:12 +0000145 Config config;
146 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
147 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create(config));
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000148 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
ajm@google.com808e0e02011-08-03 21:08:51 +0000150 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 const char* far_filename = NULL;
152 const char* near_filename = NULL;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000153 std::string out_filename;
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000155 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000156 const char* aecm_echo_path_in_filename = NULL;
157 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159 int32_t sample_rate_hz = 16000;
160 int32_t device_sample_rate_hz = 16000;
161
162 int num_capture_input_channels = 1;
163 int num_capture_output_channels = 1;
164 int num_render_channels = 1;
165
166 int samples_per_channel = sample_rate_hz / 100;
167
168 bool simulating = false;
169 bool perf_testing = false;
170 bool verbose = true;
171 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000172 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000173 int override_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000175 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000177 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000178 i++;
179 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
180 pb_filename = argv[i];
181
182 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 i++;
184 ASSERT_LT(i, argc) << "Specify filename after -ir";
185 far_filename = argv[i];
186 simulating = true;
187
188 } else if (strcmp(argv[i], "-i") == 0) {
189 i++;
190 ASSERT_LT(i, argc) << "Specify filename after -i";
191 near_filename = argv[i];
192 simulating = true;
193
194 } else if (strcmp(argv[i], "-o") == 0) {
195 i++;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000196 ASSERT_LT(i, argc) << "Specify filename without extension after -o";
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 out_filename = argv[i];
198
199 } else if (strcmp(argv[i], "-fs") == 0) {
200 i++;
201 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
202 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
203 samples_per_channel = sample_rate_hz / 100;
204
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 } else if (strcmp(argv[i], "-ch") == 0) {
206 i++;
207 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
208 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
209 i++;
210 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
211
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 } else if (strcmp(argv[i], "-rch") == 0) {
213 i++;
214 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
215 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
216
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 } else if (strcmp(argv[i], "-aec") == 0) {
218 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000219 ASSERT_EQ(apm->kNoError,
220 apm->echo_cancellation()->enable_metrics(true));
221 ASSERT_EQ(apm->kNoError,
222 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000223
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
225 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
226 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
227 // why it can give better performance despite passing zeros.
228 ASSERT_EQ(apm->kNoError,
229 apm->echo_cancellation()->enable_drift_compensation(true));
230 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
231 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
232 ASSERT_EQ(apm->kNoError,
233 apm->echo_cancellation()->enable_drift_compensation(false));
234
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000235 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
236 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
237 ASSERT_EQ(apm->kNoError,
238 apm->echo_cancellation()->enable_metrics(false));
239
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000240 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
241 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
242 ASSERT_EQ(apm->kNoError,
243 apm->echo_cancellation()->enable_delay_logging(false));
244
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000245 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
246 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
247
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000248 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
249 i++;
250 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
251 int suppression_level;
252 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
253 ASSERT_EQ(apm->kNoError,
254 apm->echo_cancellation()->set_suppression_level(
255 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
256 suppression_level)));
257
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000258 } else if (strcmp(argv[i], "--extended_filter") == 0) {
259 Config config;
260 config.Set<DelayCorrection>(new DelayCorrection(true));
261 apm->SetExtraOptions(config);
262
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 } else if (strcmp(argv[i], "-aecm") == 0) {
264 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
265
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000266 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
267 i++;
268 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
269 aecm_echo_path_in_filename = argv[i];
270
271 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
272 i++;
273 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
274 aecm_echo_path_out_filename = argv[i];
275
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000276 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
277 ASSERT_EQ(apm->kNoError,
278 apm->echo_control_mobile()->enable_comfort_noise(false));
279
280 } else if (strcmp(argv[i], "--routing_mode") == 0) {
281 i++;
282 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
283 int routing_mode;
284 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
285 ASSERT_EQ(apm->kNoError,
286 apm->echo_control_mobile()->set_routing_mode(
287 static_cast<webrtc::EchoControlMobile::RoutingMode>(
288 routing_mode)));
289
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 } else if (strcmp(argv[i], "-agc") == 0) {
291 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
292
293 } else if (strcmp(argv[i], "--analog") == 0) {
294 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
295 ASSERT_EQ(apm->kNoError,
296 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
297
298 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
299 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
300 ASSERT_EQ(apm->kNoError,
301 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
302
303 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
304 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
305 ASSERT_EQ(apm->kNoError,
306 apm->gain_control()->set_mode(GainControl::kFixedDigital));
307
308 } else if (strcmp(argv[i], "--target_level") == 0) {
309 i++;
310 int level;
311 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
312
313 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
314 ASSERT_EQ(apm->kNoError,
315 apm->gain_control()->set_target_level_dbfs(level));
316
317 } else if (strcmp(argv[i], "--compression_gain") == 0) {
318 i++;
319 int gain;
320 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
321
322 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
323 ASSERT_EQ(apm->kNoError,
324 apm->gain_control()->set_compression_gain_db(gain));
325
326 } else if (strcmp(argv[i], "--limiter") == 0) {
327 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
328 ASSERT_EQ(apm->kNoError,
329 apm->gain_control()->enable_limiter(true));
330
331 } else if (strcmp(argv[i], "--no_limiter") == 0) {
332 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
333 ASSERT_EQ(apm->kNoError,
334 apm->gain_control()->enable_limiter(false));
335
336 } else if (strcmp(argv[i], "-hpf") == 0) {
337 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
338
339 } else if (strcmp(argv[i], "-ns") == 0) {
340 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
341
342 } else if (strcmp(argv[i], "--ns_low") == 0) {
343 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
344 ASSERT_EQ(apm->kNoError,
345 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
346
347 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
348 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
349 ASSERT_EQ(apm->kNoError,
350 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
351
352 } else if (strcmp(argv[i], "--ns_high") == 0) {
353 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
354 ASSERT_EQ(apm->kNoError,
355 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
356
357 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
358 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
359 ASSERT_EQ(apm->kNoError,
360 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
361
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000362 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
363 i++;
364 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
365 ns_prob_filename = argv[i];
366
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 } else if (strcmp(argv[i], "-vad") == 0) {
368 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
369
andrew@webrtc.org89752612012-10-12 16:41:45 +0000370 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
371 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
372 ASSERT_EQ(apm->kNoError,
373 apm->voice_detection()->set_likelihood(
374 VoiceDetection::kVeryLowLikelihood));
375
376 } else if (strcmp(argv[i], "--vad_low") == 0) {
377 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
378 ASSERT_EQ(apm->kNoError,
379 apm->voice_detection()->set_likelihood(
380 VoiceDetection::kLowLikelihood));
381
382 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
383 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
384 ASSERT_EQ(apm->kNoError,
385 apm->voice_detection()->set_likelihood(
386 VoiceDetection::kModerateLikelihood));
387
388 } else if (strcmp(argv[i], "--vad_high") == 0) {
389 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
390 ASSERT_EQ(apm->kNoError,
391 apm->voice_detection()->set_likelihood(
392 VoiceDetection::kHighLikelihood));
393
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
395 i++;
396 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
397 vad_out_filename = argv[i];
398
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000399 } else if (strcmp(argv[i], "-expns") == 0) {
400 ASSERT_EQ(apm->kNoError, apm->EnableExperimentalNs(true));
401
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000402 } else if (strcmp(argv[i], "--noasm") == 0) {
403 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
404 // We need to reinitialize here if components have already been enabled.
405 ASSERT_EQ(apm->kNoError, apm->Initialize());
406
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000407 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000408 i++;
409 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
410
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000411 } else if (strcmp(argv[i], "--delay") == 0) {
412 i++;
413 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
414
niklase@google.com470e71d2011-07-07 08:21:25 +0000415 } else if (strcmp(argv[i], "--perf") == 0) {
416 perf_testing = true;
417
418 } else if (strcmp(argv[i], "--quiet") == 0) {
419 verbose = false;
420 progress = false;
421
422 } else if (strcmp(argv[i], "--no_progress") == 0) {
423 progress = false;
424
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000425 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000426 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000427 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000428 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 } else {
430 FAIL() << "Unrecognized argument " << argv[i];
431 }
432 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000433 // If we're reading a protobuf file, ensure a simulation hasn't also
434 // been requested (which makes no sense...)
435 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000436
437 if (verbose) {
438 printf("Sample rate: %d Hz\n", sample_rate_hz);
439 printf("Primary channels: %d (in), %d (out)\n",
440 num_capture_input_channels,
441 num_capture_output_channels);
442 printf("Reverse channels: %d \n", num_render_channels);
443 }
444
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000445 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 const char far_file_default[] = "apm_far.pcm";
447 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000448 const char event_filename[] = "apm_event.dat";
449 const char delay_filename[] = "apm_delay.dat";
450 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000451 const std::string vad_file_default = out_path + "vad_out.dat";
452 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000453
454 if (!simulating) {
455 far_filename = far_file_default;
456 near_filename = near_file_default;
457 }
458
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000459 if (out_filename.size() == 0) {
460 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000461 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000462 std::string out_float_filename = out_filename + ".float";
463 out_filename += ".pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000464
ajm@google.com808e0e02011-08-03 21:08:51 +0000465 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000466 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 }
468
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000469 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000470 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000471 }
472
ajm@google.com808e0e02011-08-03 21:08:51 +0000473 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000474 FILE* far_file = NULL;
475 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 FILE* event_file = NULL;
477 FILE* delay_file = NULL;
478 FILE* drift_file = NULL;
479 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000480 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000481 FILE* aecm_echo_path_in_file = NULL;
482 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000483
ajm@google.com808e0e02011-08-03 21:08:51 +0000484 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000485 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000486 } else {
487 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000488 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000489 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000490
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000491 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000492 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000493 event_file = OpenFile(event_filename, "rb");
494 delay_file = OpenFile(delay_filename, "rb");
495 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000496 }
497 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000498
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000499 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000500 if (pb_file) {
501 struct stat st;
502 stat(pb_filename, &st);
503 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000504 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000505 } else {
506 struct stat st;
507 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000508 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000509 }
510
511 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000512 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000513 }
514
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000515 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000516 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000517 }
518
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000519 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000520 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000521
ajm@google.com22e65152011-07-18 18:03:01 +0000522 const size_t path_size =
523 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000524 scoped_array<char> echo_path(new char[path_size]);
525 ASSERT_EQ(path_size, fread(echo_path.get(),
526 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000527 path_size,
528 aecm_echo_path_in_file));
529 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000530 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
531 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000532 fclose(aecm_echo_path_in_file);
533 aecm_echo_path_in_file = NULL;
534 }
535
536 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000537 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000538 }
539
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 size_t read_count = 0;
541 int reverse_count = 0;
542 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000543 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 TickInterval acc_ticks;
545
546 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000547 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000548
549 int delay_ms = 0;
550 int drift_samples = 0;
551 int capture_level = 127;
552 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000553 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000554
555 TickTime t0 = TickTime::Now();
556 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000557 int64_t max_time_us = 0;
558 int64_t max_time_reverse_us = 0;
559 int64_t min_time_us = 1e6;
560 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000561
ajm@google.com808e0e02011-08-03 21:08:51 +0000562 // TODO(ajm): Ideally we would refactor this block into separate functions,
563 // but for now we want to share the variables.
564 if (pb_file) {
565 Event event_msg;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000566 scoped_ptr<ChannelBuffer<float> > reverse_cb;
567 scoped_ptr<ChannelBuffer<float> > primary_cb;
ajm@google.com808e0e02011-08-03 21:08:51 +0000568 while (ReadMessageFromFile(pb_file, &event_msg)) {
569 std::ostringstream trace_stream;
570 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
571 << primary_count << " (primary)";
572 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000573
ajm@google.com808e0e02011-08-03 21:08:51 +0000574 if (event_msg.type() == Event::INIT) {
575 ASSERT_TRUE(event_msg.has_init());
576 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000577
ajm@google.com808e0e02011-08-03 21:08:51 +0000578 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000579 ASSERT_TRUE(msg.has_num_input_channels());
580 ASSERT_TRUE(msg.has_num_output_channels());
581 ASSERT_TRUE(msg.has_num_reverse_channels());
582 int reverse_sample_rate = msg.sample_rate();
583 if (msg.has_reverse_sample_rate())
584 reverse_sample_rate = msg.reverse_sample_rate();
585 ASSERT_EQ(apm->kNoError, apm->Initialize(msg.sample_rate(),
586 reverse_sample_rate,
587 msg.num_input_channels(),
588 msg.num_output_channels(),
589 msg.num_reverse_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000590 ASSERT_TRUE(msg.has_device_sample_rate());
591 ASSERT_EQ(apm->kNoError,
592 apm->echo_cancellation()->set_device_sample_rate_hz(
593 msg.device_sample_rate()));
594
ajm@google.com808e0e02011-08-03 21:08:51 +0000595
596 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000597 far_frame.sample_rate_hz_ = msg.sample_rate();
598 far_frame.samples_per_channel_ = samples_per_channel;
599 far_frame.num_channels_ = msg.num_reverse_channels();
600 near_frame.sample_rate_hz_ = msg.sample_rate();
601 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000602 near_frame.num_channels_ = msg.num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000603 reverse_cb.reset(new ChannelBuffer<float>(samples_per_channel,
604 msg.num_reverse_channels()));
605 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
606 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000607
608 if (verbose) {
609 printf("Init at frame: %d (primary), %d (reverse)\n",
610 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000611 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000612 printf(" Primary channels: %d (in), %d (out)\n",
613 msg.num_input_channels(),
614 msg.num_output_channels());
615 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000616 }
617
618 } else if (event_msg.type() == Event::REVERSE_STREAM) {
619 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000620 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000621 reverse_count++;
622
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000623 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
624 if (msg.has_data()) {
625 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
626 far_frame.num_channels_, msg.data().size());
627 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
628 } else {
629 for (int i = 0; i < msg.channel_size(); ++i) {
630 reverse_cb->CopyFrom(msg.channel(i).data(), i);
631 }
632 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000633
634 if (perf_testing) {
635 t0 = TickTime::Now();
636 }
637
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000638 if (msg.has_data()) {
639 ASSERT_EQ(apm->kNoError,
640 apm->AnalyzeReverseStream(&far_frame));
641 } else {
642 ASSERT_EQ(apm->kNoError,
643 apm->AnalyzeReverseStream(
644 reverse_cb->channels(),
645 far_frame.samples_per_channel_,
646 far_frame.sample_rate_hz_,
647 LayoutFromChannels(far_frame.num_channels_)));
648 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000649
650 if (perf_testing) {
651 t1 = TickTime::Now();
652 TickInterval tick_diff = t1 - t0;
653 acc_ticks += tick_diff;
654 if (tick_diff.Microseconds() > max_time_reverse_us) {
655 max_time_reverse_us = tick_diff.Microseconds();
656 }
657 if (tick_diff.Microseconds() < min_time_reverse_us) {
658 min_time_reverse_us = tick_diff.Microseconds();
659 }
660 }
661
662 } else if (event_msg.type() == Event::STREAM) {
663 ASSERT_TRUE(event_msg.has_stream());
664 const Stream msg = event_msg.stream();
665 primary_count++;
666
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000667 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000668 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000669
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000670 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
671 if (msg.has_input_data()) {
672 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
673 near_frame.num_channels_, msg.input_data().size());
674 memcpy(near_frame.data_,
675 msg.input_data().data(),
676 msg.input_data().size());
677 } else {
678 for (int i = 0; i < msg.input_channel_size(); ++i) {
679 primary_cb->CopyFrom(msg.input_channel(i).data(), i);
680 }
681 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000682
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000683 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000684 if (progress && primary_count % 100 == 0) {
685 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000686 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000687 fflush(stdout);
688 }
689
690 if (perf_testing) {
691 t0 = TickTime::Now();
692 }
693
694 ASSERT_EQ(apm->kNoError,
695 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000696 delay_ms = msg.delay() + extra_delay_ms;
697 if (override_delay_ms) {
698 delay_ms = override_delay_ms;
699 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000700 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000701 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000702 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000703
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000704 if (msg.has_keypress()) {
705 apm->set_stream_key_pressed(msg.keypress());
706 } else {
707 apm->set_stream_key_pressed(true);
708 }
709
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000710 int err = apm->kNoError;
711 if (msg.has_input_data()) {
712 err = apm->ProcessStream(&near_frame);
713 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
714 } else {
715 err = apm->ProcessStream(
716 primary_cb->channels(),
717 near_frame.samples_per_channel_,
718 near_frame.sample_rate_hz_,
719 LayoutFromChannels(near_frame.num_channels_),
720 LayoutFromChannels(apm->num_output_channels()));
721 }
722
ajm@google.com808e0e02011-08-03 21:08:51 +0000723 if (err == apm->kBadStreamParameterWarning) {
724 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
725 }
726 ASSERT_TRUE(err == apm->kNoError ||
727 err == apm->kBadStreamParameterWarning);
728
ajm@google.com808e0e02011-08-03 21:08:51 +0000729 stream_has_voice =
730 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
731 if (vad_out_file != NULL) {
732 ASSERT_EQ(1u, fwrite(&stream_has_voice,
733 sizeof(stream_has_voice),
734 1,
735 vad_out_file));
736 }
737
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000738 if (ns_prob_file != NULL) {
739 ns_speech_prob = apm->noise_suppression()->speech_probability();
740 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
741 sizeof(ns_speech_prob),
742 1,
743 ns_prob_file));
744 }
745
ajm@google.com808e0e02011-08-03 21:08:51 +0000746 if (perf_testing) {
747 t1 = TickTime::Now();
748 TickInterval tick_diff = t1 - t0;
749 acc_ticks += tick_diff;
750 if (tick_diff.Microseconds() > max_time_us) {
751 max_time_us = tick_diff.Microseconds();
752 }
753 if (tick_diff.Microseconds() < min_time_us) {
754 min_time_us = tick_diff.Microseconds();
755 }
756 }
757
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000758 size_t num_samples = samples_per_channel * apm->num_output_channels();
759 if (msg.has_input_data()) {
760 static FILE* out_file = OpenFile(out_filename, "wb");
761 ASSERT_EQ(num_samples, fwrite(near_frame.data_,
762 sizeof(*near_frame.data_),
763 num_samples,
764 out_file));
765 } else {
766 static FILE* out_float_file = OpenFile(out_float_filename, "wb");
767 ASSERT_EQ(num_samples, fwrite(primary_cb->data(),
768 sizeof(*primary_cb->data()),
769 num_samples,
770 out_float_file));
771 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000772 }
773 }
774
775 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000776
777 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000778 enum Events {
779 kInitializeEvent,
780 kRenderEvent,
781 kCaptureEvent,
782 kResetEventDeprecated
783 };
784 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000785 while (simulating || feof(event_file) == 0) {
786 std::ostringstream trace_stream;
787 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
788 << primary_count << " (primary)";
789 SCOPED_TRACE(trace_stream.str());
790
791 if (simulating) {
792 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000793 event = kCaptureEvent;
794 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000795 if (event == kRenderEvent) {
796 event = kCaptureEvent;
797 } else {
798 event = kRenderEvent;
799 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000800 }
801 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000802 read_count = fread(&event, sizeof(event), 1, event_file);
803 if (read_count != 1) {
804 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000805 }
806 }
807
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000808 far_frame.sample_rate_hz_ = sample_rate_hz;
809 far_frame.samples_per_channel_ = samples_per_channel;
810 far_frame.num_channels_ = num_render_channels;
811 near_frame.sample_rate_hz_ = sample_rate_hz;
812 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000813
ajm@google.com808e0e02011-08-03 21:08:51 +0000814 if (event == kInitializeEvent || event == kResetEventDeprecated) {
815 ASSERT_EQ(1u,
816 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
817 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000818
ajm@google.com808e0e02011-08-03 21:08:51 +0000819 ASSERT_EQ(1u,
820 fread(&device_sample_rate_hz,
821 sizeof(device_sample_rate_hz),
822 1,
823 event_file));
824
bjornv@webrtc.org6a947342014-01-16 08:41:09 +0000825 // TODO(bjornv): Replace set_sample_rate_hz() when we have a smarter
826 // AnalyzeReverseStream().
827 ASSERT_EQ(apm->kNoError, apm->set_sample_rate_hz(sample_rate_hz));
828
ajm@google.com808e0e02011-08-03 21:08:51 +0000829 ASSERT_EQ(apm->kNoError,
ajm@google.com808e0e02011-08-03 21:08:51 +0000830 apm->echo_cancellation()->set_device_sample_rate_hz(
831 device_sample_rate_hz));
832
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000833 far_frame.sample_rate_hz_ = sample_rate_hz;
834 far_frame.samples_per_channel_ = samples_per_channel;
835 far_frame.num_channels_ = num_render_channels;
836 near_frame.sample_rate_hz_ = sample_rate_hz;
837 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000838
839 if (verbose) {
840 printf("Init at frame: %d (primary), %d (reverse)\n",
841 primary_count, reverse_count);
842 printf(" Sample rate: %d Hz\n", sample_rate_hz);
843 }
844
845 } else if (event == kRenderEvent) {
846 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000847
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000848 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000849 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000850 sizeof(int16_t),
851 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000852 far_file);
853
854 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000855 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000856 // Read an equal amount from the near file to avoid errors due to
857 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000858 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000859 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000860 break; // This is expected.
861 }
862 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000863 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000864 }
865
866 if (perf_testing) {
867 t0 = TickTime::Now();
868 }
869
870 ASSERT_EQ(apm->kNoError,
871 apm->AnalyzeReverseStream(&far_frame));
872
873 if (perf_testing) {
874 t1 = TickTime::Now();
875 TickInterval tick_diff = t1 - t0;
876 acc_ticks += tick_diff;
877 if (tick_diff.Microseconds() > max_time_reverse_us) {
878 max_time_reverse_us = tick_diff.Microseconds();
879 }
880 if (tick_diff.Microseconds() < min_time_reverse_us) {
881 min_time_reverse_us = tick_diff.Microseconds();
882 }
883 }
884
885 } else if (event == kCaptureEvent) {
886 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000887 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000888
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000889 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000890 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000891 sizeof(int16_t),
892 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000893 near_file);
894
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000895 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000896 if (progress && primary_count % 100 == 0) {
897 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000898 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000899 fflush(stdout);
900 }
901 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000902 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000903 break; // This is expected.
904 }
905
906 delay_ms = 0;
907 drift_samples = 0;
908 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000909 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000910
911 // TODO(ajm): sizeof(delay_ms) for current files?
912 ASSERT_EQ(1u,
913 fread(&delay_ms, 2, 1, delay_file));
914 ASSERT_EQ(1u,
915 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
916 }
917
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000918 if (apm->gain_control()->is_enabled() &&
919 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000920 SimulateMic(capture_level, &near_frame);
921 }
922
ajm@google.com808e0e02011-08-03 21:08:51 +0000923 if (perf_testing) {
924 t0 = TickTime::Now();
925 }
926
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000927 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000928 ASSERT_EQ(apm->kNoError,
929 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000930 delay_ms += extra_delay_ms;
931 if (override_delay_ms) {
932 delay_ms = override_delay_ms;
933 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000934 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000935 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000936 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000937
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000938 apm->set_stream_key_pressed(true);
939
ajm@google.com808e0e02011-08-03 21:08:51 +0000940 int err = apm->ProcessStream(&near_frame);
941 if (err == apm->kBadStreamParameterWarning) {
942 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
943 }
944 ASSERT_TRUE(err == apm->kNoError ||
945 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000946 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000947
948 capture_level = apm->gain_control()->stream_analog_level();
949
950 stream_has_voice =
951 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
952 if (vad_out_file != NULL) {
953 ASSERT_EQ(1u, fwrite(&stream_has_voice,
954 sizeof(stream_has_voice),
955 1,
956 vad_out_file));
957 }
958
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000959 if (ns_prob_file != NULL) {
960 ns_speech_prob = apm->noise_suppression()->speech_probability();
961 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
962 sizeof(ns_speech_prob),
963 1,
964 ns_prob_file));
965 }
966
ajm@google.com808e0e02011-08-03 21:08:51 +0000967 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
968 ASSERT_EQ(capture_level_in, capture_level);
969 }
970
971 if (perf_testing) {
972 t1 = TickTime::Now();
973 TickInterval tick_diff = t1 - t0;
974 acc_ticks += tick_diff;
975 if (tick_diff.Microseconds() > max_time_us) {
976 max_time_us = tick_diff.Microseconds();
977 }
978 if (tick_diff.Microseconds() < min_time_us) {
979 min_time_us = tick_diff.Microseconds();
980 }
981 }
982
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000983 size = samples_per_channel * near_frame.num_channels_;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000984 static FILE* out_file = OpenFile(out_filename, "wb");
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000985 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000986 sizeof(int16_t),
987 size,
988 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000989 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000990 else {
991 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 }
994 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000995 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000996
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000997 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000998 const size_t path_size =
999 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001000 scoped_array<char> echo_path(new char[path_size]);
1001 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1002 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1003 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001004 path_size,
1005 aecm_echo_path_out_file));
1006 fclose(aecm_echo_path_out_file);
1007 aecm_echo_path_out_file = NULL;
1008 }
1009
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 if (verbose) {
1011 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1012 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001013
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001014 if (apm->level_estimator()->is_enabled()) {
1015 printf("\n--Level metrics--\n");
1016 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1017 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001018 if (apm->echo_cancellation()->are_metrics_enabled()) {
1019 EchoCancellation::Metrics metrics;
1020 apm->echo_cancellation()->GetMetrics(&metrics);
1021 printf("\n--Echo metrics--\n");
1022 printf("(avg, max, min)\n");
1023 printf("ERL: ");
1024 PrintStat(metrics.echo_return_loss);
1025 printf("ERLE: ");
1026 PrintStat(metrics.echo_return_loss_enhancement);
1027 printf("ANLP: ");
1028 PrintStat(metrics.a_nlp);
1029 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001030 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1031 int median = 0;
1032 int std = 0;
1033 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1034 printf("\n--Delay metrics--\n");
1035 printf("Median: %3d\n", median);
1036 printf("Standard deviation: %3d\n", std);
1037 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 }
1039
ajm@google.com808e0e02011-08-03 21:08:51 +00001040 if (!pb_file) {
1041 int8_t temp_int8;
1042 if (far_file) {
1043 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1044 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1045 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001046
ajm@google.com808e0e02011-08-03 21:08:51 +00001047 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1048 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1049
1050 if (!simulating) {
1051 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1052 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1053 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1054 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1055 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1056 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1057 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001058 }
1059
1060 if (perf_testing) {
1061 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001062 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001063 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1064 exec_time * 0.001, primary_count * 0.01);
1065 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1066 " %.3f ms (min)\n",
1067 (exec_time * 1.0) / primary_count,
1068 (max_time_us + max_time_reverse_us) / 1000.0,
1069 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001070 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001071 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001072 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 } else {
1074 printf("Warning: no capture frames\n");
1075 }
1076 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001077}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001078
ajm@google.com808e0e02011-08-03 21:08:51 +00001079} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001080} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001081
1082int main(int argc, char* argv[])
1083{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001084 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001085
andrew@webrtc.org64235092011-08-19 21:22:08 +00001086 // Optional, but removes memory leak noise from Valgrind.
1087 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 return 0;
1089}