tor-browser

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

nack.cc (6045B)


      1 /*
      2 *  Copyright (c) 2015 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/rtcp_packet/nack.h"
     12 
     13 #include <algorithm>
     14 #include <cstddef>
     15 #include <cstdint>
     16 #include <utility>
     17 #include <vector>
     18 
     19 #include "modules/rtp_rtcp/source/byte_io.h"
     20 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
     21 #include "rtc_base/checks.h"
     22 #include "rtc_base/logging.h"
     23 
     24 namespace webrtc {
     25 namespace rtcp {
     26 // RFC 4585: Feedback format.
     27 //
     28 // Common packet format:
     29 //
     30 //    0                   1                   2                   3
     31 //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     32 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     33 //   |V=2|P|   FMT   |       PT      |          length               |
     34 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     35 // 0 |                  SSRC of packet sender                        |
     36 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     37 // 4 |                  SSRC of media source                         |
     38 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     39 //   :            Feedback Control Information (FCI)                 :
     40 //   :                                                               :
     41 //
     42 // Generic NACK (RFC 4585).
     43 //
     44 // FCI:
     45 //    0                   1                   2                   3
     46 //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     47 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     48 //   |            PID                |             BLP               |
     49 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     50 Nack::Nack() = default;
     51 Nack::Nack(const Nack& rhs) = default;
     52 Nack::~Nack() = default;
     53 
     54 bool Nack::Parse(const CommonHeader& packet) {
     55  RTC_DCHECK_EQ(packet.type(), kPacketType);
     56  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
     57 
     58  if (packet.payload_size_bytes() < kCommonFeedbackLength + kNackItemLength) {
     59    RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
     60                        << " is too small for a Nack.";
     61    return false;
     62  }
     63  size_t nack_items =
     64      (packet.payload_size_bytes() - kCommonFeedbackLength) / kNackItemLength;
     65 
     66  ParseCommonFeedback(packet.payload());
     67  const uint8_t* next_nack = packet.payload() + kCommonFeedbackLength;
     68 
     69  packet_ids_.clear();
     70  packed_.resize(nack_items);
     71  for (size_t index = 0; index < nack_items; ++index) {
     72    packed_[index].first_pid = ByteReader<uint16_t>::ReadBigEndian(next_nack);
     73    packed_[index].bitmask = ByteReader<uint16_t>::ReadBigEndian(next_nack + 2);
     74    next_nack += kNackItemLength;
     75  }
     76  Unpack();
     77 
     78  return true;
     79 }
     80 
     81 size_t Nack::BlockLength() const {
     82  return kHeaderLength + kCommonFeedbackLength +
     83         packed_.size() * kNackItemLength;
     84 }
     85 
     86 bool Nack::Create(uint8_t* packet,
     87                  size_t* index,
     88                  size_t max_length,
     89                  PacketReadyCallback callback) const {
     90  RTC_DCHECK(!packed_.empty());
     91  // If nack list can't fit in packet, try to fragment.
     92  constexpr size_t kNackHeaderLength = kHeaderLength + kCommonFeedbackLength;
     93  for (size_t nack_index = 0; nack_index < packed_.size();) {
     94    size_t bytes_left_in_buffer = max_length - *index;
     95    if (bytes_left_in_buffer < kNackHeaderLength + kNackItemLength) {
     96      if (!OnBufferFull(packet, index, callback))
     97        return false;
     98      continue;
     99    }
    100    size_t num_nack_fields =
    101        std::min((bytes_left_in_buffer - kNackHeaderLength) / kNackItemLength,
    102                 packed_.size() - nack_index);
    103 
    104    size_t payload_size_bytes =
    105        kCommonFeedbackLength + (num_nack_fields * kNackItemLength);
    106    size_t payload_size_32bits = CheckedDivExact<size_t>(payload_size_bytes, 4);
    107    CreateHeader(kFeedbackMessageType, kPacketType, payload_size_32bits, packet,
    108                 index);
    109 
    110    CreateCommonFeedback(packet + *index);
    111    *index += kCommonFeedbackLength;
    112 
    113    size_t nack_end_index = nack_index + num_nack_fields;
    114    for (; nack_index < nack_end_index; ++nack_index) {
    115      const PackedNack& item = packed_[nack_index];
    116      ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 0, item.first_pid);
    117      ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 2, item.bitmask);
    118      *index += kNackItemLength;
    119    }
    120    RTC_DCHECK_LE(*index, max_length);
    121  }
    122 
    123  return true;
    124 }
    125 
    126 void Nack::SetPacketIds(const uint16_t* nack_list, size_t length) {
    127  RTC_DCHECK(nack_list);
    128  SetPacketIds(std::vector<uint16_t>(nack_list, nack_list + length));
    129 }
    130 
    131 void Nack::SetPacketIds(std::vector<uint16_t> nack_list) {
    132  RTC_DCHECK(packet_ids_.empty());
    133  RTC_DCHECK(packed_.empty());
    134  packet_ids_ = std::move(nack_list);
    135  Pack();
    136 }
    137 
    138 void Nack::Pack() {
    139  RTC_DCHECK(!packet_ids_.empty());
    140  RTC_DCHECK(packed_.empty());
    141  auto it = packet_ids_.begin();
    142  const auto end = packet_ids_.end();
    143  while (it != end) {
    144    PackedNack item;
    145    item.first_pid = *it++;
    146    // Bitmask specifies losses in any of the 16 packets following the pid.
    147    item.bitmask = 0;
    148    while (it != end) {
    149      uint16_t shift = static_cast<uint16_t>(*it - item.first_pid - 1);
    150      if (shift <= 15) {
    151        item.bitmask |= (1 << shift);
    152        ++it;
    153      } else {
    154        break;
    155      }
    156    }
    157    packed_.push_back(item);
    158  }
    159 }
    160 
    161 void Nack::Unpack() {
    162  RTC_DCHECK(packet_ids_.empty());
    163  RTC_DCHECK(!packed_.empty());
    164  for (const PackedNack& item : packed_) {
    165    packet_ids_.push_back(item.first_pid);
    166    uint16_t pid = item.first_pid + 1;
    167    for (uint16_t bitmask = item.bitmask; bitmask != 0; bitmask >>= 1, ++pid) {
    168      if (bitmask & 1)
    169        packet_ids_.push_back(pid);
    170    }
    171  }
    172 }
    173 
    174 }  // namespace rtcp
    175 }  // namespace webrtc