tor-browser

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

ulpfec_header_reader_writer.cc (5719B)


      1 /*
      2 *  Copyright (c) 2016 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 "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
     12 
     13 #include <cstdint>
     14 #include <cstring>
     15 
     16 #include "api/array_view.h"
     17 #include "api/scoped_refptr.h"
     18 #include "modules/rtp_rtcp/source/byte_io.h"
     19 #include "modules/rtp_rtcp/source/forward_error_correction.h"
     20 #include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
     21 #include "rtc_base/checks.h"
     22 
     23 namespace webrtc {
     24 
     25 namespace {
     26 
     27 // Maximum number of media packets that can be protected in one batch.
     28 constexpr size_t kMaxMediaPackets = 48;
     29 
     30 // Maximum number of media packets tracked by FEC decoder.
     31 // Maintain a sufficiently larger tracking window than `kMaxMediaPackets`
     32 // to account for packet reordering in pacer/ network.
     33 constexpr size_t kMaxTrackedMediaPackets = 4 * kMaxMediaPackets;
     34 
     35 // Maximum number of FEC packets stored inside ForwardErrorCorrection.
     36 constexpr size_t kMaxFecPackets = kMaxMediaPackets;
     37 
     38 // FEC Level 0 header size in bytes.
     39 constexpr size_t kFecLevel0HeaderSize = 10;
     40 
     41 // FEC Level 1 (ULP) header size in bytes (L bit is set).
     42 constexpr size_t kFecLevel1HeaderSizeLBitSet = 2 + kUlpfecPacketMaskSizeLBitSet;
     43 
     44 // FEC Level 1 (ULP) header size in bytes (L bit is cleared).
     45 constexpr size_t kFecLevel1HeaderSizeLBitClear =
     46    2 + kUlpfecPacketMaskSizeLBitClear;
     47 
     48 constexpr size_t kPacketMaskOffset = kFecLevel0HeaderSize + 2;
     49 
     50 size_t UlpfecHeaderSize(size_t packet_mask_size) {
     51  RTC_DCHECK_LE(packet_mask_size, kUlpfecPacketMaskSizeLBitSet);
     52  if (packet_mask_size <= kUlpfecPacketMaskSizeLBitClear) {
     53    return kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitClear;
     54  } else {
     55    return kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitSet;
     56  }
     57 }
     58 
     59 }  // namespace
     60 
     61 UlpfecHeaderReader::UlpfecHeaderReader()
     62    : FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {}
     63 
     64 UlpfecHeaderReader::~UlpfecHeaderReader() = default;
     65 
     66 bool UlpfecHeaderReader::ReadFecHeader(
     67    ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
     68  uint8_t* data = fec_packet->pkt->data.MutableData();
     69  if (fec_packet->pkt->data.size() < kPacketMaskOffset) {
     70    return false;  // Truncated packet.
     71  }
     72  bool l_bit = (data[0] & 0x40) != 0u;
     73  size_t packet_mask_size =
     74      l_bit ? kUlpfecPacketMaskSizeLBitSet : kUlpfecPacketMaskSizeLBitClear;
     75  fec_packet->fec_header_size = UlpfecHeaderSize(packet_mask_size);
     76  uint16_t seq_num_base = ByteReader<uint16_t>::ReadBigEndian(&data[2]);
     77  fec_packet->protected_streams = {{.ssrc = fec_packet->ssrc,  // Due to RED.
     78                                    .seq_num_base = seq_num_base,
     79                                    .packet_mask_offset = kPacketMaskOffset,
     80                                    .packet_mask_size = packet_mask_size}};
     81  fec_packet->protection_length =
     82      ByteReader<uint16_t>::ReadBigEndian(&data[10]);
     83 
     84  // Store length recovery field in temporary location in header.
     85  // This makes the header "compatible" with the corresponding
     86  // FlexFEC location of the length recovery field, thus simplifying
     87  // the XORing operations.
     88  memcpy(&data[2], &data[8], 2);
     89 
     90  return true;
     91 }
     92 
     93 UlpfecHeaderWriter::UlpfecHeaderWriter()
     94    : FecHeaderWriter(kMaxMediaPackets,
     95                      kMaxFecPackets,
     96                      kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitSet) {}
     97 
     98 UlpfecHeaderWriter::~UlpfecHeaderWriter() = default;
     99 
    100 // TODO(brandtr): Consider updating this implementation (which actually
    101 // returns a bound on the sequence number spread), if logic is added to
    102 // UlpfecHeaderWriter::FinalizeFecHeader to truncate packet masks which end
    103 // in a string of zeroes. (Similar to how it is done in the FlexFEC case.)
    104 size_t UlpfecHeaderWriter::MinPacketMaskSize(const uint8_t* /* packet_mask */,
    105                                             size_t packet_mask_size) const {
    106  return packet_mask_size;
    107 }
    108 
    109 size_t UlpfecHeaderWriter::FecHeaderSize(size_t packet_mask_size) const {
    110  return UlpfecHeaderSize(packet_mask_size);
    111 }
    112 
    113 void UlpfecHeaderWriter::FinalizeFecHeader(
    114    ArrayView<const ProtectedStream> protected_streams,
    115    ForwardErrorCorrection::Packet& fec_packet) const {
    116  RTC_CHECK_EQ(protected_streams.size(), 1);
    117  uint16_t seq_num_base = protected_streams[0].seq_num_base;
    118  const uint8_t* packet_mask = protected_streams[0].packet_mask.data();
    119  size_t packet_mask_size = protected_streams[0].packet_mask.size();
    120 
    121  uint8_t* data = fec_packet.data.MutableData();
    122  // Set E bit to zero.
    123  data[0] &= 0x7f;
    124  // Set L bit based on packet mask size. (Note that the packet mask
    125  // can only take on two discrete values.)
    126  bool l_bit = (packet_mask_size == kUlpfecPacketMaskSizeLBitSet);
    127  if (l_bit) {
    128    data[0] |= 0x40;  // Set the L bit.
    129  } else {
    130    RTC_DCHECK_EQ(packet_mask_size, kUlpfecPacketMaskSizeLBitClear);
    131    data[0] &= 0xbf;  // Clear the L bit.
    132  }
    133  // Copy length recovery field from temporary location.
    134  memcpy(&data[8], &data[2], 2);
    135  // Write sequence number base.
    136  ByteWriter<uint16_t>::WriteBigEndian(&data[2], seq_num_base);
    137  // Protection length is set to entire packet. (This is not
    138  // required in general.)
    139  const size_t fec_header_size = FecHeaderSize(packet_mask_size);
    140  ByteWriter<uint16_t>::WriteBigEndian(
    141      &data[10], fec_packet.data.size() - fec_header_size);
    142  // Copy the packet mask.
    143  memcpy(&data[12], packet_mask, packet_mask_size);
    144 }
    145 
    146 }  // namespace webrtc