blob: 2d7c065f903933e740cb4ba2ff2ee9712d2f2b05 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
leozwang@webrtc.org9a85d8e2012-03-16 18:03:18 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
andrew@webrtc.org81865342012-10-27 00:28:27 +000011#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000012#include <stdio.h>
13#include <string.h>
14#ifdef WEBRTC_ANDROID
15#include <sys/stat.h>
16#endif
17
andrew@webrtc.org81865342012-10-27 00:28:27 +000018#include <algorithm>
19
andrew@webrtc.org22858d42013-10-23 14:07:17 +000020#include "webrtc/common.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000021#include "webrtc/modules/audio_processing/include/audio_processing.h"
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000022#include "webrtc/modules/audio_processing/test/test_utils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000023#include "webrtc/modules/interface/module_common_types.h"
24#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
25#include "webrtc/system_wrappers/interface/scoped_ptr.h"
26#include "webrtc/system_wrappers/interface/tick_util.h"
kjellander@webrtc.org10abe252012-12-17 18:28:07 +000027#include "webrtc/test/testsupport/fileutils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000028#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000029#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000030#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000031#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000032#else
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000033#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:51 +000034#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000035#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000036
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000037namespace webrtc {
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000038
ajm@google.com808e0e02011-08-03 21:08:51 +000039using webrtc::audioproc::Event;
40using webrtc::audioproc::Init;
41using webrtc::audioproc::ReverseStream;
42using webrtc::audioproc::Stream;
43
44namespace {
niklase@google.com470e71d2011-07-07 08:21:25 +000045
andrew@webrtc.org94c74132011-09-19 15:17:57 +000046void PrintStat(const AudioProcessing::Statistic& stat) {
47 printf("%d, %d, %d\n", stat.average,
48 stat.maximum,
49 stat.minimum);
50}
51
niklase@google.com470e71d2011-07-07 08:21:25 +000052void usage() {
53 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000054 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
55 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000056 printf(
57 "process_test is a test application for AudioProcessing.\n\n"
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000058 "When a protobuf debug file is available, specify it with -pb. Alternately,\n"
59 "when -ir or -i is used, the specified files will be processed directly in\n"
60 "a simulation mode. Otherwise the full set of legacy test files is expected\n"
61 "to be present in the working directory. OUT_FILE should be specified\n"
62 "without extension to support both int and float output.\n\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000063 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000064 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000065 printf(" -fs SAMPLE_RATE_HZ\n");
66 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
67 printf(" -rch REVERSE_CHANNELS\n");
68 printf("\n");
69 printf("Component configuration:\n");
70 printf(
71 "All components are disabled by default. Each block below begins with a\n"
72 "flag to enable the component with default settings. The subsequent flags\n"
73 "in the block are used to provide configuration settings.\n");
74 printf("\n -aec Echo cancellation\n");
75 printf(" --drift_compensation\n");
76 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +000077 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +000078 printf(" --no_delay_logging\n");
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +000079 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
andrew@webrtc.org22858d42013-10-23 14:07:17 +000080 printf(" --extended_filter\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000081 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +000082 printf(" --aecm_echo_path_in_file FILE\n");
83 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +000084 printf(" --no_comfort_noise\n");
85 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000086 printf("\n -agc Gain control\n");
87 printf(" --analog\n");
88 printf(" --adaptive_digital\n");
89 printf(" --fixed_digital\n");
90 printf(" --target_level LEVEL\n");
91 printf(" --compression_gain GAIN\n");
92 printf(" --limiter\n");
93 printf(" --no_limiter\n");
94 printf("\n -hpf High pass filter\n");
95 printf("\n -ns Noise suppression\n");
96 printf(" --ns_low\n");
97 printf(" --ns_moderate\n");
98 printf(" --ns_high\n");
99 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000100 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000102 printf(" --vad_out_file FILE\n");
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000103 printf("\n -expns Experimental noise suppression\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000104 printf("\n Level metrics (enabled by default)\n");
105 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000106 printf("\n");
107 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000108 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000109 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
110 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000111 printf(" --perf Measure performance.\n");
112 printf(" --quiet Suppress text output.\n");
113 printf(" --no_progress Suppress progress.\n");
114 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000115}
116
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000117static float MicLevel2Gain(int level) {
118 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000119}
120
121static void SimulateMic(int mic_level, AudioFrame* frame) {
122 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000123 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000124 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000125 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000126 for (int n = 0; n < num_samples; n++) {
127 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000128 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000129 frame->data_[n] = static_cast<int16_t>(v);
130 }
131}
132
niklase@google.com470e71d2011-07-07 08:21:25 +0000133// void function for gtest.
134void void_main(int argc, char* argv[]) {
135 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
136 usage();
137 return;
138 }
139
140 if (argc < 2) {
141 printf("Did you mean to run without arguments?\n");
142 printf("Try `process_test --help' for more information.\n\n");
143 }
144
andrew@webrtc.orgb13a7d52014-03-27 00:11:11 +0000145 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create());
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000146 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
ajm@google.com808e0e02011-08-03 21:08:51 +0000148 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 const char* far_filename = NULL;
150 const char* near_filename = NULL;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000151 std::string out_filename;
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000153 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000154 const char* aecm_echo_path_in_filename = NULL;
155 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000156
157 int32_t sample_rate_hz = 16000;
158 int32_t device_sample_rate_hz = 16000;
159
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
niklase@google.com470e71d2011-07-07 08:21:25 +0000261 } else if (strcmp(argv[i], "-aecm") == 0) {
262 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
263
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000264 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
265 i++;
266 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
267 aecm_echo_path_in_filename = argv[i];
268
269 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
270 i++;
271 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
272 aecm_echo_path_out_filename = argv[i];
273
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000274 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
275 ASSERT_EQ(apm->kNoError,
276 apm->echo_control_mobile()->enable_comfort_noise(false));
277
278 } else if (strcmp(argv[i], "--routing_mode") == 0) {
279 i++;
280 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
281 int routing_mode;
282 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
283 ASSERT_EQ(apm->kNoError,
284 apm->echo_control_mobile()->set_routing_mode(
285 static_cast<webrtc::EchoControlMobile::RoutingMode>(
286 routing_mode)));
287
niklase@google.com470e71d2011-07-07 08:21:25 +0000288 } else if (strcmp(argv[i], "-agc") == 0) {
289 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
290
291 } else if (strcmp(argv[i], "--analog") == 0) {
292 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
293 ASSERT_EQ(apm->kNoError,
294 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
295
296 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
297 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
298 ASSERT_EQ(apm->kNoError,
299 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
300
301 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
302 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
303 ASSERT_EQ(apm->kNoError,
304 apm->gain_control()->set_mode(GainControl::kFixedDigital));
305
306 } else if (strcmp(argv[i], "--target_level") == 0) {
307 i++;
308 int level;
309 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
310
311 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
312 ASSERT_EQ(apm->kNoError,
313 apm->gain_control()->set_target_level_dbfs(level));
314
315 } else if (strcmp(argv[i], "--compression_gain") == 0) {
316 i++;
317 int gain;
318 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
319
320 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
321 ASSERT_EQ(apm->kNoError,
322 apm->gain_control()->set_compression_gain_db(gain));
323
324 } else if (strcmp(argv[i], "--limiter") == 0) {
325 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
326 ASSERT_EQ(apm->kNoError,
327 apm->gain_control()->enable_limiter(true));
328
329 } else if (strcmp(argv[i], "--no_limiter") == 0) {
330 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
331 ASSERT_EQ(apm->kNoError,
332 apm->gain_control()->enable_limiter(false));
333
334 } else if (strcmp(argv[i], "-hpf") == 0) {
335 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
336
337 } else if (strcmp(argv[i], "-ns") == 0) {
338 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
339
340 } else if (strcmp(argv[i], "--ns_low") == 0) {
341 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
342 ASSERT_EQ(apm->kNoError,
343 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
344
345 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
346 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
347 ASSERT_EQ(apm->kNoError,
348 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
349
350 } else if (strcmp(argv[i], "--ns_high") == 0) {
351 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
352 ASSERT_EQ(apm->kNoError,
353 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
354
355 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
356 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
357 ASSERT_EQ(apm->kNoError,
358 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
359
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000360 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
361 i++;
362 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
363 ns_prob_filename = argv[i];
364
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 } else if (strcmp(argv[i], "-vad") == 0) {
366 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
367
andrew@webrtc.org89752612012-10-12 16:41:45 +0000368 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
369 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
370 ASSERT_EQ(apm->kNoError,
371 apm->voice_detection()->set_likelihood(
372 VoiceDetection::kVeryLowLikelihood));
373
374 } else if (strcmp(argv[i], "--vad_low") == 0) {
375 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
376 ASSERT_EQ(apm->kNoError,
377 apm->voice_detection()->set_likelihood(
378 VoiceDetection::kLowLikelihood));
379
380 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
381 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
382 ASSERT_EQ(apm->kNoError,
383 apm->voice_detection()->set_likelihood(
384 VoiceDetection::kModerateLikelihood));
385
386 } else if (strcmp(argv[i], "--vad_high") == 0) {
387 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
388 ASSERT_EQ(apm->kNoError,
389 apm->voice_detection()->set_likelihood(
390 VoiceDetection::kHighLikelihood));
391
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
393 i++;
394 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
395 vad_out_filename = argv[i];
396
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000397 } else if (strcmp(argv[i], "-expns") == 0) {
398 ASSERT_EQ(apm->kNoError, apm->EnableExperimentalNs(true));
399
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000400 } else if (strcmp(argv[i], "--noasm") == 0) {
401 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
402 // We need to reinitialize here if components have already been enabled.
403 ASSERT_EQ(apm->kNoError, apm->Initialize());
404
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000405 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000406 i++;
407 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
408
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000409 } else if (strcmp(argv[i], "--delay") == 0) {
410 i++;
411 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
412
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 } else if (strcmp(argv[i], "--perf") == 0) {
414 perf_testing = true;
415
416 } else if (strcmp(argv[i], "--quiet") == 0) {
417 verbose = false;
418 progress = false;
419
420 } else if (strcmp(argv[i], "--no_progress") == 0) {
421 progress = false;
422
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000423 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000424 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000425 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000426 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000427 } else {
428 FAIL() << "Unrecognized argument " << argv[i];
429 }
430 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000431 // If we're reading a protobuf file, ensure a simulation hasn't also
432 // been requested (which makes no sense...)
433 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000434
435 if (verbose) {
436 printf("Sample rate: %d Hz\n", sample_rate_hz);
437 printf("Primary channels: %d (in), %d (out)\n",
438 num_capture_input_channels,
439 num_capture_output_channels);
440 printf("Reverse channels: %d \n", num_render_channels);
441 }
442
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000443 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 const char far_file_default[] = "apm_far.pcm";
445 const char near_file_default[] = "apm_near.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 const char event_filename[] = "apm_event.dat";
447 const char delay_filename[] = "apm_delay.dat";
448 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000449 const std::string vad_file_default = out_path + "vad_out.dat";
450 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000451
452 if (!simulating) {
453 far_filename = far_file_default;
454 near_filename = near_file_default;
455 }
456
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000457 if (out_filename.size() == 0) {
458 out_filename = out_path + "out";
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000460 std::string out_float_filename = out_filename + ".float";
461 out_filename += ".pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000462
ajm@google.com808e0e02011-08-03 21:08:51 +0000463 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000464 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 }
466
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000467 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000468 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000469 }
470
ajm@google.com808e0e02011-08-03 21:08:51 +0000471 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 FILE* far_file = NULL;
473 FILE* near_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000474 FILE* event_file = NULL;
475 FILE* delay_file = NULL;
476 FILE* drift_file = NULL;
477 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000478 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000479 FILE* aecm_echo_path_in_file = NULL;
480 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000481
ajm@google.com808e0e02011-08-03 21:08:51 +0000482 if (pb_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000483 pb_file = OpenFile(pb_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000484 } else {
485 if (far_filename) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000486 far_file = OpenFile(far_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000487 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000488
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000489 near_file = OpenFile(near_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000490 if (!simulating) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000491 event_file = OpenFile(event_filename, "rb");
492 delay_file = OpenFile(delay_filename, "rb");
493 drift_file = OpenFile(drift_filename, "rb");
ajm@google.com808e0e02011-08-03 21:08:51 +0000494 }
495 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000496
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000497 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000498 if (pb_file) {
499 struct stat st;
500 stat(pb_filename, &st);
501 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000502 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000503 } else {
504 struct stat st;
505 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000506 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000507 }
508
509 if (apm->voice_detection()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000510 vad_out_file = OpenFile(vad_out_filename, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 }
512
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000513 if (apm->noise_suppression()->is_enabled()) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000514 ns_prob_file = OpenFile(ns_prob_filename, "wb");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000515 }
516
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000517 if (aecm_echo_path_in_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000518 aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000519
ajm@google.com22e65152011-07-18 18:03:01 +0000520 const size_t path_size =
521 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000522 scoped_array<char> echo_path(new char[path_size]);
523 ASSERT_EQ(path_size, fread(echo_path.get(),
524 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000525 path_size,
526 aecm_echo_path_in_file));
527 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000528 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
529 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000530 fclose(aecm_echo_path_in_file);
531 aecm_echo_path_in_file = NULL;
532 }
533
534 if (aecm_echo_path_out_filename != NULL) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000535 aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb");
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000536 }
537
niklase@google.com470e71d2011-07-07 08:21:25 +0000538 size_t read_count = 0;
539 int reverse_count = 0;
540 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000541 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 TickInterval acc_ticks;
543
544 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000545 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000546
547 int delay_ms = 0;
548 int drift_samples = 0;
549 int capture_level = 127;
550 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000551 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552
553 TickTime t0 = TickTime::Now();
554 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000555 int64_t max_time_us = 0;
556 int64_t max_time_reverse_us = 0;
557 int64_t min_time_us = 1e6;
558 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559
ajm@google.com808e0e02011-08-03 21:08:51 +0000560 // TODO(ajm): Ideally we would refactor this block into separate functions,
561 // but for now we want to share the variables.
562 if (pb_file) {
563 Event event_msg;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000564 scoped_ptr<ChannelBuffer<float> > reverse_cb;
565 scoped_ptr<ChannelBuffer<float> > primary_cb;
ajm@google.com808e0e02011-08-03 21:08:51 +0000566 while (ReadMessageFromFile(pb_file, &event_msg)) {
567 std::ostringstream trace_stream;
568 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
569 << primary_count << " (primary)";
570 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000571
ajm@google.com808e0e02011-08-03 21:08:51 +0000572 if (event_msg.type() == Event::INIT) {
573 ASSERT_TRUE(event_msg.has_init());
574 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000575
ajm@google.com808e0e02011-08-03 21:08:51 +0000576 ASSERT_TRUE(msg.has_sample_rate());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000577 ASSERT_TRUE(msg.has_num_input_channels());
578 ASSERT_TRUE(msg.has_num_output_channels());
579 ASSERT_TRUE(msg.has_num_reverse_channels());
580 int reverse_sample_rate = msg.sample_rate();
581 if (msg.has_reverse_sample_rate())
582 reverse_sample_rate = msg.reverse_sample_rate();
583 ASSERT_EQ(apm->kNoError, apm->Initialize(msg.sample_rate(),
584 reverse_sample_rate,
585 msg.num_input_channels(),
586 msg.num_output_channels(),
587 msg.num_reverse_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000588 ASSERT_TRUE(msg.has_device_sample_rate());
589 ASSERT_EQ(apm->kNoError,
590 apm->echo_cancellation()->set_device_sample_rate_hz(
591 msg.device_sample_rate()));
592
ajm@google.com808e0e02011-08-03 21:08:51 +0000593
594 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000595 far_frame.sample_rate_hz_ = msg.sample_rate();
596 far_frame.samples_per_channel_ = samples_per_channel;
597 far_frame.num_channels_ = msg.num_reverse_channels();
598 near_frame.sample_rate_hz_ = msg.sample_rate();
599 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000600 near_frame.num_channels_ = msg.num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000601 reverse_cb.reset(new ChannelBuffer<float>(samples_per_channel,
602 msg.num_reverse_channels()));
603 primary_cb.reset(new ChannelBuffer<float>(samples_per_channel,
604 msg.num_input_channels()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000605
606 if (verbose) {
607 printf("Init at frame: %d (primary), %d (reverse)\n",
608 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000609 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000610 printf(" Primary channels: %d (in), %d (out)\n",
611 msg.num_input_channels(),
612 msg.num_output_channels());
613 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000614 }
615
616 } else if (event_msg.type() == Event::REVERSE_STREAM) {
617 ASSERT_TRUE(event_msg.has_reverse_stream());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000618 ReverseStream msg = event_msg.reverse_stream();
ajm@google.com808e0e02011-08-03 21:08:51 +0000619 reverse_count++;
620
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000621 ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0));
622 if (msg.has_data()) {
623 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
624 far_frame.num_channels_, msg.data().size());
625 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
626 } else {
627 for (int i = 0; i < msg.channel_size(); ++i) {
628 reverse_cb->CopyFrom(msg.channel(i).data(), i);
629 }
630 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000631
632 if (perf_testing) {
633 t0 = TickTime::Now();
634 }
635
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000636 if (msg.has_data()) {
637 ASSERT_EQ(apm->kNoError,
638 apm->AnalyzeReverseStream(&far_frame));
639 } else {
640 ASSERT_EQ(apm->kNoError,
641 apm->AnalyzeReverseStream(
642 reverse_cb->channels(),
643 far_frame.samples_per_channel_,
644 far_frame.sample_rate_hz_,
645 LayoutFromChannels(far_frame.num_channels_)));
646 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000647
648 if (perf_testing) {
649 t1 = TickTime::Now();
650 TickInterval tick_diff = t1 - t0;
651 acc_ticks += tick_diff;
652 if (tick_diff.Microseconds() > max_time_reverse_us) {
653 max_time_reverse_us = tick_diff.Microseconds();
654 }
655 if (tick_diff.Microseconds() < min_time_reverse_us) {
656 min_time_reverse_us = tick_diff.Microseconds();
657 }
658 }
659
660 } else if (event_msg.type() == Event::STREAM) {
661 ASSERT_TRUE(event_msg.has_stream());
662 const Stream msg = event_msg.stream();
663 primary_count++;
664
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000665 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000666 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000667
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000668 ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0));
669 if (msg.has_input_data()) {
670 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
671 near_frame.num_channels_, msg.input_data().size());
672 memcpy(near_frame.data_,
673 msg.input_data().data(),
674 msg.input_data().size());
675 } else {
676 for (int i = 0; i < msg.input_channel_size(); ++i) {
677 primary_cb->CopyFrom(msg.input_channel(i).data(), i);
678 }
679 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000680
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000681 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000682 if (progress && primary_count % 100 == 0) {
683 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000684 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000685 fflush(stdout);
686 }
687
688 if (perf_testing) {
689 t0 = TickTime::Now();
690 }
691
692 ASSERT_EQ(apm->kNoError,
693 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000694 delay_ms = msg.delay() + extra_delay_ms;
695 if (override_delay_ms) {
696 delay_ms = override_delay_ms;
697 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000698 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000699 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000700 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000701
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000702 if (msg.has_keypress()) {
703 apm->set_stream_key_pressed(msg.keypress());
704 } else {
705 apm->set_stream_key_pressed(true);
706 }
707
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000708 int err = apm->kNoError;
709 if (msg.has_input_data()) {
710 err = apm->ProcessStream(&near_frame);
711 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
712 } else {
713 err = apm->ProcessStream(
714 primary_cb->channels(),
715 near_frame.samples_per_channel_,
716 near_frame.sample_rate_hz_,
717 LayoutFromChannels(near_frame.num_channels_),
718 LayoutFromChannels(apm->num_output_channels()));
719 }
720
ajm@google.com808e0e02011-08-03 21:08:51 +0000721 if (err == apm->kBadStreamParameterWarning) {
722 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
723 }
724 ASSERT_TRUE(err == apm->kNoError ||
725 err == apm->kBadStreamParameterWarning);
726
ajm@google.com808e0e02011-08-03 21:08:51 +0000727 stream_has_voice =
728 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
729 if (vad_out_file != NULL) {
730 ASSERT_EQ(1u, fwrite(&stream_has_voice,
731 sizeof(stream_has_voice),
732 1,
733 vad_out_file));
734 }
735
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000736 if (ns_prob_file != NULL) {
737 ns_speech_prob = apm->noise_suppression()->speech_probability();
738 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
739 sizeof(ns_speech_prob),
740 1,
741 ns_prob_file));
742 }
743
ajm@google.com808e0e02011-08-03 21:08:51 +0000744 if (perf_testing) {
745 t1 = TickTime::Now();
746 TickInterval tick_diff = t1 - t0;
747 acc_ticks += tick_diff;
748 if (tick_diff.Microseconds() > max_time_us) {
749 max_time_us = tick_diff.Microseconds();
750 }
751 if (tick_diff.Microseconds() < min_time_us) {
752 min_time_us = tick_diff.Microseconds();
753 }
754 }
755
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000756 size_t num_samples = samples_per_channel * apm->num_output_channels();
757 if (msg.has_input_data()) {
758 static FILE* out_file = OpenFile(out_filename, "wb");
759 ASSERT_EQ(num_samples, fwrite(near_frame.data_,
760 sizeof(*near_frame.data_),
761 num_samples,
762 out_file));
763 } else {
764 static FILE* out_float_file = OpenFile(out_float_filename, "wb");
765 ASSERT_EQ(num_samples, fwrite(primary_cb->data(),
766 sizeof(*primary_cb->data()),
767 num_samples,
768 out_float_file));
769 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000770 }
771 }
772
773 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000774
775 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000776 enum Events {
777 kInitializeEvent,
778 kRenderEvent,
779 kCaptureEvent,
780 kResetEventDeprecated
781 };
782 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000783 while (simulating || feof(event_file) == 0) {
784 std::ostringstream trace_stream;
785 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
786 << primary_count << " (primary)";
787 SCOPED_TRACE(trace_stream.str());
788
789 if (simulating) {
790 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 event = kCaptureEvent;
792 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000793 if (event == kRenderEvent) {
794 event = kCaptureEvent;
795 } else {
796 event = kRenderEvent;
797 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 }
799 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000800 read_count = fread(&event, sizeof(event), 1, event_file);
801 if (read_count != 1) {
802 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000803 }
804 }
805
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000806 far_frame.sample_rate_hz_ = sample_rate_hz;
807 far_frame.samples_per_channel_ = samples_per_channel;
808 far_frame.num_channels_ = num_render_channels;
809 near_frame.sample_rate_hz_ = sample_rate_hz;
810 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000811
ajm@google.com808e0e02011-08-03 21:08:51 +0000812 if (event == kInitializeEvent || event == kResetEventDeprecated) {
813 ASSERT_EQ(1u,
814 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
815 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000816
ajm@google.com808e0e02011-08-03 21:08:51 +0000817 ASSERT_EQ(1u,
818 fread(&device_sample_rate_hz,
819 sizeof(device_sample_rate_hz),
820 1,
821 event_file));
822
bjornv@webrtc.org6a947342014-01-16 08:41:09 +0000823 // TODO(bjornv): Replace set_sample_rate_hz() when we have a smarter
824 // AnalyzeReverseStream().
825 ASSERT_EQ(apm->kNoError, apm->set_sample_rate_hz(sample_rate_hz));
826
ajm@google.com808e0e02011-08-03 21:08:51 +0000827 ASSERT_EQ(apm->kNoError,
ajm@google.com808e0e02011-08-03 21:08:51 +0000828 apm->echo_cancellation()->set_device_sample_rate_hz(
829 device_sample_rate_hz));
830
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000831 far_frame.sample_rate_hz_ = sample_rate_hz;
832 far_frame.samples_per_channel_ = samples_per_channel;
833 far_frame.num_channels_ = num_render_channels;
834 near_frame.sample_rate_hz_ = sample_rate_hz;
835 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000836
837 if (verbose) {
838 printf("Init at frame: %d (primary), %d (reverse)\n",
839 primary_count, reverse_count);
840 printf(" Sample rate: %d Hz\n", sample_rate_hz);
841 }
842
843 } else if (event == kRenderEvent) {
844 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000845
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000846 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000847 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000848 sizeof(int16_t),
849 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000850 far_file);
851
852 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000853 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000854 // Read an equal amount from the near file to avoid errors due to
855 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000856 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000857 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000858 break; // This is expected.
859 }
860 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000861 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000862 }
863
864 if (perf_testing) {
865 t0 = TickTime::Now();
866 }
867
868 ASSERT_EQ(apm->kNoError,
869 apm->AnalyzeReverseStream(&far_frame));
870
871 if (perf_testing) {
872 t1 = TickTime::Now();
873 TickInterval tick_diff = t1 - t0;
874 acc_ticks += tick_diff;
875 if (tick_diff.Microseconds() > max_time_reverse_us) {
876 max_time_reverse_us = tick_diff.Microseconds();
877 }
878 if (tick_diff.Microseconds() < min_time_reverse_us) {
879 min_time_reverse_us = tick_diff.Microseconds();
880 }
881 }
882
883 } else if (event == kCaptureEvent) {
884 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000885 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000886
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000887 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000888 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000889 sizeof(int16_t),
890 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000891 near_file);
892
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000893 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000894 if (progress && primary_count % 100 == 0) {
895 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000896 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000897 fflush(stdout);
898 }
899 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000900 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000901 break; // This is expected.
902 }
903
904 delay_ms = 0;
905 drift_samples = 0;
906 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000907 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000908
909 // TODO(ajm): sizeof(delay_ms) for current files?
910 ASSERT_EQ(1u,
911 fread(&delay_ms, 2, 1, delay_file));
912 ASSERT_EQ(1u,
913 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
914 }
915
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000916 if (apm->gain_control()->is_enabled() &&
917 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000918 SimulateMic(capture_level, &near_frame);
919 }
920
ajm@google.com808e0e02011-08-03 21:08:51 +0000921 if (perf_testing) {
922 t0 = TickTime::Now();
923 }
924
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000925 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000926 ASSERT_EQ(apm->kNoError,
927 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000928 delay_ms += extra_delay_ms;
929 if (override_delay_ms) {
930 delay_ms = override_delay_ms;
931 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000932 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000933 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000934 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000935
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000936 apm->set_stream_key_pressed(true);
937
ajm@google.com808e0e02011-08-03 21:08:51 +0000938 int err = apm->ProcessStream(&near_frame);
939 if (err == apm->kBadStreamParameterWarning) {
940 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
941 }
942 ASSERT_TRUE(err == apm->kNoError ||
943 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000944 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000945
946 capture_level = apm->gain_control()->stream_analog_level();
947
948 stream_has_voice =
949 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
950 if (vad_out_file != NULL) {
951 ASSERT_EQ(1u, fwrite(&stream_has_voice,
952 sizeof(stream_has_voice),
953 1,
954 vad_out_file));
955 }
956
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000957 if (ns_prob_file != NULL) {
958 ns_speech_prob = apm->noise_suppression()->speech_probability();
959 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
960 sizeof(ns_speech_prob),
961 1,
962 ns_prob_file));
963 }
964
ajm@google.com808e0e02011-08-03 21:08:51 +0000965 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
966 ASSERT_EQ(capture_level_in, capture_level);
967 }
968
969 if (perf_testing) {
970 t1 = TickTime::Now();
971 TickInterval tick_diff = t1 - t0;
972 acc_ticks += tick_diff;
973 if (tick_diff.Microseconds() > max_time_us) {
974 max_time_us = tick_diff.Microseconds();
975 }
976 if (tick_diff.Microseconds() < min_time_us) {
977 min_time_us = tick_diff.Microseconds();
978 }
979 }
980
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000981 size = samples_per_channel * near_frame.num_channels_;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000982 static FILE* out_file = OpenFile(out_filename, "wb");
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000983 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000984 sizeof(int16_t),
985 size,
986 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000988 else {
989 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 }
992 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000993 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000994
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000995 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000996 const size_t path_size =
997 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000998 scoped_array<char> echo_path(new char[path_size]);
999 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1000 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1001 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001002 path_size,
1003 aecm_echo_path_out_file));
1004 fclose(aecm_echo_path_out_file);
1005 aecm_echo_path_out_file = NULL;
1006 }
1007
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 if (verbose) {
1009 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1010 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001011
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001012 if (apm->level_estimator()->is_enabled()) {
1013 printf("\n--Level metrics--\n");
1014 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1015 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001016 if (apm->echo_cancellation()->are_metrics_enabled()) {
1017 EchoCancellation::Metrics metrics;
1018 apm->echo_cancellation()->GetMetrics(&metrics);
1019 printf("\n--Echo metrics--\n");
1020 printf("(avg, max, min)\n");
1021 printf("ERL: ");
1022 PrintStat(metrics.echo_return_loss);
1023 printf("ERLE: ");
1024 PrintStat(metrics.echo_return_loss_enhancement);
1025 printf("ANLP: ");
1026 PrintStat(metrics.a_nlp);
1027 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001028 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1029 int median = 0;
1030 int std = 0;
1031 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1032 printf("\n--Delay metrics--\n");
1033 printf("Median: %3d\n", median);
1034 printf("Standard deviation: %3d\n", std);
1035 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 }
1037
ajm@google.com808e0e02011-08-03 21:08:51 +00001038 if (!pb_file) {
1039 int8_t temp_int8;
1040 if (far_file) {
1041 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1042 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1043 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001044
ajm@google.com808e0e02011-08-03 21:08:51 +00001045 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1046 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1047
1048 if (!simulating) {
1049 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1050 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1051 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1052 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1053 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1054 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1055 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001056 }
1057
1058 if (perf_testing) {
1059 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001060 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1062 exec_time * 0.001, primary_count * 0.01);
1063 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1064 " %.3f ms (min)\n",
1065 (exec_time * 1.0) / primary_count,
1066 (max_time_us + max_time_reverse_us) / 1000.0,
1067 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001068 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001069 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001070 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 } else {
1072 printf("Warning: no capture frames\n");
1073 }
1074 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001075}
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001076
ajm@google.com808e0e02011-08-03 21:08:51 +00001077} // namespace
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001078} // namespace webrtc
niklase@google.com470e71d2011-07-07 08:21:25 +00001079
1080int main(int argc, char* argv[])
1081{
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001082 webrtc::void_main(argc, argv);
niklase@google.com470e71d2011-07-07 08:21:25 +00001083
andrew@webrtc.org64235092011-08-19 21:22:08 +00001084 // Optional, but removes memory leak noise from Valgrind.
1085 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 return 0;
1087}