xref: /aosp_15_r20/external/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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(absl::string_view str,uint32_t * ssrc)162 bool ParseSsrc(absl::string_view 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   std::string str_str = std::string(str);
172   unsigned long value = strtoul(str_str.c_str(), &end_ptr, base);  // NOLINT
173   if (value == ULONG_MAX && errno == ERANGE)
174     return false;  // Value out of range for unsigned long.
175   if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF)  // NOLINT
176     return false;  // Value out of range for uint32_t.
177   if (end_ptr - str_str.c_str() < static_cast<ptrdiff_t>(str.length()))
178     return false;  // Part of the string was not parsed.
179   *ssrc = static_cast<uint32_t>(value);
180   return true;
181 }
182 
ValidateExtensionId(int value)183 static bool ValidateExtensionId(int value) {
184   if (value > 0 && value <= 255)  // Value is ok.
185     return true;
186   printf("Extension ID must be between 1 and 255, not %d\n",
187          static_cast<int>(value));
188   return false;
189 }
190 
191 // Flag validators.
ValidatePayloadType(int value)192 bool ValidatePayloadType(int value) {
193   if (value >= 0 && value <= 127)  // Value is ok.
194     return true;
195   printf("Payload type must be between 0 and 127, not %d\n",
196          static_cast<int>(value));
197   return false;
198 }
199 
ValidateSsrcValue(absl::string_view str)200 bool ValidateSsrcValue(absl::string_view str) {
201   uint32_t dummy_ssrc;
202   if (ParseSsrc(str, &dummy_ssrc))  // Value is ok.
203     return true;
204   printf("Invalid SSRC: %.*s\n", static_cast<int>(str.size()), str.data());
205   return false;
206 }
207 
PrintCodecMappingEntry(absl::string_view codec,int flag)208 void PrintCodecMappingEntry(absl::string_view codec, int flag) {
209   std::cout << codec << ": " << flag << std::endl;
210 }
211 
PrintCodecMapping()212 void PrintCodecMapping() {
213   PrintCodecMappingEntry("PCM-u", absl::GetFlag(FLAGS_pcmu));
214   PrintCodecMappingEntry("PCM-a", absl::GetFlag(FLAGS_pcma));
215   PrintCodecMappingEntry("iLBC", absl::GetFlag(FLAGS_ilbc));
216   PrintCodecMappingEntry("iSAC", absl::GetFlag(FLAGS_isac));
217   PrintCodecMappingEntry("iSAC-swb (32 kHz)", absl::GetFlag(FLAGS_isac_swb));
218   PrintCodecMappingEntry("Opus", absl::GetFlag(FLAGS_opus));
219   PrintCodecMappingEntry("PCM16b-nb (8 kHz)", absl::GetFlag(FLAGS_pcm16b));
220   PrintCodecMappingEntry("PCM16b-wb (16 kHz)", absl::GetFlag(FLAGS_pcm16b_wb));
221   PrintCodecMappingEntry("PCM16b-swb32 (32 kHz)",
222                          absl::GetFlag(FLAGS_pcm16b_swb32));
223   PrintCodecMappingEntry("PCM16b-swb48 (48 kHz)",
224                          absl::GetFlag(FLAGS_pcm16b_swb48));
225   PrintCodecMappingEntry("G.722", absl::GetFlag(FLAGS_g722));
226   PrintCodecMappingEntry("AVT/DTMF (8 kHz)", absl::GetFlag(FLAGS_avt));
227   PrintCodecMappingEntry("AVT/DTMF (16 kHz)", absl::GetFlag(FLAGS_avt_16));
228   PrintCodecMappingEntry("AVT/DTMF (32 kHz)", absl::GetFlag(FLAGS_avt_32));
229   PrintCodecMappingEntry("AVT/DTMF (48 kHz)", absl::GetFlag(FLAGS_avt_48));
230   PrintCodecMappingEntry("redundant audio (RED)", absl::GetFlag(FLAGS_red));
231   PrintCodecMappingEntry("comfort noise (8 kHz)", absl::GetFlag(FLAGS_cn_nb));
232   PrintCodecMappingEntry("comfort noise (16 kHz)", absl::GetFlag(FLAGS_cn_wb));
233   PrintCodecMappingEntry("comfort noise (32 kHz)",
234                          absl::GetFlag(FLAGS_cn_swb32));
235   PrintCodecMappingEntry("comfort noise (48 kHz)",
236                          absl::GetFlag(FLAGS_cn_swb48));
237 }
238 
ValidateOutputFilesOptions(bool textlog,bool plotting,absl::string_view output_files_base_name,absl::string_view output_audio_filename)239 bool ValidateOutputFilesOptions(bool textlog,
240                                 bool plotting,
241                                 absl::string_view output_files_base_name,
242                                 absl::string_view output_audio_filename) {
243   bool output_files_base_name_specified = !output_files_base_name.empty();
244   if (!textlog && !plotting && output_files_base_name_specified) {
245     std::cout << "Error: --output_files_base_name cannot be used without at "
246                  "least one of the following flags: --textlog, --matlabplot, "
247                  "--pythonplot."
248               << std::endl;
249     return false;
250   }
251   // Without `output_audio_filename`, `output_files_base_name` is required when
252   // plotting output files must be generated (in order to form a valid output
253   // file name).
254   if (output_audio_filename.empty() && plotting &&
255       !output_files_base_name_specified) {
256     std::cout << "Error: when no output audio file is specified and "
257                  "--matlabplot and/or --pythonplot are used, "
258                  "--output_files_base_name must be also used."
259               << std::endl;
260     return false;
261   }
262   return true;
263 }
264 
CreateOptionalOutputFileName(bool output_requested,absl::string_view basename,absl::string_view output_audio_filename,absl::string_view suffix)265 absl::optional<std::string> CreateOptionalOutputFileName(
266     bool output_requested,
267     absl::string_view basename,
268     absl::string_view output_audio_filename,
269     absl::string_view suffix) {
270   if (!output_requested) {
271     return absl::nullopt;
272   }
273   if (!basename.empty()) {
274     // Override the automatic assignment.
275     rtc::StringBuilder sb(basename);
276     sb << suffix;
277     return sb.str();
278   }
279   if (!output_audio_filename.empty()) {
280     // Automatically assign name.
281     rtc::StringBuilder sb(output_audio_filename);
282     sb << suffix;
283     return sb.str();
284   }
285   std::cout << "Error: invalid text log file parameters.";
286   return absl::nullopt;
287 }
288 
289 }  // namespace
290 
main(int argc,char * argv[])291 int main(int argc, char* argv[]) {
292   std::vector<char*> args = absl::ParseCommandLine(argc, argv);
293   webrtc::test::NetEqTestFactory factory;
294   std::string usage =
295       "Tool for decoding an RTP dump file using NetEq.\n"
296       "Example usage:\n"
297       "./neteq_rtpplay input.rtp [output.{pcm, wav}]\n";
298   if (absl::GetFlag(FLAGS_codec_map)) {
299     PrintCodecMapping();
300     exit(0);
301   }
302   if (args.size() != 2 &&
303       args.size() != 3) {  // The output audio file is optional.
304     // Print usage information.
305     std::cout << usage;
306     exit(0);
307   }
308   const std::string output_audio_filename((args.size() == 3) ? args[2] : "");
309   const std::string output_files_base_name(
310       absl::GetFlag(FLAGS_output_files_base_name));
311   RTC_CHECK(ValidateOutputFilesOptions(
312       absl::GetFlag(FLAGS_textlog),
313       absl::GetFlag(FLAGS_matlabplot) || absl::GetFlag(FLAGS_pythonplot),
314       output_files_base_name, output_audio_filename));
315   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcmu)));
316   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcma)));
317   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_ilbc)));
318   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_isac)));
319   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_isac_swb)));
320   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_opus)));
321   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b)));
322   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b_wb)));
323   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b_swb32)));
324   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_pcm16b_swb48)));
325   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_g722)));
326   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt)));
327   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt_16)));
328   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt_32)));
329   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_avt_48)));
330   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_red)));
331   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_nb)));
332   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_wb)));
333   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_swb32)));
334   RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_cn_swb48)));
335   RTC_CHECK(ValidateSsrcValue(absl::GetFlag(FLAGS_ssrc)));
336   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_audio_level)));
337   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_abs_send_time)));
338   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_transport_seq_no)));
339   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_video_content_type)));
340   RTC_CHECK(ValidateExtensionId(absl::GetFlag(FLAGS_video_timing)));
341 
342   // Make force_fieldtrials persistent string during entire program live as
343   // absl::GetFlag creates temporary string and c_str() will point to
344   // deallocated string.
345   const std::string force_fieldtrials = absl::GetFlag(FLAGS_force_fieldtrials);
346   webrtc::field_trial::InitFieldTrialsFromString(force_fieldtrials.c_str());
347 
348   webrtc::test::NetEqTestFactory::Config config;
349   config.pcmu = absl::GetFlag(FLAGS_pcmu);
350   config.pcma = absl::GetFlag(FLAGS_pcma);
351   config.ilbc = absl::GetFlag(FLAGS_ilbc);
352   config.isac = absl::GetFlag(FLAGS_isac);
353   config.isac_swb = absl::GetFlag(FLAGS_isac_swb);
354   config.opus = absl::GetFlag(FLAGS_opus);
355   config.pcm16b = absl::GetFlag(FLAGS_pcm16b);
356   config.pcm16b_wb = absl::GetFlag(FLAGS_pcm16b_wb);
357   config.pcm16b_swb32 = absl::GetFlag(FLAGS_pcm16b_swb32);
358   config.pcm16b_swb48 = absl::GetFlag(FLAGS_pcm16b_swb48);
359   config.g722 = absl::GetFlag(FLAGS_g722);
360   config.avt = absl::GetFlag(FLAGS_avt);
361   config.avt_16 = absl::GetFlag(FLAGS_avt_16);
362   config.avt_32 = absl::GetFlag(FLAGS_avt_32);
363   config.avt_48 = absl::GetFlag(FLAGS_avt_48);
364   config.red = absl::GetFlag(FLAGS_red);
365   config.cn_nb = absl::GetFlag(FLAGS_cn_nb);
366   config.cn_wb = absl::GetFlag(FLAGS_cn_wb);
367   config.cn_swb32 = absl::GetFlag(FLAGS_cn_swb32);
368   config.cn_swb48 = absl::GetFlag(FLAGS_cn_swb48);
369   config.replacement_audio_file = absl::GetFlag(FLAGS_replacement_audio_file);
370   config.audio_level = absl::GetFlag(FLAGS_audio_level);
371   config.abs_send_time = absl::GetFlag(FLAGS_abs_send_time);
372   config.transport_seq_no = absl::GetFlag(FLAGS_transport_seq_no);
373   config.video_content_type = absl::GetFlag(FLAGS_video_content_type);
374   config.video_timing = absl::GetFlag(FLAGS_video_timing);
375   config.matlabplot = absl::GetFlag(FLAGS_matlabplot);
376   config.pythonplot = absl::GetFlag(FLAGS_pythonplot);
377   config.concealment_events = absl::GetFlag(FLAGS_concealment_events);
378   config.max_nr_packets_in_buffer =
379       absl::GetFlag(FLAGS_max_nr_packets_in_buffer);
380   config.enable_fast_accelerate = absl::GetFlag(FLAGS_enable_fast_accelerate);
381   if (!output_audio_filename.empty()) {
382     config.output_audio_filename = output_audio_filename;
383   }
384   config.textlog = absl::GetFlag(FLAGS_textlog);
385   config.textlog_filename = CreateOptionalOutputFileName(
386       absl::GetFlag(FLAGS_textlog), output_files_base_name,
387       output_audio_filename, ".text_log.txt");
388   config.plot_scripts_basename = CreateOptionalOutputFileName(
389       absl::GetFlag(FLAGS_matlabplot) || absl::GetFlag(FLAGS_pythonplot),
390       output_files_base_name, output_audio_filename, "");
391 
392   // Check if an SSRC value was provided.
393   if (absl::GetFlag(FLAGS_ssrc).size() > 0) {
394     uint32_t ssrc;
395     RTC_CHECK(ParseSsrc(absl::GetFlag(FLAGS_ssrc), &ssrc))
396         << "Flag verification has failed.";
397     config.ssrc_filter = absl::make_optional(ssrc);
398   }
399 
400   std::unique_ptr<webrtc::test::NetEqTest> test =
401       factory.InitializeTestFromFile(/*input_filename=*/args[1],
402                                      /*factory=*/nullptr, config);
403   RTC_CHECK(test) << "ERROR: Unable to run test";
404   test->Run();
405   return 0;
406 }
407