blob: 70c4b1531e064288d04158aeddd59cf65252b567 [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"
27#include "webrtc/test/testsupport/perf_test.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000028#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000029#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000030#else
ajm@google.com808e0e02011-08-03 21:08:51 +000031#include "webrtc/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000032#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000033
34using webrtc::AudioFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +000035using webrtc::AudioProcessing;
andrew@webrtc.org94c74132011-09-19 15:17:57 +000036using webrtc::EchoCancellation;
niklase@google.com470e71d2011-07-07 08:21:25 +000037using webrtc::GainControl;
38using webrtc::NoiseSuppression;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000039using webrtc::scoped_array;
ajm@google.com808e0e02011-08-03 21:08:51 +000040using webrtc::TickInterval;
41using webrtc::TickTime;
andrew@webrtc.org89752612012-10-12 16:41:45 +000042using webrtc::VoiceDetection;
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000043
ajm@google.com808e0e02011-08-03 21:08:51 +000044using webrtc::audioproc::Event;
45using webrtc::audioproc::Init;
46using webrtc::audioproc::ReverseStream;
47using webrtc::audioproc::Stream;
48
49namespace {
50// Returns true on success, false on error or end-of-file.
51bool ReadMessageFromFile(FILE* file,
52 ::google::protobuf::MessageLite* msg) {
53 // The "wire format" for the size is little-endian.
54 // Assume process_test is running on a little-endian machine.
andrew@webrtc.orgcb181212011-10-26 00:27:17 +000055 int32_t size = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +000056 if (fread(&size, sizeof(int32_t), 1, file) != 1) {
57 return false;
58 }
59 if (size <= 0) {
60 return false;
61 }
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000062 const size_t usize = static_cast<size_t>(size);
ajm@google.com808e0e02011-08-03 21:08:51 +000063
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000064 scoped_array<char> array(new char[usize]);
65 if (fread(array.get(), sizeof(char), usize, file) != usize) {
ajm@google.com808e0e02011-08-03 21:08:51 +000066 return false;
67 }
68
69 msg->Clear();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +000070 return msg->ParseFromArray(array.get(), usize);
ajm@google.com808e0e02011-08-03 21:08:51 +000071}
niklase@google.com470e71d2011-07-07 08:21:25 +000072
andrew@webrtc.org94c74132011-09-19 15:17:57 +000073void PrintStat(const AudioProcessing::Statistic& stat) {
74 printf("%d, %d, %d\n", stat.average,
75 stat.maximum,
76 stat.minimum);
77}
78
niklase@google.com470e71d2011-07-07 08:21:25 +000079void usage() {
80 printf(
ajm@google.com808e0e02011-08-03 21:08:51 +000081 "Usage: process_test [options] [-pb PROTOBUF_FILE]\n"
82 " [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000083 printf(
84 "process_test is a test application for AudioProcessing.\n\n"
ajm@google.com808e0e02011-08-03 21:08:51 +000085 "When a protobuf debug file is available, specify it with -pb.\n"
86 "Alternately, when -ir or -i is used, the specified files will be\n"
87 "processed directly in a simulation mode. Otherwise the full set of\n"
88 "legacy test files is expected to be present in the working directory.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000089 printf("\n");
90 printf("Options\n");
ajm@google.com808e0e02011-08-03 21:08:51 +000091 printf("General configuration (only used for the simulation mode):\n");
niklase@google.com470e71d2011-07-07 08:21:25 +000092 printf(" -fs SAMPLE_RATE_HZ\n");
93 printf(" -ch CHANNELS_IN CHANNELS_OUT\n");
94 printf(" -rch REVERSE_CHANNELS\n");
95 printf("\n");
96 printf("Component configuration:\n");
97 printf(
98 "All components are disabled by default. Each block below begins with a\n"
99 "flag to enable the component with default settings. The subsequent flags\n"
100 "in the block are used to provide configuration settings.\n");
101 printf("\n -aec Echo cancellation\n");
102 printf(" --drift_compensation\n");
103 printf(" --no_drift_compensation\n");
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000104 printf(" --no_echo_metrics\n");
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000105 printf(" --no_delay_logging\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000106 printf("\n -aecm Echo control mobile\n");
bjornv@google.com238a0222011-07-15 14:51:52 +0000107 printf(" --aecm_echo_path_in_file FILE\n");
108 printf(" --aecm_echo_path_out_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000109 printf("\n -agc Gain control\n");
110 printf(" --analog\n");
111 printf(" --adaptive_digital\n");
112 printf(" --fixed_digital\n");
113 printf(" --target_level LEVEL\n");
114 printf(" --compression_gain GAIN\n");
115 printf(" --limiter\n");
116 printf(" --no_limiter\n");
117 printf("\n -hpf High pass filter\n");
118 printf("\n -ns Noise suppression\n");
119 printf(" --ns_low\n");
120 printf(" --ns_moderate\n");
121 printf(" --ns_high\n");
122 printf(" --ns_very_high\n");
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000123 printf(" --ns_prob_file FILE\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000124 printf("\n -vad Voice activity detection\n");
ajm@google.com808e0e02011-08-03 21:08:51 +0000125 printf(" --vad_out_file FILE\n");
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000126 printf("\n Level metrics (enabled by default)\n");
127 printf(" --no_level_metrics\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000128 printf("\n");
129 printf("Modifiers:\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000130 printf(" --noasm Disable SSE optimization.\n");
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000131 printf(" --delay DELAY Add DELAY ms to input value.\n");
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000132 printf(" --perf Measure performance.\n");
133 printf(" --quiet Suppress text output.\n");
134 printf(" --no_progress Suppress progress.\n");
135 printf(" --debug_file FILE Dump a debug recording.\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000136}
137
andrew@webrtc.org81865342012-10-27 00:28:27 +0000138static double MicLevel2Gain(int level) {
139 return pow(10.0, ((level - 127.0) / 128.0 * 80.) / 20.);
140}
141
142static void SimulateMic(int mic_level, AudioFrame* frame) {
143 mic_level = std::min(std::max(mic_level, 0), 255);
144 double mic_gain = MicLevel2Gain(mic_level);
145 int num_samples = frame->samples_per_channel_ * frame->num_channels_;
146 double v;
147 for (int n = 0; n < num_samples; n++) {
148 v = floor(frame->data_[n] * mic_gain + 0.5);
149 v = std::max(std::min(32767., v), -32768.);
150 frame->data_[n] = static_cast<int16_t>(v);
151 }
152}
153
niklase@google.com470e71d2011-07-07 08:21:25 +0000154// void function for gtest.
155void void_main(int argc, char* argv[]) {
156 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
157 usage();
158 return;
159 }
160
161 if (argc < 2) {
162 printf("Did you mean to run without arguments?\n");
163 printf("Try `process_test --help' for more information.\n\n");
164 }
165
166 AudioProcessing* apm = AudioProcessing::Create(0);
167 ASSERT_TRUE(apm != NULL);
168
ajm@google.com808e0e02011-08-03 21:08:51 +0000169 const char* pb_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 const char* far_filename = NULL;
171 const char* near_filename = NULL;
172 const char* out_filename = NULL;
173 const char* vad_out_filename = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000174 const char* ns_prob_filename = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000175 const char* aecm_echo_path_in_filename = NULL;
176 const char* aecm_echo_path_out_filename = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000177
178 int32_t sample_rate_hz = 16000;
179 int32_t device_sample_rate_hz = 16000;
180
181 int num_capture_input_channels = 1;
182 int num_capture_output_channels = 1;
183 int num_render_channels = 1;
184
185 int samples_per_channel = sample_rate_hz / 100;
186
187 bool simulating = false;
188 bool perf_testing = false;
189 bool verbose = true;
190 bool progress = true;
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000191 int extra_delay_ms = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 //bool interleaved = true;
193
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000194 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 for (int i = 1; i < argc; i++) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000196 if (strcmp(argv[i], "-pb") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000197 i++;
198 ASSERT_LT(i, argc) << "Specify protobuf filename after -pb";
199 pb_filename = argv[i];
200
201 } else if (strcmp(argv[i], "-ir") == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 i++;
203 ASSERT_LT(i, argc) << "Specify filename after -ir";
204 far_filename = argv[i];
205 simulating = true;
206
207 } else if (strcmp(argv[i], "-i") == 0) {
208 i++;
209 ASSERT_LT(i, argc) << "Specify filename after -i";
210 near_filename = argv[i];
211 simulating = true;
212
213 } else if (strcmp(argv[i], "-o") == 0) {
214 i++;
215 ASSERT_LT(i, argc) << "Specify filename after -o";
216 out_filename = argv[i];
217
218 } else if (strcmp(argv[i], "-fs") == 0) {
219 i++;
220 ASSERT_LT(i, argc) << "Specify sample rate after -fs";
221 ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz));
222 samples_per_channel = sample_rate_hz / 100;
223
224 ASSERT_EQ(apm->kNoError,
225 apm->set_sample_rate_hz(sample_rate_hz));
226
227 } else if (strcmp(argv[i], "-ch") == 0) {
228 i++;
229 ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch";
230 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_input_channels));
231 i++;
232 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_capture_output_channels));
233
234 ASSERT_EQ(apm->kNoError,
235 apm->set_num_channels(num_capture_input_channels,
236 num_capture_output_channels));
237
238 } else if (strcmp(argv[i], "-rch") == 0) {
239 i++;
240 ASSERT_LT(i, argc) << "Specify number of channels after -rch";
241 ASSERT_EQ(1, sscanf(argv[i], "%d", &num_render_channels));
242
243 ASSERT_EQ(apm->kNoError,
244 apm->set_num_reverse_channels(num_render_channels));
245
246 } else if (strcmp(argv[i], "-aec") == 0) {
247 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000248 ASSERT_EQ(apm->kNoError,
249 apm->echo_cancellation()->enable_metrics(true));
250 ASSERT_EQ(apm->kNoError,
251 apm->echo_cancellation()->enable_delay_logging(true));
niklase@google.com470e71d2011-07-07 08:21:25 +0000252
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 } else if (strcmp(argv[i], "--drift_compensation") == 0) {
254 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
255 // TODO(ajm): this is enabled in the VQE test app by default. Investigate
256 // why it can give better performance despite passing zeros.
257 ASSERT_EQ(apm->kNoError,
258 apm->echo_cancellation()->enable_drift_compensation(true));
259 } else if (strcmp(argv[i], "--no_drift_compensation") == 0) {
260 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
261 ASSERT_EQ(apm->kNoError,
262 apm->echo_cancellation()->enable_drift_compensation(false));
263
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000264 } else if (strcmp(argv[i], "--no_echo_metrics") == 0) {
265 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
266 ASSERT_EQ(apm->kNoError,
267 apm->echo_cancellation()->enable_metrics(false));
268
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000269 } else if (strcmp(argv[i], "--no_delay_logging") == 0) {
270 ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
271 ASSERT_EQ(apm->kNoError,
272 apm->echo_cancellation()->enable_delay_logging(false));
273
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000274 } else if (strcmp(argv[i], "--no_level_metrics") == 0) {
275 ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false));
276
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 } else if (strcmp(argv[i], "-aecm") == 0) {
278 ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
279
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000280 } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) {
281 i++;
282 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file";
283 aecm_echo_path_in_filename = argv[i];
284
285 } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) {
286 i++;
287 ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file";
288 aecm_echo_path_out_filename = argv[i];
289
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 } else if (strcmp(argv[i], "-agc") == 0) {
291 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
292
293 } else if (strcmp(argv[i], "--analog") == 0) {
294 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
295 ASSERT_EQ(apm->kNoError,
296 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
297
298 } else if (strcmp(argv[i], "--adaptive_digital") == 0) {
299 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
300 ASSERT_EQ(apm->kNoError,
301 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital));
302
303 } else if (strcmp(argv[i], "--fixed_digital") == 0) {
304 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
305 ASSERT_EQ(apm->kNoError,
306 apm->gain_control()->set_mode(GainControl::kFixedDigital));
307
308 } else if (strcmp(argv[i], "--target_level") == 0) {
309 i++;
310 int level;
311 ASSERT_EQ(1, sscanf(argv[i], "%d", &level));
312
313 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
314 ASSERT_EQ(apm->kNoError,
315 apm->gain_control()->set_target_level_dbfs(level));
316
317 } else if (strcmp(argv[i], "--compression_gain") == 0) {
318 i++;
319 int gain;
320 ASSERT_EQ(1, sscanf(argv[i], "%d", &gain));
321
322 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
323 ASSERT_EQ(apm->kNoError,
324 apm->gain_control()->set_compression_gain_db(gain));
325
326 } else if (strcmp(argv[i], "--limiter") == 0) {
327 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
328 ASSERT_EQ(apm->kNoError,
329 apm->gain_control()->enable_limiter(true));
330
331 } else if (strcmp(argv[i], "--no_limiter") == 0) {
332 ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
333 ASSERT_EQ(apm->kNoError,
334 apm->gain_control()->enable_limiter(false));
335
336 } else if (strcmp(argv[i], "-hpf") == 0) {
337 ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true));
338
339 } else if (strcmp(argv[i], "-ns") == 0) {
340 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
341
342 } else if (strcmp(argv[i], "--ns_low") == 0) {
343 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
344 ASSERT_EQ(apm->kNoError,
345 apm->noise_suppression()->set_level(NoiseSuppression::kLow));
346
347 } else if (strcmp(argv[i], "--ns_moderate") == 0) {
348 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
349 ASSERT_EQ(apm->kNoError,
350 apm->noise_suppression()->set_level(NoiseSuppression::kModerate));
351
352 } else if (strcmp(argv[i], "--ns_high") == 0) {
353 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
354 ASSERT_EQ(apm->kNoError,
355 apm->noise_suppression()->set_level(NoiseSuppression::kHigh));
356
357 } else if (strcmp(argv[i], "--ns_very_high") == 0) {
358 ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
359 ASSERT_EQ(apm->kNoError,
360 apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh));
361
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000362 } else if (strcmp(argv[i], "--ns_prob_file") == 0) {
363 i++;
364 ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file";
365 ns_prob_filename = argv[i];
366
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 } else if (strcmp(argv[i], "-vad") == 0) {
368 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
369
andrew@webrtc.org89752612012-10-12 16:41:45 +0000370 } else if (strcmp(argv[i], "--vad_very_low") == 0) {
371 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
372 ASSERT_EQ(apm->kNoError,
373 apm->voice_detection()->set_likelihood(
374 VoiceDetection::kVeryLowLikelihood));
375
376 } else if (strcmp(argv[i], "--vad_low") == 0) {
377 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
378 ASSERT_EQ(apm->kNoError,
379 apm->voice_detection()->set_likelihood(
380 VoiceDetection::kLowLikelihood));
381
382 } else if (strcmp(argv[i], "--vad_moderate") == 0) {
383 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
384 ASSERT_EQ(apm->kNoError,
385 apm->voice_detection()->set_likelihood(
386 VoiceDetection::kModerateLikelihood));
387
388 } else if (strcmp(argv[i], "--vad_high") == 0) {
389 ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
390 ASSERT_EQ(apm->kNoError,
391 apm->voice_detection()->set_likelihood(
392 VoiceDetection::kHighLikelihood));
393
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 } else if (strcmp(argv[i], "--vad_out_file") == 0) {
395 i++;
396 ASSERT_LT(i, argc) << "Specify filename after --vad_out_file";
397 vad_out_filename = argv[i];
398
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000399 } else if (strcmp(argv[i], "--noasm") == 0) {
400 WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM;
401 // We need to reinitialize here if components have already been enabled.
402 ASSERT_EQ(apm->kNoError, apm->Initialize());
403
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000404 } else if (strcmp(argv[i], "--delay") == 0) {
405 i++;
406 ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms));
407
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 } else if (strcmp(argv[i], "--perf") == 0) {
409 perf_testing = true;
410
411 } else if (strcmp(argv[i], "--quiet") == 0) {
412 verbose = false;
413 progress = false;
414
415 } else if (strcmp(argv[i], "--no_progress") == 0) {
416 progress = false;
417
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000418 } else if (strcmp(argv[i], "--debug_file") == 0) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000419 i++;
andrew@webrtc.orgcb181212011-10-26 00:27:17 +0000420 ASSERT_LT(i, argc) << "Specify filename after --debug_file";
ajm@google.com808e0e02011-08-03 21:08:51 +0000421 ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 } else {
423 FAIL() << "Unrecognized argument " << argv[i];
424 }
425 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000426 // If we're reading a protobuf file, ensure a simulation hasn't also
427 // been requested (which makes no sense...)
428 ASSERT_FALSE(pb_filename && simulating);
niklase@google.com470e71d2011-07-07 08:21:25 +0000429
430 if (verbose) {
431 printf("Sample rate: %d Hz\n", sample_rate_hz);
432 printf("Primary channels: %d (in), %d (out)\n",
433 num_capture_input_channels,
434 num_capture_output_channels);
435 printf("Reverse channels: %d \n", num_render_channels);
436 }
437
438 const char far_file_default[] = "apm_far.pcm";
439 const char near_file_default[] = "apm_near.pcm";
440 const char out_file_default[] = "out.pcm";
441 const char event_filename[] = "apm_event.dat";
442 const char delay_filename[] = "apm_delay.dat";
443 const char drift_filename[] = "apm_drift.dat";
444 const char vad_file_default[] = "vad_out.dat";
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000445 const char ns_prob_file_default[] = "ns_prob.dat";
niklase@google.com470e71d2011-07-07 08:21:25 +0000446
447 if (!simulating) {
448 far_filename = far_file_default;
449 near_filename = near_file_default;
450 }
451
ajm@google.com808e0e02011-08-03 21:08:51 +0000452 if (!out_filename) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000453 out_filename = out_file_default;
454 }
455
ajm@google.com808e0e02011-08-03 21:08:51 +0000456 if (!vad_out_filename) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 vad_out_filename = vad_file_default;
458 }
459
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000460 if (!ns_prob_filename) {
461 ns_prob_filename = ns_prob_file_default;
462 }
463
ajm@google.com808e0e02011-08-03 21:08:51 +0000464 FILE* pb_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 FILE* far_file = NULL;
466 FILE* near_file = NULL;
467 FILE* out_file = NULL;
468 FILE* event_file = NULL;
469 FILE* delay_file = NULL;
470 FILE* drift_file = NULL;
471 FILE* vad_out_file = NULL;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000472 FILE* ns_prob_file = NULL;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000473 FILE* aecm_echo_path_in_file = NULL;
474 FILE* aecm_echo_path_out_file = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000475
ajm@google.com808e0e02011-08-03 21:08:51 +0000476 if (pb_filename) {
477 pb_file = fopen(pb_filename, "rb");
478 ASSERT_TRUE(NULL != pb_file) << "Unable to open protobuf file "
479 << pb_filename;
480 } else {
481 if (far_filename) {
482 far_file = fopen(far_filename, "rb");
483 ASSERT_TRUE(NULL != far_file) << "Unable to open far-end audio file "
484 << far_filename;
485 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000486
ajm@google.com808e0e02011-08-03 21:08:51 +0000487 near_file = fopen(near_filename, "rb");
488 ASSERT_TRUE(NULL != near_file) << "Unable to open near-end audio file "
489 << near_filename;
490 if (!simulating) {
491 event_file = fopen(event_filename, "rb");
492 ASSERT_TRUE(NULL != event_file) << "Unable to open event file "
493 << event_filename;
494
495 delay_file = fopen(delay_filename, "rb");
496 ASSERT_TRUE(NULL != delay_file) << "Unable to open buffer file "
497 << delay_filename;
498
499 drift_file = fopen(drift_filename, "rb");
500 ASSERT_TRUE(NULL != drift_file) << "Unable to open drift file "
501 << drift_filename;
502 }
503 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000504
505 out_file = fopen(out_filename, "wb");
506 ASSERT_TRUE(NULL != out_file) << "Unable to open output audio file "
507 << out_filename;
508
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000509 int near_size_bytes = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000510 if (pb_file) {
511 struct stat st;
512 stat(pb_filename, &st);
513 // Crude estimate, but should be good enough.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000514 near_size_bytes = st.st_size / 3;
ajm@google.com808e0e02011-08-03 21:08:51 +0000515 } else {
516 struct stat st;
517 stat(near_filename, &st);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000518 near_size_bytes = st.st_size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 }
520
521 if (apm->voice_detection()->is_enabled()) {
522 vad_out_file = fopen(vad_out_filename, "wb");
523 ASSERT_TRUE(NULL != vad_out_file) << "Unable to open VAD output file "
524 << vad_out_file;
525 }
526
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000527 if (apm->noise_suppression()->is_enabled()) {
528 ns_prob_file = fopen(ns_prob_filename, "wb");
529 ASSERT_TRUE(NULL != ns_prob_file) << "Unable to open NS output file "
530 << ns_prob_file;
531 }
532
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000533 if (aecm_echo_path_in_filename != NULL) {
534 aecm_echo_path_in_file = fopen(aecm_echo_path_in_filename, "rb");
535 ASSERT_TRUE(NULL != aecm_echo_path_in_file) << "Unable to open file "
536 << aecm_echo_path_in_filename;
537
ajm@google.com22e65152011-07-18 18:03:01 +0000538 const size_t path_size =
539 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000540 scoped_array<char> echo_path(new char[path_size]);
541 ASSERT_EQ(path_size, fread(echo_path.get(),
542 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000543 path_size,
544 aecm_echo_path_in_file));
545 EXPECT_EQ(apm->kNoError,
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000546 apm->echo_control_mobile()->SetEchoPath(echo_path.get(),
547 path_size));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000548 fclose(aecm_echo_path_in_file);
549 aecm_echo_path_in_file = NULL;
550 }
551
552 if (aecm_echo_path_out_filename != NULL) {
553 aecm_echo_path_out_file = fopen(aecm_echo_path_out_filename, "wb");
554 ASSERT_TRUE(NULL != aecm_echo_path_out_file) << "Unable to open file "
555 << aecm_echo_path_out_filename;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000556 }
557
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 size_t read_count = 0;
559 int reverse_count = 0;
560 int primary_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000561 int near_read_bytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 TickInterval acc_ticks;
563
564 AudioFrame far_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000565 AudioFrame near_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000566
567 int delay_ms = 0;
568 int drift_samples = 0;
569 int capture_level = 127;
570 int8_t stream_has_voice = 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000571 float ns_speech_prob = 0.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000572
573 TickTime t0 = TickTime::Now();
574 TickTime t1 = t0;
575 WebRtc_Word64 max_time_us = 0;
576 WebRtc_Word64 max_time_reverse_us = 0;
577 WebRtc_Word64 min_time_us = 1e6;
578 WebRtc_Word64 min_time_reverse_us = 1e6;
579
ajm@google.com808e0e02011-08-03 21:08:51 +0000580 // TODO(ajm): Ideally we would refactor this block into separate functions,
581 // but for now we want to share the variables.
582 if (pb_file) {
583 Event event_msg;
584 while (ReadMessageFromFile(pb_file, &event_msg)) {
585 std::ostringstream trace_stream;
586 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
587 << primary_count << " (primary)";
588 SCOPED_TRACE(trace_stream.str());
niklase@google.com470e71d2011-07-07 08:21:25 +0000589
ajm@google.com808e0e02011-08-03 21:08:51 +0000590 if (event_msg.type() == Event::INIT) {
591 ASSERT_TRUE(event_msg.has_init());
592 const Init msg = event_msg.init();
niklase@google.com470e71d2011-07-07 08:21:25 +0000593
ajm@google.com808e0e02011-08-03 21:08:51 +0000594 ASSERT_TRUE(msg.has_sample_rate());
595 ASSERT_EQ(apm->kNoError,
596 apm->set_sample_rate_hz(msg.sample_rate()));
597
598 ASSERT_TRUE(msg.has_device_sample_rate());
599 ASSERT_EQ(apm->kNoError,
600 apm->echo_cancellation()->set_device_sample_rate_hz(
601 msg.device_sample_rate()));
602
603 ASSERT_TRUE(msg.has_num_input_channels());
604 ASSERT_TRUE(msg.has_num_output_channels());
605 ASSERT_EQ(apm->kNoError,
606 apm->set_num_channels(msg.num_input_channels(),
607 msg.num_output_channels()));
608
609 ASSERT_TRUE(msg.has_num_reverse_channels());
610 ASSERT_EQ(apm->kNoError,
611 apm->set_num_reverse_channels(msg.num_reverse_channels()));
612
613 samples_per_channel = msg.sample_rate() / 100;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000614 far_frame.sample_rate_hz_ = msg.sample_rate();
615 far_frame.samples_per_channel_ = samples_per_channel;
616 far_frame.num_channels_ = msg.num_reverse_channels();
617 near_frame.sample_rate_hz_ = msg.sample_rate();
618 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000619
620 if (verbose) {
621 printf("Init at frame: %d (primary), %d (reverse)\n",
622 primary_count, reverse_count);
andrew@webrtc.orgba028a32011-11-23 20:37:12 +0000623 printf(" Sample rate: %d Hz\n", msg.sample_rate());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000624 printf(" Primary channels: %d (in), %d (out)\n",
625 msg.num_input_channels(),
626 msg.num_output_channels());
627 printf(" Reverse channels: %d \n", msg.num_reverse_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000628 }
629
630 } else if (event_msg.type() == Event::REVERSE_STREAM) {
631 ASSERT_TRUE(event_msg.has_reverse_stream());
632 const ReverseStream msg = event_msg.reverse_stream();
633 reverse_count++;
634
635 ASSERT_TRUE(msg.has_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000636 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000637 far_frame.num_channels_, msg.data().size());
638 memcpy(far_frame.data_, msg.data().data(), msg.data().size());
ajm@google.com808e0e02011-08-03 21:08:51 +0000639
640 if (perf_testing) {
641 t0 = TickTime::Now();
642 }
643
644 ASSERT_EQ(apm->kNoError,
645 apm->AnalyzeReverseStream(&far_frame));
646
647 if (perf_testing) {
648 t1 = TickTime::Now();
649 TickInterval tick_diff = t1 - t0;
650 acc_ticks += tick_diff;
651 if (tick_diff.Microseconds() > max_time_reverse_us) {
652 max_time_reverse_us = tick_diff.Microseconds();
653 }
654 if (tick_diff.Microseconds() < min_time_reverse_us) {
655 min_time_reverse_us = tick_diff.Microseconds();
656 }
657 }
658
659 } else if (event_msg.type() == Event::STREAM) {
660 ASSERT_TRUE(event_msg.has_stream());
661 const Stream msg = event_msg.stream();
662 primary_count++;
663
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000664 // ProcessStream could have changed this for the output frame.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000665 near_frame.num_channels_ = apm->num_input_channels();
ajm@google.com808e0e02011-08-03 21:08:51 +0000666
667 ASSERT_TRUE(msg.has_input_data());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000668 ASSERT_EQ(sizeof(int16_t) * samples_per_channel *
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000669 near_frame.num_channels_, msg.input_data().size());
670 memcpy(near_frame.data_,
ajm@google.com808e0e02011-08-03 21:08:51 +0000671 msg.input_data().data(),
672 msg.input_data().size());
673
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000674 near_read_bytes += msg.input_data().size();
ajm@google.com808e0e02011-08-03 21:08:51 +0000675 if (progress && primary_count % 100 == 0) {
676 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000677 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000678 fflush(stdout);
679 }
680
andrew@webrtc.org81865342012-10-27 00:28:27 +0000681 if (apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
682 SimulateMic(capture_level, &near_frame);
683 }
684
ajm@google.com808e0e02011-08-03 21:08:51 +0000685 if (perf_testing) {
686 t0 = TickTime::Now();
687 }
688
689 ASSERT_EQ(apm->kNoError,
690 apm->gain_control()->set_stream_analog_level(msg.level()));
691 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000692 apm->set_stream_delay_ms(msg.delay() + extra_delay_ms));
ajm@google.com808e0e02011-08-03 21:08:51 +0000693 ASSERT_EQ(apm->kNoError,
694 apm->echo_cancellation()->set_stream_drift_samples(msg.drift()));
695
696 int err = apm->ProcessStream(&near_frame);
697 if (err == apm->kBadStreamParameterWarning) {
698 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
699 }
700 ASSERT_TRUE(err == apm->kNoError ||
701 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000702 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000703
704 capture_level = apm->gain_control()->stream_analog_level();
705
706 stream_has_voice =
707 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
708 if (vad_out_file != NULL) {
709 ASSERT_EQ(1u, fwrite(&stream_has_voice,
710 sizeof(stream_has_voice),
711 1,
712 vad_out_file));
713 }
714
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000715 if (ns_prob_file != NULL) {
716 ns_speech_prob = apm->noise_suppression()->speech_probability();
717 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
718 sizeof(ns_speech_prob),
719 1,
720 ns_prob_file));
721 }
722
ajm@google.com808e0e02011-08-03 21:08:51 +0000723 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
724 ASSERT_EQ(msg.level(), capture_level);
725 }
726
727 if (perf_testing) {
728 t1 = TickTime::Now();
729 TickInterval tick_diff = t1 - t0;
730 acc_ticks += tick_diff;
731 if (tick_diff.Microseconds() > max_time_us) {
732 max_time_us = tick_diff.Microseconds();
733 }
734 if (tick_diff.Microseconds() < min_time_us) {
735 min_time_us = tick_diff.Microseconds();
736 }
737 }
738
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000739 size_t size = samples_per_channel * near_frame.num_channels_;
740 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000741 sizeof(int16_t),
742 size,
743 out_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000744 }
745 }
746
747 ASSERT_TRUE(feof(pb_file));
ajm@google.com808e0e02011-08-03 21:08:51 +0000748
749 } else {
bjornv@google.coma2c6ea02011-09-27 08:04:45 +0000750 enum Events {
751 kInitializeEvent,
752 kRenderEvent,
753 kCaptureEvent,
754 kResetEventDeprecated
755 };
756 int16_t event = 0;
ajm@google.com808e0e02011-08-03 21:08:51 +0000757 while (simulating || feof(event_file) == 0) {
758 std::ostringstream trace_stream;
759 trace_stream << "Processed frames: " << reverse_count << " (reverse), "
760 << primary_count << " (primary)";
761 SCOPED_TRACE(trace_stream.str());
762
763 if (simulating) {
764 if (far_file == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 event = kCaptureEvent;
766 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000767 if (event == kRenderEvent) {
768 event = kCaptureEvent;
769 } else {
770 event = kRenderEvent;
771 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000772 }
773 } else {
ajm@google.com808e0e02011-08-03 21:08:51 +0000774 read_count = fread(&event, sizeof(event), 1, event_file);
775 if (read_count != 1) {
776 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000777 }
778 }
779
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000780 far_frame.sample_rate_hz_ = sample_rate_hz;
781 far_frame.samples_per_channel_ = samples_per_channel;
782 far_frame.num_channels_ = num_render_channels;
783 near_frame.sample_rate_hz_ = sample_rate_hz;
784 near_frame.samples_per_channel_ = samples_per_channel;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000785
ajm@google.com808e0e02011-08-03 21:08:51 +0000786 if (event == kInitializeEvent || event == kResetEventDeprecated) {
787 ASSERT_EQ(1u,
788 fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file));
789 samples_per_channel = sample_rate_hz / 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000790
ajm@google.com808e0e02011-08-03 21:08:51 +0000791 ASSERT_EQ(1u,
792 fread(&device_sample_rate_hz,
793 sizeof(device_sample_rate_hz),
794 1,
795 event_file));
796
797 ASSERT_EQ(apm->kNoError,
798 apm->set_sample_rate_hz(sample_rate_hz));
799
800 ASSERT_EQ(apm->kNoError,
801 apm->echo_cancellation()->set_device_sample_rate_hz(
802 device_sample_rate_hz));
803
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000804 far_frame.sample_rate_hz_ = sample_rate_hz;
805 far_frame.samples_per_channel_ = samples_per_channel;
806 far_frame.num_channels_ = num_render_channels;
807 near_frame.sample_rate_hz_ = sample_rate_hz;
808 near_frame.samples_per_channel_ = samples_per_channel;
ajm@google.com808e0e02011-08-03 21:08:51 +0000809
810 if (verbose) {
811 printf("Init at frame: %d (primary), %d (reverse)\n",
812 primary_count, reverse_count);
813 printf(" Sample rate: %d Hz\n", sample_rate_hz);
814 }
815
816 } else if (event == kRenderEvent) {
817 reverse_count++;
ajm@google.com808e0e02011-08-03 21:08:51 +0000818
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000819 size_t size = samples_per_channel * num_render_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000820 read_count = fread(far_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000821 sizeof(int16_t),
822 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000823 far_file);
824
825 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000826 if (read_count != size) {
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000827 // Read an equal amount from the near file to avoid errors due to
828 // not reaching end-of-file.
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000829 EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000830 SEEK_CUR));
ajm@google.com808e0e02011-08-03 21:08:51 +0000831 break; // This is expected.
832 }
833 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000834 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000835 }
836
837 if (perf_testing) {
838 t0 = TickTime::Now();
839 }
840
841 ASSERT_EQ(apm->kNoError,
842 apm->AnalyzeReverseStream(&far_frame));
843
844 if (perf_testing) {
845 t1 = TickTime::Now();
846 TickInterval tick_diff = t1 - t0;
847 acc_ticks += tick_diff;
848 if (tick_diff.Microseconds() > max_time_reverse_us) {
849 max_time_reverse_us = tick_diff.Microseconds();
850 }
851 if (tick_diff.Microseconds() < min_time_reverse_us) {
852 min_time_reverse_us = tick_diff.Microseconds();
853 }
854 }
855
856 } else if (event == kCaptureEvent) {
857 primary_count++;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000858 near_frame.num_channels_ = num_capture_input_channels;
ajm@google.com808e0e02011-08-03 21:08:51 +0000859
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000860 size_t size = samples_per_channel * num_capture_input_channels;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000861 read_count = fread(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000862 sizeof(int16_t),
863 size,
ajm@google.com808e0e02011-08-03 21:08:51 +0000864 near_file);
865
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000866 near_read_bytes += read_count * sizeof(int16_t);
ajm@google.com808e0e02011-08-03 21:08:51 +0000867 if (progress && primary_count % 100 == 0) {
868 printf("%.0f%% complete\r",
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000869 (near_read_bytes * 100.0) / near_size_bytes);
ajm@google.com808e0e02011-08-03 21:08:51 +0000870 fflush(stdout);
871 }
872 if (simulating) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000873 if (read_count != size) {
ajm@google.com808e0e02011-08-03 21:08:51 +0000874 break; // This is expected.
875 }
876
877 delay_ms = 0;
878 drift_samples = 0;
879 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000880 ASSERT_EQ(size, read_count);
ajm@google.com808e0e02011-08-03 21:08:51 +0000881
882 // TODO(ajm): sizeof(delay_ms) for current files?
883 ASSERT_EQ(1u,
884 fread(&delay_ms, 2, 1, delay_file));
885 ASSERT_EQ(1u,
886 fread(&drift_samples, sizeof(drift_samples), 1, drift_file));
887 }
888
andrew@webrtc.org81865342012-10-27 00:28:27 +0000889 if (apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) {
890 SimulateMic(capture_level, &near_frame);
891 }
892
ajm@google.com808e0e02011-08-03 21:08:51 +0000893 if (perf_testing) {
894 t0 = TickTime::Now();
895 }
896
897 // TODO(ajm): fake an analog gain while simulating.
898
899 int capture_level_in = capture_level;
900 ASSERT_EQ(apm->kNoError,
901 apm->gain_control()->set_stream_analog_level(capture_level));
902 ASSERT_EQ(apm->kNoError,
andrew@webrtc.org4b13fc92011-11-09 19:27:11 +0000903 apm->set_stream_delay_ms(delay_ms + extra_delay_ms));
ajm@google.com808e0e02011-08-03 21:08:51 +0000904 ASSERT_EQ(apm->kNoError,
905 apm->echo_cancellation()->set_stream_drift_samples(drift_samples));
906
907 int err = apm->ProcessStream(&near_frame);
908 if (err == apm->kBadStreamParameterWarning) {
909 printf("Bad parameter warning. %s\n", trace_stream.str().c_str());
910 }
911 ASSERT_TRUE(err == apm->kNoError ||
912 err == apm->kBadStreamParameterWarning);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000913 ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels());
ajm@google.com808e0e02011-08-03 21:08:51 +0000914
915 capture_level = apm->gain_control()->stream_analog_level();
916
917 stream_has_voice =
918 static_cast<int8_t>(apm->voice_detection()->stream_has_voice());
919 if (vad_out_file != NULL) {
920 ASSERT_EQ(1u, fwrite(&stream_has_voice,
921 sizeof(stream_has_voice),
922 1,
923 vad_out_file));
924 }
925
bjornv@webrtc.org08329f42012-07-12 21:00:43 +0000926 if (ns_prob_file != NULL) {
927 ns_speech_prob = apm->noise_suppression()->speech_probability();
928 ASSERT_EQ(1u, fwrite(&ns_speech_prob,
929 sizeof(ns_speech_prob),
930 1,
931 ns_prob_file));
932 }
933
ajm@google.com808e0e02011-08-03 21:08:51 +0000934 if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) {
935 ASSERT_EQ(capture_level_in, capture_level);
936 }
937
938 if (perf_testing) {
939 t1 = TickTime::Now();
940 TickInterval tick_diff = t1 - t0;
941 acc_ticks += tick_diff;
942 if (tick_diff.Microseconds() > max_time_us) {
943 max_time_us = tick_diff.Microseconds();
944 }
945 if (tick_diff.Microseconds() < min_time_us) {
946 min_time_us = tick_diff.Microseconds();
947 }
948 }
949
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000950 size = samples_per_channel * near_frame.num_channels_;
951 ASSERT_EQ(size, fwrite(near_frame.data_,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000952 sizeof(int16_t),
953 size,
954 out_file));
niklase@google.com470e71d2011-07-07 08:21:25 +0000955 }
ajm@google.com808e0e02011-08-03 21:08:51 +0000956 else {
957 FAIL() << "Event " << event << " is unrecognized";
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000959 }
960 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000961 printf("100%% complete\r");
niklase@google.com470e71d2011-07-07 08:21:25 +0000962
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000963 if (aecm_echo_path_out_file != NULL) {
ajm@google.com22e65152011-07-18 18:03:01 +0000964 const size_t path_size =
965 apm->echo_control_mobile()->echo_path_size_bytes();
andrew@webrtc.org3119ecf2011-11-01 17:00:18 +0000966 scoped_array<char> echo_path(new char[path_size]);
967 apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size);
968 ASSERT_EQ(path_size, fwrite(echo_path.get(),
969 sizeof(char),
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000970 path_size,
971 aecm_echo_path_out_file));
972 fclose(aecm_echo_path_out_file);
973 aecm_echo_path_out_file = NULL;
974 }
975
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 if (verbose) {
977 printf("\nProcessed frames: %d (primary), %d (reverse)\n",
978 primary_count, reverse_count);
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000979
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000980 if (apm->level_estimator()->is_enabled()) {
981 printf("\n--Level metrics--\n");
982 printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS());
983 }
andrew@webrtc.org94c74132011-09-19 15:17:57 +0000984 if (apm->echo_cancellation()->are_metrics_enabled()) {
985 EchoCancellation::Metrics metrics;
986 apm->echo_cancellation()->GetMetrics(&metrics);
987 printf("\n--Echo metrics--\n");
988 printf("(avg, max, min)\n");
989 printf("ERL: ");
990 PrintStat(metrics.echo_return_loss);
991 printf("ERLE: ");
992 PrintStat(metrics.echo_return_loss_enhancement);
993 printf("ANLP: ");
994 PrintStat(metrics.a_nlp);
995 }
bjornv@google.com1ba3dbe2011-10-03 08:18:10 +0000996 if (apm->echo_cancellation()->is_delay_logging_enabled()) {
997 int median = 0;
998 int std = 0;
999 apm->echo_cancellation()->GetDelayMetrics(&median, &std);
1000 printf("\n--Delay metrics--\n");
1001 printf("Median: %3d\n", median);
1002 printf("Standard deviation: %3d\n", std);
1003 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 }
1005
ajm@google.com808e0e02011-08-03 21:08:51 +00001006 if (!pb_file) {
1007 int8_t temp_int8;
1008 if (far_file) {
1009 read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file);
1010 EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed";
1011 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001012
ajm@google.com808e0e02011-08-03 21:08:51 +00001013 read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file);
1014 EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed";
1015
1016 if (!simulating) {
1017 read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file);
1018 EXPECT_NE(0, feof(event_file)) << "Event file not fully processed";
1019 read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file);
1020 EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed";
1021 read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file);
1022 EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed";
1023 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001024 }
1025
1026 if (perf_testing) {
1027 if (primary_count > 0) {
1028 WebRtc_Word64 exec_time = acc_ticks.Milliseconds();
1029 printf("\nTotal time: %.3f s, file time: %.2f s\n",
1030 exec_time * 0.001, primary_count * 0.01);
1031 printf("Time per frame: %.3f ms (average), %.3f ms (max),"
1032 " %.3f ms (min)\n",
1033 (exec_time * 1.0) / primary_count,
1034 (max_time_us + max_time_reverse_us) / 1000.0,
1035 (min_time_us + min_time_reverse_us) / 1000.0);
kma@webrtc.org0e739502012-12-07 15:26:28 +00001036 // Record the results with Perf test tools.
1037 webrtc::test::PrintResult("time_per_10ms_frame", "", "audioproc",
1038 (exec_time * 1000) / primary_count, "us", false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001039 } else {
1040 printf("Warning: no capture frames\n");
1041 }
1042 }
1043
1044 AudioProcessing::Destroy(apm);
1045 apm = NULL;
1046}
ajm@google.com808e0e02011-08-03 21:08:51 +00001047} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +00001048
1049int main(int argc, char* argv[])
1050{
1051 void_main(argc, argv);
1052
andrew@webrtc.org64235092011-08-19 21:22:08 +00001053 // Optional, but removes memory leak noise from Valgrind.
1054 google::protobuf::ShutdownProtobufLibrary();
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 return 0;
1056}