tor-browser

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

flexfec_header_reader_writer.cc (14222B)


      1 /*
      2 *  Copyright (c) 2023 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/flexfec_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 #include "rtc_base/logging.h"
     23 
     24 namespace webrtc {
     25 
     26 namespace {
     27 
     28 // Maximum number of media packets that can be protected in one batch.
     29 constexpr size_t kMaxMediaPackets = 48;  // Since we are reusing ULPFEC masks.
     30 
     31 // Maximum number of media packets tracked by FEC decoder.
     32 // Maintain a sufficiently larger tracking window than `kMaxMediaPackets`
     33 // to account for packet reordering in pacer/ network.
     34 constexpr size_t kMaxTrackedMediaPackets = 4 * kMaxMediaPackets;
     35 
     36 // Maximum number of FEC packets stored inside ForwardErrorCorrection.
     37 constexpr size_t kMaxFecPackets = kMaxMediaPackets;
     38 
     39 // Size (in bytes) of packet masks, given number of K bits set.
     40 constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
     41 
     42 // Size (in bytes) of part of header which is not packet mask specific.
     43 constexpr size_t kBaseHeaderSize = 8;
     44 
     45 // Size (in bytes) of part of header which is stream specific.
     46 constexpr size_t kStreamSpecificHeaderSize = 2;
     47 
     48 // Size (in bytes) of header, given the single stream packet mask size, i.e.
     49 // the number of K-bits set.
     50 constexpr size_t kHeaderSizes[] = {
     51    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[0],
     52    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1],
     53    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]};
     54 
     55 // Here we count the K-bits as belonging to the packet mask.
     56 // This can be used in conjunction with FlexfecHeaderWriter::MinPacketMaskSize,
     57 // which calculates a bound on the needed packet mask size including K-bits,
     58 // given a packet mask without K-bits.
     59 size_t FlexfecHeaderSize(size_t packet_mask_size) {
     60  RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]);
     61  if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) {
     62    return kHeaderSizes[0];
     63  } else if (packet_mask_size <= kFlexfecPacketMaskSizes[1]) {
     64    return kHeaderSizes[1];
     65  }
     66  return kHeaderSizes[2];
     67 }
     68 
     69 }  // namespace
     70 
     71 FlexfecHeaderReader::FlexfecHeaderReader()
     72    : FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {}
     73 
     74 FlexfecHeaderReader::~FlexfecHeaderReader() = default;
     75 
     76 // TODO(brandtr): Update this function when we support flexible masks,
     77 // and retransmissions.
     78 bool FlexfecHeaderReader::ReadFecHeader(
     79    ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
     80  // Protected ssrcs should already be populated from RTP header.
     81  if (fec_packet->protected_streams.empty()) {
     82    RTC_LOG(LS_WARNING)
     83        << "Discarding FlexFEC packet with no protected sources.";
     84    return false;
     85  }
     86  if (fec_packet->pkt->data.size() <=
     87      kBaseHeaderSize + kStreamSpecificHeaderSize) {
     88    RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
     89    return false;
     90  }
     91  uint8_t* const data = fec_packet->pkt->data.MutableData();
     92  bool r_bit = (data[0] & 0x80) != 0;
     93  if (r_bit) {
     94    RTC_LOG(LS_INFO)
     95        << "FlexFEC packet with retransmission bit set. We do not yet "
     96           "support this, thus discarding the packet.";
     97    return false;
     98  }
     99  bool f_bit = (data[0] & 0x40) != 0;
    100  if (f_bit) {
    101    RTC_LOG(LS_INFO)
    102        << "FlexFEC packet with inflexible generator matrix. We do "
    103           "not yet support this, thus discarding packet.";
    104    return false;
    105  }
    106 
    107  // First seq_num will be in byte index 8
    108  // (See FEC header schematic in flexfec_header_reader_writer.h.)
    109  size_t byte_index = 8;
    110  for (size_t i = 0; i < fec_packet->protected_streams.size(); ++i) {
    111    if (fec_packet->pkt->data.size() < byte_index + kStreamSpecificHeaderSize) {
    112      RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
    113      return false;
    114    }
    115 
    116    fec_packet->protected_streams[i].seq_num_base =
    117        ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
    118    byte_index += kStreamSpecificHeaderSize;
    119 
    120    // Parse the FlexFEC packet mask and remove the interleaved K-bits.
    121    // (See FEC header schematic in flexfec_header_reader_writer.h.)
    122    // We store the packed packet mask in-band, which "destroys" the standards
    123    // compliance of the header. That is fine though, since the code that
    124    // reads from the header (from this point and onwards) is aware of this.
    125    // TODO(brandtr): When the FEC packet classes have been refactored, store
    126    // the packed packet masks out-of-band, thus leaving the FlexFEC header as
    127    // is.
    128    //
    129    // We treat the mask parts as unsigned integers with host order endianness
    130    // in order to simplify the bit shifting between bytes.
    131    if (fec_packet->pkt->data.size() <
    132        (byte_index + kFlexfecPacketMaskSizes[0])) {
    133      RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
    134      return false;
    135    }
    136    fec_packet->protected_streams[i].packet_mask_offset = byte_index;
    137    bool k_bit0 = (data[byte_index] & 0x80) != 0;
    138    uint16_t mask_part0 =
    139        ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
    140    // Shift away K-bit 0, implicitly clearing the last bit.
    141    mask_part0 <<= 1;
    142    ByteWriter<uint16_t>::WriteBigEndian(&data[byte_index], mask_part0);
    143    byte_index += kFlexfecPacketMaskSizes[0];
    144    if (!k_bit0) {
    145      // The first K-bit is clear, and the packet mask is thus only 2 bytes
    146      // long. We have finished reading the properties for current ssrc.
    147      fec_packet->protected_streams[i].packet_mask_size =
    148          kFlexfecPacketMaskSizes[0];
    149    } else {
    150      if (fec_packet->pkt->data.size() <
    151          (byte_index + kFlexfecPacketMaskSizes[1] -
    152           kFlexfecPacketMaskSizes[0])) {
    153        return false;
    154      }
    155      bool k_bit1 = (data[byte_index] & 0x80) != 0;
    156      // We have already shifted the first two bytes of the packet mask one step
    157      // to the left, thus removing K-bit 0. We will now shift the next four
    158      // bytes of the packet mask two steps to the left. (One step for the
    159      // removed K-bit 0, and one step for the to be removed K-bit 1).
    160      uint8_t bit15 = (data[byte_index] >> 6) & 0x01;
    161      data[byte_index - 1] |= bit15;
    162      uint32_t mask_part1 =
    163          ByteReader<uint32_t>::ReadBigEndian(&data[byte_index]);
    164      // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
    165      mask_part1 <<= 2;
    166      ByteWriter<uint32_t>::WriteBigEndian(&data[byte_index], mask_part1);
    167      byte_index += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
    168      if (!k_bit1) {
    169        // The first K-bit is set, but the second K-bit is clear. The packet
    170        // mask is thus 6 bytes long. We have finished reading the properties
    171        // for current ssrc.
    172        fec_packet->protected_streams[i].packet_mask_size =
    173            kFlexfecPacketMaskSizes[1];
    174      } else {
    175        if (fec_packet->pkt->data.size() <
    176            (byte_index + kFlexfecPacketMaskSizes[2] -
    177             kFlexfecPacketMaskSizes[1])) {
    178          RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
    179          return false;
    180        }
    181        fec_packet->protected_streams[i].packet_mask_size =
    182            kFlexfecPacketMaskSizes[2];
    183        // At this point, K-bits 0 and 1 have been removed, and the front-most
    184        // part of the FlexFEC packet mask has been packed accordingly. We will
    185        // now shift the remaining part of the packet mask two steps to
    186        // the left. This corresponds to the (in total) two K-bits, which
    187        // have been removed.
    188        uint8_t tail_bits = (data[byte_index] >> 6) & 0x03;
    189        data[byte_index - 1] |= tail_bits;
    190        uint64_t mask_part2 =
    191            ByteReader<uint64_t>::ReadBigEndian(&data[byte_index]);
    192        // Shift away bit 46, and bit 47, which were copied to the previous
    193        // part of the mask, implicitly clearing the last two bits.
    194        mask_part2 <<= 2;
    195        ByteWriter<uint64_t>::WriteBigEndian(&data[byte_index], mask_part2);
    196        byte_index += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1];
    197      }
    198    }
    199  }
    200 
    201  fec_packet->fec_header_size = byte_index;
    202 
    203  // In FlexFEC, all media packets are protected in their entirety.
    204  fec_packet->protection_length =
    205      fec_packet->pkt->data.size() - fec_packet->fec_header_size;
    206 
    207  return true;
    208 }
    209 
    210 FlexfecHeaderWriter::FlexfecHeaderWriter()
    211    : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
    212 
    213 FlexfecHeaderWriter::~FlexfecHeaderWriter() = default;
    214 
    215 size_t FlexfecHeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask,
    216                                              size_t packet_mask_size) const {
    217  if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear &&
    218      (packet_mask[1] & 0x01) == 0) {
    219    // Packet mask is 16 bits long, with bit 15 clear.
    220    // It can be used as is.
    221    return kFlexfecPacketMaskSizes[0];
    222  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
    223    // Packet mask is 16 bits long, with bit 15 set.
    224    // We must expand the packet mask with zeros in the FlexFEC header.
    225    return kFlexfecPacketMaskSizes[1];
    226  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet &&
    227             (packet_mask[5] & 0x03) == 0) {
    228    // Packet mask is 48 bits long, with bits 46 and 47 clear.
    229    // It can be used as is.
    230    return kFlexfecPacketMaskSizes[1];
    231  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
    232    // Packet mask is 48 bits long, with at least one of bits 46 and 47 set.
    233    // We must expand it with zeros.
    234    return kFlexfecPacketMaskSizes[2];
    235  }
    236  RTC_DCHECK_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size
    237                          << ".";
    238  return kFlexfecPacketMaskSizes[2];
    239 }
    240 
    241 size_t FlexfecHeaderWriter::FecHeaderSize(size_t packet_mask_size) const {
    242  return FlexfecHeaderSize(packet_mask_size);
    243 }
    244 
    245 // This function adapts the precomputed ULPFEC packet masks to the
    246 // FlexFEC header standard. Note that the header size is computed by
    247 // FecHeaderSize(), so in this function we can be sure that we are
    248 // writing in space that is intended for the header.
    249 //
    250 // TODO(brandtr): Update this function when we support offset-based masks
    251 // and retransmissions.
    252 void FlexfecHeaderWriter::FinalizeFecHeader(
    253    ArrayView<const ProtectedStream> protected_streams,
    254    ForwardErrorCorrection::Packet& fec_packet) const {
    255  uint8_t* data = fec_packet.data.MutableData();
    256  *data &= 0x7f;  // Clear R bit.
    257  *data &= 0xbf;  // Clear F bit.
    258 
    259  // First seq_num will be in byte index 8
    260  // (See FEC header schematic in flexfec_header_reader_writer.h.)
    261  uint8_t* write_at = data + 8;
    262  for (const ProtectedStream& protected_stream : protected_streams) {
    263    ByteWriter<uint16_t>::WriteBigEndian(write_at,
    264                                         protected_stream.seq_num_base);
    265    write_at += kStreamSpecificHeaderSize;
    266    // Adapt ULPFEC packet mask to FlexFEC header.
    267    //
    268    // We treat the mask parts as unsigned integers with host order endianness
    269    // in order to simplify the bit shifting between bytes.
    270    if (protected_stream.packet_mask.size() == kUlpfecPacketMaskSizeLBitSet) {
    271      // The packet mask is 48 bits long.
    272      uint16_t tmp_mask_part0 =
    273          ByteReader<uint16_t>::ReadBigEndian(&protected_stream.packet_mask[0]);
    274      uint32_t tmp_mask_part1 =
    275          ByteReader<uint32_t>::ReadBigEndian(&protected_stream.packet_mask[2]);
    276 
    277      tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
    278      ByteWriter<uint16_t>::WriteBigEndian(write_at, tmp_mask_part0);
    279      *write_at |= 0x80;  // Set K-bit 0.
    280      write_at += kFlexfecPacketMaskSizes[0];
    281      tmp_mask_part1 >>= 2;  // Shift twice, thus clearing K-bit 1 and bit 15.
    282      ByteWriter<uint32_t>::WriteBigEndian(write_at, tmp_mask_part1);
    283 
    284      bool bit15 = (protected_stream.packet_mask[1] & 0x01) != 0;
    285      if (bit15)
    286        *write_at |= 0x40;  // Set bit 15.
    287 
    288      bool bit46 = (protected_stream.packet_mask[5] & 0x02) != 0;
    289      bool bit47 = (protected_stream.packet_mask[5] & 0x01) != 0;
    290      if (!bit46 && !bit47) {
    291        write_at += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
    292      } else {
    293        *write_at |= 0x80;  // Set K-bit 1.
    294        write_at += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
    295        // Clear all trailing bits.
    296        memset(write_at, 0,
    297               kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1]);
    298        if (bit46)
    299          *write_at |= 0x80;  // Set bit 46.
    300        if (bit47)
    301          *write_at |= 0x40;  // Set bit 47.
    302        write_at += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1];
    303      }
    304    } else if (protected_stream.packet_mask.size() ==
    305               kUlpfecPacketMaskSizeLBitClear) {
    306      // The packet mask is 16 bits long.
    307      uint16_t tmp_mask_part0 =
    308          ByteReader<uint16_t>::ReadBigEndian(&protected_stream.packet_mask[0]);
    309 
    310      tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
    311      ByteWriter<uint16_t>::WriteBigEndian(write_at, tmp_mask_part0);
    312      bool bit15 = (protected_stream.packet_mask[1] & 0x01) != 0;
    313      if (!bit15) {
    314        write_at += kFlexfecPacketMaskSizes[0];
    315      } else {
    316        *write_at |= 0x80;  // Set K-bit 0.
    317        write_at += kFlexfecPacketMaskSizes[0];
    318        // Clear all trailing bits.
    319        memset(write_at, 0U,
    320               kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0]);
    321        *write_at |= 0x40;  // Set bit 15.
    322        write_at += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
    323      }
    324    } else {
    325      RTC_DCHECK_NOTREACHED() << "Incorrect packet mask size: "
    326                              << protected_stream.packet_mask.size() << ".";
    327    }
    328  }
    329 }
    330 
    331 }  // namespace webrtc