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 // TODO(hlundin): The functionality in this file should be moved into one or 12 // several classes. 13 14 #include <assert.h> 15 #include <errno.h> 16 #include <limits.h> // For ULONG_MAX returned by strtoul. 17 #include <stdio.h> 18 #include <stdlib.h> // For strtoul. 19 20 #include <algorithm> 21 #include <iostream> 22 #include <limits> 23 #include <string> 24 25 #include "google/gflags.h" 26 #include "webrtc/base/checks.h" 27 #include "webrtc/base/safe_conversions.h" 28 #include "webrtc/base/scoped_ptr.h" 29 #include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h" 30 #include "webrtc/modules/audio_coding/neteq/include/neteq.h" 31 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" 32 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h" 33 #include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h" 34 #include "webrtc/modules/audio_coding/neteq/tools/packet.h" 35 #include "webrtc/modules/audio_coding/neteq/tools/rtc_event_log_source.h" 36 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" 37 #include "webrtc/modules/include/module_common_types.h" 38 #include "webrtc/system_wrappers/include/trace.h" 39 #include "webrtc/test/rtp_file_reader.h" 40 #include "webrtc/test/testsupport/fileutils.h" 41 #include "webrtc/typedefs.h" 42 43 using webrtc::NetEq; 44 using webrtc::WebRtcRTPHeader; 45 46 namespace { 47 48 // Parses the input string for a valid SSRC (at the start of the string). If a 49 // valid SSRC is found, it is written to the output variable |ssrc|, and true is 50 // returned. Otherwise, false is returned. 51 bool ParseSsrc(const std::string& str, uint32_t* ssrc) { 52 if (str.empty()) 53 return true; 54 int base = 10; 55 // Look for "0x" or "0X" at the start and change base to 16 if found. 56 if ((str.compare(0, 2, "0x") == 0) || (str.compare(0, 2, "0X") == 0)) 57 base = 16; 58 errno = 0; 59 char* end_ptr; 60 unsigned long value = strtoul(str.c_str(), &end_ptr, base); 61 if (value == ULONG_MAX && errno == ERANGE) 62 return false; // Value out of range for unsigned long. 63 if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF) 64 return false; // Value out of range for uint32_t. 65 if (end_ptr - str.c_str() < static_cast<ptrdiff_t>(str.length())) 66 return false; // Part of the string was not parsed. 67 *ssrc = static_cast<uint32_t>(value); 68 return true; 69 } 70 71 // Flag validators. 72 bool ValidatePayloadType(const char* flagname, int32_t value) { 73 if (value >= 0 && value <= 127) // Value is ok. 74 return true; 75 printf("Invalid value for --%s: %d\n", flagname, static_cast<int>(value)); 76 return false; 77 } 78 79 bool ValidateSsrcValue(const char* flagname, const std::string& str) { 80 uint32_t dummy_ssrc; 81 return ParseSsrc(str, &dummy_ssrc); 82 } 83 84 // Define command line flags. 85 DEFINE_int32(pcmu, 0, "RTP payload type for PCM-u"); 86 const bool pcmu_dummy = 87 google::RegisterFlagValidator(&FLAGS_pcmu, &ValidatePayloadType); 88 DEFINE_int32(pcma, 8, "RTP payload type for PCM-a"); 89 const bool pcma_dummy = 90 google::RegisterFlagValidator(&FLAGS_pcma, &ValidatePayloadType); 91 DEFINE_int32(ilbc, 102, "RTP payload type for iLBC"); 92 const bool ilbc_dummy = 93 google::RegisterFlagValidator(&FLAGS_ilbc, &ValidatePayloadType); 94 DEFINE_int32(isac, 103, "RTP payload type for iSAC"); 95 const bool isac_dummy = 96 google::RegisterFlagValidator(&FLAGS_isac, &ValidatePayloadType); 97 DEFINE_int32(isac_swb, 104, "RTP payload type for iSAC-swb (32 kHz)"); 98 const bool isac_swb_dummy = 99 google::RegisterFlagValidator(&FLAGS_isac_swb, &ValidatePayloadType); 100 DEFINE_int32(opus, 111, "RTP payload type for Opus"); 101 const bool opus_dummy = 102 google::RegisterFlagValidator(&FLAGS_opus, &ValidatePayloadType); 103 DEFINE_int32(pcm16b, 93, "RTP payload type for PCM16b-nb (8 kHz)"); 104 const bool pcm16b_dummy = 105 google::RegisterFlagValidator(&FLAGS_pcm16b, &ValidatePayloadType); 106 DEFINE_int32(pcm16b_wb, 94, "RTP payload type for PCM16b-wb (16 kHz)"); 107 const bool pcm16b_wb_dummy = 108 google::RegisterFlagValidator(&FLAGS_pcm16b_wb, &ValidatePayloadType); 109 DEFINE_int32(pcm16b_swb32, 95, "RTP payload type for PCM16b-swb32 (32 kHz)"); 110 const bool pcm16b_swb32_dummy = 111 google::RegisterFlagValidator(&FLAGS_pcm16b_swb32, &ValidatePayloadType); 112 DEFINE_int32(pcm16b_swb48, 96, "RTP payload type for PCM16b-swb48 (48 kHz)"); 113 const bool pcm16b_swb48_dummy = 114 google::RegisterFlagValidator(&FLAGS_pcm16b_swb48, &ValidatePayloadType); 115 DEFINE_int32(g722, 9, "RTP payload type for G.722"); 116 const bool g722_dummy = 117 google::RegisterFlagValidator(&FLAGS_g722, &ValidatePayloadType); 118 DEFINE_int32(avt, 106, "RTP payload type for AVT/DTMF"); 119 const bool avt_dummy = 120 google::RegisterFlagValidator(&FLAGS_avt, &ValidatePayloadType); 121 DEFINE_int32(red, 117, "RTP payload type for redundant audio (RED)"); 122 const bool red_dummy = 123 google::RegisterFlagValidator(&FLAGS_red, &ValidatePayloadType); 124 DEFINE_int32(cn_nb, 13, "RTP payload type for comfort noise (8 kHz)"); 125 const bool cn_nb_dummy = 126 google::RegisterFlagValidator(&FLAGS_cn_nb, &ValidatePayloadType); 127 DEFINE_int32(cn_wb, 98, "RTP payload type for comfort noise (16 kHz)"); 128 const bool cn_wb_dummy = 129 google::RegisterFlagValidator(&FLAGS_cn_wb, &ValidatePayloadType); 130 DEFINE_int32(cn_swb32, 99, "RTP payload type for comfort noise (32 kHz)"); 131 const bool cn_swb32_dummy = 132 google::RegisterFlagValidator(&FLAGS_cn_swb32, &ValidatePayloadType); 133 DEFINE_int32(cn_swb48, 100, "RTP payload type for comfort noise (48 kHz)"); 134 const bool cn_swb48_dummy = 135 google::RegisterFlagValidator(&FLAGS_cn_swb48, &ValidatePayloadType); 136 DEFINE_bool(codec_map, false, "Prints the mapping between RTP payload type and " 137 "codec"); 138 DEFINE_string(replacement_audio_file, "", 139 "A PCM file that will be used to populate ""dummy"" RTP packets"); 140 DEFINE_string(ssrc, 141 "", 142 "Only use packets with this SSRC (decimal or hex, the latter " 143 "starting with 0x)"); 144 const bool hex_ssrc_dummy = 145 google::RegisterFlagValidator(&FLAGS_ssrc, &ValidateSsrcValue); 146 147 // Maps a codec type to a printable name string. 148 std::string CodecName(webrtc::NetEqDecoder codec) { 149 switch (codec) { 150 case webrtc::NetEqDecoder::kDecoderPCMu: 151 return "PCM-u"; 152 case webrtc::NetEqDecoder::kDecoderPCMa: 153 return "PCM-a"; 154 case webrtc::NetEqDecoder::kDecoderILBC: 155 return "iLBC"; 156 case webrtc::NetEqDecoder::kDecoderISAC: 157 return "iSAC"; 158 case webrtc::NetEqDecoder::kDecoderISACswb: 159 return "iSAC-swb (32 kHz)"; 160 case webrtc::NetEqDecoder::kDecoderOpus: 161 return "Opus"; 162 case webrtc::NetEqDecoder::kDecoderPCM16B: 163 return "PCM16b-nb (8 kHz)"; 164 case webrtc::NetEqDecoder::kDecoderPCM16Bwb: 165 return "PCM16b-wb (16 kHz)"; 166 case webrtc::NetEqDecoder::kDecoderPCM16Bswb32kHz: 167 return "PCM16b-swb32 (32 kHz)"; 168 case webrtc::NetEqDecoder::kDecoderPCM16Bswb48kHz: 169 return "PCM16b-swb48 (48 kHz)"; 170 case webrtc::NetEqDecoder::kDecoderG722: 171 return "G.722"; 172 case webrtc::NetEqDecoder::kDecoderRED: 173 return "redundant audio (RED)"; 174 case webrtc::NetEqDecoder::kDecoderAVT: 175 return "AVT/DTMF"; 176 case webrtc::NetEqDecoder::kDecoderCNGnb: 177 return "comfort noise (8 kHz)"; 178 case webrtc::NetEqDecoder::kDecoderCNGwb: 179 return "comfort noise (16 kHz)"; 180 case webrtc::NetEqDecoder::kDecoderCNGswb32kHz: 181 return "comfort noise (32 kHz)"; 182 case webrtc::NetEqDecoder::kDecoderCNGswb48kHz: 183 return "comfort noise (48 kHz)"; 184 default: 185 assert(false); 186 return "undefined"; 187 } 188 } 189 190 void RegisterPayloadType(NetEq* neteq, 191 webrtc::NetEqDecoder codec, 192 const std::string& name, 193 google::int32 flag) { 194 if (neteq->RegisterPayloadType(codec, name, static_cast<uint8_t>(flag))) { 195 std::cerr << "Cannot register payload type " << flag << " as " 196 << CodecName(codec) << std::endl; 197 exit(1); 198 } 199 } 200 201 // Registers all decoders in |neteq|. 202 void RegisterPayloadTypes(NetEq* neteq) { 203 assert(neteq); 204 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderPCMu, "pcmu", 205 FLAGS_pcmu); 206 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderPCMa, "pcma", 207 FLAGS_pcma); 208 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderILBC, "ilbc", 209 FLAGS_ilbc); 210 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderISAC, "isac", 211 FLAGS_isac); 212 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderISACswb, "isac-swb", 213 FLAGS_isac_swb); 214 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderOpus, "opus", 215 FLAGS_opus); 216 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderPCM16B, "pcm16-nb", 217 FLAGS_pcm16b); 218 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb", 219 FLAGS_pcm16b_wb); 220 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderPCM16Bswb32kHz, 221 "pcm16-swb32", FLAGS_pcm16b_swb32); 222 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderPCM16Bswb48kHz, 223 "pcm16-swb48", FLAGS_pcm16b_swb48); 224 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderG722, "g722", 225 FLAGS_g722); 226 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderAVT, "avt", 227 FLAGS_avt); 228 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderRED, "red", 229 FLAGS_red); 230 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderCNGnb, "cng-nb", 231 FLAGS_cn_nb); 232 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderCNGwb, "cng-wb", 233 FLAGS_cn_wb); 234 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderCNGswb32kHz, 235 "cng-swb32", FLAGS_cn_swb32); 236 RegisterPayloadType(neteq, webrtc::NetEqDecoder::kDecoderCNGswb48kHz, 237 "cng-swb48", FLAGS_cn_swb48); 238 } 239 240 void PrintCodecMappingEntry(webrtc::NetEqDecoder codec, google::int32 flag) { 241 std::cout << CodecName(codec) << ": " << flag << std::endl; 242 } 243 244 void PrintCodecMapping() { 245 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderPCMu, FLAGS_pcmu); 246 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderPCMa, FLAGS_pcma); 247 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderILBC, FLAGS_ilbc); 248 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderISAC, FLAGS_isac); 249 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderISACswb, FLAGS_isac_swb); 250 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderOpus, FLAGS_opus); 251 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderPCM16B, FLAGS_pcm16b); 252 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderPCM16Bwb, 253 FLAGS_pcm16b_wb); 254 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderPCM16Bswb32kHz, 255 FLAGS_pcm16b_swb32); 256 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderPCM16Bswb48kHz, 257 FLAGS_pcm16b_swb48); 258 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderG722, FLAGS_g722); 259 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderAVT, FLAGS_avt); 260 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderRED, FLAGS_red); 261 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderCNGnb, FLAGS_cn_nb); 262 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderCNGwb, FLAGS_cn_wb); 263 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderCNGswb32kHz, 264 FLAGS_cn_swb32); 265 PrintCodecMappingEntry(webrtc::NetEqDecoder::kDecoderCNGswb48kHz, 266 FLAGS_cn_swb48); 267 } 268 269 bool IsComfortNoise(uint8_t payload_type) { 270 return payload_type == FLAGS_cn_nb || payload_type == FLAGS_cn_wb || 271 payload_type == FLAGS_cn_swb32 || payload_type == FLAGS_cn_swb48; 272 } 273 274 int CodecSampleRate(uint8_t payload_type) { 275 if (payload_type == FLAGS_pcmu || payload_type == FLAGS_pcma || 276 payload_type == FLAGS_ilbc || payload_type == FLAGS_pcm16b || 277 payload_type == FLAGS_cn_nb) 278 return 8000; 279 if (payload_type == FLAGS_isac || payload_type == FLAGS_pcm16b_wb || 280 payload_type == FLAGS_g722 || payload_type == FLAGS_cn_wb) 281 return 16000; 282 if (payload_type == FLAGS_isac_swb || payload_type == FLAGS_pcm16b_swb32 || 283 payload_type == FLAGS_cn_swb32) 284 return 32000; 285 if (payload_type == FLAGS_opus || payload_type == FLAGS_pcm16b_swb48 || 286 payload_type == FLAGS_cn_swb48) 287 return 48000; 288 if (payload_type == FLAGS_avt || payload_type == FLAGS_red) 289 return 0; 290 return -1; 291 } 292 293 int CodecTimestampRate(uint8_t payload_type) { 294 return (payload_type == FLAGS_g722) ? 8000 : CodecSampleRate(payload_type); 295 } 296 297 size_t ReplacePayload(webrtc::test::InputAudioFile* replacement_audio_file, 298 rtc::scoped_ptr<int16_t[]>* replacement_audio, 299 rtc::scoped_ptr<uint8_t[]>* payload, 300 size_t* payload_mem_size_bytes, 301 size_t* frame_size_samples, 302 WebRtcRTPHeader* rtp_header, 303 const webrtc::test::Packet* next_packet) { 304 size_t payload_len = 0; 305 // Check for CNG. 306 if (IsComfortNoise(rtp_header->header.payloadType)) { 307 // If CNG, simply insert a zero-energy one-byte payload. 308 if (*payload_mem_size_bytes < 1) { 309 (*payload).reset(new uint8_t[1]); 310 *payload_mem_size_bytes = 1; 311 } 312 (*payload)[0] = 127; // Max attenuation of CNG. 313 payload_len = 1; 314 } else { 315 assert(next_packet->virtual_payload_length_bytes() > 0); 316 // Check if payload length has changed. 317 if (next_packet->header().sequenceNumber == 318 rtp_header->header.sequenceNumber + 1) { 319 if (*frame_size_samples != 320 next_packet->header().timestamp - rtp_header->header.timestamp) { 321 *frame_size_samples = 322 next_packet->header().timestamp - rtp_header->header.timestamp; 323 (*replacement_audio).reset( 324 new int16_t[*frame_size_samples]); 325 *payload_mem_size_bytes = 2 * *frame_size_samples; 326 (*payload).reset(new uint8_t[*payload_mem_size_bytes]); 327 } 328 } 329 // Get new speech. 330 assert((*replacement_audio).get()); 331 if (CodecTimestampRate(rtp_header->header.payloadType) != 332 CodecSampleRate(rtp_header->header.payloadType) || 333 rtp_header->header.payloadType == FLAGS_red || 334 rtp_header->header.payloadType == FLAGS_avt) { 335 // Some codecs have different sample and timestamp rates. And neither 336 // RED nor DTMF is supported for replacement. 337 std::cerr << "Codec not supported for audio replacement." << 338 std::endl; 339 webrtc::Trace::ReturnTrace(); 340 exit(1); 341 } 342 assert(*frame_size_samples > 0); 343 if (!replacement_audio_file->Read(*frame_size_samples, 344 (*replacement_audio).get())) { 345 std::cerr << "Could not read replacement audio file." << std::endl; 346 webrtc::Trace::ReturnTrace(); 347 exit(1); 348 } 349 // Encode it as PCM16. 350 assert((*payload).get()); 351 payload_len = WebRtcPcm16b_Encode((*replacement_audio).get(), 352 *frame_size_samples, 353 (*payload).get()); 354 assert(payload_len == 2 * *frame_size_samples); 355 // Change payload type to PCM16. 356 switch (CodecSampleRate(rtp_header->header.payloadType)) { 357 case 8000: 358 rtp_header->header.payloadType = static_cast<uint8_t>(FLAGS_pcm16b); 359 break; 360 case 16000: 361 rtp_header->header.payloadType = static_cast<uint8_t>(FLAGS_pcm16b_wb); 362 break; 363 case 32000: 364 rtp_header->header.payloadType = 365 static_cast<uint8_t>(FLAGS_pcm16b_swb32); 366 break; 367 case 48000: 368 rtp_header->header.payloadType = 369 static_cast<uint8_t>(FLAGS_pcm16b_swb48); 370 break; 371 default: 372 std::cerr << "Payload type " << 373 static_cast<int>(rtp_header->header.payloadType) << 374 " not supported or unknown." << std::endl; 375 webrtc::Trace::ReturnTrace(); 376 exit(1); 377 } 378 } 379 return payload_len; 380 } 381 382 } // namespace 383 384 int main(int argc, char* argv[]) { 385 static const int kMaxChannels = 5; 386 static const size_t kMaxSamplesPerMs = 48000 / 1000; 387 static const int kOutputBlockSizeMs = 10; 388 389 std::string program_name = argv[0]; 390 std::string usage = "Tool for decoding an RTP dump file using NetEq.\n" 391 "Run " + program_name + " --helpshort for usage.\n" 392 "Example usage:\n" + program_name + 393 " input.rtp output.{pcm, wav}\n"; 394 google::SetUsageMessage(usage); 395 google::ParseCommandLineFlags(&argc, &argv, true); 396 397 if (FLAGS_codec_map) { 398 PrintCodecMapping(); 399 } 400 401 if (argc != 3) { 402 if (FLAGS_codec_map) { 403 // We have already printed the codec map. Just end the program. 404 return 0; 405 } 406 // Print usage information. 407 std::cout << google::ProgramUsage(); 408 return 0; 409 } 410 411 printf("Input file: %s\n", argv[1]); 412 413 bool is_rtp_dump = false; 414 rtc::scoped_ptr<webrtc::test::PacketSource> file_source; 415 webrtc::test::RtcEventLogSource* event_log_source = nullptr; 416 if (webrtc::test::RtpFileSource::ValidRtpDump(argv[1]) || 417 webrtc::test::RtpFileSource::ValidPcap(argv[1])) { 418 is_rtp_dump = true; 419 file_source.reset(webrtc::test::RtpFileSource::Create(argv[1])); 420 } else { 421 event_log_source = webrtc::test::RtcEventLogSource::Create(argv[1]); 422 file_source.reset(event_log_source); 423 } 424 425 assert(file_source.get()); 426 427 // Check if an SSRC value was provided. 428 if (!FLAGS_ssrc.empty()) { 429 uint32_t ssrc; 430 RTC_CHECK(ParseSsrc(FLAGS_ssrc, &ssrc)) << "Flag verification has failed."; 431 file_source->SelectSsrc(ssrc); 432 } 433 434 // Check if a replacement audio file was provided, and if so, open it. 435 bool replace_payload = false; 436 rtc::scoped_ptr<webrtc::test::InputAudioFile> replacement_audio_file; 437 if (!FLAGS_replacement_audio_file.empty()) { 438 replacement_audio_file.reset( 439 new webrtc::test::InputAudioFile(FLAGS_replacement_audio_file)); 440 replace_payload = true; 441 } 442 443 // Read first packet. 444 rtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket()); 445 if (!packet) { 446 printf( 447 "Warning: input file is empty, or the filters did not match any " 448 "packets\n"); 449 webrtc::Trace::ReturnTrace(); 450 return 0; 451 } 452 if (packet->payload_length_bytes() == 0 && !replace_payload) { 453 std::cerr << "Warning: input file contains header-only packets, but no " 454 << "replacement file is specified." << std::endl; 455 webrtc::Trace::ReturnTrace(); 456 return -1; 457 } 458 459 // Check the sample rate. 460 int sample_rate_hz = CodecSampleRate(packet->header().payloadType); 461 if (sample_rate_hz <= 0) { 462 printf("Warning: Invalid sample rate from RTP packet.\n"); 463 webrtc::Trace::ReturnTrace(); 464 return 0; 465 } 466 467 // Open the output file now that we know the sample rate. (Rate is only needed 468 // for wav files.) 469 // Check output file type. 470 std::string output_file_name = argv[2]; 471 rtc::scoped_ptr<webrtc::test::AudioSink> output; 472 if (output_file_name.size() >= 4 && 473 output_file_name.substr(output_file_name.size() - 4) == ".wav") { 474 // Open a wav file. 475 output.reset( 476 new webrtc::test::OutputWavFile(output_file_name, sample_rate_hz)); 477 } else { 478 // Open a pcm file. 479 output.reset(new webrtc::test::OutputAudioFile(output_file_name)); 480 } 481 482 std::cout << "Output file: " << argv[2] << std::endl; 483 484 // Enable tracing. 485 webrtc::Trace::CreateTrace(); 486 webrtc::Trace::SetTraceFile((webrtc::test::OutputPath() + 487 "neteq_trace.txt").c_str()); 488 webrtc::Trace::set_level_filter(webrtc::kTraceAll); 489 490 // Initialize NetEq instance. 491 NetEq::Config config; 492 config.sample_rate_hz = sample_rate_hz; 493 NetEq* neteq = NetEq::Create(config); 494 RegisterPayloadTypes(neteq); 495 496 497 // Set up variables for audio replacement if needed. 498 rtc::scoped_ptr<webrtc::test::Packet> next_packet; 499 bool next_packet_available = false; 500 size_t input_frame_size_timestamps = 0; 501 rtc::scoped_ptr<int16_t[]> replacement_audio; 502 rtc::scoped_ptr<uint8_t[]> payload; 503 size_t payload_mem_size_bytes = 0; 504 if (replace_payload) { 505 // Initially assume that the frame size is 30 ms at the initial sample rate. 506 // This value will be replaced with the correct one as soon as two 507 // consecutive packets are found. 508 input_frame_size_timestamps = 30 * sample_rate_hz / 1000; 509 replacement_audio.reset(new int16_t[input_frame_size_timestamps]); 510 payload_mem_size_bytes = 2 * input_frame_size_timestamps; 511 payload.reset(new uint8_t[payload_mem_size_bytes]); 512 next_packet.reset(file_source->NextPacket()); 513 assert(next_packet); 514 next_packet_available = true; 515 } 516 517 // This is the main simulation loop. 518 // Set the simulation clock to start immediately with the first packet. 519 int64_t start_time_ms = rtc::checked_cast<int64_t>(packet->time_ms()); 520 int64_t time_now_ms = start_time_ms; 521 int64_t next_input_time_ms = time_now_ms; 522 int64_t next_output_time_ms = time_now_ms; 523 if (time_now_ms % kOutputBlockSizeMs != 0) { 524 // Make sure that next_output_time_ms is rounded up to the next multiple 525 // of kOutputBlockSizeMs. (Legacy bit-exactness.) 526 next_output_time_ms += 527 kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs; 528 } 529 530 bool packet_available = true; 531 bool output_event_available = true; 532 if (!is_rtp_dump) { 533 next_output_time_ms = event_log_source->NextAudioOutputEventMs(); 534 if (next_output_time_ms == std::numeric_limits<int64_t>::max()) 535 output_event_available = false; 536 start_time_ms = time_now_ms = 537 std::min(next_input_time_ms, next_output_time_ms); 538 } 539 while (packet_available || output_event_available) { 540 // Advance time to next event. 541 time_now_ms = std::min(next_input_time_ms, next_output_time_ms); 542 // Check if it is time to insert packet. 543 while (time_now_ms >= next_input_time_ms && packet_available) { 544 assert(packet->virtual_payload_length_bytes() > 0); 545 // Parse RTP header. 546 WebRtcRTPHeader rtp_header; 547 packet->ConvertHeader(&rtp_header); 548 const uint8_t* payload_ptr = packet->payload(); 549 size_t payload_len = packet->payload_length_bytes(); 550 if (replace_payload) { 551 payload_len = ReplacePayload(replacement_audio_file.get(), 552 &replacement_audio, 553 &payload, 554 &payload_mem_size_bytes, 555 &input_frame_size_timestamps, 556 &rtp_header, 557 next_packet.get()); 558 payload_ptr = payload.get(); 559 } 560 int error = neteq->InsertPacket( 561 rtp_header, rtc::ArrayView<const uint8_t>(payload_ptr, payload_len), 562 static_cast<uint32_t>(packet->time_ms() * sample_rate_hz / 1000)); 563 if (error != NetEq::kOK) { 564 if (neteq->LastError() == NetEq::kUnknownRtpPayloadType) { 565 std::cerr << "RTP Payload type " 566 << static_cast<int>(rtp_header.header.payloadType) 567 << " is unknown." << std::endl; 568 std::cerr << "Use --codec_map to view default mapping." << std::endl; 569 std::cerr << "Use --helpshort for information on how to make custom " 570 "mappings." << std::endl; 571 } else { 572 std::cerr << "InsertPacket returned error code " << neteq->LastError() 573 << std::endl; 574 std::cerr << "Header data:" << std::endl; 575 std::cerr << " PT = " 576 << static_cast<int>(rtp_header.header.payloadType) 577 << std::endl; 578 std::cerr << " SN = " << rtp_header.header.sequenceNumber 579 << std::endl; 580 std::cerr << " TS = " << rtp_header.header.timestamp << std::endl; 581 } 582 } 583 584 // Get next packet from file. 585 webrtc::test::Packet* temp_packet = file_source->NextPacket(); 586 if (temp_packet) { 587 packet.reset(temp_packet); 588 if (replace_payload) { 589 // At this point |packet| contains the packet *after* |next_packet|. 590 // Swap Packet objects between |packet| and |next_packet|. 591 packet.swap(next_packet); 592 // Swap the status indicators unless they're already the same. 593 if (packet_available != next_packet_available) { 594 packet_available = !packet_available; 595 next_packet_available = !next_packet_available; 596 } 597 } 598 next_input_time_ms = rtc::checked_cast<int64_t>(packet->time_ms()); 599 } else { 600 // Set next input time to the maximum value of int64_t to prevent the 601 // time_now_ms from becoming stuck at the final value. 602 next_input_time_ms = std::numeric_limits<int64_t>::max(); 603 packet_available = false; 604 } 605 } 606 607 // Check if it is time to get output audio. 608 while (time_now_ms >= next_output_time_ms && output_event_available) { 609 static const size_t kOutDataLen = 610 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels; 611 int16_t out_data[kOutDataLen]; 612 size_t num_channels; 613 size_t samples_per_channel; 614 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel, 615 &num_channels, NULL); 616 if (error != NetEq::kOK) { 617 std::cerr << "GetAudio returned error code " << 618 neteq->LastError() << std::endl; 619 } else { 620 // Calculate sample rate from output size. 621 sample_rate_hz = rtc::checked_cast<int>( 622 1000 * samples_per_channel / kOutputBlockSizeMs); 623 } 624 625 // Write to file. 626 // TODO(hlundin): Make writing to file optional. 627 size_t write_len = samples_per_channel * num_channels; 628 if (!output->WriteArray(out_data, write_len)) { 629 std::cerr << "Error while writing to file" << std::endl; 630 webrtc::Trace::ReturnTrace(); 631 exit(1); 632 } 633 if (is_rtp_dump) { 634 next_output_time_ms += kOutputBlockSizeMs; 635 if (!packet_available) 636 output_event_available = false; 637 } else { 638 next_output_time_ms = event_log_source->NextAudioOutputEventMs(); 639 if (next_output_time_ms == std::numeric_limits<int64_t>::max()) 640 output_event_available = false; 641 } 642 } 643 } 644 printf("Simulation done\n"); 645 printf("Produced %i ms of audio\n", 646 static_cast<int>(time_now_ms - start_time_ms)); 647 648 delete neteq; 649 webrtc::Trace::ReturnTrace(); 650 return 0; 651 } 652