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