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
43using webrtc::NetEq;
44using webrtc::WebRtcRTPHeader;
45
46namespace {
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.
51bool 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.
72bool 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
79bool 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.
85DEFINE_int32(pcmu, 0, "RTP payload type for PCM-u");
86const bool pcmu_dummy =
87    google::RegisterFlagValidator(&FLAGS_pcmu, &ValidatePayloadType);
88DEFINE_int32(pcma, 8, "RTP payload type for PCM-a");
89const bool pcma_dummy =
90    google::RegisterFlagValidator(&FLAGS_pcma, &ValidatePayloadType);
91DEFINE_int32(ilbc, 102, "RTP payload type for iLBC");
92const bool ilbc_dummy =
93    google::RegisterFlagValidator(&FLAGS_ilbc, &ValidatePayloadType);
94DEFINE_int32(isac, 103, "RTP payload type for iSAC");
95const bool isac_dummy =
96    google::RegisterFlagValidator(&FLAGS_isac, &ValidatePayloadType);
97DEFINE_int32(isac_swb, 104, "RTP payload type for iSAC-swb (32 kHz)");
98const bool isac_swb_dummy =
99    google::RegisterFlagValidator(&FLAGS_isac_swb, &ValidatePayloadType);
100DEFINE_int32(opus, 111, "RTP payload type for Opus");
101const bool opus_dummy =
102    google::RegisterFlagValidator(&FLAGS_opus, &ValidatePayloadType);
103DEFINE_int32(pcm16b, 93, "RTP payload type for PCM16b-nb (8 kHz)");
104const bool pcm16b_dummy =
105    google::RegisterFlagValidator(&FLAGS_pcm16b, &ValidatePayloadType);
106DEFINE_int32(pcm16b_wb, 94, "RTP payload type for PCM16b-wb (16 kHz)");
107const bool pcm16b_wb_dummy =
108    google::RegisterFlagValidator(&FLAGS_pcm16b_wb, &ValidatePayloadType);
109DEFINE_int32(pcm16b_swb32, 95, "RTP payload type for PCM16b-swb32 (32 kHz)");
110const bool pcm16b_swb32_dummy =
111    google::RegisterFlagValidator(&FLAGS_pcm16b_swb32, &ValidatePayloadType);
112DEFINE_int32(pcm16b_swb48, 96, "RTP payload type for PCM16b-swb48 (48 kHz)");
113const bool pcm16b_swb48_dummy =
114    google::RegisterFlagValidator(&FLAGS_pcm16b_swb48, &ValidatePayloadType);
115DEFINE_int32(g722, 9, "RTP payload type for G.722");
116const bool g722_dummy =
117    google::RegisterFlagValidator(&FLAGS_g722, &ValidatePayloadType);
118DEFINE_int32(avt, 106, "RTP payload type for AVT/DTMF");
119const bool avt_dummy =
120    google::RegisterFlagValidator(&FLAGS_avt, &ValidatePayloadType);
121DEFINE_int32(red, 117, "RTP payload type for redundant audio (RED)");
122const bool red_dummy =
123    google::RegisterFlagValidator(&FLAGS_red, &ValidatePayloadType);
124DEFINE_int32(cn_nb, 13, "RTP payload type for comfort noise (8 kHz)");
125const bool cn_nb_dummy =
126    google::RegisterFlagValidator(&FLAGS_cn_nb, &ValidatePayloadType);
127DEFINE_int32(cn_wb, 98, "RTP payload type for comfort noise (16 kHz)");
128const bool cn_wb_dummy =
129    google::RegisterFlagValidator(&FLAGS_cn_wb, &ValidatePayloadType);
130DEFINE_int32(cn_swb32, 99, "RTP payload type for comfort noise (32 kHz)");
131const bool cn_swb32_dummy =
132    google::RegisterFlagValidator(&FLAGS_cn_swb32, &ValidatePayloadType);
133DEFINE_int32(cn_swb48, 100, "RTP payload type for comfort noise (48 kHz)");
134const bool cn_swb48_dummy =
135    google::RegisterFlagValidator(&FLAGS_cn_swb48, &ValidatePayloadType);
136DEFINE_bool(codec_map, false, "Prints the mapping between RTP payload type and "
137    "codec");
138DEFINE_string(replacement_audio_file, "",
139              "A PCM file that will be used to populate ""dummy"" RTP packets");
140DEFINE_string(ssrc,
141              "",
142              "Only use packets with this SSRC (decimal or hex, the latter "
143              "starting with 0x)");
144const bool hex_ssrc_dummy =
145    google::RegisterFlagValidator(&FLAGS_ssrc, &ValidateSsrcValue);
146
147// Maps a codec type to a printable name string.
148std::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
190void 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|.
202void 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
240void PrintCodecMappingEntry(webrtc::NetEqDecoder codec, google::int32 flag) {
241  std::cout << CodecName(codec) << ": " << flag << std::endl;
242}
243
244void 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
269bool 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
274int 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
293int CodecTimestampRate(uint8_t payload_type) {
294  return (payload_type == FLAGS_g722) ? 8000 : CodecSampleRate(payload_type);
295}
296
297size_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
384int 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