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