tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rtp_encode.cc (12957B)


      1 /*
      2 *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include <cstdint>
     12 #include <cstdio>
     13 #include <memory>
     14 #include <utility>
     15 
     16 #ifdef WIN32
     17 #include <winsock2.h>
     18 #endif
     19 
     20 #include <map>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include "absl/flags/flag.h"
     25 #include "absl/flags/parse.h"
     26 #include "api/audio/audio_frame.h"
     27 #include "api/audio_codecs/L16/audio_encoder_L16.h"
     28 #include "api/audio_codecs/g711/audio_encoder_g711.h"
     29 #include "api/audio_codecs/g722/audio_encoder_g722.h"
     30 #include "api/audio_codecs/opus/audio_encoder_opus.h"
     31 #include "api/environment/environment_factory.h"
     32 #include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
     33 #include "modules/audio_coding/include/audio_coding_module.h"
     34 #include "modules/audio_coding/include/audio_coding_module_typedefs.h"
     35 #include "modules/audio_coding/neteq/tools/input_audio_file.h"
     36 #include "rtc_base/checks.h"
     37 #include "rtc_base/ip_address.h"
     38 #include "rtc_base/numerics/safe_conversions.h"
     39 
     40 ABSL_FLAG(bool, list_codecs, false, "Enumerate all codecs");
     41 ABSL_FLAG(std::string, codec, "opus", "Codec to use");
     42 ABSL_FLAG(int,
     43          frame_len,
     44          0,
     45          "Frame length in ms; 0 indicates codec default value");
     46 ABSL_FLAG(int, bitrate, 0, "Bitrate in bps; 0 indicates codec default value");
     47 ABSL_FLAG(int,
     48          payload_type,
     49          -1,
     50          "RTP payload type; -1 indicates codec default value");
     51 ABSL_FLAG(int,
     52          cng_payload_type,
     53          -1,
     54          "RTP payload type for CNG; -1 indicates default value");
     55 ABSL_FLAG(int, ssrc, 0, "SSRC to write to the RTP header");
     56 ABSL_FLAG(bool, dtx, false, "Use DTX/CNG");
     57 ABSL_FLAG(int, sample_rate, 48000, "Sample rate of the input file");
     58 ABSL_FLAG(bool, fec, false, "Use Opus FEC");
     59 ABSL_FLAG(int, expected_loss, 0, "Expected packet loss percentage");
     60 
     61 namespace webrtc {
     62 namespace test {
     63 namespace {
     64 
     65 // Add new codecs here, and to the map below.
     66 enum class CodecType {
     67  kOpus,
     68  kPcmU,
     69  kPcmA,
     70  kG722,
     71  kPcm16b8,
     72  kPcm16b16,
     73  kPcm16b32,
     74  kPcm16b48,
     75 };
     76 
     77 struct CodecTypeAndInfo {
     78  CodecType type;
     79  int default_payload_type;
     80  bool internal_dtx;
     81 };
     82 
     83 // List all supported codecs here. This map defines the command-line parameter
     84 // value (the key string) for selecting each codec, together with information
     85 // whether it is using internal or external DTX/CNG.
     86 const std::map<std::string, CodecTypeAndInfo>& CodecList() {
     87  static const auto* const codec_list =
     88      new std::map<std::string, CodecTypeAndInfo>{
     89          {"opus",
     90           {.type = CodecType::kOpus,
     91            .default_payload_type = 111,
     92            .internal_dtx = true}},
     93          {"pcmu",
     94           {.type = CodecType::kPcmU,
     95            .default_payload_type = 0,
     96            .internal_dtx = false}},
     97          {"pcma",
     98           {.type = CodecType::kPcmA,
     99            .default_payload_type = 8,
    100            .internal_dtx = false}},
    101          {"g722",
    102           {.type = CodecType::kG722,
    103            .default_payload_type = 9,
    104            .internal_dtx = false}},
    105          {"pcm16b_8",
    106           {.type = CodecType::kPcm16b8,
    107            .default_payload_type = 93,
    108            .internal_dtx = false}},
    109          {"pcm16b_16",
    110           {.type = CodecType::kPcm16b16,
    111            .default_payload_type = 94,
    112            .internal_dtx = false}},
    113          {"pcm16b_32",
    114           {.type = CodecType::kPcm16b32,
    115            .default_payload_type = 95,
    116            .internal_dtx = false}},
    117          {"pcm16b_48",
    118           {.type = CodecType::kPcm16b48,
    119            .default_payload_type = 96,
    120            .internal_dtx = false}}};
    121  return *codec_list;
    122 }
    123 
    124 // This class will receive callbacks from ACM when a packet is ready, and write
    125 // it to the output file.
    126 class Packetizer : public AudioPacketizationCallback {
    127 public:
    128  Packetizer(FILE* out_file, uint32_t ssrc, int timestamp_rate_hz)
    129      : out_file_(out_file),
    130        ssrc_(ssrc),
    131        timestamp_rate_hz_(timestamp_rate_hz) {}
    132 
    133  int32_t SendData(AudioFrameType /* frame_type */,
    134                   uint8_t payload_type,
    135                   uint32_t timestamp,
    136                   const uint8_t* payload_data,
    137                   size_t payload_len_bytes,
    138                   int64_t /* absolute_capture_timestamp_ms */) override {
    139    if (payload_len_bytes == 0) {
    140      return 0;
    141    }
    142 
    143    constexpr size_t kRtpHeaderLength = 12;
    144    constexpr size_t kRtpDumpHeaderLength = 8;
    145    const uint16_t length = htons(checked_cast<uint16_t>(
    146        kRtpHeaderLength + kRtpDumpHeaderLength + payload_len_bytes));
    147    const uint16_t plen =
    148        htons(checked_cast<uint16_t>(kRtpHeaderLength + payload_len_bytes));
    149    const uint32_t offset = htonl(timestamp / (timestamp_rate_hz_ / 1000));
    150    RTC_CHECK_EQ(fwrite(&length, sizeof(uint16_t), 1, out_file_), 1);
    151    RTC_CHECK_EQ(fwrite(&plen, sizeof(uint16_t), 1, out_file_), 1);
    152    RTC_CHECK_EQ(fwrite(&offset, sizeof(uint32_t), 1, out_file_), 1);
    153 
    154    const uint8_t rtp_header[] = {0x80,
    155                                  static_cast<uint8_t>(payload_type & 0x7F),
    156                                  static_cast<uint8_t>(sequence_number_ >> 8),
    157                                  static_cast<uint8_t>(sequence_number_),
    158                                  static_cast<uint8_t>(timestamp >> 24),
    159                                  static_cast<uint8_t>(timestamp >> 16),
    160                                  static_cast<uint8_t>(timestamp >> 8),
    161                                  static_cast<uint8_t>(timestamp),
    162                                  static_cast<uint8_t>(ssrc_ >> 24),
    163                                  static_cast<uint8_t>(ssrc_ >> 16),
    164                                  static_cast<uint8_t>(ssrc_ >> 8),
    165                                  static_cast<uint8_t>(ssrc_)};
    166    static_assert(sizeof(rtp_header) == kRtpHeaderLength, "");
    167    RTC_CHECK_EQ(
    168        fwrite(rtp_header, sizeof(uint8_t), kRtpHeaderLength, out_file_),
    169        kRtpHeaderLength);
    170    ++sequence_number_;  // Intended to wrap on overflow.
    171 
    172    RTC_CHECK_EQ(
    173        fwrite(payload_data, sizeof(uint8_t), payload_len_bytes, out_file_),
    174        payload_len_bytes);
    175 
    176    return 0;
    177  }
    178 
    179 private:
    180  FILE* const out_file_;
    181  const uint32_t ssrc_;
    182  const int timestamp_rate_hz_;
    183  uint16_t sequence_number_ = 0;
    184 };
    185 
    186 void SetFrameLenIfFlagIsPositive(int* config_frame_len) {
    187  if (absl::GetFlag(FLAGS_frame_len) > 0) {
    188    *config_frame_len = absl::GetFlag(FLAGS_frame_len);
    189  }
    190 }
    191 
    192 template <typename T>
    193 typename T::Config GetCodecConfig() {
    194  typename T::Config config;
    195  SetFrameLenIfFlagIsPositive(&config.frame_size_ms);
    196  RTC_CHECK(config.IsOk());
    197  return config;
    198 }
    199 
    200 AudioEncoderL16::Config Pcm16bConfig(CodecType codec_type) {
    201  auto config = GetCodecConfig<AudioEncoderL16>();
    202  switch (codec_type) {
    203    case CodecType::kPcm16b8:
    204      config.sample_rate_hz = 8000;
    205      return config;
    206    case CodecType::kPcm16b16:
    207      config.sample_rate_hz = 16000;
    208      return config;
    209    case CodecType::kPcm16b32:
    210      config.sample_rate_hz = 32000;
    211      return config;
    212    case CodecType::kPcm16b48:
    213      config.sample_rate_hz = 48000;
    214      return config;
    215    default:
    216      RTC_DCHECK_NOTREACHED();
    217      return config;
    218  }
    219 }
    220 
    221 std::unique_ptr<AudioEncoder> CreateEncoder(CodecType codec_type,
    222                                            int payload_type) {
    223  switch (codec_type) {
    224    case CodecType::kOpus: {
    225      AudioEncoderOpus::Config config = GetCodecConfig<AudioEncoderOpus>();
    226      if (absl::GetFlag(FLAGS_bitrate) > 0) {
    227        config.bitrate_bps = absl::GetFlag(FLAGS_bitrate);
    228      }
    229      config.dtx_enabled = absl::GetFlag(FLAGS_dtx);
    230      config.fec_enabled = absl::GetFlag(FLAGS_fec);
    231      RTC_CHECK(config.IsOk());
    232      return AudioEncoderOpus::MakeAudioEncoder(CreateEnvironment(), config,
    233                                                {.payload_type = payload_type});
    234    }
    235 
    236    case CodecType::kPcmU:
    237    case CodecType::kPcmA: {
    238      AudioEncoderG711::Config config = GetCodecConfig<AudioEncoderG711>();
    239      config.type = codec_type == CodecType::kPcmU
    240                        ? AudioEncoderG711::Config::Type::kPcmU
    241                        : AudioEncoderG711::Config::Type::kPcmA;
    242      RTC_CHECK(config.IsOk());
    243      return AudioEncoderG711::MakeAudioEncoder(config, payload_type);
    244    }
    245 
    246    case CodecType::kG722: {
    247      return AudioEncoderG722::MakeAudioEncoder(
    248          GetCodecConfig<AudioEncoderG722>(), payload_type);
    249    }
    250 
    251    case CodecType::kPcm16b8:
    252    case CodecType::kPcm16b16:
    253    case CodecType::kPcm16b32:
    254    case CodecType::kPcm16b48: {
    255      return AudioEncoderL16::MakeAudioEncoder(Pcm16bConfig(codec_type),
    256                                               payload_type);
    257    }
    258  }
    259  RTC_DCHECK_NOTREACHED();
    260  return nullptr;
    261 }
    262 
    263 AudioEncoderCngConfig GetCngConfig(int sample_rate_hz) {
    264  AudioEncoderCngConfig cng_config;
    265  const auto default_payload_type = [&] {
    266    switch (sample_rate_hz) {
    267      case 8000:
    268        return 13;
    269      case 16000:
    270        return 98;
    271      case 32000:
    272        return 99;
    273      case 48000:
    274        return 100;
    275      default:
    276        RTC_DCHECK_NOTREACHED();
    277    }
    278    return 0;
    279  };
    280  cng_config.payload_type = absl::GetFlag(FLAGS_cng_payload_type) != -1
    281                                ? absl::GetFlag(FLAGS_cng_payload_type)
    282                                : default_payload_type();
    283  return cng_config;
    284 }
    285 
    286 int RunRtpEncode(int argc, char* argv[]) {
    287  std::vector<char*> args = absl::ParseCommandLine(argc, argv);
    288  const std::string usage =
    289      "Tool for generating an RTP dump file from audio input.\n"
    290      "Example usage:\n"
    291      "./rtp_encode input.pcm output.rtp --codec=[codec] "
    292      "--frame_len=[frame_len] --bitrate=[bitrate]\n\n";
    293  if (!absl::GetFlag(FLAGS_list_codecs) && args.size() != 3) {
    294    printf("%s", usage.c_str());
    295    return 1;
    296  }
    297 
    298  if (absl::GetFlag(FLAGS_list_codecs)) {
    299    printf("The following arguments are valid --codec parameters:\n");
    300    for (const auto& c : CodecList()) {
    301      printf("  %s\n", c.first.c_str());
    302    }
    303    return 0;
    304  }
    305 
    306  const auto codec_it = CodecList().find(absl::GetFlag(FLAGS_codec));
    307  if (codec_it == CodecList().end()) {
    308    printf("%s is not a valid codec name.\n",
    309           absl::GetFlag(FLAGS_codec).c_str());
    310    printf("Use argument --list_codecs to see all valid codec names.\n");
    311    return 1;
    312  }
    313 
    314  // Create the codec.
    315  const int payload_type = absl::GetFlag(FLAGS_payload_type) == -1
    316                               ? codec_it->second.default_payload_type
    317                               : absl::GetFlag(FLAGS_payload_type);
    318  std::unique_ptr<AudioEncoder> codec =
    319      CreateEncoder(codec_it->second.type, payload_type);
    320 
    321  // Create an external VAD/CNG encoder if needed.
    322  if (absl::GetFlag(FLAGS_dtx) && !codec_it->second.internal_dtx) {
    323    AudioEncoderCngConfig cng_config = GetCngConfig(codec->SampleRateHz());
    324    RTC_DCHECK(codec);
    325    cng_config.speech_encoder = std::move(codec);
    326    codec = CreateComfortNoiseEncoder(std::move(cng_config));
    327  }
    328  RTC_DCHECK(codec);
    329 
    330  // Set up ACM.
    331  const int timestamp_rate_hz = codec->RtpTimestampRateHz();
    332  auto acm(AudioCodingModule::Create());
    333  acm->SetEncoder(std::move(codec));
    334  acm->SetPacketLossRate(absl::GetFlag(FLAGS_expected_loss));
    335 
    336  // Open files.
    337  printf("Input file: %s\n", args[1]);
    338  InputAudioFile input_file(args[1], false);  // Open input in non-looping mode.
    339  FILE* out_file = fopen(args[2], "wb");
    340  RTC_CHECK(out_file) << "Could not open file " << args[2] << " for writing";
    341  printf("Output file: %s\n", args[2]);
    342  fprintf(out_file, "#!rtpplay1.0 \n");  //,
    343  // Write 3 32-bit values followed by 2 16-bit values, all set to 0. This means
    344  // a total of 16 bytes.
    345  const uint8_t file_header[16] = {0};
    346  RTC_CHECK_EQ(fwrite(file_header, sizeof(file_header), 1, out_file), 1);
    347 
    348  // Create and register the packetizer, which will write the packets to file.
    349  Packetizer packetizer(out_file, absl::GetFlag(FLAGS_ssrc), timestamp_rate_hz);
    350  RTC_DCHECK_EQ(acm->RegisterTransportCallback(&packetizer), 0);
    351 
    352  AudioFrame audio_frame;
    353  audio_frame.samples_per_channel_ =
    354      absl::GetFlag(FLAGS_sample_rate) / 100;  // 10 ms
    355  audio_frame.sample_rate_hz_ = absl::GetFlag(FLAGS_sample_rate);
    356  audio_frame.num_channels_ = 1;
    357 
    358  while (input_file.Read(audio_frame.samples_per_channel_,
    359                         audio_frame.mutable_data())) {
    360    RTC_CHECK_GE(acm->Add10MsData(audio_frame), 0);
    361    audio_frame.timestamp_ += audio_frame.samples_per_channel_;
    362  }
    363 
    364  return 0;
    365 }
    366 
    367 }  // namespace
    368 }  // namespace test
    369 }  // namespace webrtc
    370 
    371 int main(int argc, char* argv[]) {
    372  return webrtc::test::RunRtpEncode(argc, argv);
    373 }