Home | History | Annotate | Download | only in tools
      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