1 /*
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 
11 #include <iostream>
12 #include <string>
13 
14 #include "absl/flags/flag.h"
15 #include "absl/flags/parse.h"
16 #include "absl/strings/string_view.h"
17 #include "absl/types/optional.h"
18 #include "modules/audio_coding/neteq/tools/neteq_test.h"
19 #include "modules/audio_coding/neteq/tools/neteq_test_factory.h"
20 #include "rtc_base/strings/string_builder.h"
21 #include "system_wrappers/include/field_trial.h"
22 #include "test/field_trial.h"
23 
24 using TestConfig = webrtc::test::NetEqTestFactory::Config;
25 
26 ABSL_FLAG(bool,
27           codec_map,
28           false,
29           "Prints the mapping between RTP payload type and "
30           "codec");
31 ABSL_FLAG(std::string,
32           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.");
37 ABSL_FLAG(int, pcmu, TestConfig::default_pcmu(), "RTP payload type for PCM-u");
38 ABSL_FLAG(int, pcma, TestConfig::default_pcma(), "RTP payload type for PCM-a");
39 ABSL_FLAG(int, ilbc, TestConfig::default_ilbc(), "RTP payload type for iLBC");
40 ABSL_FLAG(int, isac, TestConfig::default_isac(), "RTP payload type for iSAC");
41 ABSL_FLAG(int,
42           isac_swb,
43           TestConfig::default_isac_swb(),
44           "RTP payload type for iSAC-swb (32 kHz)");
45 ABSL_FLAG(int, opus, TestConfig::default_opus(), "RTP payload type for Opus");
46 ABSL_FLAG(int,
47           pcm16b,
48           TestConfig::default_pcm16b(),
49           "RTP payload type for PCM16b-nb (8 kHz)");
50 ABSL_FLAG(int,
51           pcm16b_wb,
52           TestConfig::default_pcm16b_wb(),
53           "RTP payload type for PCM16b-wb (16 kHz)");
54 ABSL_FLAG(int,
55           pcm16b_swb32,
56           TestConfig::default_pcm16b_swb32(),
57           "RTP payload type for PCM16b-swb32 (32 kHz)");
58 ABSL_FLAG(int,
59           pcm16b_swb48,
60           TestConfig::default_pcm16b_swb48(),
61           "RTP payload type for PCM16b-swb48 (48 kHz)");
62 ABSL_FLAG(int, g722, TestConfig::default_g722(), "RTP payload type for G.722");
63 ABSL_FLAG(int,
64           avt,
65           TestConfig::default_avt(),
66           "RTP payload type for AVT/DTMF (8 kHz)");
67 ABSL_FLAG(int,
68           avt_16,
69           TestConfig::default_avt_16(),
70           "RTP payload type for AVT/DTMF (16 kHz)");
71 ABSL_FLAG(int,
72           avt_32,
73           TestConfig::default_avt_32(),
74           "RTP payload type for AVT/DTMF (32 kHz)");
75 ABSL_FLAG(int,
76           avt_48,
77           TestConfig::default_avt_48(),
78           "RTP payload type for AVT/DTMF (48 kHz)");
79 ABSL_FLAG(int,
80           red,
81           TestConfig::default_red(),
82           "RTP payload type for redundant audio (RED)");
83 ABSL_FLAG(int,
84           cn_nb,
85           TestConfig::default_cn_nb(),
86           "RTP payload type for comfort noise (8 kHz)");
87 ABSL_FLAG(int,
88           cn_wb,
89           TestConfig::default_cn_wb(),
90           "RTP payload type for comfort noise (16 kHz)");
91 ABSL_FLAG(int,
92           cn_swb32,
93           TestConfig::default_cn_swb32(),
94           "RTP payload type for comfort noise (32 kHz)");
95 ABSL_FLAG(int,
96           cn_swb48,
97           TestConfig::default_cn_swb48(),
98           "RTP payload type for comfort noise (48 kHz)");
99 ABSL_FLAG(std::string,
100           replacement_audio_file,
101           "",
102           "A PCM file that will be used to populate dummy"
103           " RTP packets");
104 ABSL_FLAG(std::string,
105           ssrc,
106           "",
107           "Only use packets with this SSRC (decimal or hex, the latter "
108           "starting with 0x)");
109 ABSL_FLAG(int,
110           audio_level,
111           TestConfig::default_audio_level(),
112           "Extension ID for audio level (RFC 6464)");
113 ABSL_FLAG(int,
114           abs_send_time,
115           TestConfig::default_abs_send_time(),
116           "Extension ID for absolute sender time");
117 ABSL_FLAG(int,
118           transport_seq_no,
119           TestConfig::default_transport_seq_no(),
120           "Extension ID for transport sequence number");
121 ABSL_FLAG(int,
122           video_content_type,
123           TestConfig::default_video_content_type(),
124           "Extension ID for video content type");
125 ABSL_FLAG(int,
126           video_timing,
127           TestConfig::default_video_timing(),
128           "Extension ID for video timing");
129 ABSL_FLAG(std::string,
130           output_files_base_name,
131           "",
132           "Custom path used as prefix for the output files - i.e., "
133           "matlab plot, python plot, text log.");
134 ABSL_FLAG(bool,
135           matlabplot,
136           false,
137           "Generates a matlab script for plotting the delay profile");
138 ABSL_FLAG(bool,
139           pythonplot,
140           false,
141           "Generates a python script for plotting the delay profile");
142 ABSL_FLAG(bool,
143           textlog,
144           false,
145           "Generates a text log describing the simulation on a "
146           "step-by-step basis.");
147 ABSL_FLAG(bool, concealment_events, false, "Prints concealment events");
148 ABSL_FLAG(int,
149           max_nr_packets_in_buffer,
150           TestConfig::default_max_nr_packets_in_buffer(),
151           "Maximum allowed number of packets in the buffer");
152 ABSL_FLAG(bool,
153           enable_fast_accelerate,
154           false,
155           "Enables jitter buffer fast accelerate");
156 
157 namespace {
158 
159 // Parses the input string for a valid SSRC (at the start of the string). If a
160 // valid SSRC is found, it is written to the output variable |ssrc|, and true is
161 // returned. Otherwise, false is returned.
ParseSsrc(const std::string & str,uint32_t * ssrc)162 bool ParseSsrc(const std::string& str, uint32_t* ssrc) {
163   if (str.empty())
164     return true;
165   int base = 10;
166   // Look for "0x" or "0X" at the start and change base to 16 if found.
167   if ((str.compare(0, 2, "0x") == 0) || (str.compare(0, 2, "0X") == 0))
168     base = 16;
169   errno = 0;
170   char* end_ptr;
171   unsigned long value = strtoul(str.c_str(), &end_ptr, base);  // NOLINT
172   if (value == ULONG_MAX && errno == ERANGE)
173     return false;  // Value out of range for unsigned long.
174   if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF)  // NOLINT
175     return false;  // Value out of range for uint32_t.
176   if (end_ptr - str.c_str() < static_cast<ptrdiff_t>(str.length()))
177     return false;  // Part of the string was not parsed.
178   *ssrc = static_cast<uint32_t>(value);
179   return true;
180 }
181 
ValidateExtensionId(int value)182 static bool ValidateExtensionId(int value) {
183   if (value > 0 && value <= 255)  // Value is ok.
184     return true;
185   printf("Extension ID must be between 1 and 255, not %d\n",
186          static_cast<int>(value));
187   return false;
188 }
189 
190 // Flag validators.
ValidatePayloadType(int value)191 bool ValidatePayloadType(int value) {
192   if (value >= 0 && value <= 127)  // Value is ok.
193     return true;
194   printf("Payload type must be between 0 and 127, not %d\n",
195          static_cast<int>(value));
196   return false;
197 }
198 
ValidateSsrcValue(const std::string & str)199 bool ValidateSsrcValue(const std::string& str) {
200   uint32_t dummy_ssrc;
201   if (ParseSsrc(str, &dummy_ssrc))  // Value is ok.
202     return true;
203   printf("Invalid SSRC: %s\n", str.c_str());
204   return false;
205 }
206 
PrintCodecMappingEntry(const char * codec,int flag)207 void PrintCodecMappingEntry(const char* codec, int flag) {
208   std::cout << codec << ": " << flag << std::endl;
209 }
210 
PrintCodecMapping()211 void PrintCodecMapping() {
212   PrintCodecMappingEntry("PCM-u", absl::GetFlag(FLAGS_pcmu));
213   PrintCodecMappingEntry("PCM-a", absl::GetFlag(FLAGS_pcma));
214   PrintCodecMappingEntry("iLBC", absl::GetFlag(FLAGS_ilbc));
215   PrintCodecMappingEntry("iSAC", absl::GetFlag(FLAGS_isac));
216   PrintCodecMappingEntry("iSAC-swb (32 kHz)", absl::GetFlag(FLAGS_isac_swb));
217   PrintCodecMappingEntry("Opus", absl::GetFlag(FLAGS_opus));
218   PrintCodecMappingEntry("PCM16b-nb (8 kHz)", absl::GetFlag(FLAGS_pcm16b));
219   PrintCodecMappingEntry("PCM16b-wb (16 kHz)", absl::GetFlag(FLAGS_pcm16b_wb));
220   PrintCodecMappingEntry("PCM16b-swb32 (32 kHz)",
221                          absl::GetFlag(FLAGS_pcm16b_swb32));
222   PrintCodecMappingEntry("PCM16b-swb48 (48 kHz)",
223                          absl::GetFlag(FLAGS_pcm16b_swb48));
224   PrintCodecMappingEntry("G.722", absl::GetFlag(FLAGS_g722));
225   PrintCodecMappingEntry("AVT/DTMF (8 kHz)", absl::GetFlag(FLAGS_avt));
226   PrintCodecMappingEntry("AVT/DTMF (16 kHz)", absl::GetFlag(FLAGS_avt_16));
227   PrintCodecMappingEntry("AVT/DTMF (32 kHz)", absl::GetFlag(FLAGS_avt_32));
228   PrintCodecMappingEntry("AVT/DTMF (48 kHz)", absl::GetFlag(FLAGS_avt_48));
229   PrintCodecMappingEntry("redundant audio (RED)", absl::GetFlag(FLAGS_red));
230   PrintCodecMappingEntry("comfort noise (8 kHz)", absl::GetFlag(FLAGS_cn_nb));
231   PrintCodecMappingEntry("comfort noise (16 kHz)", absl::GetFlag(FLAGS_cn_wb));
232   PrintCodecMappingEntry("comfort noise (32 kHz)",
233                          absl::GetFlag(FLAGS_cn_swb32));
234   PrintCodecMappingEntry("comfort noise (48 kHz)",
235                          absl::GetFlag(FLAGS_cn_swb48));
236 }
237 
ValidateOutputFilesOptions(bool textlog,bool plotting,absl::string_view output_files_base_name,absl::string_view output_audio_filename)238 bool ValidateOutputFilesOptions(bool textlog,
239                                 bool plotting,
240                                 absl::string_view output_files_base_name,
241                                 absl::string_view output_audio_filename) {
242   bool output_files_base_name_specified = !output_files_base_name.empty();
243   if (!textlog && !plotting && output_files_base_name_specified) {
244     std::cout << "Error: --output_files_base_name cannot be used without at "
245                  "least one of the following flags: --textlog, --matlabplot, "
246                  "--pythonplot."
247               << std::endl;
248     return false;
249   }
250   // Without |output_audio_filename|, |output_files_base_name| is required when
251   // plotting output files must be generated (in order to form a valid output
252   // file name).
253   if (output_audio_filename.empty() && plotting &&
254       !output_files_base_name_specified) {
255     std::cout << "Error: when no output audio file is specified and "
256                  "--matlabplot and/or --pythonplot are used, "
257                  "--output_files_base_name must be also used."
258               << std::endl;
259     return false;
260   }
261   return true;
262 }
263 
CreateOptionalOutputFileName(bool output_requested,absl::string_view basename,absl::string_view output_audio_filename,absl::string_view suffix)264 absl::optional<std::string> CreateOptionalOutputFileName(
265     bool output_requested,
266     absl::string_view basename,
267     absl::string_view output_audio_filename,
268     absl::string_view suffix) {
269   if (!output_requested) {
270     return absl::nullopt;
271   }
272   if (!basename.empty()) {
273     // Override the automatic assignment.
274     rtc::StringBuilder sb(basename);
275     sb << suffix;
276     return sb.str();
277   }
278   if (!output_audio_filename.empty()) {
279     // Automatically assign name.
280     rtc::StringBuilder sb(output_audio_filename);
281     sb << suffix;
282     return sb.str();
283   }
284   std::cout << "Error: invalid text log file parameters.";
285   return absl::nullopt;
286 }
287 
288 }  // namespace
289 
main(int argc,char * argv[])290 int main(int argc, char* argv[]) {
291   std::vector<char*> args = absl::ParseCommandLine(argc, argv);
292   webrtc::test::NetEqTestFactory factory;
293   std::string usage =
294       "Tool for decoding an RTP dump file using NetEq.\n"
295       "Example usage:\n"
296       "./neteq_rtpplay input.rtp [output.{pcm, wav}]\n";
297   if (absl::GetFlag(FLAGS_codec_map)) {
298     PrintCodecMapping();
299     exit(0);
300   }
301   if (args.size() != 2 &&
302       args.size() != 3) {  // The output audio file is optional.
303     // Print usage information.
304     std::cout << usage;
305     exit(0);
306   }
307   const std::string output_audio_filename((args.size() == 3) ? args[2] : "");
308   const std::string output_files_base_name(
309       absl::GetFlag(FLAGS_output_files_base_name));
310   RTC_CHECK(ValidateOutputFilesOptions(
311       absl::GetFlag(FLAGS_textlog),
312       absl::GetFlag(FLAGS_matlabplot) || absl::GetFlag(FLAGS_pythonplot),
313       output_files_base_name, output_audio_filename));
314   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcmu)));
315   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcma)));
316   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_ilbc)));
317   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_isac)));
318   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_isac_swb)));
319   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_opus)));
320   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b)));
321   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b_wb)));
322   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b_swb32)));
323   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b_swb48)));
324   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_g722)));
325   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt)));
326   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt_16)));
327   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt_32)));
328   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt_48)));
329   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_red)));
330   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_nb)));
331   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_wb)));
332   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_swb32)));
333   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_swb48)));
334   RTC_CHECK(ValidateSsrcValue(absl::GetFlag(FLAGS_ssrc)));
335   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_audio_level)));
336   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_abs_send_time)));
337   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_transport_seq_no)));
338   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_video_content_type)));
339   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_video_timing)));
340 
341   // Make force_fieldtrials persistent string during entire program live as
342   // absl::GetFlag creates temporary string and c_str() will point to
343   // deallocated string.
344   const std::string force_fieldtrials = absl::GetFlag(FLAGS_force_fieldtrials);
345   webrtc::field_trial::InitFieldTrialsFromString(force_fieldtrials.c_str());
346 
347   webrtc::test::NetEqTestFactory::Config config;
348   config.pcmu = absl::GetFlag(FLAGS_pcmu);
349   config.pcma = absl::GetFlag(FLAGS_pcma);
350   config.ilbc = absl::GetFlag(FLAGS_ilbc);
351   config.isac = absl::GetFlag(FLAGS_isac);
352   config.isac_swb = absl::GetFlag(FLAGS_isac_swb);
353   config.opus = absl::GetFlag(FLAGS_opus);
354   config.pcm16b = absl::GetFlag(FLAGS_pcm16b);
355   config.pcm16b_wb = absl::GetFlag(FLAGS_pcm16b_wb);
356   config.pcm16b_swb32 = absl::GetFlag(FLAGS_pcm16b_swb32);
357   config.pcm16b_swb48 = absl::GetFlag(FLAGS_pcm16b_swb48);
358   config.g722 = absl::GetFlag(FLAGS_g722);
359   config.avt = absl::GetFlag(FLAGS_avt);
360   config.avt_16 = absl::GetFlag(FLAGS_avt_16);
361   config.avt_32 = absl::GetFlag(FLAGS_avt_32);
362   config.avt_48 = absl::GetFlag(FLAGS_avt_48);
363   config.red = absl::GetFlag(FLAGS_red);
364   config.cn_nb = absl::GetFlag(FLAGS_cn_nb);
365   config.cn_wb = absl::GetFlag(FLAGS_cn_wb);
366   config.cn_swb32 = absl::GetFlag(FLAGS_cn_swb32);
367   config.cn_swb48 = absl::GetFlag(FLAGS_cn_swb48);
368   config.replacement_audio_file = absl::GetFlag(FLAGS_replacement_audio_file);
369   config.audio_level = absl::GetFlag(FLAGS_audio_level);
370   config.abs_send_time = absl::GetFlag(FLAGS_abs_send_time);
371   config.transport_seq_no = absl::GetFlag(FLAGS_transport_seq_no);
372   config.video_content_type = absl::GetFlag(FLAGS_video_content_type);
373   config.video_timing = absl::GetFlag(FLAGS_video_timing);
374   config.matlabplot = absl::GetFlag(FLAGS_matlabplot);
375   config.pythonplot = absl::GetFlag(FLAGS_pythonplot);
376   config.concealment_events = absl::GetFlag(FLAGS_concealment_events);
377   config.max_nr_packets_in_buffer =
378       absl::GetFlag(FLAGS_max_nr_packets_in_buffer);
379   config.enable_fast_accelerate = absl::GetFlag(FLAGS_enable_fast_accelerate);
380   if (!output_audio_filename.empty()) {
381     config.output_audio_filename = output_audio_filename;
382   }
383   config.textlog = absl::GetFlag(FLAGS_textlog);
384   config.textlog_filename = CreateOptionalOutputFileName(
385       absl::GetFlag(FLAGS_textlog), output_files_base_name,
386       output_audio_filename, ".text_log.txt");
387   config.plot_scripts_basename = CreateOptionalOutputFileName(
388       absl::GetFlag(FLAGS_matlabplot) || absl::GetFlag(FLAGS_pythonplot),
389       output_files_base_name, output_audio_filename, "");
390 
391   // Check if an SSRC value was provided.
392   if (absl::GetFlag(FLAGS_ssrc).size() > 0) {
393     uint32_t ssrc;
394     RTC_CHECK(ParseSsrc(absl::GetFlag(FLAGS_ssrc), &ssrc))
395         << "Flag verification has failed.";
396     config.ssrc_filter = absl::make_optional(ssrc);
397   }
398 
399   std::unique_ptr<webrtc::test::NetEqTest> test =
400       factory.InitializeTestFromFile(/*input_filename=*/args[1],
401                                      /*factory=*/nullptr, config);
402   RTC_CHECK(test) << "ERROR: Unable to run test";
403   test->Run();
404   return 0;
405 }
406