• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Parse(const RtcpCommonHeader & header,const uint8_t * payload)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 
Create(uint8_t * packet,size_t * index,size_t max_length,RtcpPacket::PacketReadyCallback * callback) const75 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 
BlockLength() const114 size_t Nack::BlockLength() const {
115   return (packed_.size() * kNackItemLength) + kCommonFeedbackLength +
116          kHeaderLength;
117 }
118 
WithList(const uint16_t * nack_list,size_t length)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 
Pack()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 
Unpack()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