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