blob: 7ebc326ee512931ab58d618af55cbdb7372baac9 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
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
Ivo Creusenf81b0f12018-09-11 10:30:58 +020011#include <iostream>
12#include <string>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000013
Alessio Bazzica5ad789c2019-03-13 11:51:44 +010014#include "absl/strings/string_view.h"
15#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "modules/audio_coding/neteq/tools/neteq_test.h"
Ivo Creusen55de08e2018-09-03 11:49:27 +020017#include "modules/audio_coding/neteq/tools/neteq_test_factory.h"
Ivo Creusenf81b0f12018-09-11 10:30:58 +020018#include "rtc_base/flags.h"
Alessio Bazzica5ad789c2019-03-13 11:51:44 +010019#include "rtc_base/strings/string_builder.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020020#include "system_wrappers/include/field_trial.h"
Ivo Creusenf81b0f12018-09-11 10:30:58 +020021#include "test/field_trial.h"
22
Ivo Creusenba7886b2019-02-26 13:03:21 +010023namespace {
24
25using TestConfig = webrtc::test::NetEqTestFactory::Config;
26
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020027WEBRTC_DEFINE_bool(codec_map,
28 false,
29 "Prints the mapping between RTP payload type and "
30 "codec");
31WEBRTC_DEFINE_string(
Ivo Creusenf81b0f12018-09-11 10:30:58 +020032 force_fieldtrials,
33 "",
34 "Field trials control experimental feature code which can be forced. "
35 "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
36 " will assign the group Enable to field trial WebRTC-FooFeature.");
Mirko Bonadei2dfa9982018-10-18 11:35:32 +020037WEBRTC_DEFINE_bool(help, false, "Prints this message");
Ivo Creusenba7886b2019-02-26 13:03:21 +010038// Define command line flags.
39WEBRTC_DEFINE_int(pcmu,
40 TestConfig::default_pcmu(),
41 "RTP payload type for PCM-u");
42WEBRTC_DEFINE_int(pcma,
43 TestConfig::default_pcma(),
44 "RTP payload type for PCM-a");
45WEBRTC_DEFINE_int(ilbc,
46 TestConfig::default_ilbc(),
47 "RTP payload type for iLBC");
48WEBRTC_DEFINE_int(isac,
49 TestConfig::default_isac(),
50 "RTP payload type for iSAC");
51WEBRTC_DEFINE_int(isac_swb,
52 TestConfig::default_isac_swb(),
53 "RTP payload type for iSAC-swb (32 kHz)");
54WEBRTC_DEFINE_int(opus,
55 TestConfig::default_opus(),
56 "RTP payload type for Opus");
57WEBRTC_DEFINE_int(pcm16b,
58 TestConfig::default_pcm16b(),
59 "RTP payload type for PCM16b-nb (8 kHz)");
60WEBRTC_DEFINE_int(pcm16b_wb,
61 TestConfig::default_pcm16b_wb(),
62 "RTP payload type for PCM16b-wb (16 kHz)");
63WEBRTC_DEFINE_int(pcm16b_swb32,
64 TestConfig::default_pcm16b_swb32(),
65 "RTP payload type for PCM16b-swb32 (32 kHz)");
66WEBRTC_DEFINE_int(pcm16b_swb48,
67 TestConfig::default_pcm16b_swb48(),
68 "RTP payload type for PCM16b-swb48 (48 kHz)");
69WEBRTC_DEFINE_int(g722,
70 TestConfig::default_g722(),
71 "RTP payload type for G.722");
72WEBRTC_DEFINE_int(avt,
73 TestConfig::default_avt(),
74 "RTP payload type for AVT/DTMF (8 kHz)");
75WEBRTC_DEFINE_int(avt_16,
76 TestConfig::default_avt_16(),
77 "RTP payload type for AVT/DTMF (16 kHz)");
78WEBRTC_DEFINE_int(avt_32,
79 TestConfig::default_avt_32(),
80 "RTP payload type for AVT/DTMF (32 kHz)");
81WEBRTC_DEFINE_int(avt_48,
82 TestConfig::default_avt_48(),
83 "RTP payload type for AVT/DTMF (48 kHz)");
84WEBRTC_DEFINE_int(red,
85 TestConfig::default_red(),
86 "RTP payload type for redundant audio (RED)");
87WEBRTC_DEFINE_int(cn_nb,
88 TestConfig::default_cn_nb(),
89 "RTP payload type for comfort noise (8 kHz)");
90WEBRTC_DEFINE_int(cn_wb,
91 TestConfig::default_cn_wb(),
92 "RTP payload type for comfort noise (16 kHz)");
93WEBRTC_DEFINE_int(cn_swb32,
94 TestConfig::default_cn_swb32(),
95 "RTP payload type for comfort noise (32 kHz)");
96WEBRTC_DEFINE_int(cn_swb48,
97 TestConfig::default_cn_swb48(),
98 "RTP payload type for comfort noise (48 kHz)");
99WEBRTC_DEFINE_string(replacement_audio_file,
100 "",
101 "A PCM file that will be used to populate dummy"
102 " RTP packets");
103WEBRTC_DEFINE_string(
104 ssrc,
105 "",
106 "Only use packets with this SSRC (decimal or hex, the latter "
107 "starting with 0x)");
108WEBRTC_DEFINE_int(audio_level,
109 TestConfig::default_audio_level(),
110 "Extension ID for audio level (RFC 6464)");
111WEBRTC_DEFINE_int(abs_send_time,
112 TestConfig::default_abs_send_time(),
113 "Extension ID for absolute sender time");
114WEBRTC_DEFINE_int(transport_seq_no,
115 TestConfig::default_transport_seq_no(),
116 "Extension ID for transport sequence number");
117WEBRTC_DEFINE_int(video_content_type,
118 TestConfig::default_video_content_type(),
119 "Extension ID for video content type");
120WEBRTC_DEFINE_int(video_timing,
121 TestConfig::default_video_timing(),
122 "Extension ID for video timing");
Alessio Bazzica5ad789c2019-03-13 11:51:44 +0100123WEBRTC_DEFINE_string(output_files_base_name,
124 "",
125 "Custom path used as prefix for the output files - i.e., "
126 "matlab plot, python plot, text log.");
Ivo Creusenba7886b2019-02-26 13:03:21 +0100127WEBRTC_DEFINE_bool(matlabplot,
128 false,
129 "Generates a matlab script for plotting the delay profile");
130WEBRTC_DEFINE_bool(pythonplot,
131 false,
132 "Generates a python script for plotting the delay profile");
133WEBRTC_DEFINE_bool(textlog,
134 false,
135 "Generates a text log describing the simulation on a "
136 "step-by-step basis.");
137WEBRTC_DEFINE_bool(concealment_events, false, "Prints concealment events");
138WEBRTC_DEFINE_int(max_nr_packets_in_buffer,
139 TestConfig::default_max_nr_packets_in_buffer(),
140 "Maximum allowed number of packets in the buffer");
141WEBRTC_DEFINE_bool(enable_fast_accelerate,
142 false,
143 "Enables jitter buffer fast accelerate");
144
145// Parses the input string for a valid SSRC (at the start of the string). If a
146// valid SSRC is found, it is written to the output variable |ssrc|, and true is
147// returned. Otherwise, false is returned.
148bool ParseSsrc(const std::string& str, uint32_t* ssrc) {
149 if (str.empty())
150 return true;
151 int base = 10;
152 // Look for "0x" or "0X" at the start and change base to 16 if found.
153 if ((str.compare(0, 2, "0x") == 0) || (str.compare(0, 2, "0X") == 0))
154 base = 16;
155 errno = 0;
156 char* end_ptr;
157 unsigned long value = strtoul(str.c_str(), &end_ptr, base); // NOLINT
158 if (value == ULONG_MAX && errno == ERANGE)
159 return false; // Value out of range for unsigned long.
160 if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF) // NOLINT
161 return false; // Value out of range for uint32_t.
162 if (end_ptr - str.c_str() < static_cast<ptrdiff_t>(str.length()))
163 return false; // Part of the string was not parsed.
164 *ssrc = static_cast<uint32_t>(value);
165 return true;
166}
167
168static bool ValidateExtensionId(int value) {
169 if (value > 0 && value <= 255) // Value is ok.
170 return true;
171 printf("Extension ID must be between 1 and 255, not %d\n",
172 static_cast<int>(value));
173 return false;
174}
175
176// Flag validators.
177bool ValidatePayloadType(int value) {
178 if (value >= 0 && value <= 127) // Value is ok.
179 return true;
180 printf("Payload type must be between 0 and 127, not %d\n",
181 static_cast<int>(value));
182 return false;
183}
184
185bool ValidateSsrcValue(const std::string& str) {
186 uint32_t dummy_ssrc;
187 if (ParseSsrc(str, &dummy_ssrc)) // Value is ok.
188 return true;
189 printf("Invalid SSRC: %s\n", str.c_str());
190 return false;
191}
192
193void PrintCodecMappingEntry(const char* codec, int flag) {
194 std::cout << codec << ": " << flag << std::endl;
195}
196
197void PrintCodecMapping() {
198 PrintCodecMappingEntry("PCM-u", FLAG_pcmu);
199 PrintCodecMappingEntry("PCM-a", FLAG_pcma);
200 PrintCodecMappingEntry("iLBC", FLAG_ilbc);
201 PrintCodecMappingEntry("iSAC", FLAG_isac);
202 PrintCodecMappingEntry("iSAC-swb (32 kHz)", FLAG_isac_swb);
203 PrintCodecMappingEntry("Opus", FLAG_opus);
204 PrintCodecMappingEntry("PCM16b-nb (8 kHz)", FLAG_pcm16b);
205 PrintCodecMappingEntry("PCM16b-wb (16 kHz)", FLAG_pcm16b_wb);
206 PrintCodecMappingEntry("PCM16b-swb32 (32 kHz)", FLAG_pcm16b_swb32);
207 PrintCodecMappingEntry("PCM16b-swb48 (48 kHz)", FLAG_pcm16b_swb48);
208 PrintCodecMappingEntry("G.722", FLAG_g722);
209 PrintCodecMappingEntry("AVT/DTMF (8 kHz)", FLAG_avt);
210 PrintCodecMappingEntry("AVT/DTMF (16 kHz)", FLAG_avt_16);
211 PrintCodecMappingEntry("AVT/DTMF (32 kHz)", FLAG_avt_32);
212 PrintCodecMappingEntry("AVT/DTMF (48 kHz)", FLAG_avt_48);
213 PrintCodecMappingEntry("redundant audio (RED)", FLAG_red);
214 PrintCodecMappingEntry("comfort noise (8 kHz)", FLAG_cn_nb);
215 PrintCodecMappingEntry("comfort noise (16 kHz)", FLAG_cn_wb);
216 PrintCodecMappingEntry("comfort noise (32 kHz)", FLAG_cn_swb32);
217 PrintCodecMappingEntry("comfort noise (48 kHz)", FLAG_cn_swb48);
218}
219
Alessio Bazzica5ad789c2019-03-13 11:51:44 +0100220bool ValidateOutputFilesOptions(bool textlog,
221 bool plotting,
222 absl::string_view output_files_base_name,
223 absl::string_view output_audio_filename) {
224 bool output_files_base_name_specified = !output_files_base_name.empty();
225 if (!textlog && !plotting && output_files_base_name_specified) {
226 std::cout << "Error: --output_files_base_name cannot be used without at "
227 << "least one of the following flags: --textlog, --matlabplot, "
228 << "--pythonplot." << std::endl;
229 return false;
230 }
231 // Without |output_audio_filename|, |output_files_base_name| is required when
232 // one or more output files must be generated (in order to form a valid output
233 // file name).
234 if (output_audio_filename.empty() && (textlog || plotting) &&
235 !output_files_base_name_specified) {
236 std::cout << "Error: when no output audio file is specified and --textlog, "
237 << "--matlabplot and/or --pythonplot are used, "
238 << "--output_files_base_name must be also used." << std::endl;
239 return false;
240 }
241 return true;
242}
243
244absl::optional<std::string> CreateOptionalOutputFileName(
245 bool output_requested,
246 absl::string_view basename,
247 absl::string_view output_audio_filename,
248 absl::string_view suffix) {
249 if (!output_requested) {
250 return absl::nullopt;
251 }
252 if (!basename.empty()) {
253 // Override the automatic assignment.
254 rtc::StringBuilder sb(basename);
255 sb << suffix;
256 return sb.str();
257 }
258 if (!output_audio_filename.empty()) {
259 // Automatically assign name.
260 rtc::StringBuilder sb(output_audio_filename);
261 sb << suffix;
262 return sb.str();
263 }
264 std::cout << "Error: invalid text log file parameters.";
265 return absl::nullopt;
266}
267
Ivo Creusenba7886b2019-02-26 13:03:21 +0100268} // namespace
henrik.lundin303d3e12016-05-26 05:56:03 -0700269
270int main(int argc, char* argv[]) {
Ivo Creusen55de08e2018-09-03 11:49:27 +0200271 webrtc::test::NetEqTestFactory factory;
Ivo Creusenf81b0f12018-09-11 10:30:58 +0200272 std::string program_name = argv[0];
273 std::string usage =
274 "Tool for decoding an RTP dump file using NetEq.\n"
275 "Run " +
276 program_name +
277 " --help for usage.\n"
278 "Example usage:\n" +
Alessio Bazzica5ad789c2019-03-13 11:51:44 +0100279 program_name + " input.rtp [output.{pcm, wav}]\n";
Ivo Creusenf81b0f12018-09-11 10:30:58 +0200280 if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true)) {
281 exit(1);
282 }
283 if (FLAG_help) {
284 std::cout << usage;
285 rtc::FlagList::Print(nullptr, false);
286 exit(0);
287 }
288 if (FLAG_codec_map) {
Ivo Creusenba7886b2019-02-26 13:03:21 +0100289 PrintCodecMapping();
290 exit(0);
Ivo Creusenf81b0f12018-09-11 10:30:58 +0200291 }
Alessio Bazzica5ad789c2019-03-13 11:51:44 +0100292 if (argc < 2 || argc > 3) { // The output audio file is optional.
Ivo Creusenf81b0f12018-09-11 10:30:58 +0200293 // Print usage information.
294 std::cout << usage;
295 exit(0);
296 }
Alessio Bazzica5ad789c2019-03-13 11:51:44 +0100297 const std::string output_audio_filename((argc == 3) ? argv[2] : "");
298 const std::string output_files_base_name(FLAG_output_files_base_name);
299 RTC_CHECK(ValidateOutputFilesOptions(
300 FLAG_textlog, FLAG_matlabplot || FLAG_pythonplot, output_files_base_name,
301 output_audio_filename));
Ivo Creusenba7886b2019-02-26 13:03:21 +0100302 RTC_CHECK(ValidatePayloadType(FLAG_pcmu));
303 RTC_CHECK(ValidatePayloadType(FLAG_pcma));
304 RTC_CHECK(ValidatePayloadType(FLAG_ilbc));
305 RTC_CHECK(ValidatePayloadType(FLAG_isac));
306 RTC_CHECK(ValidatePayloadType(FLAG_isac_swb));
307 RTC_CHECK(ValidatePayloadType(FLAG_opus));
308 RTC_CHECK(ValidatePayloadType(FLAG_pcm16b));
309 RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_wb));
310 RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb32));
311 RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb48));
312 RTC_CHECK(ValidatePayloadType(FLAG_g722));
313 RTC_CHECK(ValidatePayloadType(FLAG_avt));
314 RTC_CHECK(ValidatePayloadType(FLAG_avt_16));
315 RTC_CHECK(ValidatePayloadType(FLAG_avt_32));
316 RTC_CHECK(ValidatePayloadType(FLAG_avt_48));
317 RTC_CHECK(ValidatePayloadType(FLAG_red));
318 RTC_CHECK(ValidatePayloadType(FLAG_cn_nb));
319 RTC_CHECK(ValidatePayloadType(FLAG_cn_wb));
320 RTC_CHECK(ValidatePayloadType(FLAG_cn_swb32));
321 RTC_CHECK(ValidatePayloadType(FLAG_cn_swb48));
322 RTC_CHECK(ValidateSsrcValue(FLAG_ssrc));
323 RTC_CHECK(ValidateExtensionId(FLAG_audio_level));
324 RTC_CHECK(ValidateExtensionId(FLAG_abs_send_time));
325 RTC_CHECK(ValidateExtensionId(FLAG_transport_seq_no));
326 RTC_CHECK(ValidateExtensionId(FLAG_video_content_type));
327 RTC_CHECK(ValidateExtensionId(FLAG_video_timing));
328
Ivo Creusenf81b0f12018-09-11 10:30:58 +0200329 webrtc::test::ValidateFieldTrialsStringOrDie(FLAG_force_fieldtrials);
330 webrtc::field_trial::InitFieldTrialsFromString(FLAG_force_fieldtrials);
Ivo Creusenba7886b2019-02-26 13:03:21 +0100331 webrtc::test::NetEqTestFactory::Config config;
332 config.pcmu = FLAG_pcmu;
333 config.pcma = FLAG_pcma;
334 config.ilbc = FLAG_ilbc;
335 config.isac = FLAG_isac;
336 config.isac_swb = FLAG_isac_swb;
337 config.opus = FLAG_opus;
338 config.pcm16b = FLAG_pcm16b;
339 config.pcm16b_wb = FLAG_pcm16b_wb;
340 config.pcm16b_swb32 = FLAG_pcm16b_swb32;
341 config.pcm16b_swb48 = FLAG_pcm16b_swb48;
342 config.g722 = FLAG_g722;
343 config.avt = FLAG_avt;
344 config.avt_16 = FLAG_avt_16;
345 config.avt_32 = FLAG_avt_32;
346 config.avt_48 = FLAG_avt_48;
347 config.red = FLAG_red;
348 config.cn_nb = FLAG_cn_nb;
349 config.cn_wb = FLAG_cn_wb;
350 config.cn_swb32 = FLAG_cn_swb32;
351 config.cn_swb48 = FLAG_cn_swb48;
352 config.replacement_audio_file = FLAG_replacement_audio_file;
353 config.audio_level = FLAG_audio_level;
354 config.abs_send_time = FLAG_abs_send_time;
355 config.transport_seq_no = FLAG_transport_seq_no;
356 config.video_content_type = FLAG_video_content_type;
357 config.video_timing = FLAG_video_timing;
358 config.matlabplot = FLAG_matlabplot;
359 config.pythonplot = FLAG_pythonplot;
Ivo Creusenba7886b2019-02-26 13:03:21 +0100360 config.concealment_events = FLAG_concealment_events;
361 config.max_nr_packets_in_buffer = FLAG_max_nr_packets_in_buffer;
362 config.enable_fast_accelerate = FLAG_enable_fast_accelerate;
Alessio Bazzica5ad789c2019-03-13 11:51:44 +0100363 if (!output_audio_filename.empty()) {
364 config.output_audio_filename = output_audio_filename;
365 }
366 config.textlog_filename =
367 CreateOptionalOutputFileName(FLAG_textlog, output_files_base_name,
368 output_audio_filename, ".text_log.txt");
369 config.plot_scripts_basename = CreateOptionalOutputFileName(
370 FLAG_matlabplot || FLAG_pythonplot, output_files_base_name,
371 output_audio_filename, "");
372
Ivo Creusenba7886b2019-02-26 13:03:21 +0100373 // Check if an SSRC value was provided.
374 if (strlen(FLAG_ssrc) > 0) {
375 uint32_t ssrc;
376 RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed.";
377 config.ssrc_filter = absl::make_optional(ssrc);
378 }
379
Alessio Bazzica5ad789c2019-03-13 11:51:44 +0100380 std::unique_ptr<webrtc::test::NetEqTest> test = factory.InitializeTest(
381 /*input_filename=*/argv[1], config);
Ivo Creusen55de08e2018-09-03 11:49:27 +0200382 test->Run();
383 return 0;
henrik.lundin303d3e12016-05-26 05:56:03 -0700384}