blob: 05d7eea7582f5dfe1b30fc84c1e52cddfb05aa44 [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"
22#include "webrtc/modules/interface/module_common_types.h"
23#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
24#include "webrtc/system_wrappers/interface/scoped_ptr.h"
25#include "webrtc/system_wrappers/interface/tick_util.h"
kjellander@webrtc.org10abe252012-12-17 18:28:07 +000026#include "webrtc/test/testsupport/fileutils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000027#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000028#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000029#include "gtest/gtest.h"
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000030#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000031#else
pbos@webrtc.org8c34cee2013-05-28 09:24:03 +000032#include "testing/gtest/include/gtest/gtest.h"
ajm@google.com808e0e02011-08-03 21:08:51 +000033#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000034#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000035
36using webrtc::AudioFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +000037using webrtc::AudioProcessing;
andrew@webrtc.org22858d42013-10-23 14:07:17 +000038using webrtc::Config;
39using webrtc::DelayCorrection;
andrew@webrtc.org94c74132011-09-19 15:17:57 +000040using webrtc::EchoCancellation;
niklase@google.com470e71d2011-07-07 08:21:25 +000041using webrtc::GainControl;
42using webrtc::NoiseSuppression;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000043using webrtc::scoped_array;
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +000044using webrtc::scoped_ptr;
ajm@google.com808e0e02011-08-03 21:08:51 +000045using webrtc::TickInterval;
46using webrtc::TickTime;
andrew@webrtc.org89752612012-10-12 16:41:45 +000047using webrtc::VoiceDetection;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000048
ajm@google.com808e0e02011-08-03 21:08:51 +000049using webrtc::audioproc::Event;
50using webrtc::audioproc::Init;
51using webrtc::audioproc::ReverseStream;
52using webrtc::audioproc::Stream;
53
54namespace {
55// Returns true on success, false on error or end-of-file.
56bool ReadMessageFromFile(FILE* file,
57 ::google::protobuf::MessageLite* msg) {
58 // The "wire format" for the size is little-endian.
59 // Assume process_test is running on a little-endian machine.
andrew@webrtc.orgcb181212011-10-26 00:27:17 +000060 int32_t size = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +000061 if (fread(&size, sizeof(int32_t), 1, file) != 1) {
62 return false;
63 }
64 if (size <= 0) {
65 return false;
66 }
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000067 const size_t usize = static_cast<size_t>(size);
ajm@google.com808e0e02011-08-03 21:08:51 +000068
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000069 scoped_array<char> array(new char[usize]);
70 if (fread(array.get(), sizeof(char), usize, file) != usize) {
ajm@google.com808e0e02011-08-03 21:08:51 +000071 return false;
72 }
73
74 msg->Clear();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000075 return msg->ParseFromArray(array.get(), usize);
ajm@google.com808e0e02011-08-03 21:08:51 +000076}
niklase@google.com470e71d2011-07-07 08:21:25 +000077
andrew@webrtc.org94c74132011-09-19 15:17:57 +000078void PrintStat(const AudioProcessing::Statistic& stat) {
79 printf("%d, %d, %d\n", stat.average,
80 stat.maximum,
81 stat.minimum);
82}
83
niklase@google.com470e71d2011-07-07 08:21:25 +000084void usage() {
85 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000086 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
87 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000088 printf(
89 "process_test is a test application for AudioProcessing.\n\n"
ajm@google.com808e0e02011-08-03 21:08:51 +000090 "When a protobuf debug file is available, specify it with -pb.\n"
91 "Alternately, when -ir or -i is used, the specified files will be\n"
92 "processed directly in a simulation mode. Otherwise the full set of\n"
93 "legacy test files is expected to be present in the working directory.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000094 printf("\n");
95 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000096 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000097 printf(" -fs SAMPLE_RATE_HZ\n");
98 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
99 printf(" -rch REVERSE_CHANNELS\n");
100 printf("\n");
101 printf("Component configuration:\n");
102 printf(
103 "All components are disabled by default. Each block below begins with a\n"
104 "flag to enable the component with default settings. The subsequent flags\n"
105 "in the block are used to provide configuration settings.\n");
106 printf("\n -aec Echo cancellation\n");
107 printf(" --drift_compensation\n");
108 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000109 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000110 printf(" --no_delay_logging\n");
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000111 printf(" --aec_suppression_level LEVEL [0 - 2]\n");
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000112 printf(" --extended_filter\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +0000114 printf(" --aecm_echo_path_in_file FILE\n");
115 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000116 printf(" --no_comfort_noise\n");
117 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 printf("\n -agc Gain control\n");
119 printf(" --analog\n");
120 printf(" --adaptive_digital\n");
121 printf(" --fixed_digital\n");
122 printf(" --target_level LEVEL\n");
123 printf(" --compression_gain GAIN\n");
124 printf(" --limiter\n");
125 printf(" --no_limiter\n");
126 printf("\n -hpf High pass filter\n");
127 printf("\n -ns Noise suppression\n");
128 printf(" --ns_low\n");
129 printf(" --ns_moderate\n");
130 printf(" --ns_high\n");
131 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000132 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000134 printf(" --vad_out_file FILE\n");
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000135 printf("\n -expns Experimental Noise suppression\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000136 printf("\n Level metrics (enabled by default)\n");
137 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 printf("\n");
139 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000140 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000141 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
142 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000143 printf(" --perf Measure performance.\n");
144 printf(" --quiet Suppress text output.\n");
145 printf(" --no_progress Suppress progress.\n");
146 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000147}
148
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000149static float MicLevel2Gain(int level) {
150 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000151}
152
153static void SimulateMic(int mic_level, AudioFrame* frame) {
154 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000155 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000156 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000157 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000158 for (int n = 0; n < num_samples; n++) {
159 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000160 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000161 frame->data_[n] = static_cast<int16_t>(v);
162 }
163}
164
niklase@google.com470e71d2011-07-07 08:21:25 +0000165// void function for gtest.
166void void_main(int argc, char* argv[]) {
167 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
168 usage();
169 return;
170 }
171
172 if (argc < 2) {
173 printf("Did you mean to run without arguments?\n");
174 printf("Try `process_test --help' for more information.\n\n");
175 }
176
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000177 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create(0));
178 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000179
ajm@google.com808e0e02011-08-03 21:08:51 +0000180 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000181 const char* far_filename = NULL;
182 const char* near_filename = NULL;
183 const char* out_filename = NULL;
184 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000185 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000186 const char* aecm_echo_path_in_filename = NULL;
187 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000188
189 int32_t sample_rate_hz = 16000;
190 int32_t device_sample_rate_hz = 16000;
191
192 int num_capture_input_channels = 1;
193 int num_capture_output_channels = 1;
194 int num_render_channels = 1;
195
196 int samples_per_channel = sample_rate_hz / 100;
197
198 bool simulating = false;
199 bool perf_testing = false;
200 bool verbose = true;
201 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000202 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000203 int override_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000204 //bool interleaved = true;
205
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000206 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000208 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000209 i++;
210 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
211 pb_filename = argv[i];
212
213 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 i++;
215 ASSERT_LT(i, argc) << "Specify filename after -ir";
216 far_filename = argv[i];
217 simulating = true;
218
219 } else if (strcmp(argv[i], "-i") == 0) {
220 i++;
221 ASSERT_LT(i, argc) << "Specify filename after -i";
222 near_filename = argv[i];
223 simulating = true;
224
225 } else if (strcmp(argv[i], "-o") == 0) {
226 i++;
227 ASSERT_LT(i, argc) << "Specify filename after -o";
228 out_filename = argv[i];
229
230 } else if (strcmp(argv[i], "-fs") == 0) {
231 i++;
232 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
233 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
234 samples_per_channel = sample_rate_hz / 100;
235
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 } else if (strcmp(argv[i], "-ch") == 0) {
237 i++;
238 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
239 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
240 i++;
241 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
242
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 } else if (strcmp(argv[i], "-rch") == 0) {
244 i++;
245 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
246 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
247
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 } else if (strcmp(argv[i], "-aec") == 0) {
249 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000250 ASSERT_EQ(apm->kNoError,
251 apm->echo_cancellation()->enable_metrics(true));
252 ASSERT_EQ(apm->kNoError,
253 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000254
niklase@google.com470e71d2011-07-07 08:21:25 +0000255 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
256 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
257 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
258 // why it can give better performance despite passing zeros.
259 ASSERT_EQ(apm->kNoError,
260 apm->echo_cancellation()->enable_drift_compensation(true));
261 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
262 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
263 ASSERT_EQ(apm->kNoError,
264 apm->echo_cancellation()->enable_drift_compensation(false));
265
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000266 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
267 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
268 ASSERT_EQ(apm->kNoError,
269 apm->echo_cancellation()->enable_metrics(false));
270
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000271 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
272 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
273 ASSERT_EQ(apm->kNoError,
274 apm->echo_cancellation()->enable_delay_logging(false));
275
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000276 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
277 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
278
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000279 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
280 i++;
281 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
282 int suppression_level;
283 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
284 ASSERT_EQ(apm->kNoError,
285 apm->echo_cancellation()->set_suppression_level(
286 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
287 suppression_level)));
288
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000289 } else if (strcmp(argv[i], "--extended_filter") == 0) {
290 Config config;
291 config.Set<DelayCorrection>(new DelayCorrection(true));
292 apm->SetExtraOptions(config);
293
niklase@google.com470e71d2011-07-07 08:21:25 +0000294 } else if (strcmp(argv[i], "-aecm") == 0) {
295 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
296
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000297 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
298 i++;
299 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
300 aecm_echo_path_in_filename = argv[i];
301
302 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
303 i++;
304 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
305 aecm_echo_path_out_filename = argv[i];
306
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000307 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
308 ASSERT_EQ(apm->kNoError,
309 apm->echo_control_mobile()->enable_comfort_noise(false));
310
311 } else if (strcmp(argv[i], "--routing_mode") == 0) {
312 i++;
313 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
314 int routing_mode;
315 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
316 ASSERT_EQ(apm->kNoError,
317 apm->echo_control_mobile()->set_routing_mode(
318 static_cast<webrtc::EchoControlMobile::RoutingMode>(
319 routing_mode)));
320
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 } else if (strcmp(argv[i], "-agc") == 0) {
322 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
323
324 } else if (strcmp(argv[i], "--analog") == 0) {
325 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
326 ASSERT_EQ(apm->kNoError,
327 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
328
329 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
330 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
331 ASSERT_EQ(apm->kNoError,
332 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
333
334 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
335 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
336 ASSERT_EQ(apm->kNoError,
337 apm->gain_control()->set_mode(GainControl::kFixedDigital));
338
339 } else if (strcmp(argv[i], "--target_level") == 0) {
340 i++;
341 int level;
342 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
343
344 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
345 ASSERT_EQ(apm->kNoError,
346 apm->gain_control()->set_target_level_dbfs(level));
347
348 } else if (strcmp(argv[i], "--compression_gain") == 0) {
349 i++;
350 int gain;
351 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
352
353 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
354 ASSERT_EQ(apm->kNoError,
355 apm->gain_control()->set_compression_gain_db(gain));
356
357 } else if (strcmp(argv[i], "--limiter") == 0) {
358 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
359 ASSERT_EQ(apm->kNoError,
360 apm->gain_control()->enable_limiter(true));
361
362 } else if (strcmp(argv[i], "--no_limiter") == 0) {
363 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
364 ASSERT_EQ(apm->kNoError,
365 apm->gain_control()->enable_limiter(false));
366
367 } else if (strcmp(argv[i], "-hpf") == 0) {
368 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
369
370 } else if (strcmp(argv[i], "-ns") == 0) {
371 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
372
373 } else if (strcmp(argv[i], "--ns_low") == 0) {
374 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
375 ASSERT_EQ(apm->kNoError,
376 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
377
378 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
379 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
380 ASSERT_EQ(apm->kNoError,
381 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
382
383 } else if (strcmp(argv[i], "--ns_high") == 0) {
384 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
385 ASSERT_EQ(apm->kNoError,
386 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
387
388 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
389 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
390 ASSERT_EQ(apm->kNoError,
391 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
392
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000393 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
394 i++;
395 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
396 ns_prob_filename = argv[i];
397
niklase@google.com470e71d2011-07-07 08:21:25 +0000398 } else if (strcmp(argv[i], "-vad") == 0) {
399 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
400
andrew@webrtc.org89752612012-10-12 16:41:45 +0000401 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
402 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
403 ASSERT_EQ(apm->kNoError,
404 apm->voice_detection()->set_likelihood(
405 VoiceDetection::kVeryLowLikelihood));
406
407 } else if (strcmp(argv[i], "--vad_low") == 0) {
408 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
409 ASSERT_EQ(apm->kNoError,
410 apm->voice_detection()->set_likelihood(
411 VoiceDetection::kLowLikelihood));
412
413 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
414 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
415 ASSERT_EQ(apm->kNoError,
416 apm->voice_detection()->set_likelihood(
417 VoiceDetection::kModerateLikelihood));
418
419 } else if (strcmp(argv[i], "--vad_high") == 0) {
420 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
421 ASSERT_EQ(apm->kNoError,
422 apm->voice_detection()->set_likelihood(
423 VoiceDetection::kHighLikelihood));
424
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
426 i++;
427 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
428 vad_out_filename = argv[i];
429
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000430 } else if (strcmp(argv[i], "-expns") == 0) {
431 ASSERT_EQ(apm->kNoError, apm->EnableExperimentalNs(true));
432
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000433 } else if (strcmp(argv[i], "--noasm") == 0) {
434 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
435 // We need to reinitialize here if components have already been enabled.
436 ASSERT_EQ(apm->kNoError, apm->Initialize());
437
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000438 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000439 i++;
440 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
441
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000442 } else if (strcmp(argv[i], "--delay") == 0) {
443 i++;
444 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
445
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 } else if (strcmp(argv[i], "--perf") == 0) {
447 perf_testing = true;
448
449 } else if (strcmp(argv[i], "--quiet") == 0) {
450 verbose = false;
451 progress = false;
452
453 } else if (strcmp(argv[i], "--no_progress") == 0) {
454 progress = false;
455
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000456 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000457 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000458 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000459 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000460 } else {
461 FAIL() << "Unrecognized argument " << argv[i];
462 }
463 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000464 // If we're reading a protobuf file, ensure a simulation hasn't also
465 // been requested (which makes no sense...)
466 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000467
468 if (verbose) {
469 printf("Sample rate: %d Hz\n", sample_rate_hz);
470 printf("Primary channels: %d (in), %d (out)\n",
471 num_capture_input_channels,
472 num_capture_output_channels);
473 printf("Reverse channels: %d \n", num_render_channels);
474 }
475
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000476 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 const char far_file_default[] = "apm_far.pcm";
478 const char near_file_default[] = "apm_near.pcm";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000479 const std::string out_file_default = out_path + "out.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000480 const char event_filename[] = "apm_event.dat";
481 const char delay_filename[] = "apm_delay.dat";
482 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000483 const std::string vad_file_default = out_path + "vad_out.dat";
484 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
486 if (!simulating) {
487 far_filename = far_file_default;
488 near_filename = near_file_default;
489 }
490
ajm@google.com808e0e02011-08-03 21:08:51 +0000491 if (!out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000492 out_filename = out_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000493 }
494
ajm@google.com808e0e02011-08-03 21:08:51 +0000495 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000496 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 }
498
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000499 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000500 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000501 }
502
ajm@google.com808e0e02011-08-03 21:08:51 +0000503 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 FILE* far_file = NULL;
505 FILE* near_file = NULL;
506 FILE* out_file = NULL;
507 FILE* event_file = NULL;
508 FILE* delay_file = NULL;
509 FILE* drift_file = NULL;
510 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000511 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000512 FILE* aecm_echo_path_in_file = NULL;
513 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000514
ajm@google.com808e0e02011-08-03 21:08:51 +0000515 if (pb_filename) {
516 pb_file = fopen(pb_filename, "rb");
517 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
518 << pb_filename;
519 } else {
520 if (far_filename) {
521 far_file = fopen(far_filename, "rb");
522 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
523 << far_filename;
524 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000525
ajm@google.com808e0e02011-08-03 21:08:51 +0000526 near_file = fopen(near_filename, "rb");
527 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
528 << near_filename;
529 if (!simulating) {
530 event_file = fopen(event_filename, "rb");
531 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
532 << event_filename;
533
534 delay_file = fopen(delay_filename, "rb");
535 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
536 << delay_filename;
537
538 drift_file = fopen(drift_filename, "rb");
539 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
540 << drift_filename;
541 }
542 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000543
544 out_file = fopen(out_filename, "wb");
545 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
546 << out_filename;
547
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000548 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000549 if (pb_file) {
550 struct stat st;
551 stat(pb_filename, &st);
552 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000553 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000554 } else {
555 struct stat st;
556 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000557 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 }
559
560 if (apm->voice_detection()->is_enabled()) {
561 vad_out_file = fopen(vad_out_filename, "wb");
562 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
563 << vad_out_file;
564 }
565
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000566 if (apm->noise_suppression()->is_enabled()) {
567 ns_prob_file = fopen(ns_prob_filename, "wb");
568 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
569 << ns_prob_file;
570 }
571
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000572 if (aecm_echo_path_in_filename != NULL) {
573 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
574 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
575 << aecm_echo_path_in_filename;
576
ajm@google.com22e65152011-07-18 18:03:01 +0000577 const size_t path_size =
578 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000579 scoped_array<char> echo_path(new char[path_size]);
580 ASSERT_EQ(path_size, fread(echo_path.get(),
581 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000582 path_size,
583 aecm_echo_path_in_file));
584 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000585 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
586 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000587 fclose(aecm_echo_path_in_file);
588 aecm_echo_path_in_file = NULL;
589 }
590
591 if (aecm_echo_path_out_filename != NULL) {
592 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
593 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
594 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000595 }
596
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 size_t read_count = 0;
598 int reverse_count = 0;
599 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000600 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000601 TickInterval acc_ticks;
602
603 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000605
606 int delay_ms = 0;
607 int drift_samples = 0;
608 int capture_level = 127;
609 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000610 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000611
612 TickTime t0 = TickTime::Now();
613 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000614 int64_t max_time_us = 0;
615 int64_t max_time_reverse_us = 0;
616 int64_t min_time_us = 1e6;
617 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000618
ajm@google.com808e0e02011-08-03 21:08:51 +0000619 // TODO(ajm): Ideally we would refactor this block into separate functions,
620 // but for now we want to share the variables.
621 if (pb_file) {
622 Event event_msg;
623 while (ReadMessageFromFile(pb_file, &event_msg)) {
624 std::ostringstream trace_stream;
625 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
626 << primary_count << " (primary)";
627 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000628
ajm@google.com808e0e02011-08-03 21:08:51 +0000629 if (event_msg.type() == Event::INIT) {
630 ASSERT_TRUE(event_msg.has_init());
631 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000632
ajm@google.com808e0e02011-08-03 21:08:51 +0000633 ASSERT_TRUE(msg.has_sample_rate());
bjornv@webrtc.org6a947342014-01-16 08:41:09 +0000634 // TODO(bjornv): Replace set_sample_rate_hz() when we have a smarter
635 // AnalyzeReverseStream().
636 ASSERT_EQ(apm->kNoError, apm->set_sample_rate_hz(msg.sample_rate()));
ajm@google.com808e0e02011-08-03 21:08:51 +0000637 ASSERT_TRUE(msg.has_device_sample_rate());
638 ASSERT_EQ(apm->kNoError,
639 apm->echo_cancellation()->set_device_sample_rate_hz(
640 msg.device_sample_rate()));
641
642 ASSERT_TRUE(msg.has_num_input_channels());
643 ASSERT_TRUE(msg.has_num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000644 ASSERT_TRUE(msg.has_num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000645
646 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000647 far_frame.sample_rate_hz_ = msg.sample_rate();
648 far_frame.samples_per_channel_ = samples_per_channel;
649 far_frame.num_channels_ = msg.num_reverse_channels();
650 near_frame.sample_rate_hz_ = msg.sample_rate();
651 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000652 near_frame.num_channels_ = msg.num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000653
654 if (verbose) {
655 printf("Init at frame: %d (primary), %d (reverse)\n",
656 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000657 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000658 printf(" Primary channels: %d (in), %d (out)\n",
659 msg.num_input_channels(),
660 msg.num_output_channels());
661 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000662 }
663
664 } else if (event_msg.type() == Event::REVERSE_STREAM) {
665 ASSERT_TRUE(event_msg.has_reverse_stream());
666 const ReverseStream msg = event_msg.reverse_stream();
667 reverse_count++;
668
669 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000670 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000671 far_frame.num_channels_, msg.data().size());
672 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000673
674 if (perf_testing) {
675 t0 = TickTime::Now();
676 }
677
678 ASSERT_EQ(apm->kNoError,
679 apm->AnalyzeReverseStream(&far_frame));
680
681 if (perf_testing) {
682 t1 = TickTime::Now();
683 TickInterval tick_diff = t1 - t0;
684 acc_ticks += tick_diff;
685 if (tick_diff.Microseconds() > max_time_reverse_us) {
686 max_time_reverse_us = tick_diff.Microseconds();
687 }
688 if (tick_diff.Microseconds() < min_time_reverse_us) {
689 min_time_reverse_us = tick_diff.Microseconds();
690 }
691 }
692
693 } else if (event_msg.type() == Event::STREAM) {
694 ASSERT_TRUE(event_msg.has_stream());
695 const Stream msg = event_msg.stream();
696 primary_count++;
697
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000698 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000699 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000700
701 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000702 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000703 near_frame.num_channels_, msg.input_data().size());
704 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000705 msg.input_data().data(),
706 msg.input_data().size());
707
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000708 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000709 if (progress && primary_count % 100 == 0) {
710 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000711 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000712 fflush(stdout);
713 }
714
715 if (perf_testing) {
716 t0 = TickTime::Now();
717 }
718
719 ASSERT_EQ(apm->kNoError,
720 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000721 delay_ms = msg.delay() + extra_delay_ms;
722 if (override_delay_ms) {
723 delay_ms = override_delay_ms;
724 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000725 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000726 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000727 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000728
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000729 if (msg.has_keypress()) {
730 apm->set_stream_key_pressed(msg.keypress());
731 } else {
732 apm->set_stream_key_pressed(true);
733 }
734
ajm@google.com808e0e02011-08-03 21:08:51 +0000735 int err = apm->ProcessStream(&near_frame);
736 if (err == apm->kBadStreamParameterWarning) {
737 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
738 }
739 ASSERT_TRUE(err == apm->kNoError ||
740 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000741 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000742
ajm@google.com808e0e02011-08-03 21:08:51 +0000743 stream_has_voice =
744 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
745 if (vad_out_file != NULL) {
746 ASSERT_EQ(1u, fwrite(&stream_has_voice,
747 sizeof(stream_has_voice),
748 1,
749 vad_out_file));
750 }
751
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000752 if (ns_prob_file != NULL) {
753 ns_speech_prob = apm->noise_suppression()->speech_probability();
754 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
755 sizeof(ns_speech_prob),
756 1,
757 ns_prob_file));
758 }
759
ajm@google.com808e0e02011-08-03 21:08:51 +0000760 if (perf_testing) {
761 t1 = TickTime::Now();
762 TickInterval tick_diff = t1 - t0;
763 acc_ticks += tick_diff;
764 if (tick_diff.Microseconds() > max_time_us) {
765 max_time_us = tick_diff.Microseconds();
766 }
767 if (tick_diff.Microseconds() < min_time_us) {
768 min_time_us = tick_diff.Microseconds();
769 }
770 }
771
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000772 size_t size = samples_per_channel * near_frame.num_channels_;
773 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000774 sizeof(int16_t),
775 size,
776 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000777 }
778 }
779
780 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000781
782 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000783 enum Events {
784 kInitializeEvent,
785 kRenderEvent,
786 kCaptureEvent,
787 kResetEventDeprecated
788 };
789 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000790 while (simulating || feof(event_file) == 0) {
791 std::ostringstream trace_stream;
792 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
793 << primary_count << " (primary)";
794 SCOPED_TRACE(trace_stream.str());
795
796 if (simulating) {
797 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 event = kCaptureEvent;
799 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000800 if (event == kRenderEvent) {
801 event = kCaptureEvent;
802 } else {
803 event = kRenderEvent;
804 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000805 }
806 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000807 read_count = fread(&event, sizeof(event), 1, event_file);
808 if (read_count != 1) {
809 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000810 }
811 }
812
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000813 far_frame.sample_rate_hz_ = sample_rate_hz;
814 far_frame.samples_per_channel_ = samples_per_channel;
815 far_frame.num_channels_ = num_render_channels;
816 near_frame.sample_rate_hz_ = sample_rate_hz;
817 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000818
ajm@google.com808e0e02011-08-03 21:08:51 +0000819 if (event == kInitializeEvent || event == kResetEventDeprecated) {
820 ASSERT_EQ(1u,
821 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
822 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000823
ajm@google.com808e0e02011-08-03 21:08:51 +0000824 ASSERT_EQ(1u,
825 fread(&device_sample_rate_hz,
826 sizeof(device_sample_rate_hz),
827 1,
828 event_file));
829
bjornv@webrtc.org6a947342014-01-16 08:41:09 +0000830 // TODO(bjornv): Replace set_sample_rate_hz() when we have a smarter
831 // AnalyzeReverseStream().
832 ASSERT_EQ(apm->kNoError, apm->set_sample_rate_hz(sample_rate_hz));
833
ajm@google.com808e0e02011-08-03 21:08:51 +0000834 ASSERT_EQ(apm->kNoError,
ajm@google.com808e0e02011-08-03 21:08:51 +0000835 apm->echo_cancellation()->set_device_sample_rate_hz(
836 device_sample_rate_hz));
837
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000838 far_frame.sample_rate_hz_ = sample_rate_hz;
839 far_frame.samples_per_channel_ = samples_per_channel;
840 far_frame.num_channels_ = num_render_channels;
841 near_frame.sample_rate_hz_ = sample_rate_hz;
842 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000843
844 if (verbose) {
845 printf("Init at frame: %d (primary), %d (reverse)\n",
846 primary_count, reverse_count);
847 printf(" Sample rate: %d Hz\n", sample_rate_hz);
848 }
849
850 } else if (event == kRenderEvent) {
851 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000852
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000853 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000854 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000855 sizeof(int16_t),
856 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000857 far_file);
858
859 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000860 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000861 // Read an equal amount from the near file to avoid errors due to
862 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000863 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000864 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000865 break; // This is expected.
866 }
867 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000868 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000869 }
870
871 if (perf_testing) {
872 t0 = TickTime::Now();
873 }
874
875 ASSERT_EQ(apm->kNoError,
876 apm->AnalyzeReverseStream(&far_frame));
877
878 if (perf_testing) {
879 t1 = TickTime::Now();
880 TickInterval tick_diff = t1 - t0;
881 acc_ticks += tick_diff;
882 if (tick_diff.Microseconds() > max_time_reverse_us) {
883 max_time_reverse_us = tick_diff.Microseconds();
884 }
885 if (tick_diff.Microseconds() < min_time_reverse_us) {
886 min_time_reverse_us = tick_diff.Microseconds();
887 }
888 }
889
890 } else if (event == kCaptureEvent) {
891 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000892 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000893
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000894 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000895 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000896 sizeof(int16_t),
897 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000898 near_file);
899
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000900 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000901 if (progress && primary_count % 100 == 0) {
902 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000903 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000904 fflush(stdout);
905 }
906 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000907 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000908 break; // This is expected.
909 }
910
911 delay_ms = 0;
912 drift_samples = 0;
913 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000914 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000915
916 // TODO(ajm): sizeof(delay_ms) for current files?
917 ASSERT_EQ(1u,
918 fread(&delay_ms, 2, 1, delay_file));
919 ASSERT_EQ(1u,
920 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
921 }
922
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000923 if (apm->gain_control()->is_enabled() &&
924 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000925 SimulateMic(capture_level, &near_frame);
926 }
927
ajm@google.com808e0e02011-08-03 21:08:51 +0000928 if (perf_testing) {
929 t0 = TickTime::Now();
930 }
931
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000932 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000933 ASSERT_EQ(apm->kNoError,
934 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000935 delay_ms += extra_delay_ms;
936 if (override_delay_ms) {
937 delay_ms = override_delay_ms;
938 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000939 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000940 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000941 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000942
aluebs@webrtc.orgbc1d2242014-02-25 16:50:22 +0000943 apm->set_stream_key_pressed(true);
944
ajm@google.com808e0e02011-08-03 21:08:51 +0000945 int err = apm->ProcessStream(&near_frame);
946 if (err == apm->kBadStreamParameterWarning) {
947 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
948 }
949 ASSERT_TRUE(err == apm->kNoError ||
950 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000951 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000952
953 capture_level = apm->gain_control()->stream_analog_level();
954
955 stream_has_voice =
956 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
957 if (vad_out_file != NULL) {
958 ASSERT_EQ(1u, fwrite(&stream_has_voice,
959 sizeof(stream_has_voice),
960 1,
961 vad_out_file));
962 }
963
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000964 if (ns_prob_file != NULL) {
965 ns_speech_prob = apm->noise_suppression()->speech_probability();
966 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
967 sizeof(ns_speech_prob),
968 1,
969 ns_prob_file));
970 }
971
ajm@google.com808e0e02011-08-03 21:08:51 +0000972 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
973 ASSERT_EQ(capture_level_in, capture_level);
974 }
975
976 if (perf_testing) {
977 t1 = TickTime::Now();
978 TickInterval tick_diff = t1 - t0;
979 acc_ticks += tick_diff;
980 if (tick_diff.Microseconds() > max_time_us) {
981 max_time_us = tick_diff.Microseconds();
982 }
983 if (tick_diff.Microseconds() < min_time_us) {
984 min_time_us = tick_diff.Microseconds();
985 }
986 }
987
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000988 size = samples_per_channel * near_frame.num_channels_;
989 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000990 sizeof(int16_t),
991 size,
992 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000994 else {
995 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 }
998 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000999 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001000
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001001 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001002 const size_t path_size =
1003 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001004 scoped_array<char> echo_path(new char[path_size]);
1005 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1006 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1007 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001008 path_size,
1009 aecm_echo_path_out_file));
1010 fclose(aecm_echo_path_out_file);
1011 aecm_echo_path_out_file = NULL;
1012 }
1013
niklase@google.com470e71d2011-07-07 08:21:25 +00001014 if (verbose) {
1015 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1016 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001017
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001018 if (apm->level_estimator()->is_enabled()) {
1019 printf("\n--Level metrics--\n");
1020 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1021 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001022 if (apm->echo_cancellation()->are_metrics_enabled()) {
1023 EchoCancellation::Metrics metrics;
1024 apm->echo_cancellation()->GetMetrics(&metrics);
1025 printf("\n--Echo metrics--\n");
1026 printf("(avg, max, min)\n");
1027 printf("ERL: ");
1028 PrintStat(metrics.echo_return_loss);
1029 printf("ERLE: ");
1030 PrintStat(metrics.echo_return_loss_enhancement);
1031 printf("ANLP: ");
1032 PrintStat(metrics.a_nlp);
1033 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001034 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1035 int median = 0;
1036 int std = 0;
1037 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1038 printf("\n--Delay metrics--\n");
1039 printf("Median: %3d\n", median);
1040 printf("Standard deviation: %3d\n", std);
1041 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 }
1043
ajm@google.com808e0e02011-08-03 21:08:51 +00001044 if (!pb_file) {
1045 int8_t temp_int8;
1046 if (far_file) {
1047 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1048 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1049 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001050
ajm@google.com808e0e02011-08-03 21:08:51 +00001051 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1052 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1053
1054 if (!simulating) {
1055 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1056 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1057 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1058 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1059 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1060 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1061 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001062 }
1063
1064 if (perf_testing) {
1065 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001066 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1068 exec_time * 0.001, primary_count * 0.01);
1069 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1070 " %.3f ms (min)\n",
1071 (exec_time * 1.0) / primary_count,
1072 (max_time_us + max_time_reverse_us) / 1000.0,
1073 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001074 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001075 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001076 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001077 } else {
1078 printf("Warning: no capture frames\n");
1079 }
1080 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001081}
ajm@google.com808e0e02011-08-03 21:08:51 +00001082} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001083
1084int main(int argc, char* argv[])
1085{
1086 void_main(argc, argv);
1087
andrew@webrtc.org64235092011-08-19 21:22:08 +00001088 // Optional, but removes memory leak noise from Valgrind.
1089 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 return 0;
1091}