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