blob: fa6d378d017899e6fb33c56637f94403f5071e28 [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
niklase@google.com470e71d2011-07-07 08:21:25 +000020#include "gtest/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000021
kma@webrtc.org0e739502012-12-07 15:26:28 +000022#include "webrtc/modules/audio_processing/include/audio_processing.h"
23#include "webrtc/modules/interface/module_common_types.h"
24#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
25#include "webrtc/system_wrappers/interface/scoped_ptr.h"
26#include "webrtc/system_wrappers/interface/tick_util.h"
kjellander@webrtc.org10abe252012-12-17 18:28:07 +000027#include "webrtc/test/testsupport/fileutils.h"
kma@webrtc.org0e739502012-12-07 15:26:28 +000028#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000029#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
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
ajm@google.com808e0e02011-08-03 21:08:51 +000032#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000033#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000034
35using webrtc::AudioFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +000036using webrtc::AudioProcessing;
andrew@webrtc.org94c74132011-09-19 15:17:57 +000037using webrtc::EchoCancellation;
niklase@google.com470e71d2011-07-07 08:21:25 +000038using webrtc::GainControl;
39using webrtc::NoiseSuppression;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000040using webrtc::scoped_array;
ajm@google.com808e0e02011-08-03 21:08:51 +000041using webrtc::TickInterval;
42using webrtc::TickTime;
andrew@webrtc.org89752612012-10-12 16:41:45 +000043using webrtc::VoiceDetection;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000044
ajm@google.com808e0e02011-08-03 21:08:51 +000045using webrtc::audioproc::Event;
46using webrtc::audioproc::Init;
47using webrtc::audioproc::ReverseStream;
48using webrtc::audioproc::Stream;
49
50namespace {
51// Returns true on success, false on error or end-of-file.
52bool ReadMessageFromFile(FILE* file,
53 ::google::protobuf::MessageLite* msg) {
54 // The "wire format" for the size is little-endian.
55 // Assume process_test is running on a little-endian machine.
andrew@webrtc.orgcb181212011-10-26 00:27:17 +000056 int32_t size = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +000057 if (fread(&size, sizeof(int32_t), 1, file) != 1) {
58 return false;
59 }
60 if (size <= 0) {
61 return false;
62 }
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000063 const size_t usize = static_cast<size_t>(size);
ajm@google.com808e0e02011-08-03 21:08:51 +000064
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000065 scoped_array<char> array(new char[usize]);
66 if (fread(array.get(), sizeof(char), usize, file) != usize) {
ajm@google.com808e0e02011-08-03 21:08:51 +000067 return false;
68 }
69
70 msg->Clear();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000071 return msg->ParseFromArray(array.get(), usize);
ajm@google.com808e0e02011-08-03 21:08:51 +000072}
niklase@google.com470e71d2011-07-07 08:21:25 +000073
andrew@webrtc.org94c74132011-09-19 15:17:57 +000074void PrintStat(const AudioProcessing::Statistic& stat) {
75 printf("%d, %d, %d\n", stat.average,
76 stat.maximum,
77 stat.minimum);
78}
79
niklase@google.com470e71d2011-07-07 08:21:25 +000080void usage() {
81 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000082 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
83 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000084 printf(
85 "process_test is a test application for AudioProcessing.\n\n"
ajm@google.com808e0e02011-08-03 21:08:51 +000086 "When a protobuf debug file is available, specify it with -pb.\n"
87 "Alternately, when -ir or -i is used, the specified files will be\n"
88 "processed directly in a simulation mode. Otherwise the full set of\n"
89 "legacy test files is expected to be present in the working directory.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000090 printf("\n");
91 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000092 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000093 printf(" -fs SAMPLE_RATE_HZ\n");
94 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
95 printf(" -rch REVERSE_CHANNELS\n");
96 printf("\n");
97 printf("Component configuration:\n");
98 printf(
99 "All components are disabled by default. Each block below begins with a\n"
100 "flag to enable the component with default settings. The subsequent flags\n"
101 "in the block are used to provide configuration settings.\n");
102 printf("\n -aec Echo cancellation\n");
103 printf(" --drift_compensation\n");
104 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000105 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000106 printf(" --no_delay_logging\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +0000108 printf(" --aecm_echo_path_in_file FILE\n");
109 printf(" --aecm_echo_path_out_file FILE\n");
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000110 printf(" --no_comfort_noise\n");
111 printf(" --routing_mode MODE [0 - 4]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000112 printf("\n -agc Gain control\n");
113 printf(" --analog\n");
114 printf(" --adaptive_digital\n");
115 printf(" --fixed_digital\n");
116 printf(" --target_level LEVEL\n");
117 printf(" --compression_gain GAIN\n");
118 printf(" --limiter\n");
119 printf(" --no_limiter\n");
120 printf("\n -hpf High pass filter\n");
121 printf("\n -ns Noise suppression\n");
122 printf(" --ns_low\n");
123 printf(" --ns_moderate\n");
124 printf(" --ns_high\n");
125 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000126 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000127 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000128 printf(" --vad_out_file FILE\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000129 printf("\n Level metrics (enabled by default)\n");
130 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 printf("\n");
132 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000133 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000134 printf(" --delay DELAY Add DELAY ms to input value.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000135 printf(" --perf Measure performance.\n");
136 printf(" --quiet Suppress text output.\n");
137 printf(" --no_progress Suppress progress.\n");
138 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000141static float MicLevel2Gain(int level) {
142 return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000143}
144
145static void SimulateMic(int mic_level, AudioFrame* frame) {
146 mic_level = std::min(std::max(mic_level, 0), 255);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000147 float mic_gain = MicLevel2Gain(mic_level);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000148 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000149 float v;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000150 for (int n = 0; n < num_samples; n++) {
151 v = floor(frame->data_[n] * mic_gain + 0.5);
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000152 v = std::max(std::min(32767.0f, v), -32768.0f);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000153 frame->data_[n] = static_cast<int16_t>(v);
154 }
155}
156
niklase@google.com470e71d2011-07-07 08:21:25 +0000157// void function for gtest.
158void void_main(int argc, char* argv[]) {
159 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
160 usage();
161 return;
162 }
163
164 if (argc < 2) {
165 printf("Did you mean to run without arguments?\n");
166 printf("Try `process_test --help' for more information.\n\n");
167 }
168
169 AudioProcessing* apm = AudioProcessing::Create(0);
170 ASSERT_TRUE(apm != NULL);
171
ajm@google.com808e0e02011-08-03 21:08:51 +0000172 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000173 const char* far_filename = NULL;
174 const char* near_filename = NULL;
175 const char* out_filename = NULL;
176 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000177 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000178 const char* aecm_echo_path_in_filename = NULL;
179 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000180
181 int32_t sample_rate_hz = 16000;
182 int32_t device_sample_rate_hz = 16000;
183
184 int num_capture_input_channels = 1;
185 int num_capture_output_channels = 1;
186 int num_render_channels = 1;
187
188 int samples_per_channel = sample_rate_hz / 100;
189
190 bool simulating = false;
191 bool perf_testing = false;
192 bool verbose = true;
193 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000194 int extra_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 //bool interleaved = true;
196
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000197 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000199 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000200 i++;
201 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
202 pb_filename = argv[i];
203
204 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 i++;
206 ASSERT_LT(i, argc) << "Specify filename after -ir";
207 far_filename = argv[i];
208 simulating = true;
209
210 } else if (strcmp(argv[i], "-i") == 0) {
211 i++;
212 ASSERT_LT(i, argc) << "Specify filename after -i";
213 near_filename = argv[i];
214 simulating = true;
215
216 } else if (strcmp(argv[i], "-o") == 0) {
217 i++;
218 ASSERT_LT(i, argc) << "Specify filename after -o";
219 out_filename = argv[i];
220
221 } else if (strcmp(argv[i], "-fs") == 0) {
222 i++;
223 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
224 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
225 samples_per_channel = sample_rate_hz / 100;
226
227 ASSERT_EQ(apm->kNoError,
228 apm->set_sample_rate_hz(sample_rate_hz));
229
230 } else if (strcmp(argv[i], "-ch") == 0) {
231 i++;
232 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
233 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
234 i++;
235 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
236
237 ASSERT_EQ(apm->kNoError,
238 apm->set_num_channels(num_capture_input_channels,
239 num_capture_output_channels));
240
241 } else if (strcmp(argv[i], "-rch") == 0) {
242 i++;
243 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
244 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
245
246 ASSERT_EQ(apm->kNoError,
247 apm->set_num_reverse_channels(num_render_channels));
248
249 } else if (strcmp(argv[i], "-aec") == 0) {
250 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000251 ASSERT_EQ(apm->kNoError,
252 apm->echo_cancellation()->enable_metrics(true));
253 ASSERT_EQ(apm->kNoError,
254 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000255
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
257 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
258 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
259 // why it can give better performance despite passing zeros.
260 ASSERT_EQ(apm->kNoError,
261 apm->echo_cancellation()->enable_drift_compensation(true));
262 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
263 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
264 ASSERT_EQ(apm->kNoError,
265 apm->echo_cancellation()->enable_drift_compensation(false));
266
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000267 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
268 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
269 ASSERT_EQ(apm->kNoError,
270 apm->echo_cancellation()->enable_metrics(false));
271
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000272 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
273 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
274 ASSERT_EQ(apm->kNoError,
275 apm->echo_cancellation()->enable_delay_logging(false));
276
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000277 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
278 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
279
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 } else if (strcmp(argv[i], "-aecm") == 0) {
281 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
282
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000283 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
284 i++;
285 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
286 aecm_echo_path_in_filename = argv[i];
287
288 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
289 i++;
290 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
291 aecm_echo_path_out_filename = argv[i];
292
andrew@webrtc.org1acb3b32013-04-26 00:39:27 +0000293 } else if (strcmp(argv[i], "--no_comfort_noise") == 0) {
294 ASSERT_EQ(apm->kNoError,
295 apm->echo_control_mobile()->enable_comfort_noise(false));
296
297 } else if (strcmp(argv[i], "--routing_mode") == 0) {
298 i++;
299 ASSERT_LT(i, argc) << "Specify mode after --routing_mode";
300 int routing_mode;
301 ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode));
302 ASSERT_EQ(apm->kNoError,
303 apm->echo_control_mobile()->set_routing_mode(
304 static_cast<webrtc::EchoControlMobile::RoutingMode>(
305 routing_mode)));
306
niklase@google.com470e71d2011-07-07 08:21:25 +0000307 } else if (strcmp(argv[i], "-agc") == 0) {
308 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
309
310 } else if (strcmp(argv[i], "--analog") == 0) {
311 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
312 ASSERT_EQ(apm->kNoError,
313 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
314
315 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
316 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
317 ASSERT_EQ(apm->kNoError,
318 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
319
320 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
321 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
322 ASSERT_EQ(apm->kNoError,
323 apm->gain_control()->set_mode(GainControl::kFixedDigital));
324
325 } else if (strcmp(argv[i], "--target_level") == 0) {
326 i++;
327 int level;
328 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
329
330 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
331 ASSERT_EQ(apm->kNoError,
332 apm->gain_control()->set_target_level_dbfs(level));
333
334 } else if (strcmp(argv[i], "--compression_gain") == 0) {
335 i++;
336 int gain;
337 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
338
339 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
340 ASSERT_EQ(apm->kNoError,
341 apm->gain_control()->set_compression_gain_db(gain));
342
343 } else if (strcmp(argv[i], "--limiter") == 0) {
344 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
345 ASSERT_EQ(apm->kNoError,
346 apm->gain_control()->enable_limiter(true));
347
348 } else if (strcmp(argv[i], "--no_limiter") == 0) {
349 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
350 ASSERT_EQ(apm->kNoError,
351 apm->gain_control()->enable_limiter(false));
352
353 } else if (strcmp(argv[i], "-hpf") == 0) {
354 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
355
356 } else if (strcmp(argv[i], "-ns") == 0) {
357 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
358
359 } else if (strcmp(argv[i], "--ns_low") == 0) {
360 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
361 ASSERT_EQ(apm->kNoError,
362 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
363
364 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
365 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
366 ASSERT_EQ(apm->kNoError,
367 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
368
369 } else if (strcmp(argv[i], "--ns_high") == 0) {
370 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
371 ASSERT_EQ(apm->kNoError,
372 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
373
374 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
375 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
376 ASSERT_EQ(apm->kNoError,
377 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
378
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000379 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
380 i++;
381 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
382 ns_prob_filename = argv[i];
383
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 } else if (strcmp(argv[i], "-vad") == 0) {
385 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
386
andrew@webrtc.org89752612012-10-12 16:41:45 +0000387 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
388 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
389 ASSERT_EQ(apm->kNoError,
390 apm->voice_detection()->set_likelihood(
391 VoiceDetection::kVeryLowLikelihood));
392
393 } else if (strcmp(argv[i], "--vad_low") == 0) {
394 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
395 ASSERT_EQ(apm->kNoError,
396 apm->voice_detection()->set_likelihood(
397 VoiceDetection::kLowLikelihood));
398
399 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
400 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
401 ASSERT_EQ(apm->kNoError,
402 apm->voice_detection()->set_likelihood(
403 VoiceDetection::kModerateLikelihood));
404
405 } else if (strcmp(argv[i], "--vad_high") == 0) {
406 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
407 ASSERT_EQ(apm->kNoError,
408 apm->voice_detection()->set_likelihood(
409 VoiceDetection::kHighLikelihood));
410
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
412 i++;
413 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
414 vad_out_filename = argv[i];
415
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000416 } else if (strcmp(argv[i], "--noasm") == 0) {
417 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
418 // We need to reinitialize here if components have already been enabled.
419 ASSERT_EQ(apm->kNoError, apm->Initialize());
420
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000421 } else if (strcmp(argv[i], "--delay") == 0) {
422 i++;
423 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
424
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 } else if (strcmp(argv[i], "--perf") == 0) {
426 perf_testing = true;
427
428 } else if (strcmp(argv[i], "--quiet") == 0) {
429 verbose = false;
430 progress = false;
431
432 } else if (strcmp(argv[i], "--no_progress") == 0) {
433 progress = false;
434
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000435 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000436 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000437 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000438 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 } else {
440 FAIL() << "Unrecognized argument " << argv[i];
441 }
442 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000443 // If we're reading a protobuf file, ensure a simulation hasn't also
444 // been requested (which makes no sense...)
445 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000446
447 if (verbose) {
448 printf("Sample rate: %d Hz\n", sample_rate_hz);
449 printf("Primary channels: %d (in), %d (out)\n",
450 num_capture_input_channels,
451 num_capture_output_channels);
452 printf("Reverse channels: %d \n", num_render_channels);
453 }
454
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000455 const std::string out_path = webrtc::test::OutputPath();
niklase@google.com470e71d2011-07-07 08:21:25 +0000456 const char far_file_default[] = "apm_far.pcm";
457 const char near_file_default[] = "apm_near.pcm";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000458 const std::string out_file_default = out_path + "out.pcm";
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 const char event_filename[] = "apm_event.dat";
460 const char delay_filename[] = "apm_delay.dat";
461 const char drift_filename[] = "apm_drift.dat";
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000462 const std::string vad_file_default = out_path + "vad_out.dat";
463 const std::string ns_prob_file_default = out_path + "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000464
465 if (!simulating) {
466 far_filename = far_file_default;
467 near_filename = near_file_default;
468 }
469
ajm@google.com808e0e02011-08-03 21:08:51 +0000470 if (!out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000471 out_filename = out_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 }
473
ajm@google.com808e0e02011-08-03 21:08:51 +0000474 if (!vad_out_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000475 vad_out_filename = vad_file_default.c_str();
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 }
477
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000478 if (!ns_prob_filename) {
kjellander@webrtc.org10abe252012-12-17 18:28:07 +0000479 ns_prob_filename = ns_prob_file_default.c_str();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000480 }
481
ajm@google.com808e0e02011-08-03 21:08:51 +0000482 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 FILE* far_file = NULL;
484 FILE* near_file = NULL;
485 FILE* out_file = NULL;
486 FILE* event_file = NULL;
487 FILE* delay_file = NULL;
488 FILE* drift_file = NULL;
489 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000490 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000491 FILE* aecm_echo_path_in_file = NULL;
492 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000493
ajm@google.com808e0e02011-08-03 21:08:51 +0000494 if (pb_filename) {
495 pb_file = fopen(pb_filename, "rb");
496 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
497 << pb_filename;
498 } else {
499 if (far_filename) {
500 far_file = fopen(far_filename, "rb");
501 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
502 << far_filename;
503 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000504
ajm@google.com808e0e02011-08-03 21:08:51 +0000505 near_file = fopen(near_filename, "rb");
506 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
507 << near_filename;
508 if (!simulating) {
509 event_file = fopen(event_filename, "rb");
510 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
511 << event_filename;
512
513 delay_file = fopen(delay_filename, "rb");
514 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
515 << delay_filename;
516
517 drift_file = fopen(drift_filename, "rb");
518 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
519 << drift_filename;
520 }
521 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000522
523 out_file = fopen(out_filename, "wb");
524 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
525 << out_filename;
526
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000527 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000528 if (pb_file) {
529 struct stat st;
530 stat(pb_filename, &st);
531 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000532 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000533 } else {
534 struct stat st;
535 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000536 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000537 }
538
539 if (apm->voice_detection()->is_enabled()) {
540 vad_out_file = fopen(vad_out_filename, "wb");
541 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
542 << vad_out_file;
543 }
544
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000545 if (apm->noise_suppression()->is_enabled()) {
546 ns_prob_file = fopen(ns_prob_filename, "wb");
547 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
548 << ns_prob_file;
549 }
550
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000551 if (aecm_echo_path_in_filename != NULL) {
552 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
553 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
554 << aecm_echo_path_in_filename;
555
ajm@google.com22e65152011-07-18 18:03:01 +0000556 const size_t path_size =
557 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000558 scoped_array<char> echo_path(new char[path_size]);
559 ASSERT_EQ(path_size, fread(echo_path.get(),
560 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000561 path_size,
562 aecm_echo_path_in_file));
563 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000564 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
565 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000566 fclose(aecm_echo_path_in_file);
567 aecm_echo_path_in_file = NULL;
568 }
569
570 if (aecm_echo_path_out_filename != NULL) {
571 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
572 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
573 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000574 }
575
niklase@google.com470e71d2011-07-07 08:21:25 +0000576 size_t read_count = 0;
577 int reverse_count = 0;
578 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000579 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000580 TickInterval acc_ticks;
581
582 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
585 int delay_ms = 0;
586 int drift_samples = 0;
587 int capture_level = 127;
588 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000589 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000590
591 TickTime t0 = TickTime::Now();
592 TickTime t1 = t0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000593 int64_t max_time_us = 0;
594 int64_t max_time_reverse_us = 0;
595 int64_t min_time_us = 1e6;
596 int64_t min_time_reverse_us = 1e6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597
ajm@google.com808e0e02011-08-03 21:08:51 +0000598 // TODO(ajm): Ideally we would refactor this block into separate functions,
599 // but for now we want to share the variables.
600 if (pb_file) {
601 Event event_msg;
602 while (ReadMessageFromFile(pb_file, &event_msg)) {
603 std::ostringstream trace_stream;
604 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
605 << primary_count << " (primary)";
606 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000607
ajm@google.com808e0e02011-08-03 21:08:51 +0000608 if (event_msg.type() == Event::INIT) {
609 ASSERT_TRUE(event_msg.has_init());
610 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000611
ajm@google.com808e0e02011-08-03 21:08:51 +0000612 ASSERT_TRUE(msg.has_sample_rate());
613 ASSERT_EQ(apm->kNoError,
614 apm->set_sample_rate_hz(msg.sample_rate()));
615
616 ASSERT_TRUE(msg.has_device_sample_rate());
617 ASSERT_EQ(apm->kNoError,
618 apm->echo_cancellation()->set_device_sample_rate_hz(
619 msg.device_sample_rate()));
620
621 ASSERT_TRUE(msg.has_num_input_channels());
622 ASSERT_TRUE(msg.has_num_output_channels());
623 ASSERT_EQ(apm->kNoError,
624 apm->set_num_channels(msg.num_input_channels(),
625 msg.num_output_channels()));
626
627 ASSERT_TRUE(msg.has_num_reverse_channels());
628 ASSERT_EQ(apm->kNoError,
629 apm->set_num_reverse_channels(msg.num_reverse_channels()));
630
631 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000632 far_frame.sample_rate_hz_ = msg.sample_rate();
633 far_frame.samples_per_channel_ = samples_per_channel;
634 far_frame.num_channels_ = msg.num_reverse_channels();
635 near_frame.sample_rate_hz_ = msg.sample_rate();
636 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000637 near_frame.num_channels_ = msg.num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000638
639 if (verbose) {
640 printf("Init at frame: %d (primary), %d (reverse)\n",
641 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000642 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000643 printf(" Primary channels: %d (in), %d (out)\n",
644 msg.num_input_channels(),
645 msg.num_output_channels());
646 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000647 }
648
649 } else if (event_msg.type() == Event::REVERSE_STREAM) {
650 ASSERT_TRUE(event_msg.has_reverse_stream());
651 const ReverseStream msg = event_msg.reverse_stream();
652 reverse_count++;
653
654 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000655 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000656 far_frame.num_channels_, msg.data().size());
657 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000658
659 if (perf_testing) {
660 t0 = TickTime::Now();
661 }
662
663 ASSERT_EQ(apm->kNoError,
664 apm->AnalyzeReverseStream(&far_frame));
665
666 if (perf_testing) {
667 t1 = TickTime::Now();
668 TickInterval tick_diff = t1 - t0;
669 acc_ticks += tick_diff;
670 if (tick_diff.Microseconds() > max_time_reverse_us) {
671 max_time_reverse_us = tick_diff.Microseconds();
672 }
673 if (tick_diff.Microseconds() < min_time_reverse_us) {
674 min_time_reverse_us = tick_diff.Microseconds();
675 }
676 }
677
678 } else if (event_msg.type() == Event::STREAM) {
679 ASSERT_TRUE(event_msg.has_stream());
680 const Stream msg = event_msg.stream();
681 primary_count++;
682
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000683 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000684 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000685
686 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000687 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000688 near_frame.num_channels_, msg.input_data().size());
689 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000690 msg.input_data().data(),
691 msg.input_data().size());
692
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000693 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000694 if (progress && primary_count % 100 == 0) {
695 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000696 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000697 fflush(stdout);
698 }
699
700 if (perf_testing) {
701 t0 = TickTime::Now();
702 }
703
704 ASSERT_EQ(apm->kNoError,
705 apm->gain_control()->set_stream_analog_level(msg.level()));
706 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000707 apm->set_stream_delay_ms(msg.delay() + extra_delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000708 apm->echo_cancellation()->set_stream_drift_samples(msg.drift());
ajm@google.com808e0e02011-08-03 21:08:51 +0000709
710 int err = apm->ProcessStream(&near_frame);
711 if (err == apm->kBadStreamParameterWarning) {
712 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
713 }
714 ASSERT_TRUE(err == apm->kNoError ||
715 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000716 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000717
ajm@google.com808e0e02011-08-03 21:08:51 +0000718 stream_has_voice =
719 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
720 if (vad_out_file != NULL) {
721 ASSERT_EQ(1u, fwrite(&stream_has_voice,
722 sizeof(stream_has_voice),
723 1,
724 vad_out_file));
725 }
726
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000727 if (ns_prob_file != NULL) {
728 ns_speech_prob = apm->noise_suppression()->speech_probability();
729 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
730 sizeof(ns_speech_prob),
731 1,
732 ns_prob_file));
733 }
734
ajm@google.com808e0e02011-08-03 21:08:51 +0000735 if (perf_testing) {
736 t1 = TickTime::Now();
737 TickInterval tick_diff = t1 - t0;
738 acc_ticks += tick_diff;
739 if (tick_diff.Microseconds() > max_time_us) {
740 max_time_us = tick_diff.Microseconds();
741 }
742 if (tick_diff.Microseconds() < min_time_us) {
743 min_time_us = tick_diff.Microseconds();
744 }
745 }
746
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000747 size_t size = samples_per_channel * near_frame.num_channels_;
748 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000749 sizeof(int16_t),
750 size,
751 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000752 }
753 }
754
755 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000756
757 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000758 enum Events {
759 kInitializeEvent,
760 kRenderEvent,
761 kCaptureEvent,
762 kResetEventDeprecated
763 };
764 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000765 while (simulating || feof(event_file) == 0) {
766 std::ostringstream trace_stream;
767 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
768 << primary_count << " (primary)";
769 SCOPED_TRACE(trace_stream.str());
770
771 if (simulating) {
772 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000773 event = kCaptureEvent;
774 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000775 if (event == kRenderEvent) {
776 event = kCaptureEvent;
777 } else {
778 event = kRenderEvent;
779 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000780 }
781 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000782 read_count = fread(&event, sizeof(event), 1, event_file);
783 if (read_count != 1) {
784 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000785 }
786 }
787
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000788 far_frame.sample_rate_hz_ = sample_rate_hz;
789 far_frame.samples_per_channel_ = samples_per_channel;
790 far_frame.num_channels_ = num_render_channels;
791 near_frame.sample_rate_hz_ = sample_rate_hz;
792 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000793
ajm@google.com808e0e02011-08-03 21:08:51 +0000794 if (event == kInitializeEvent || event == kResetEventDeprecated) {
795 ASSERT_EQ(1u,
796 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
797 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000798
ajm@google.com808e0e02011-08-03 21:08:51 +0000799 ASSERT_EQ(1u,
800 fread(&device_sample_rate_hz,
801 sizeof(device_sample_rate_hz),
802 1,
803 event_file));
804
805 ASSERT_EQ(apm->kNoError,
806 apm->set_sample_rate_hz(sample_rate_hz));
807
808 ASSERT_EQ(apm->kNoError,
809 apm->echo_cancellation()->set_device_sample_rate_hz(
810 device_sample_rate_hz));
811
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000812 far_frame.sample_rate_hz_ = sample_rate_hz;
813 far_frame.samples_per_channel_ = samples_per_channel;
814 far_frame.num_channels_ = num_render_channels;
815 near_frame.sample_rate_hz_ = sample_rate_hz;
816 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000817
818 if (verbose) {
819 printf("Init at frame: %d (primary), %d (reverse)\n",
820 primary_count, reverse_count);
821 printf(" Sample rate: %d Hz\n", sample_rate_hz);
822 }
823
824 } else if (event == kRenderEvent) {
825 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000826
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000827 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000828 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000829 sizeof(int16_t),
830 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000831 far_file);
832
833 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000834 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000835 // Read an equal amount from the near file to avoid errors due to
836 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000837 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000838 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000839 break; // This is expected.
840 }
841 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000842 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000843 }
844
845 if (perf_testing) {
846 t0 = TickTime::Now();
847 }
848
849 ASSERT_EQ(apm->kNoError,
850 apm->AnalyzeReverseStream(&far_frame));
851
852 if (perf_testing) {
853 t1 = TickTime::Now();
854 TickInterval tick_diff = t1 - t0;
855 acc_ticks += tick_diff;
856 if (tick_diff.Microseconds() > max_time_reverse_us) {
857 max_time_reverse_us = tick_diff.Microseconds();
858 }
859 if (tick_diff.Microseconds() < min_time_reverse_us) {
860 min_time_reverse_us = tick_diff.Microseconds();
861 }
862 }
863
864 } else if (event == kCaptureEvent) {
865 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000866 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000867
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000868 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000869 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000870 sizeof(int16_t),
871 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000872 near_file);
873
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000874 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000875 if (progress && primary_count % 100 == 0) {
876 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000877 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000878 fflush(stdout);
879 }
880 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000881 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000882 break; // This is expected.
883 }
884
885 delay_ms = 0;
886 drift_samples = 0;
887 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000888 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000889
890 // TODO(ajm): sizeof(delay_ms) for current files?
891 ASSERT_EQ(1u,
892 fread(&delay_ms, 2, 1, delay_file));
893 ASSERT_EQ(1u,
894 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
895 }
896
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000897 if (apm->gain_control()->is_enabled() &&
898 apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000899 SimulateMic(capture_level, &near_frame);
900 }
901
ajm@google.com808e0e02011-08-03 21:08:51 +0000902 if (perf_testing) {
903 t0 = TickTime::Now();
904 }
905
andrew@webrtc.orgbafdae32013-01-11 23:11:29 +0000906 const int capture_level_in = capture_level;
ajm@google.com808e0e02011-08-03 21:08:51 +0000907 ASSERT_EQ(apm->kNoError,
908 apm->gain_control()->set_stream_analog_level(capture_level));
909 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000910 apm->set_stream_delay_ms(delay_ms + extra_delay_ms));
andrew@webrtc.org6be1e932013-03-01 18:47:28 +0000911 apm->echo_cancellation()->set_stream_drift_samples(drift_samples);
ajm@google.com808e0e02011-08-03 21:08:51 +0000912
913 int err = apm->ProcessStream(&near_frame);
914 if (err == apm->kBadStreamParameterWarning) {
915 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
916 }
917 ASSERT_TRUE(err == apm->kNoError ||
918 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000919 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000920
921 capture_level = apm->gain_control()->stream_analog_level();
922
923 stream_has_voice =
924 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
925 if (vad_out_file != NULL) {
926 ASSERT_EQ(1u, fwrite(&stream_has_voice,
927 sizeof(stream_has_voice),
928 1,
929 vad_out_file));
930 }
931
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000932 if (ns_prob_file != NULL) {
933 ns_speech_prob = apm->noise_suppression()->speech_probability();
934 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
935 sizeof(ns_speech_prob),
936 1,
937 ns_prob_file));
938 }
939
ajm@google.com808e0e02011-08-03 21:08:51 +0000940 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
941 ASSERT_EQ(capture_level_in, capture_level);
942 }
943
944 if (perf_testing) {
945 t1 = TickTime::Now();
946 TickInterval tick_diff = t1 - t0;
947 acc_ticks += tick_diff;
948 if (tick_diff.Microseconds() > max_time_us) {
949 max_time_us = tick_diff.Microseconds();
950 }
951 if (tick_diff.Microseconds() < min_time_us) {
952 min_time_us = tick_diff.Microseconds();
953 }
954 }
955
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000956 size = samples_per_channel * near_frame.num_channels_;
957 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000958 sizeof(int16_t),
959 size,
960 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000961 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000962 else {
963 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000965 }
966 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000967 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000968
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000969 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000970 const size_t path_size =
971 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000972 scoped_array<char> echo_path(new char[path_size]);
973 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
974 ASSERT_EQ(path_size, fwrite(echo_path.get(),
975 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000976 path_size,
977 aecm_echo_path_out_file));
978 fclose(aecm_echo_path_out_file);
979 aecm_echo_path_out_file = NULL;
980 }
981
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 if (verbose) {
983 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
984 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000985
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000986 if (apm->level_estimator()->is_enabled()) {
987 printf("\n--Level metrics--\n");
988 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
989 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000990 if (apm->echo_cancellation()->are_metrics_enabled()) {
991 EchoCancellation::Metrics metrics;
992 apm->echo_cancellation()->GetMetrics(&metrics);
993 printf("\n--Echo metrics--\n");
994 printf("(avg, max, min)\n");
995 printf("ERL: ");
996 PrintStat(metrics.echo_return_loss);
997 printf("ERLE: ");
998 PrintStat(metrics.echo_return_loss_enhancement);
999 printf("ANLP: ");
1000 PrintStat(metrics.a_nlp);
1001 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +00001002 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
1003 int median = 0;
1004 int std = 0;
1005 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1006 printf("\n--Delay metrics--\n");
1007 printf("Median: %3d\n", median);
1008 printf("Standard deviation: %3d\n", std);
1009 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 }
1011
ajm@google.com808e0e02011-08-03 21:08:51 +00001012 if (!pb_file) {
1013 int8_t temp_int8;
1014 if (far_file) {
1015 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1016 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1017 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001018
ajm@google.com808e0e02011-08-03 21:08:51 +00001019 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1020 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1021
1022 if (!simulating) {
1023 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1024 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1025 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1026 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1027 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1028 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1029 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 }
1031
1032 if (perf_testing) {
1033 if (primary_count > 0) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001034 int64_t exec_time = acc_ticks.Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1036 exec_time * 0.001, primary_count * 0.01);
1037 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1038 " %.3f ms (min)\n",
1039 (exec_time * 1.0) / primary_count,
1040 (max_time_us + max_time_reverse_us) / 1000.0,
1041 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001042 // Record the results with Perf test tools.
kjellander@webrtc.org00ab7cf2013-02-11 12:33:03 +00001043 webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame",
kma@webrtc.org0e739502012-12-07 15:26:28 +00001044 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 } else {
1046 printf("Warning: no capture frames\n");
1047 }
1048 }
1049
1050 AudioProcessing::Destroy(apm);
1051 apm = NULL;
1052}
ajm@google.com808e0e02011-08-03 21:08:51 +00001053} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001054
1055int main(int argc, char* argv[])
1056{
1057 void_main(argc, argv);
1058
andrew@webrtc.org64235092011-08-19 21:22:08 +00001059 // Optional, but removes memory leak noise from Valgrind.
1060 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 return 0;
1062}