blob: 6bf6a7d99fbc30cc94142b6ac8a3780b318ae60f [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");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000135 printf("\n Level metrics (enabled by default)\n");
136 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 printf("\n");
138 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000139 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000140 printf(" --add_delay DELAY Add DELAY ms to input value.\n");
141 printf(" --delay DELAY Override input delay with DELAY ms.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000142 printf(" --perf Measure performance.\n");
143 printf(" --quiet Suppress text output.\n");
144 printf(" --no_progress Suppress progress.\n");
145 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000146}
147
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000148static float MicLevel2Gain(int level) {
149 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000150}
151
152static void SimulateMic(int mic_level, AudioFrame* frame) {
153 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000154 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000155 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000156 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000157 for (int n = 0; n < num_samples; n++) {
158 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000159 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000160 frame->data_[n] = static_cast<int16_t>(v);
161 }
162}
163
niklase@google.com470e71d2011-07-07 08:21:25 +0000164// void function for gtest.
165void void_main(int argc, char* argv[]) {
166 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
167 usage();
168 return;
169 }
170
171 if (argc < 2) {
172 printf("Did you mean to run without arguments?\n");
173 printf("Try `process_test --help' for more information.\n\n");
174 }
175
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000176 scoped_ptr<AudioProcessing> apm(AudioProcessing::Create(0));
177 ASSERT_TRUE(apm.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178
ajm@google.com808e0e02011-08-03 21:08:51 +0000179 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 const char* far_filename = NULL;
181 const char* near_filename = NULL;
182 const char* out_filename = NULL;
183 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000184 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000185 const char* aecm_echo_path_in_filename = NULL;
186 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187
188 int32_t sample_rate_hz = 16000;
189 int32_t device_sample_rate_hz = 16000;
190
191 int num_capture_input_channels = 1;
192 int num_capture_output_channels = 1;
193 int num_render_channels = 1;
194
195 int samples_per_channel = sample_rate_hz / 100;
196
197 bool simulating = false;
198 bool perf_testing = false;
199 bool verbose = true;
200 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000201 int extra_delay_ms = 0;
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000202 int override_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 //bool interleaved = true;
204
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000205 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000207 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000208 i++;
209 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
210 pb_filename = argv[i];
211
212 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 i++;
214 ASSERT_LT(i, argc) << "Specify filename after -ir";
215 far_filename = argv[i];
216 simulating = true;
217
218 } else if (strcmp(argv[i], "-i") == 0) {
219 i++;
220 ASSERT_LT(i, argc) << "Specify filename after -i";
221 near_filename = argv[i];
222 simulating = true;
223
224 } else if (strcmp(argv[i], "-o") == 0) {
225 i++;
226 ASSERT_LT(i, argc) << "Specify filename after -o";
227 out_filename = argv[i];
228
229 } else if (strcmp(argv[i], "-fs") == 0) {
230 i++;
231 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
232 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
233 samples_per_channel = sample_rate_hz / 100;
234
235 ASSERT_EQ(apm->kNoError,
236 apm->set_sample_rate_hz(sample_rate_hz));
237
238 } else if (strcmp(argv[i], "-ch") == 0) {
239 i++;
240 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
241 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
242 i++;
243 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
244
245 ASSERT_EQ(apm->kNoError,
246 apm->set_num_channels(num_capture_input_channels,
247 num_capture_output_channels));
248
249 } else if (strcmp(argv[i], "-rch") == 0) {
250 i++;
251 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
252 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
253
254 ASSERT_EQ(apm->kNoError,
255 apm->set_num_reverse_channels(num_render_channels));
256
257 } else if (strcmp(argv[i], "-aec") == 0) {
258 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000259 ASSERT_EQ(apm->kNoError,
260 apm->echo_cancellation()->enable_metrics(true));
261 ASSERT_EQ(apm->kNoError,
262 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000263
niklase@google.com470e71d2011-07-07 08:21:25 +0000264 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
265 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
266 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
267 // why it can give better performance despite passing zeros.
268 ASSERT_EQ(apm->kNoError,
269 apm->echo_cancellation()->enable_drift_compensation(true));
270 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
271 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
272 ASSERT_EQ(apm->kNoError,
273 apm->echo_cancellation()->enable_drift_compensation(false));
274
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000275 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
276 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
277 ASSERT_EQ(apm->kNoError,
278 apm->echo_cancellation()->enable_metrics(false));
279
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000280 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
281 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
282 ASSERT_EQ(apm->kNoError,
283 apm->echo_cancellation()->enable_delay_logging(false));
284
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000285 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
286 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
287
andrew@webrtc.orgdff69c52013-04-30 23:01:09 +0000288 } else if (strcmp(argv[i], "--aec_suppression_level") == 0) {
289 i++;
290 ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level";
291 int suppression_level;
292 ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level));
293 ASSERT_EQ(apm->kNoError,
294 apm->echo_cancellation()->set_suppression_level(
295 static_cast<webrtc::EchoCancellation::SuppressionLevel>(
296 suppression_level)));
297
andrew@webrtc.org22858d42013-10-23 14:07:17 +0000298 } else if (strcmp(argv[i], "--extended_filter") == 0) {
299 Config config;
300 config.Set<DelayCorrection>(new DelayCorrection(true));
301 apm->SetExtraOptions(config);
302
niklase@google.com470e71d2011-07-07 08:21:25 +0000303 } else if (strcmp(argv[i], "-aecm") == 0) {
304 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
305
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000306 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
307 i++;
308 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
309 aecm_echo_path_in_filename = argv[i];
310
311 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
312 i++;
313 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
314 aecm_echo_path_out_filename = argv[i];
315
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000316 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
317 ASSERT_EQ(apm->kNoError,
318 apm->echo_control_mobile()->enable_comfort_noise(false));
319
320 } else if (strcmp(argv[i], "--routing_mode") == 0) {
321 i++;
322 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
323 int routing_mode;
324 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
325 ASSERT_EQ(apm->kNoError,
326 apm->echo_control_mobile()->set_routing_mode(
327 static_cast<webrtc::EchoControlMobile::RoutingMode>(
328 routing_mode)));
329
niklase@google.com470e71d2011-07-07 08:21:25 +0000330 } else if (strcmp(argv[i], "-agc") == 0) {
331 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
332
333 } else if (strcmp(argv[i], "--analog") == 0) {
334 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
335 ASSERT_EQ(apm->kNoError,
336 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
337
338 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
339 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
340 ASSERT_EQ(apm->kNoError,
341 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
342
343 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
344 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
345 ASSERT_EQ(apm->kNoError,
346 apm->gain_control()->set_mode(GainControl::kFixedDigital));
347
348 } else if (strcmp(argv[i], "--target_level") == 0) {
349 i++;
350 int level;
351 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
352
353 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
354 ASSERT_EQ(apm->kNoError,
355 apm->gain_control()->set_target_level_dbfs(level));
356
357 } else if (strcmp(argv[i], "--compression_gain") == 0) {
358 i++;
359 int gain;
360 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
361
362 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
363 ASSERT_EQ(apm->kNoError,
364 apm->gain_control()->set_compression_gain_db(gain));
365
366 } else if (strcmp(argv[i], "--limiter") == 0) {
367 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
368 ASSERT_EQ(apm->kNoError,
369 apm->gain_control()->enable_limiter(true));
370
371 } else if (strcmp(argv[i], "--no_limiter") == 0) {
372 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
373 ASSERT_EQ(apm->kNoError,
374 apm->gain_control()->enable_limiter(false));
375
376 } else if (strcmp(argv[i], "-hpf") == 0) {
377 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
378
379 } else if (strcmp(argv[i], "-ns") == 0) {
380 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
381
382 } else if (strcmp(argv[i], "--ns_low") == 0) {
383 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
384 ASSERT_EQ(apm->kNoError,
385 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
386
387 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
388 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
389 ASSERT_EQ(apm->kNoError,
390 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
391
392 } else if (strcmp(argv[i], "--ns_high") == 0) {
393 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
394 ASSERT_EQ(apm->kNoError,
395 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
396
397 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
398 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
399 ASSERT_EQ(apm->kNoError,
400 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
401
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000402 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
403 i++;
404 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
405 ns_prob_filename = argv[i];
406
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 } else if (strcmp(argv[i], "-vad") == 0) {
408 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
409
andrew@webrtc.org89752612012-10-12 16:41:45 +0000410 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
411 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
412 ASSERT_EQ(apm->kNoError,
413 apm->voice_detection()->set_likelihood(
414 VoiceDetection::kVeryLowLikelihood));
415
416 } else if (strcmp(argv[i], "--vad_low") == 0) {
417 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
418 ASSERT_EQ(apm->kNoError,
419 apm->voice_detection()->set_likelihood(
420 VoiceDetection::kLowLikelihood));
421
422 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
423 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
424 ASSERT_EQ(apm->kNoError,
425 apm->voice_detection()->set_likelihood(
426 VoiceDetection::kModerateLikelihood));
427
428 } else if (strcmp(argv[i], "--vad_high") == 0) {
429 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
430 ASSERT_EQ(apm->kNoError,
431 apm->voice_detection()->set_likelihood(
432 VoiceDetection::kHighLikelihood));
433
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
435 i++;
436 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
437 vad_out_filename = argv[i];
438
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000439 } else if (strcmp(argv[i], "--noasm") == 0) {
440 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
441 // We need to reinitialize here if components have already been enabled.
442 ASSERT_EQ(apm->kNoError, apm->Initialize());
443
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000444 } else if (strcmp(argv[i], "--add_delay") == 0) {
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000445 i++;
446 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
447
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000448 } else if (strcmp(argv[i], "--delay") == 0) {
449 i++;
450 ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms));
451
niklase@google.com470e71d2011-07-07 08:21:25 +0000452 } else if (strcmp(argv[i], "--perf") == 0) {
453 perf_testing = true;
454
455 } else if (strcmp(argv[i], "--quiet") == 0) {
456 verbose = false;
457 progress = false;
458
459 } else if (strcmp(argv[i], "--no_progress") == 0) {
460 progress = false;
461
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000462 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000463 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000464 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000465 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000466 } else {
467 FAIL() << "Unrecognized argument " << argv[i];
468 }
469 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000470 // If we're reading a protobuf file, ensure a simulation hasn't also
471 // been requested (which makes no sense...)
472 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000473
474 if (verbose) {
475 printf("Sample rate: %d Hz\n", sample_rate_hz);
476 printf("Primary channels: %d (in), %d (out)\n",
477 num_capture_input_channels,
478 num_capture_output_channels);
479 printf("Reverse channels: %d \n", num_render_channels);
480 }
481
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000482 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 const char far_file_default[] = "apm_far.pcm";
484 const char near_file_default[] = "apm_near.pcm";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000485 const std::string out_file_default = out_path + "out.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 const char event_filename[] = "apm_event.dat";
487 const char delay_filename[] = "apm_delay.dat";
488 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000489 const std::string vad_file_default = out_path + "vad_out.dat";
490 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000491
492 if (!simulating) {
493 far_filename = far_file_default;
494 near_filename = near_file_default;
495 }
496
ajm@google.com808e0e02011-08-03 21:08:51 +0000497 if (!out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000498 out_filename = out_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 }
500
ajm@google.com808e0e02011-08-03 21:08:51 +0000501 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000502 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 }
504
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000505 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000506 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000507 }
508
ajm@google.com808e0e02011-08-03 21:08:51 +0000509 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 FILE* far_file = NULL;
511 FILE* near_file = NULL;
512 FILE* out_file = NULL;
513 FILE* event_file = NULL;
514 FILE* delay_file = NULL;
515 FILE* drift_file = NULL;
516 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000517 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000518 FILE* aecm_echo_path_in_file = NULL;
519 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000520
ajm@google.com808e0e02011-08-03 21:08:51 +0000521 if (pb_filename) {
522 pb_file = fopen(pb_filename, "rb");
523 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
524 << pb_filename;
525 } else {
526 if (far_filename) {
527 far_file = fopen(far_filename, "rb");
528 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
529 << far_filename;
530 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000531
ajm@google.com808e0e02011-08-03 21:08:51 +0000532 near_file = fopen(near_filename, "rb");
533 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
534 << near_filename;
535 if (!simulating) {
536 event_file = fopen(event_filename, "rb");
537 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
538 << event_filename;
539
540 delay_file = fopen(delay_filename, "rb");
541 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
542 << delay_filename;
543
544 drift_file = fopen(drift_filename, "rb");
545 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
546 << drift_filename;
547 }
548 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000549
550 out_file = fopen(out_filename, "wb");
551 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
552 << out_filename;
553
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000554 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000555 if (pb_file) {
556 struct stat st;
557 stat(pb_filename, &st);
558 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000559 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000560 } else {
561 struct stat st;
562 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000563 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000564 }
565
566 if (apm->voice_detection()->is_enabled()) {
567 vad_out_file = fopen(vad_out_filename, "wb");
568 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
569 << vad_out_file;
570 }
571
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000572 if (apm->noise_suppression()->is_enabled()) {
573 ns_prob_file = fopen(ns_prob_filename, "wb");
574 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
575 << ns_prob_file;
576 }
577
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000578 if (aecm_echo_path_in_filename != NULL) {
579 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
580 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
581 << aecm_echo_path_in_filename;
582
ajm@google.com22e65152011-07-18 18:03:01 +0000583 const size_t path_size =
584 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000585 scoped_array<char> echo_path(new char[path_size]);
586 ASSERT_EQ(path_size, fread(echo_path.get(),
587 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000588 path_size,
589 aecm_echo_path_in_file));
590 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000591 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
592 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000593 fclose(aecm_echo_path_in_file);
594 aecm_echo_path_in_file = NULL;
595 }
596
597 if (aecm_echo_path_out_filename != NULL) {
598 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
599 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
600 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000601 }
602
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 size_t read_count = 0;
604 int reverse_count = 0;
605 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000606 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000607 TickInterval acc_ticks;
608
609 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000610 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000611
612 int delay_ms = 0;
613 int drift_samples = 0;
614 int capture_level = 127;
615 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000616 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000617
618 TickTime t0 = TickTime::Now();
619 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000620 int64_t max_time_us = 0;
621 int64_t max_time_reverse_us = 0;
622 int64_t min_time_us = 1e6;
623 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000624
ajm@google.com808e0e02011-08-03 21:08:51 +0000625 // TODO(ajm): Ideally we would refactor this block into separate functions,
626 // but for now we want to share the variables.
627 if (pb_file) {
628 Event event_msg;
629 while (ReadMessageFromFile(pb_file, &event_msg)) {
630 std::ostringstream trace_stream;
631 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
632 << primary_count << " (primary)";
633 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000634
ajm@google.com808e0e02011-08-03 21:08:51 +0000635 if (event_msg.type() == Event::INIT) {
636 ASSERT_TRUE(event_msg.has_init());
637 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000638
ajm@google.com808e0e02011-08-03 21:08:51 +0000639 ASSERT_TRUE(msg.has_sample_rate());
640 ASSERT_EQ(apm->kNoError,
641 apm->set_sample_rate_hz(msg.sample_rate()));
642
643 ASSERT_TRUE(msg.has_device_sample_rate());
644 ASSERT_EQ(apm->kNoError,
645 apm->echo_cancellation()->set_device_sample_rate_hz(
646 msg.device_sample_rate()));
647
648 ASSERT_TRUE(msg.has_num_input_channels());
649 ASSERT_TRUE(msg.has_num_output_channels());
650 ASSERT_EQ(apm->kNoError,
651 apm->set_num_channels(msg.num_input_channels(),
652 msg.num_output_channels()));
653
654 ASSERT_TRUE(msg.has_num_reverse_channels());
655 ASSERT_EQ(apm->kNoError,
656 apm->set_num_reverse_channels(msg.num_reverse_channels()));
657
658 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000659 far_frame.sample_rate_hz_ = msg.sample_rate();
660 far_frame.samples_per_channel_ = samples_per_channel;
661 far_frame.num_channels_ = msg.num_reverse_channels();
662 near_frame.sample_rate_hz_ = msg.sample_rate();
663 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000664 near_frame.num_channels_ = msg.num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000665
666 if (verbose) {
667 printf("Init at frame: %d (primary), %d (reverse)\n",
668 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000669 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000670 printf(" Primary channels: %d (in), %d (out)\n",
671 msg.num_input_channels(),
672 msg.num_output_channels());
673 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000674 }
675
676 } else if (event_msg.type() == Event::REVERSE_STREAM) {
677 ASSERT_TRUE(event_msg.has_reverse_stream());
678 const ReverseStream msg = event_msg.reverse_stream();
679 reverse_count++;
680
681 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000682 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000683 far_frame.num_channels_, msg.data().size());
684 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000685
686 if (perf_testing) {
687 t0 = TickTime::Now();
688 }
689
690 ASSERT_EQ(apm->kNoError,
691 apm->AnalyzeReverseStream(&far_frame));
692
693 if (perf_testing) {
694 t1 = TickTime::Now();
695 TickInterval tick_diff = t1 - t0;
696 acc_ticks += tick_diff;
697 if (tick_diff.Microseconds() > max_time_reverse_us) {
698 max_time_reverse_us = tick_diff.Microseconds();
699 }
700 if (tick_diff.Microseconds() < min_time_reverse_us) {
701 min_time_reverse_us = tick_diff.Microseconds();
702 }
703 }
704
705 } else if (event_msg.type() == Event::STREAM) {
706 ASSERT_TRUE(event_msg.has_stream());
707 const Stream msg = event_msg.stream();
708 primary_count++;
709
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000710 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000711 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000712
713 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000714 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000715 near_frame.num_channels_, msg.input_data().size());
716 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000717 msg.input_data().data(),
718 msg.input_data().size());
719
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000720 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000721 if (progress && primary_count % 100 == 0) {
722 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000723 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000724 fflush(stdout);
725 }
726
727 if (perf_testing) {
728 t0 = TickTime::Now();
729 }
730
731 ASSERT_EQ(apm->kNoError,
732 apm->gain_control()->set_stream_analog_level(msg.level()));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000733 delay_ms = msg.delay() + extra_delay_ms;
734 if (override_delay_ms) {
735 delay_ms = override_delay_ms;
736 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000737 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000738 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000739 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000740
741 int err = apm->ProcessStream(&near_frame);
742 if (err == apm->kBadStreamParameterWarning) {
743 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
744 }
745 ASSERT_TRUE(err == apm->kNoError ||
746 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000747 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000748
ajm@google.com808e0e02011-08-03 21:08:51 +0000749 stream_has_voice =
750 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
751 if (vad_out_file != NULL) {
752 ASSERT_EQ(1u, fwrite(&stream_has_voice,
753 sizeof(stream_has_voice),
754 1,
755 vad_out_file));
756 }
757
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000758 if (ns_prob_file != NULL) {
759 ns_speech_prob = apm->noise_suppression()->speech_probability();
760 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
761 sizeof(ns_speech_prob),
762 1,
763 ns_prob_file));
764 }
765
ajm@google.com808e0e02011-08-03 21:08:51 +0000766 if (perf_testing) {
767 t1 = TickTime::Now();
768 TickInterval tick_diff = t1 - t0;
769 acc_ticks += tick_diff;
770 if (tick_diff.Microseconds() > max_time_us) {
771 max_time_us = tick_diff.Microseconds();
772 }
773 if (tick_diff.Microseconds() < min_time_us) {
774 min_time_us = tick_diff.Microseconds();
775 }
776 }
777
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000778 size_t size = samples_per_channel * near_frame.num_channels_;
779 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000780 sizeof(int16_t),
781 size,
782 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000783 }
784 }
785
786 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000787
788 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000789 enum Events {
790 kInitializeEvent,
791 kRenderEvent,
792 kCaptureEvent,
793 kResetEventDeprecated
794 };
795 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000796 while (simulating || feof(event_file) == 0) {
797 std::ostringstream trace_stream;
798 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
799 << primary_count << " (primary)";
800 SCOPED_TRACE(trace_stream.str());
801
802 if (simulating) {
803 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 event = kCaptureEvent;
805 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000806 if (event == kRenderEvent) {
807 event = kCaptureEvent;
808 } else {
809 event = kRenderEvent;
810 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000811 }
812 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000813 read_count = fread(&event, sizeof(event), 1, event_file);
814 if (read_count != 1) {
815 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000816 }
817 }
818
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000819 far_frame.sample_rate_hz_ = sample_rate_hz;
820 far_frame.samples_per_channel_ = samples_per_channel;
821 far_frame.num_channels_ = num_render_channels;
822 near_frame.sample_rate_hz_ = sample_rate_hz;
823 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000824
ajm@google.com808e0e02011-08-03 21:08:51 +0000825 if (event == kInitializeEvent || event == kResetEventDeprecated) {
826 ASSERT_EQ(1u,
827 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
828 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000829
ajm@google.com808e0e02011-08-03 21:08:51 +0000830 ASSERT_EQ(1u,
831 fread(&device_sample_rate_hz,
832 sizeof(device_sample_rate_hz),
833 1,
834 event_file));
835
836 ASSERT_EQ(apm->kNoError,
837 apm->set_sample_rate_hz(sample_rate_hz));
838
839 ASSERT_EQ(apm->kNoError,
840 apm->echo_cancellation()->set_device_sample_rate_hz(
841 device_sample_rate_hz));
842
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000843 far_frame.sample_rate_hz_ = sample_rate_hz;
844 far_frame.samples_per_channel_ = samples_per_channel;
845 far_frame.num_channels_ = num_render_channels;
846 near_frame.sample_rate_hz_ = sample_rate_hz;
847 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000848
849 if (verbose) {
850 printf("Init at frame: %d (primary), %d (reverse)\n",
851 primary_count, reverse_count);
852 printf(" Sample rate: %d Hz\n", sample_rate_hz);
853 }
854
855 } else if (event == kRenderEvent) {
856 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000857
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000858 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000859 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000860 sizeof(int16_t),
861 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000862 far_file);
863
864 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000865 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000866 // Read an equal amount from the near file to avoid errors due to
867 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000868 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000869 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000870 break; // This is expected.
871 }
872 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000873 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000874 }
875
876 if (perf_testing) {
877 t0 = TickTime::Now();
878 }
879
880 ASSERT_EQ(apm->kNoError,
881 apm->AnalyzeReverseStream(&far_frame));
882
883 if (perf_testing) {
884 t1 = TickTime::Now();
885 TickInterval tick_diff = t1 - t0;
886 acc_ticks += tick_diff;
887 if (tick_diff.Microseconds() > max_time_reverse_us) {
888 max_time_reverse_us = tick_diff.Microseconds();
889 }
890 if (tick_diff.Microseconds() < min_time_reverse_us) {
891 min_time_reverse_us = tick_diff.Microseconds();
892 }
893 }
894
895 } else if (event == kCaptureEvent) {
896 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000897 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000898
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000899 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000900 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000901 sizeof(int16_t),
902 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000903 near_file);
904
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000905 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000906 if (progress && primary_count % 100 == 0) {
907 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000908 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000909 fflush(stdout);
910 }
911 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000912 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000913 break; // This is expected.
914 }
915
916 delay_ms = 0;
917 drift_samples = 0;
918 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000919 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000920
921 // TODO(ajm): sizeof(delay_ms) for current files?
922 ASSERT_EQ(1u,
923 fread(&delay_ms, 2, 1, delay_file));
924 ASSERT_EQ(1u,
925 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
926 }
927
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000928 if (apm->gain_control()->is_enabled() &&
929 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000930 SimulateMic(capture_level, &near_frame);
931 }
932
ajm@google.com808e0e02011-08-03 21:08:51 +0000933 if (perf_testing) {
934 t0 = TickTime::Now();
935 }
936
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000937 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000938 ASSERT_EQ(apm->kNoError,
939 apm->gain_control()->set_stream_analog_level(capture_level));
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000940 delay_ms += extra_delay_ms;
941 if (override_delay_ms) {
942 delay_ms = override_delay_ms;
943 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000944 ASSERT_EQ(apm->kNoError,
andrew@webrtc.orgca764ab2013-10-07 16:44:32 +0000945 apm->set_stream_delay_ms(delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000946 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000947
948 int err = apm->ProcessStream(&near_frame);
949 if (err == apm->kBadStreamParameterWarning) {
950 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
951 }
952 ASSERT_TRUE(err == apm->kNoError ||
953 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000954 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000955
956 capture_level = apm->gain_control()->stream_analog_level();
957
958 stream_has_voice =
959 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
960 if (vad_out_file != NULL) {
961 ASSERT_EQ(1u, fwrite(&stream_has_voice,
962 sizeof(stream_has_voice),
963 1,
964 vad_out_file));
965 }
966
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000967 if (ns_prob_file != NULL) {
968 ns_speech_prob = apm->noise_suppression()->speech_probability();
969 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
970 sizeof(ns_speech_prob),
971 1,
972 ns_prob_file));
973 }
974
ajm@google.com808e0e02011-08-03 21:08:51 +0000975 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
976 ASSERT_EQ(capture_level_in, capture_level);
977 }
978
979 if (perf_testing) {
980 t1 = TickTime::Now();
981 TickInterval tick_diff = t1 - t0;
982 acc_ticks += tick_diff;
983 if (tick_diff.Microseconds() > max_time_us) {
984 max_time_us = tick_diff.Microseconds();
985 }
986 if (tick_diff.Microseconds() < min_time_us) {
987 min_time_us = tick_diff.Microseconds();
988 }
989 }
990
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000991 size = samples_per_channel * near_frame.num_channels_;
992 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000993 sizeof(int16_t),
994 size,
995 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000997 else {
998 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000999 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 }
1001 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001002 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +00001003
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001004 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +00001005 const size_t path_size =
1006 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +00001007 scoped_array<char> echo_path(new char[path_size]);
1008 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
1009 ASSERT_EQ(path_size, fwrite(echo_path.get(),
1010 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +00001011 path_size,
1012 aecm_echo_path_out_file));
1013 fclose(aecm_echo_path_out_file);
1014 aecm_echo_path_out_file = NULL;
1015 }
1016
niklase@google.com470e71d2011-07-07 08:21:25 +00001017 if (verbose) {
1018 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
1019 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001020
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001021 if (apm->level_estimator()->is_enabled()) {
1022 printf("\n--Level metrics--\n");
1023 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
1024 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +00001025 if (apm->echo_cancellation()->are_metrics_enabled()) {
1026 EchoCancellation::Metrics metrics;
1027 apm->echo_cancellation()->GetMetrics(&metrics);
1028 printf("\n--Echo metrics--\n");
1029 printf("(avg, max, min)\n");
1030 printf("ERL: ");
1031 PrintStat(metrics.echo_return_loss);
1032 printf("ERLE: ");
1033 PrintStat(metrics.echo_return_loss_enhancement);
1034 printf("ANLP: ");
1035 PrintStat(metrics.a_nlp);
1036 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001037 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1038 int median = 0;
1039 int std = 0;
1040 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1041 printf("\n--Delay metrics--\n");
1042 printf("Median: %3d\n", median);
1043 printf("Standard deviation: %3d\n", std);
1044 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 }
1046
ajm@google.com808e0e02011-08-03 21:08:51 +00001047 if (!pb_file) {
1048 int8_t temp_int8;
1049 if (far_file) {
1050 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1051 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1052 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001053
ajm@google.com808e0e02011-08-03 21:08:51 +00001054 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1055 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1056
1057 if (!simulating) {
1058 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1059 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1060 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1061 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1062 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1063 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1064 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 }
1066
1067 if (perf_testing) {
1068 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001069 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1071 exec_time * 0.001, primary_count * 0.01);
1072 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1073 " %.3f ms (min)\n",
1074 (exec_time * 1.0) / primary_count,
1075 (max_time_us + max_time_reverse_us) / 1000.0,
1076 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001077 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001078 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001079 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 } else {
1081 printf("Warning: no capture frames\n");
1082 }
1083 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001084}
ajm@google.com808e0e02011-08-03 21:08:51 +00001085} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001086
1087int main(int argc, char* argv[])
1088{
1089 void_main(argc, argv);
1090
andrew@webrtc.org64235092011-08-19 21:22:08 +00001091 // Optional, but removes memory leak noise from Valgrind.
1092 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 return 0;
1094}