• 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 "modules/rtp_rtcp/source/rtcp_packet/nack.h"
12 
13 #include <algorithm>
14 #include <cstdint>
15 #include <utility>
16 
17 #include "modules/rtp_rtcp/source/byte_io.h"
18 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 
22 namespace webrtc {
23 namespace rtcp {
24 constexpr uint8_t Nack::kFeedbackMessageType;
25 constexpr size_t Nack::kNackItemLength;
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 
Parse(const CommonHeader & packet)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 
BlockLength() const81 size_t Nack::BlockLength() const {
82   return kHeaderLength + kCommonFeedbackLength +
83          packed_.size() * kNackItemLength;
84 }
85 
Create(uint8_t * packet,size_t * index,size_t max_length,PacketReadyCallback callback) const86 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 =
107         rtc::CheckedDivExact<size_t>(payload_size_bytes, 4);
108     CreateHeader(kFeedbackMessageType, kPacketType, payload_size_32bits, packet,
109                  index);
110 
111     CreateCommonFeedback(packet + *index);
112     *index += kCommonFeedbackLength;
113 
114     size_t nack_end_index = nack_index + num_nack_fields;
115     for (; nack_index < nack_end_index; ++nack_index) {
116       const PackedNack& item = packed_[nack_index];
117       ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 0, item.first_pid);
118       ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 2, item.bitmask);
119       *index += kNackItemLength;
120     }
121     RTC_DCHECK_LE(*index, max_length);
122   }
123 
124   return true;
125 }
126 
SetPacketIds(const uint16_t * nack_list,size_t length)127 void Nack::SetPacketIds(const uint16_t* nack_list, size_t length) {
128   RTC_DCHECK(nack_list);
129   SetPacketIds(std::vector<uint16_t>(nack_list, nack_list + length));
130 }
131 
SetPacketIds(std::vector<uint16_t> nack_list)132 void Nack::SetPacketIds(std::vector<uint16_t> nack_list) {
133   RTC_DCHECK(packet_ids_.empty());
134   RTC_DCHECK(packed_.empty());
135   packet_ids_ = std::move(nack_list);
136   Pack();
137 }
138 
Pack()139 void Nack::Pack() {
140   RTC_DCHECK(!packet_ids_.empty());
141   RTC_DCHECK(packed_.empty());
142   auto it = packet_ids_.begin();
143   const auto end = packet_ids_.end();
144   while (it != end) {
145     PackedNack item;
146     item.first_pid = *it++;
147     // Bitmask specifies losses in any of the 16 packets following the pid.
148     item.bitmask = 0;
149     while (it != end) {
150       uint16_t shift = static_cast<uint16_t>(*it - item.first_pid - 1);
151       if (shift <= 15) {
152         item.bitmask |= (1 << shift);
153         ++it;
154       } else {
155         break;
156       }
157     }
158     packed_.push_back(item);
159   }
160 }
161 
Unpack()162 void Nack::Unpack() {
163   RTC_DCHECK(packet_ids_.empty());
164   RTC_DCHECK(!packed_.empty());
165   for (const PackedNack& item : packed_) {
166     packet_ids_.push_back(item.first_pid);
167     uint16_t pid = item.first_pid + 1;
168     for (uint16_t bitmask = item.bitmask; bitmask != 0; bitmask >>= 1, ++pid) {
169       if (bitmask & 1)
170         packet_ids_.push_back(pid);
171     }
172   }
173 }
174 
175 }  // namespace rtcp
176 }  // namespace webrtc
177