| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" | 11 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" |
| 12 | 12 |
| 13 #include <algorithm> |
| 14 |
| 13 #include "webrtc/base/checks.h" | 15 #include "webrtc/base/checks.h" |
| 14 #include "webrtc/base/logging.h" | 16 #include "webrtc/base/logging.h" |
| 15 #include "webrtc/modules/include/module_common_types.h" | 17 #include "webrtc/modules/include/module_common_types.h" |
| 16 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 18 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
| 17 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h" | 19 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h" |
| 18 | 20 |
| 19 namespace webrtc { | 21 namespace webrtc { |
| 20 namespace rtcp { | 22 namespace rtcp { |
| 21 namespace { | 23 namespace { |
| 22 // Header size: | 24 // Header size: |
| 23 // * 4 bytes Common RTCP Packet Header | 25 // * 4 bytes Common RTCP Packet Header |
| 24 // * 8 bytes Common Packet Format for RTCP Feedback Messages | 26 // * 8 bytes Common Packet Format for RTCP Feedback Messages |
| 25 // * 8 bytes FeedbackPacket header | 27 // * 8 bytes FeedbackPacket header |
| 26 constexpr size_t kTransportFeedbackHeaderSizeBytes = 4 + 8 + 8; | 28 constexpr size_t kTransportFeedbackHeaderSizeBytes = 4 + 8 + 8; |
| 27 constexpr size_t kChunkSizeBytes = 2; | 29 constexpr size_t kChunkSizeBytes = 2; |
| 28 constexpr size_t kRunLengthCapacity = 0x1FFF; | |
| 29 // TODO(sprang): Add support for dynamic max size for easier fragmentation, | 30 // TODO(sprang): Add support for dynamic max size for easier fragmentation, |
| 30 // eg. set it to what's left in the buffer or IP_PACKET_SIZE. | 31 // eg. set it to what's left in the buffer or IP_PACKET_SIZE. |
| 31 // Size constraint imposed by RTCP common header: 16bit size field interpreted | 32 // Size constraint imposed by RTCP common header: 16bit size field interpreted |
| 32 // as number of four byte words minus the first header word. | 33 // as number of four byte words minus the first header word. |
| 33 constexpr size_t kMaxSizeBytes = (1 << 16) * 4; | 34 constexpr size_t kMaxSizeBytes = (1 << 16) * 4; |
| 34 // Payload size: | 35 // Payload size: |
| 35 // * 8 bytes Common Packet Format for RTCP Feedback Messages | 36 // * 8 bytes Common Packet Format for RTCP Feedback Messages |
| 36 // * 8 bytes FeedbackPacket header. | 37 // * 8 bytes FeedbackPacket header. |
| 37 // * 2 bytes for one chunk. | 38 // * 2 bytes for one chunk. |
| 38 constexpr size_t kMinPayloadSizeBytes = 8 + 8 + 2; | 39 constexpr size_t kMinPayloadSizeBytes = 8 + 8 + 2; |
| 39 constexpr size_t kBaseScaleFactor = | 40 constexpr size_t kBaseScaleFactor = |
| 40 TransportFeedback::kDeltaScaleFactor * (1 << 8); | 41 TransportFeedback::kDeltaScaleFactor * (1 << 8); |
| 41 | 42 constexpr int64_t kTimeWrapPeriodUs = (1ll << 24) * kBaseScaleFactor; |
| 42 uint8_t EncodeSymbol(TransportFeedback::StatusSymbol symbol) { | 43 |
| 43 switch (symbol) { | 44 // Message format |
| 44 case TransportFeedback::StatusSymbol::kNotReceived: | 45 // |
| 45 return 0; | 46 // 0 1 2 3 |
| 46 case TransportFeedback::StatusSymbol::kReceivedSmallDelta: | 47 // 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 return 1; | 48 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 48 case TransportFeedback::StatusSymbol::kReceivedLargeDelta: | 49 // |V=2|P| FMT=15 | PT=205 | length | |
| 49 return 2; | 50 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 50 } | 51 // 0 | SSRC of packet sender | |
| 51 RTC_NOTREACHED(); | 52 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 52 return 0; | 53 // 4 | SSRC of media source | |
| 53 } | 54 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 54 | 55 // 8 | base sequence number | packet status count | |
| 55 TransportFeedback::StatusSymbol DecodeSymbol(uint8_t value) { | 56 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 56 switch (value) { | 57 // 12 | reference time | fb pkt. count | |
| 57 case 0: | 58 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 58 return TransportFeedback::StatusSymbol::kNotReceived; | 59 // 16 | packet chunk | packet chunk | |
| 59 case 1: | 60 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 60 return TransportFeedback::StatusSymbol::kReceivedSmallDelta; | 61 // . . |
| 61 case 2: | 62 // . . |
| 62 return TransportFeedback::StatusSymbol::kReceivedLargeDelta; | 63 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 63 case 3: | 64 // | packet chunk | recv delta | recv delta | |
| 64 // It is invalid, but |value| comes from network, so can be any. | 65 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 65 return TransportFeedback::StatusSymbol::kNotReceived; | 66 // . . |
| 66 default: | 67 // . . |
| 67 // Caller should pass 2 bits max. | 68 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 68 RTC_NOTREACHED(); | 69 // | recv delta | recv delta | zero padding | |
| 69 return TransportFeedback::StatusSymbol::kNotReceived; | 70 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 70 } | |
| 71 } | |
| 72 | |
| 73 } // namespace | 71 } // namespace |
| 74 constexpr uint8_t TransportFeedback::kFeedbackMessageType; | 72 constexpr uint8_t TransportFeedback::kFeedbackMessageType; |
| 75 | 73 constexpr size_t TransportFeedback::kMaxReportedPackets; |
| 76 class TransportFeedback::PacketStatusChunk { | 74 |
| 75 // Keep delta_sizes that can be encoded into single chunk if it is last chunk. |
| 76 class TransportFeedback::LastChunk { |
| 77 public: | 77 public: |
| 78 virtual ~PacketStatusChunk() {} | 78 using DeltaSize = TransportFeedback::DeltaSize; |
| 79 virtual uint16_t NumSymbols() const = 0; | 79 |
| 80 virtual void AppendSymbolsTo( | 80 LastChunk(); |
| 81 std::vector<TransportFeedback::StatusSymbol>* vec) const = 0; | 81 |
| 82 virtual void WriteTo(uint8_t* buffer) const = 0; | 82 bool Empty() const; |
| 83 void Clear(); |
| 84 // Return if delta sizes still can be encoded into single chunk with added |
| 85 // |delta_size|. |
| 86 bool CanAdd(DeltaSize delta_size) const; |
| 87 // Add |delta_size|, assumes |CanAdd(delta_size)|, |
| 88 void Add(DeltaSize delta_size); |
| 89 |
| 90 // Encode chunk as large as possible removing encoded delta sizes. |
| 91 // Assume CanAdd() == false for some valid delta_size. |
| 92 uint16_t Emit(); |
| 93 // Encode all stored delta_sizes into single chunk, pad with 0s if needed. |
| 94 uint16_t EncodeLast() const; |
| 95 |
| 96 // Decode up to |max_size| delta sizes from |chunk|. |
| 97 void Decode(uint16_t chunk, size_t max_size); |
| 98 // Appends content of the Lastchunk to |deltas|. |
| 99 void AppendTo(std::vector<DeltaSize>* deltas) const; |
| 100 |
| 101 private: |
| 102 static constexpr size_t kMaxRunLengthCapacity = 0x1fff; |
| 103 static constexpr size_t kMaxOneBitCapacity = 14; |
| 104 static constexpr size_t kMaxTwoBitCapacity = 7; |
| 105 static constexpr size_t kMaxVectorCapacity = kMaxOneBitCapacity; |
| 106 static constexpr DeltaSize kLarge = 2; |
| 107 |
| 108 uint16_t EncodeOneBit() const; |
| 109 void DecodeOneBit(uint16_t chunk, size_t max_size); |
| 110 |
| 111 uint16_t EncodeTwoBit(size_t size) const; |
| 112 void DecodeTwoBit(uint16_t chunk, size_t max_size); |
| 113 |
| 114 uint16_t EncodeRunLength() const; |
| 115 void DecodeRunLength(uint16_t chunk, size_t max_size); |
| 116 |
| 117 DeltaSize delta_sizes_[kMaxVectorCapacity]; |
| 118 uint16_t size_; |
| 119 bool all_same_; |
| 120 bool has_large_delta_; |
| 83 }; | 121 }; |
| 84 | 122 constexpr size_t TransportFeedback::LastChunk::kMaxRunLengthCapacity; |
| 85 TransportFeedback::TransportFeedback() | 123 constexpr size_t TransportFeedback::LastChunk::kMaxOneBitCapacity; |
| 86 : base_seq_(-1), | 124 constexpr size_t TransportFeedback::LastChunk::kMaxTwoBitCapacity; |
| 87 base_time_(-1), | 125 constexpr size_t TransportFeedback::LastChunk::kMaxVectorCapacity; |
| 88 feedback_seq_(0), | 126 |
| 89 last_seq_(-1), | 127 TransportFeedback::LastChunk::LastChunk() { |
| 90 last_timestamp_(-1), | 128 Clear(); |
| 91 first_symbol_cardinality_(0), | 129 } |
| 92 vec_needs_two_bit_symbols_(false), | 130 |
| 93 size_bytes_(kTransportFeedbackHeaderSizeBytes) {} | 131 bool TransportFeedback::LastChunk::Empty() const { |
| 94 | 132 return size_ == 0; |
| 95 TransportFeedback::~TransportFeedback() { | 133 } |
| 96 for (PacketStatusChunk* chunk : status_chunks_) | 134 |
| 97 delete chunk; | 135 void TransportFeedback::LastChunk::Clear() { |
| 136 size_ = 0; |
| 137 all_same_ = true; |
| 138 has_large_delta_ = false; |
| 139 } |
| 140 |
| 141 bool TransportFeedback::LastChunk::CanAdd(DeltaSize delta_size) const { |
| 142 RTC_DCHECK_LE(delta_size, 2); |
| 143 if (size_ < kMaxTwoBitCapacity) |
| 144 return true; |
| 145 if (size_ < kMaxOneBitCapacity && !has_large_delta_ && delta_size != kLarge) |
| 146 return true; |
| 147 if (size_ < kMaxRunLengthCapacity && all_same_ && |
| 148 delta_sizes_[0] == delta_size) |
| 149 return true; |
| 150 return false; |
| 151 } |
| 152 |
| 153 void TransportFeedback::LastChunk::Add(DeltaSize delta_size) { |
| 154 RTC_DCHECK(CanAdd(delta_size)); |
| 155 if (size_ < kMaxVectorCapacity) |
| 156 delta_sizes_[size_] = delta_size; |
| 157 size_++; |
| 158 all_same_ = all_same_ && delta_size == delta_sizes_[0]; |
| 159 has_large_delta_ = has_large_delta_ || delta_size == kLarge; |
| 160 } |
| 161 |
| 162 uint16_t TransportFeedback::LastChunk::Emit() { |
| 163 RTC_DCHECK(!CanAdd(0) || !CanAdd(1) || !CanAdd(2)); |
| 164 if (all_same_) { |
| 165 uint16_t chunk = EncodeRunLength(); |
| 166 Clear(); |
| 167 return chunk; |
| 168 } |
| 169 if (size_ == kMaxOneBitCapacity) { |
| 170 uint16_t chunk = EncodeOneBit(); |
| 171 Clear(); |
| 172 return chunk; |
| 173 } |
| 174 RTC_DCHECK_GE(size_, kMaxTwoBitCapacity); |
| 175 uint16_t chunk = EncodeTwoBit(kMaxTwoBitCapacity); |
| 176 // Remove |kMaxTwoBitCapacity| encoded delta sizes: |
| 177 // Shift remaining delta sizes and recalculate all_same_ && has_large_delta_. |
| 178 size_ -= kMaxTwoBitCapacity; |
| 179 all_same_ = true; |
| 180 has_large_delta_ = false; |
| 181 for (size_t i = 0; i < size_; ++i) { |
| 182 DeltaSize delta_size = delta_sizes_[kMaxTwoBitCapacity + i]; |
| 183 delta_sizes_[i] = delta_size; |
| 184 all_same_ = all_same_ && delta_size == delta_sizes_[0]; |
| 185 has_large_delta_ = has_large_delta_ || delta_size == kLarge; |
| 186 } |
| 187 |
| 188 return chunk; |
| 189 } |
| 190 |
| 191 uint16_t TransportFeedback::LastChunk::EncodeLast() const { |
| 192 RTC_DCHECK_GT(size_, 0); |
| 193 if (all_same_) |
| 194 return EncodeRunLength(); |
| 195 if (size_ <= kMaxTwoBitCapacity) |
| 196 return EncodeTwoBit(size_); |
| 197 return EncodeOneBit(); |
| 198 } |
| 199 |
| 200 // Appends content of the Lastchunk to |deltas|. |
| 201 void TransportFeedback::LastChunk::AppendTo( |
| 202 std::vector<DeltaSize>* deltas) const { |
| 203 if (all_same_) { |
| 204 deltas->insert(deltas->end(), size_, delta_sizes_[0]); |
| 205 } else { |
| 206 deltas->insert(deltas->end(), delta_sizes_, delta_sizes_ + size_); |
| 207 } |
| 208 } |
| 209 |
| 210 void TransportFeedback::LastChunk::Decode(uint16_t chunk, size_t max_size) { |
| 211 if ((chunk & 0x8000) == 0) { |
| 212 DecodeRunLength(chunk, max_size); |
| 213 } else if ((chunk & 0x4000) == 0) { |
| 214 DecodeOneBit(chunk, max_size); |
| 215 } else { |
| 216 DecodeTwoBit(chunk, max_size); |
| 217 } |
| 98 } | 218 } |
| 99 | 219 |
| 100 // One Bit Status Vector Chunk | 220 // One Bit Status Vector Chunk |
| 101 // | 221 // |
| 102 // 0 1 | 222 // 0 1 |
| 103 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 | 223 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
| 104 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 224 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 105 // |T|S| symbol list | | 225 // |T|S| symbol list | |
| 106 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 226 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 107 // | 227 // |
| 108 // T = 1 | 228 // T = 1 |
| 109 // S = 0 | 229 // S = 0 |
| 110 // symbol list = 14 entries where 0 = not received, 1 = received | 230 // Symbol list = 14 entries where 0 = not received, 1 = received 1-byte delta. |
| 111 | 231 uint16_t TransportFeedback::LastChunk::EncodeOneBit() const { |
| 112 class OneBitVectorChunk : public TransportFeedback::PacketStatusChunk { | 232 RTC_DCHECK(!has_large_delta_); |
| 113 public: | 233 RTC_DCHECK_LE(size_, kMaxOneBitCapacity); |
| 114 static constexpr size_t kCapacity = 14; | 234 uint16_t chunk = 0x8000; |
| 115 | 235 for (size_t i = 0; i < size_; ++i) |
| 116 explicit OneBitVectorChunk( | 236 chunk |= delta_sizes_[i] << (kMaxOneBitCapacity - 1 - i); |
| 117 std::deque<TransportFeedback::StatusSymbol>* symbols) { | 237 return chunk; |
| 118 size_t input_size = symbols->size(); | 238 } |
| 119 for (size_t i = 0; i < kCapacity; ++i) { | 239 |
| 120 if (i < input_size) { | 240 void TransportFeedback::LastChunk::DecodeOneBit(uint16_t chunk, |
| 121 symbols_[i] = symbols->front(); | 241 size_t max_size) { |
| 122 symbols->pop_front(); | 242 RTC_DCHECK_EQ(chunk & 0xc000, 0x8000); |
| 123 } else { | 243 size_ = std::min(kMaxOneBitCapacity, max_size); |
| 124 symbols_[i] = TransportFeedback::StatusSymbol::kNotReceived; | 244 has_large_delta_ = false; |
| 125 } | 245 all_same_ = false; |
| 126 } | 246 for (size_t i = 0; i < size_; ++i) |
| 127 } | 247 delta_sizes_[i] = (chunk >> (kMaxOneBitCapacity - 1 - i)) & 0x01; |
| 128 | 248 } |
| 129 ~OneBitVectorChunk() override {} | |
| 130 | |
| 131 uint16_t NumSymbols() const override { return kCapacity; } | |
| 132 | |
| 133 void AppendSymbolsTo( | |
| 134 std::vector<TransportFeedback::StatusSymbol>* vec) const override { | |
| 135 vec->insert(vec->end(), &symbols_[0], &symbols_[kCapacity]); | |
| 136 } | |
| 137 | |
| 138 void WriteTo(uint8_t* buffer) const override { | |
| 139 constexpr int kSymbolsInFirstByte = 6; | |
| 140 constexpr int kSymbolsInSecondByte = 8; | |
| 141 buffer[0] = 0x80u; | |
| 142 for (int i = 0; i < kSymbolsInFirstByte; ++i) { | |
| 143 uint8_t encoded_symbol = EncodeSymbol(symbols_[i]); | |
| 144 RTC_DCHECK_LE(encoded_symbol, 1); | |
| 145 buffer[0] |= encoded_symbol << (kSymbolsInFirstByte - (i + 1)); | |
| 146 } | |
| 147 buffer[1] = 0x00u; | |
| 148 for (int i = 0; i < kSymbolsInSecondByte; ++i) { | |
| 149 uint8_t encoded_symbol = EncodeSymbol(symbols_[i + kSymbolsInFirstByte]); | |
| 150 RTC_DCHECK_LE(encoded_symbol, 1); | |
| 151 buffer[1] |= encoded_symbol << (kSymbolsInSecondByte - (i + 1)); | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 static OneBitVectorChunk* ParseFrom(const uint8_t* data) { | |
| 156 OneBitVectorChunk* chunk = new OneBitVectorChunk(); | |
| 157 | |
| 158 size_t index = 0; | |
| 159 for (int i = 5; i >= 0; --i) // Last 5 bits from first byte. | |
| 160 chunk->symbols_[index++] = DecodeSymbol((data[0] >> i) & 0x01); | |
| 161 for (int i = 7; i >= 0; --i) // 8 bits from the last byte. | |
| 162 chunk->symbols_[index++] = DecodeSymbol((data[1] >> i) & 0x01); | |
| 163 | |
| 164 return chunk; | |
| 165 } | |
| 166 | |
| 167 private: | |
| 168 OneBitVectorChunk() {} | |
| 169 | |
| 170 TransportFeedback::StatusSymbol symbols_[kCapacity]; | |
| 171 }; | |
| 172 | 249 |
| 173 // Two Bit Status Vector Chunk | 250 // Two Bit Status Vector Chunk |
| 174 // | 251 // |
| 175 // 0 1 | 252 // 0 1 |
| 176 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 | 253 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
| 177 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 254 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 178 // |T|S| symbol list | | 255 // |T|S| symbol list | |
| 179 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 256 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 180 // | 257 // |
| 181 // T = 1 | 258 // T = 1 |
| 182 // S = 1 | 259 // S = 1 |
| 183 // symbol list = 7 entries of two bits each, see (Encode|Decode)Symbol | 260 // symbol list = 7 entries of two bits each. |
| 261 uint16_t TransportFeedback::LastChunk::EncodeTwoBit(size_t size) const { |
| 262 RTC_DCHECK_LE(size, size_); |
| 263 uint16_t chunk = 0xc000; |
| 264 for (size_t i = 0; i < size; ++i) |
| 265 chunk |= delta_sizes_[i] << 2 * (kMaxTwoBitCapacity - 1 - i); |
| 266 return chunk; |
| 267 } |
| 184 | 268 |
| 185 class TwoBitVectorChunk : public TransportFeedback::PacketStatusChunk { | 269 void TransportFeedback::LastChunk::DecodeTwoBit(uint16_t chunk, |
| 186 public: | 270 size_t max_size) { |
| 187 static constexpr size_t kCapacity = 7; | 271 RTC_DCHECK_EQ(chunk & 0xc000, 0xc000); |
| 272 size_ = std::min(kMaxTwoBitCapacity, max_size); |
| 273 has_large_delta_ = true; |
| 274 all_same_ = false; |
| 275 for (size_t i = 0; i < size_; ++i) |
| 276 delta_sizes_[i] = (chunk >> 2 * (kMaxTwoBitCapacity - 1 - i)) & 0x03; |
| 277 } |
| 188 | 278 |
| 189 explicit TwoBitVectorChunk( | 279 // Run Length Status Vector Chunk |
| 190 std::deque<TransportFeedback::StatusSymbol>* symbols) { | |
| 191 size_t input_size = symbols->size(); | |
| 192 for (size_t i = 0; i < kCapacity; ++i) { | |
| 193 if (i < input_size) { | |
| 194 symbols_[i] = symbols->front(); | |
| 195 symbols->pop_front(); | |
| 196 } else { | |
| 197 symbols_[i] = TransportFeedback::StatusSymbol::kNotReceived; | |
| 198 } | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 ~TwoBitVectorChunk() override {} | |
| 203 | |
| 204 uint16_t NumSymbols() const override { return kCapacity; } | |
| 205 | |
| 206 void AppendSymbolsTo( | |
| 207 std::vector<TransportFeedback::StatusSymbol>* vec) const override { | |
| 208 vec->insert(vec->end(), &symbols_[0], &symbols_[kCapacity]); | |
| 209 } | |
| 210 | |
| 211 void WriteTo(uint8_t* buffer) const override { | |
| 212 buffer[0] = 0xC0; | |
| 213 buffer[0] |= EncodeSymbol(symbols_[0]) << 4; | |
| 214 buffer[0] |= EncodeSymbol(symbols_[1]) << 2; | |
| 215 buffer[0] |= EncodeSymbol(symbols_[2]); | |
| 216 buffer[1] = EncodeSymbol(symbols_[3]) << 6; | |
| 217 buffer[1] |= EncodeSymbol(symbols_[4]) << 4; | |
| 218 buffer[1] |= EncodeSymbol(symbols_[5]) << 2; | |
| 219 buffer[1] |= EncodeSymbol(symbols_[6]); | |
| 220 } | |
| 221 | |
| 222 static TwoBitVectorChunk* ParseFrom(const uint8_t* buffer) { | |
| 223 TwoBitVectorChunk* chunk = new TwoBitVectorChunk(); | |
| 224 | |
| 225 chunk->symbols_[0] = DecodeSymbol((buffer[0] >> 4) & 0x03); | |
| 226 chunk->symbols_[1] = DecodeSymbol((buffer[0] >> 2) & 0x03); | |
| 227 chunk->symbols_[2] = DecodeSymbol(buffer[0] & 0x03); | |
| 228 chunk->symbols_[3] = DecodeSymbol((buffer[1] >> 6) & 0x03); | |
| 229 chunk->symbols_[4] = DecodeSymbol((buffer[1] >> 4) & 0x03); | |
| 230 chunk->symbols_[5] = DecodeSymbol((buffer[1] >> 2) & 0x03); | |
| 231 chunk->symbols_[6] = DecodeSymbol(buffer[1] & 0x03); | |
| 232 | |
| 233 return chunk; | |
| 234 } | |
| 235 | |
| 236 private: | |
| 237 TwoBitVectorChunk() {} | |
| 238 | |
| 239 TransportFeedback::StatusSymbol symbols_[kCapacity]; | |
| 240 }; | |
| 241 | |
| 242 // Two Bit Status Vector Chunk | |
| 243 // | 280 // |
| 244 // 0 1 | 281 // 0 1 |
| 245 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 | 282 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
| 246 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 283 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 247 // |T| S | Run Length | | 284 // |T| S | Run Length | |
| 248 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 285 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 249 // | 286 // |
| 250 // T = 0 | 287 // T = 0 |
| 251 // S = symbol, see (Encode|Decode)Symbol | 288 // S = symbol |
| 252 // Run Length = Unsigned integer denoting the run length of the symbol | 289 // Run Length = Unsigned integer denoting the run length of the symbol |
| 290 uint16_t TransportFeedback::LastChunk::EncodeRunLength() const { |
| 291 RTC_DCHECK(all_same_); |
| 292 RTC_DCHECK_LE(size_, kMaxRunLengthCapacity); |
| 293 return (delta_sizes_[0] << 13) | size_; |
| 294 } |
| 253 | 295 |
| 254 class RunLengthChunk : public TransportFeedback::PacketStatusChunk { | 296 void TransportFeedback::LastChunk::DecodeRunLength(uint16_t chunk, |
| 255 public: | 297 size_t max_count) { |
| 256 RunLengthChunk(TransportFeedback::StatusSymbol symbol, size_t size) | 298 RTC_DCHECK_EQ(chunk & 0x8000, 0); |
| 257 : symbol_(symbol), size_(size) { | 299 size_ = std::min<size_t>(chunk & 0x1fff, max_count); |
| 258 RTC_DCHECK_LE(size, 0x1FFFu); | 300 size_t delta_size = (chunk >> 13) & 0x03; |
| 259 } | 301 has_large_delta_ = delta_size >= kLarge; |
| 302 all_same_ = true; |
| 303 // To make it consistent with Add function, populate delta_sizes_ beyound 1st. |
| 304 for (size_t i = 0; i < std::min<size_t>(size_, kMaxVectorCapacity); ++i) |
| 305 delta_sizes_[i] = delta_size; |
| 306 } |
| 260 | 307 |
| 261 ~RunLengthChunk() override {} | 308 TransportFeedback::TransportFeedback() |
| 309 : base_seq_no_(0), |
| 310 num_seq_no_(0), |
| 311 base_time_ticks_(0), |
| 312 feedback_seq_(0), |
| 313 last_timestamp_us_(0), |
| 314 last_chunk_(new LastChunk()), |
| 315 size_bytes_(kTransportFeedbackHeaderSizeBytes) {} |
| 262 | 316 |
| 263 uint16_t NumSymbols() const override { return size_; } | 317 TransportFeedback::~TransportFeedback() {} |
| 264 | |
| 265 void AppendSymbolsTo( | |
| 266 std::vector<TransportFeedback::StatusSymbol>* vec) const override { | |
| 267 vec->insert(vec->end(), size_, symbol_); | |
| 268 } | |
| 269 | |
| 270 void WriteTo(uint8_t* buffer) const override { | |
| 271 buffer[0] = EncodeSymbol(symbol_) << 5; // Write S (T = 0 implicitly) | |
| 272 buffer[0] |= (size_ >> 8) & 0x1F; // 5 most significant bits of run length. | |
| 273 buffer[1] = size_ & 0xFF; // 8 least significant bits of run length. | |
| 274 } | |
| 275 | |
| 276 static RunLengthChunk* ParseFrom(const uint8_t* buffer) { | |
| 277 RTC_DCHECK_EQ(0, buffer[0] & 0x80); | |
| 278 TransportFeedback::StatusSymbol symbol = | |
| 279 DecodeSymbol((buffer[0] >> 5) & 0x03); | |
| 280 uint16_t count = (static_cast<uint16_t>(buffer[0] & 0x1F) << 8) | buffer[1]; | |
| 281 | |
| 282 return new RunLengthChunk(symbol, count); | |
| 283 } | |
| 284 | |
| 285 private: | |
| 286 const TransportFeedback::StatusSymbol symbol_; | |
| 287 const size_t size_; | |
| 288 }; | |
| 289 | |
| 290 // Unwrap to a larger type, for easier handling of wraps. | |
| 291 int64_t TransportFeedback::Unwrap(uint16_t sequence_number) { | |
| 292 if (last_seq_ == -1) | |
| 293 return sequence_number; | |
| 294 | |
| 295 int64_t delta = sequence_number - last_seq_; | |
| 296 if (IsNewerSequenceNumber(sequence_number, | |
| 297 static_cast<uint16_t>(last_seq_))) { | |
| 298 if (delta < 0) | |
| 299 delta += (1 << 16); | |
| 300 } else if (delta > 0) { | |
| 301 delta -= (1 << 16); | |
| 302 } | |
| 303 | |
| 304 return last_seq_ + delta; | |
| 305 } | |
| 306 | 318 |
| 307 void TransportFeedback::SetBase(uint16_t base_sequence, | 319 void TransportFeedback::SetBase(uint16_t base_sequence, |
| 308 int64_t ref_timestamp_us) { | 320 int64_t ref_timestamp_us) { |
| 309 RTC_DCHECK_EQ(-1, base_seq_); | 321 RTC_DCHECK_EQ(num_seq_no_, 0); |
| 310 RTC_DCHECK_NE(-1, ref_timestamp_us); | 322 RTC_DCHECK_GE(ref_timestamp_us, 0); |
| 311 base_seq_ = base_sequence; | 323 base_seq_no_ = base_sequence; |
| 312 // last_seq_ is the sequence number of the last packed added _before_ a call | 324 base_time_ticks_ = (ref_timestamp_us % kTimeWrapPeriodUs) / kBaseScaleFactor; |
| 313 // to WithReceivedPacket(). Since the first sequence to be added is | 325 last_timestamp_us_ = GetBaseTimeUs(); |
| 314 // base_sequence, we need this to be one lower in order for potential missing | |
| 315 // packets to be populated properly. | |
| 316 last_seq_ = base_sequence - 1; | |
| 317 base_time_ = ref_timestamp_us / kBaseScaleFactor; | |
| 318 last_timestamp_ = base_time_ * kBaseScaleFactor; | |
| 319 } | 326 } |
| 320 | 327 |
| 321 void TransportFeedback::SetFeedbackSequenceNumber(uint8_t feedback_sequence) { | 328 void TransportFeedback::SetFeedbackSequenceNumber(uint8_t feedback_sequence) { |
| 322 feedback_seq_ = feedback_sequence; | 329 feedback_seq_ = feedback_sequence; |
| 323 } | 330 } |
| 324 | 331 |
| 325 bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number, | 332 bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number, |
| 326 int64_t timestamp) { | 333 int64_t timestamp_us) { |
| 327 RTC_DCHECK_NE(-1, base_seq_); | |
| 328 int64_t seq = Unwrap(sequence_number); | |
| 329 if (seq != base_seq_ && seq <= last_seq_) | |
| 330 return false; | |
| 331 | |
| 332 // Convert to ticks and round. | 334 // Convert to ticks and round. |
| 333 int64_t delta_full = timestamp - last_timestamp_; | 335 int64_t delta_full = (timestamp_us - last_timestamp_us_) % kTimeWrapPeriodUs; |
| 336 if (delta_full > kTimeWrapPeriodUs / 2) |
| 337 delta_full -= kTimeWrapPeriodUs; |
| 334 delta_full += | 338 delta_full += |
| 335 delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2; | 339 delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2; |
| 336 delta_full /= kDeltaScaleFactor; | 340 delta_full /= kDeltaScaleFactor; |
| 337 | 341 |
| 338 int16_t delta = static_cast<int16_t>(delta_full); | 342 int16_t delta = static_cast<int16_t>(delta_full); |
| 339 // If larger than 16bit signed, we can't represent it - need new fb packet. | 343 // If larger than 16bit signed, we can't represent it - need new fb packet. |
| 340 if (delta != delta_full) { | 344 if (delta != delta_full) { |
| 341 LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )"; | 345 LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )"; |
| 342 return false; | 346 return false; |
| 343 } | 347 } |
| 344 | 348 |
| 345 StatusSymbol symbol; | 349 uint16_t next_seq_no = base_seq_no_ + num_seq_no_; |
| 346 if (delta >= 0 && delta <= 0xFF) { | 350 if (sequence_number != next_seq_no) { |
| 347 symbol = StatusSymbol::kReceivedSmallDelta; | 351 uint16_t last_seq_no = next_seq_no - 1; |
| 348 } else { | 352 if (!IsNewerSequenceNumber(sequence_number, last_seq_no)) |
| 349 symbol = StatusSymbol::kReceivedLargeDelta; | |
| 350 } | |
| 351 | |
| 352 if (!AddSymbol(symbol, seq)) | |
| 353 return false; | |
| 354 | |
| 355 receive_deltas_.push_back(delta); | |
| 356 last_timestamp_ += delta * kDeltaScaleFactor; | |
| 357 return true; | |
| 358 } | |
| 359 | |
| 360 // Add a symbol for a received packet, with the given sequence number. This | |
| 361 // method will add any "packet not received" symbols needed before this one. | |
| 362 bool TransportFeedback::AddSymbol(StatusSymbol symbol, int64_t seq) { | |
| 363 while (last_seq_ < seq - 1) { | |
| 364 if (!Encode(StatusSymbol::kNotReceived)) | |
| 365 return false; | 353 return false; |
| 366 ++last_seq_; | 354 for (; next_seq_no != sequence_number; ++next_seq_no) |
| 367 } | 355 if (!AddDeltaSize(0)) |
| 368 | 356 return false; |
| 369 if (!Encode(symbol)) | 357 } |
| 370 return false; | 358 |
| 371 | 359 DeltaSize delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2; |
| 372 last_seq_ = seq; | 360 if (!AddDeltaSize(delta_size)) |
| 373 return true; | 361 return false; |
| 374 } | 362 |
| 375 | 363 packets_.emplace_back(sequence_number, delta); |
| 376 // Append a symbol to the internal symbol vector. If the new state cannot be | 364 last_timestamp_us_ += delta * kDeltaScaleFactor; |
| 377 // represented using a single status chunk, a chunk will first be emitted and | |
| 378 // the associated symbols removed from the internal symbol vector. | |
| 379 bool TransportFeedback::Encode(StatusSymbol symbol) { | |
| 380 if (last_seq_ - base_seq_ + 1 > 0xFFFF) { | |
| 381 LOG(LS_WARNING) << "Packet status count too large ( >= 2^16 )"; | |
| 382 return false; | |
| 383 } | |
| 384 | |
| 385 bool is_two_bit = false; | |
| 386 int delta_size = -1; | |
| 387 switch (symbol) { | |
| 388 case StatusSymbol::kReceivedSmallDelta: | |
| 389 delta_size = 1; | |
| 390 is_two_bit = false; | |
| 391 break; | |
| 392 case StatusSymbol::kReceivedLargeDelta: | |
| 393 delta_size = 2; | |
| 394 is_two_bit = true; | |
| 395 break; | |
| 396 case StatusSymbol::kNotReceived: | |
| 397 is_two_bit = false; | |
| 398 delta_size = 0; | |
| 399 break; | |
| 400 } | |
| 401 RTC_DCHECK_GE(delta_size, 0); | |
| 402 | |
| 403 if (symbol_vec_.empty()) { | |
| 404 if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes) | |
| 405 return false; | |
| 406 | |
| 407 symbol_vec_.push_back(symbol); | |
| 408 vec_needs_two_bit_symbols_ = is_two_bit; | |
| 409 first_symbol_cardinality_ = 1; | |
| 410 size_bytes_ += delta_size + kChunkSizeBytes; | |
| 411 return true; | |
| 412 } | |
| 413 if (size_bytes_ + delta_size > kMaxSizeBytes) | |
| 414 return false; | |
| 415 | |
| 416 // Capacity, in number of symbols, that a vector chunk could hold. | |
| 417 size_t capacity = vec_needs_two_bit_symbols_ ? TwoBitVectorChunk::kCapacity | |
| 418 : OneBitVectorChunk::kCapacity; | |
| 419 | |
| 420 // first_symbol_cardinality_ is the number of times the first symbol in | |
| 421 // symbol_vec is repeated. So if that is equal to the size of symbol_vec, | |
| 422 // there is only one kind of symbol - we can potentially RLE encode it. | |
| 423 // If we have less than (capacity) symbols in symbol_vec, we can't know | |
| 424 // for certain this will be RLE-encoded; if a different symbol is added | |
| 425 // these symbols will be needed to emit a vector chunk instead. However, | |
| 426 // if first_symbol_cardinality_ > capacity, then we cannot encode the | |
| 427 // current state as a vector chunk - we must first emit symbol_vec as an | |
| 428 // RLE-chunk and then add the new symbol. | |
| 429 bool rle_candidate = symbol_vec_.size() == first_symbol_cardinality_ || | |
| 430 first_symbol_cardinality_ > capacity; | |
| 431 if (rle_candidate) { | |
| 432 if (symbol_vec_.back() == symbol) { | |
| 433 ++first_symbol_cardinality_; | |
| 434 if (first_symbol_cardinality_ <= capacity) { | |
| 435 symbol_vec_.push_back(symbol); | |
| 436 } else if (first_symbol_cardinality_ == kRunLengthCapacity) { | |
| 437 // Max length for an RLE-chunk reached. | |
| 438 EmitRunLengthChunk(); | |
| 439 } | |
| 440 size_bytes_ += delta_size; | |
| 441 return true; | |
| 442 } else { | |
| 443 // New symbol does not match what's already in symbol_vec. | |
| 444 if (first_symbol_cardinality_ >= capacity) { | |
| 445 // Symbols in symbol_vec can only be RLE-encoded. Emit the RLE-chunk | |
| 446 // and re-add input. symbol_vec is then guaranteed to have room for the | |
| 447 // symbol, so recursion cannot continue. | |
| 448 EmitRunLengthChunk(); | |
| 449 return Encode(symbol); | |
| 450 } | |
| 451 // Fall through and treat state as non RLE-candidate. | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 // If this code point is reached, symbols in symbol_vec cannot be RLE-encoded. | |
| 456 | |
| 457 if (is_two_bit && !vec_needs_two_bit_symbols_) { | |
| 458 // If the symbols in symbol_vec can be encoded using a one-bit chunk but | |
| 459 // the input symbol cannot, first check if we can simply change target type. | |
| 460 vec_needs_two_bit_symbols_ = true; | |
| 461 if (symbol_vec_.size() >= TwoBitVectorChunk::kCapacity) { | |
| 462 // symbol_vec contains more symbols than we can encode in a single | |
| 463 // two-bit chunk. Emit a new vector append to the remains, if any. | |
| 464 if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes) | |
| 465 return false; | |
| 466 EmitVectorChunk(); | |
| 467 // If symbol_vec isn't empty after emitting a vector chunk, we need to | |
| 468 // account for chunk size (otherwise handled by Encode method). | |
| 469 if (!symbol_vec_.empty()) | |
| 470 size_bytes_ += kChunkSizeBytes; | |
| 471 return Encode(symbol); | |
| 472 } | |
| 473 // symbol_vec symbols fit within a single two-bit vector chunk. | |
| 474 capacity = TwoBitVectorChunk::kCapacity; | |
| 475 } | |
| 476 | |
| 477 symbol_vec_.push_back(symbol); | |
| 478 if (symbol_vec_.size() == capacity) | |
| 479 EmitVectorChunk(); | |
| 480 | |
| 481 size_bytes_ += delta_size; | 365 size_bytes_ += delta_size; |
| 482 return true; | 366 return true; |
| 483 } | 367 } |
| 484 | 368 |
| 485 // Upon packet completion, emit any remaining symbols in symbol_vec that have | |
| 486 // not yet been emitted in a status chunk. | |
| 487 void TransportFeedback::EmitRemaining() { | |
| 488 if (symbol_vec_.empty()) | |
| 489 return; | |
| 490 | |
| 491 size_t capacity = vec_needs_two_bit_symbols_ ? TwoBitVectorChunk::kCapacity | |
| 492 : OneBitVectorChunk::kCapacity; | |
| 493 if (first_symbol_cardinality_ > capacity) { | |
| 494 EmitRunLengthChunk(); | |
| 495 } else { | |
| 496 EmitVectorChunk(); | |
| 497 } | |
| 498 } | |
| 499 | |
| 500 void TransportFeedback::EmitVectorChunk() { | |
| 501 if (vec_needs_two_bit_symbols_) { | |
| 502 status_chunks_.push_back(new TwoBitVectorChunk(&symbol_vec_)); | |
| 503 } else { | |
| 504 status_chunks_.push_back(new OneBitVectorChunk(&symbol_vec_)); | |
| 505 } | |
| 506 // Update first symbol cardinality to match what is potentially left in in | |
| 507 // symbol_vec. | |
| 508 first_symbol_cardinality_ = 1; | |
| 509 for (size_t i = 1; i < symbol_vec_.size(); ++i) { | |
| 510 if (symbol_vec_[i] != symbol_vec_[0]) | |
| 511 break; | |
| 512 ++first_symbol_cardinality_; | |
| 513 } | |
| 514 } | |
| 515 | |
| 516 void TransportFeedback::EmitRunLengthChunk() { | |
| 517 RTC_DCHECK_GE(first_symbol_cardinality_, symbol_vec_.size()); | |
| 518 status_chunks_.push_back( | |
| 519 new RunLengthChunk(symbol_vec_.front(), first_symbol_cardinality_)); | |
| 520 symbol_vec_.clear(); | |
| 521 } | |
| 522 | |
| 523 size_t TransportFeedback::BlockLength() const { | |
| 524 // Round size_bytes_ up to multiple of 32bits. | |
| 525 return (size_bytes_ + 3) & (~static_cast<size_t>(3)); | |
| 526 } | |
| 527 | |
| 528 uint16_t TransportFeedback::GetBaseSequence() const { | 369 uint16_t TransportFeedback::GetBaseSequence() const { |
| 529 return base_seq_; | 370 return base_seq_no_; |
| 530 } | |
| 531 | |
| 532 int64_t TransportFeedback::GetBaseTimeUs() const { | |
| 533 return base_time_ * kBaseScaleFactor; | |
| 534 } | 371 } |
| 535 | 372 |
| 536 std::vector<TransportFeedback::StatusSymbol> | 373 std::vector<TransportFeedback::StatusSymbol> |
| 537 TransportFeedback::GetStatusVector() const { | 374 TransportFeedback::GetStatusVector() const { |
| 538 std::vector<TransportFeedback::StatusSymbol> symbols; | 375 std::vector<TransportFeedback::StatusSymbol> symbols; |
| 539 for (PacketStatusChunk* chunk : status_chunks_) | 376 uint16_t seq_no = GetBaseSequence(); |
| 540 chunk->AppendSymbolsTo(&symbols); | 377 for (const auto& packet : packets_) { |
| 541 int64_t status_count = last_seq_ - base_seq_ + 1; | 378 for (; seq_no != packet.sequence_number; ++seq_no) |
| 542 // If packet ends with a vector chunk, it may contain extraneous "packet not | 379 symbols.push_back(StatusSymbol::kNotReceived); |
| 543 // received"-symbols at the end. Crop any such symbols. | 380 if (packet.delta_ticks >= 0x00 && packet.delta_ticks <= 0xff) { |
| 544 symbols.erase(symbols.begin() + status_count, symbols.end()); | 381 symbols.push_back(StatusSymbol::kReceivedSmallDelta); |
| 382 } else { |
| 383 symbols.push_back(StatusSymbol::kReceivedLargeDelta); |
| 384 } |
| 385 ++seq_no; |
| 386 } |
| 545 return symbols; | 387 return symbols; |
| 546 } | 388 } |
| 547 | 389 |
| 548 std::vector<int16_t> TransportFeedback::GetReceiveDeltas() const { | 390 std::vector<int16_t> TransportFeedback::GetReceiveDeltas() const { |
| 549 return receive_deltas_; | 391 std::vector<int16_t> deltas; |
| 392 for (const auto& packet : packets_) |
| 393 deltas.push_back(packet.delta_ticks); |
| 394 return deltas; |
| 395 } |
| 396 |
| 397 int64_t TransportFeedback::GetBaseTimeUs() const { |
| 398 return static_cast<int64_t>(base_time_ticks_) * kBaseScaleFactor; |
| 550 } | 399 } |
| 551 | 400 |
| 552 std::vector<int64_t> TransportFeedback::GetReceiveDeltasUs() const { | 401 std::vector<int64_t> TransportFeedback::GetReceiveDeltasUs() const { |
| 553 if (receive_deltas_.empty()) | |
| 554 return std::vector<int64_t>(); | |
| 555 | |
| 556 std::vector<int64_t> us_deltas; | 402 std::vector<int64_t> us_deltas; |
| 557 for (int16_t delta : receive_deltas_) | 403 for (const auto& packet : packets_) |
| 558 us_deltas.push_back(static_cast<int64_t>(delta) * kDeltaScaleFactor); | 404 us_deltas.push_back(packet.delta_ticks * kDeltaScaleFactor); |
| 559 | |
| 560 return us_deltas; | 405 return us_deltas; |
| 561 } | 406 } |
| 562 | 407 |
| 408 // De-serialize packet. |
| 409 bool TransportFeedback::Parse(const CommonHeader& packet) { |
| 410 RTC_DCHECK_EQ(packet.type(), kPacketType); |
| 411 RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); |
| 412 |
| 413 if (packet.payload_size_bytes() < kMinPayloadSizeBytes) { |
| 414 LOG(LS_WARNING) << "Buffer too small (" << packet.payload_size_bytes() |
| 415 << " bytes) to fit a " |
| 416 "FeedbackPacket. Minimum size = " |
| 417 << kMinPayloadSizeBytes; |
| 418 return false; |
| 419 } |
| 420 |
| 421 const uint8_t* const payload = packet.payload(); |
| 422 ParseCommonFeedback(payload); |
| 423 |
| 424 base_seq_no_ = ByteReader<uint16_t>::ReadBigEndian(&payload[8]); |
| 425 size_t status_count = ByteReader<uint16_t>::ReadBigEndian(&payload[10]); |
| 426 base_time_ticks_ = ByteReader<int32_t, 3>::ReadBigEndian(&payload[12]); |
| 427 feedback_seq_ = payload[15]; |
| 428 Clear(); |
| 429 size_t index = 16; |
| 430 const size_t end_index = packet.payload_size_bytes(); |
| 431 |
| 432 if (status_count == 0) { |
| 433 LOG(LS_WARNING) << "Empty feedback messages not allowed."; |
| 434 return false; |
| 435 } |
| 436 |
| 437 std::vector<uint8_t> delta_sizes; |
| 438 delta_sizes.reserve(status_count); |
| 439 while (delta_sizes.size() < status_count) { |
| 440 if (index + kChunkSizeBytes > end_index) { |
| 441 LOG(LS_WARNING) << "Buffer overflow while parsing packet."; |
| 442 Clear(); |
| 443 return false; |
| 444 } |
| 445 |
| 446 uint16_t chunk = ByteReader<uint16_t>::ReadBigEndian(&payload[index]); |
| 447 index += kChunkSizeBytes; |
| 448 encoded_chunks_.push_back(chunk); |
| 449 last_chunk_->Decode(chunk, status_count - delta_sizes.size()); |
| 450 last_chunk_->AppendTo(&delta_sizes); |
| 451 } |
| 452 // Last chunk is stored in the |last_chunk_|. |
| 453 encoded_chunks_.pop_back(); |
| 454 RTC_DCHECK_EQ(delta_sizes.size(), status_count); |
| 455 num_seq_no_ = status_count; |
| 456 |
| 457 uint16_t seq_no = base_seq_no_; |
| 458 for (size_t delta_size : delta_sizes) { |
| 459 if (index + delta_size > end_index) { |
| 460 LOG(LS_WARNING) << "Buffer overflow while parsing packet."; |
| 461 Clear(); |
| 462 return false; |
| 463 } |
| 464 switch (delta_size) { |
| 465 case 0: |
| 466 break; |
| 467 case 1: { |
| 468 int16_t delta = payload[index]; |
| 469 packets_.emplace_back(seq_no, delta); |
| 470 last_timestamp_us_ += delta * kDeltaScaleFactor; |
| 471 index += delta_size; |
| 472 break; |
| 473 } |
| 474 case 2: { |
| 475 int16_t delta = ByteReader<int16_t>::ReadBigEndian(&payload[index]); |
| 476 packets_.emplace_back(seq_no, delta); |
| 477 last_timestamp_us_ += delta * kDeltaScaleFactor; |
| 478 index += delta_size; |
| 479 break; |
| 480 } |
| 481 case 3: |
| 482 Clear(); |
| 483 LOG(LS_WARNING) << "Invalid delta_size for seq_no " << seq_no; |
| 484 return false; |
| 485 default: |
| 486 RTC_NOTREACHED(); |
| 487 break; |
| 488 } |
| 489 ++seq_no; |
| 490 } |
| 491 size_bytes_ = RtcpPacket::kHeaderLength + index; |
| 492 RTC_DCHECK_LE(index, end_index); |
| 493 return true; |
| 494 } |
| 495 |
| 496 std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom( |
| 497 const uint8_t* buffer, |
| 498 size_t length) { |
| 499 CommonHeader header; |
| 500 if (!header.Parse(buffer, length)) |
| 501 return nullptr; |
| 502 if (header.type() != kPacketType || header.fmt() != kFeedbackMessageType) |
| 503 return nullptr; |
| 504 std::unique_ptr<TransportFeedback> parsed(new TransportFeedback); |
| 505 if (!parsed->Parse(header)) |
| 506 return nullptr; |
| 507 return parsed; |
| 508 } |
| 509 |
| 510 bool TransportFeedback::IsConsistent() const { |
| 511 size_t packet_size = kTransportFeedbackHeaderSizeBytes; |
| 512 std::vector<DeltaSize> delta_sizes; |
| 513 LastChunk chunk_decoder; |
| 514 for (uint16_t chunk : encoded_chunks_) { |
| 515 chunk_decoder.Decode(chunk, kMaxReportedPackets); |
| 516 chunk_decoder.AppendTo(&delta_sizes); |
| 517 packet_size += kChunkSizeBytes; |
| 518 } |
| 519 if (!last_chunk_->Empty()) { |
| 520 last_chunk_->AppendTo(&delta_sizes); |
| 521 packet_size += kChunkSizeBytes; |
| 522 } |
| 523 if (num_seq_no_ != delta_sizes.size()) { |
| 524 LOG(LS_ERROR) << delta_sizes.size() << " packets encoded. Expected " |
| 525 << num_seq_no_; |
| 526 return false; |
| 527 } |
| 528 int64_t timestamp_us = base_time_ticks_ * kBaseScaleFactor; |
| 529 auto packet_it = packets_.begin(); |
| 530 uint16_t seq_no = base_seq_no_; |
| 531 for (DeltaSize delta_size : delta_sizes) { |
| 532 if (delta_size > 0) { |
| 533 if (packet_it == packets_.end()) { |
| 534 LOG(LS_ERROR) << "Failed to find delta for seq_no " << seq_no; |
| 535 return false; |
| 536 } |
| 537 if (packet_it->sequence_number != seq_no) { |
| 538 LOG(LS_ERROR) << "Expected to find delta for seq_no " << seq_no |
| 539 << ". Next delta is for " << packet_it->sequence_number; |
| 540 return false; |
| 541 } |
| 542 if (delta_size == 1 && |
| 543 (packet_it->delta_ticks < 0 || packet_it->delta_ticks > 0xff)) { |
| 544 LOG(LS_ERROR) << "Delta " << packet_it->delta_ticks << " for seq_no " |
| 545 << seq_no << " doesn't fit into one byte"; |
| 546 return false; |
| 547 } |
| 548 timestamp_us += packet_it->delta_ticks * kDeltaScaleFactor; |
| 549 ++packet_it; |
| 550 } |
| 551 packet_size += delta_size; |
| 552 ++seq_no; |
| 553 } |
| 554 if (packet_it != packets_.end()) { |
| 555 LOG(LS_ERROR) << "Unencoded delta for seq_no " |
| 556 << packet_it->sequence_number; |
| 557 return false; |
| 558 } |
| 559 if (timestamp_us != last_timestamp_us_) { |
| 560 LOG(LS_ERROR) << "Last timestamp mismatch. Calculated: " << timestamp_us |
| 561 << ". Saved: " << last_timestamp_us_; |
| 562 return false; |
| 563 } |
| 564 if (size_bytes_ != packet_size) { |
| 565 LOG(LS_ERROR) << "Rtcp packet size mismatch. Calculated: " << packet_size |
| 566 << ". Saved: " << size_bytes_; |
| 567 return false; |
| 568 } |
| 569 return true; |
| 570 } |
| 571 |
| 563 // Serialize packet. | 572 // Serialize packet. |
| 564 bool TransportFeedback::Create(uint8_t* packet, | 573 bool TransportFeedback::Create(uint8_t* packet, |
| 565 size_t* position, | 574 size_t* position, |
| 566 size_t max_length, | 575 size_t max_length, |
| 567 PacketReadyCallback* callback) const { | 576 PacketReadyCallback* callback) const { |
| 568 if (base_seq_ == -1) | 577 if (num_seq_no_ == 0) |
| 569 return false; | 578 return false; |
| 570 | 579 |
| 571 while (*position + BlockLength() > max_length) { | 580 while (*position + BlockLength() > max_length) { |
| 572 if (!OnBufferFull(packet, position, callback)) | 581 if (!OnBufferFull(packet, position, callback)) |
| 573 return false; | 582 return false; |
| 574 } | 583 } |
| 575 const size_t position_end = *position + BlockLength(); | 584 const size_t position_end = *position + BlockLength(); |
| 576 | 585 |
| 577 CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, | 586 CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, |
| 578 position); | 587 position); |
| 579 CreateCommonFeedback(packet + *position); | 588 CreateCommonFeedback(packet + *position); |
| 580 *position += kCommonFeedbackLength; | 589 *position += kCommonFeedbackLength; |
| 581 | 590 |
| 582 RTC_DCHECK_LE(base_seq_, 0xFFFF); | 591 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_no_); |
| 583 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_); | |
| 584 *position += 2; | 592 *position += 2; |
| 585 | 593 |
| 586 int64_t status_count = last_seq_ - base_seq_ + 1; | 594 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], num_seq_no_); |
| 587 RTC_DCHECK_LE(status_count, 0xFFFF); | |
| 588 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], status_count); | |
| 589 *position += 2; | 595 *position += 2; |
| 590 | 596 |
| 591 ByteWriter<int32_t, 3>::WriteBigEndian(&packet[*position], | 597 ByteWriter<int32_t, 3>::WriteBigEndian(&packet[*position], base_time_ticks_); |
| 592 static_cast<int32_t>(base_time_)); | |
| 593 *position += 3; | 598 *position += 3; |
| 594 | 599 |
| 595 packet[(*position)++] = feedback_seq_; | 600 packet[(*position)++] = feedback_seq_; |
| 596 | 601 |
| 597 // TODO(sprang): Get rid of this cast. | 602 for (uint16_t chunk : encoded_chunks_) { |
| 598 const_cast<TransportFeedback*>(this)->EmitRemaining(); | 603 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk); |
| 599 for (PacketStatusChunk* chunk : status_chunks_) { | 604 *position += 2; |
| 600 chunk->WriteTo(&packet[*position]); | 605 } |
| 606 if (!last_chunk_->Empty()) { |
| 607 uint16_t chunk = last_chunk_->EncodeLast(); |
| 608 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk); |
| 601 *position += 2; | 609 *position += 2; |
| 602 } | 610 } |
| 603 | 611 |
| 604 for (int16_t delta : receive_deltas_) { | 612 for (const auto& received_packet : packets_) { |
| 613 int16_t delta = received_packet.delta_ticks; |
| 605 if (delta >= 0 && delta <= 0xFF) { | 614 if (delta >= 0 && delta <= 0xFF) { |
| 606 packet[(*position)++] = delta; | 615 packet[(*position)++] = delta; |
| 607 } else { | 616 } else { |
| 608 ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta); | 617 ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta); |
| 609 *position += 2; | 618 *position += 2; |
| 610 } | 619 } |
| 611 } | 620 } |
| 612 | 621 |
| 613 while ((*position % 4) != 0) | 622 while ((*position % 4) != 0) |
| 614 packet[(*position)++] = 0; | 623 packet[(*position)++] = 0; |
| 615 | 624 |
| 616 RTC_DCHECK_EQ(*position, position_end); | 625 RTC_DCHECK_EQ(*position, position_end); |
| 617 return true; | 626 return true; |
| 618 } | 627 } |
| 619 | 628 |
| 620 // Message format | 629 size_t TransportFeedback::BlockLength() const { |
| 621 // | 630 // Round size_bytes_ up to multiple of 32bits. |
| 622 // 0 1 2 3 | 631 return (size_bytes_ + 3) & (~static_cast<size_t>(3)); |
| 623 // 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 | |
| 624 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 625 // |V=2|P| FMT=15 | PT=205 | length | | |
| 626 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 627 // 0 | SSRC of packet sender | | |
| 628 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 629 // 4 | SSRC of media source | | |
| 630 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 631 // 8 | base sequence number | packet status count | | |
| 632 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 633 // 12 | reference time | fb pkt. count | | |
| 634 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 635 // 16 | packet chunk | packet chunk | | |
| 636 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 637 // . . | |
| 638 // . . | |
| 639 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 640 // | packet chunk | recv delta | recv delta | | |
| 641 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 642 // . . | |
| 643 // . . | |
| 644 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 645 // | recv delta | recv delta | zero padding | | |
| 646 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 647 | |
| 648 // De-serialize packet. | |
| 649 bool TransportFeedback::Parse(const CommonHeader& packet) { | |
| 650 RTC_DCHECK_EQ(packet.type(), kPacketType); | |
| 651 RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); | |
| 652 | |
| 653 if (packet.payload_size_bytes() < kMinPayloadSizeBytes) { | |
| 654 LOG(LS_WARNING) << "Buffer too small (" << packet.payload_size_bytes() | |
| 655 << " bytes) to fit a " | |
| 656 "FeedbackPacket. Minimum size = " | |
| 657 << kMinPayloadSizeBytes; | |
| 658 return false; | |
| 659 } | |
| 660 // TODO(danilchap): Make parse work correctly with not new objects. | |
| 661 RTC_DCHECK(status_chunks_.empty()) << "Parse expects object to be new."; | |
| 662 | |
| 663 const uint8_t* const payload = packet.payload(); | |
| 664 | |
| 665 ParseCommonFeedback(payload); | |
| 666 | |
| 667 base_seq_ = ByteReader<uint16_t>::ReadBigEndian(&payload[8]); | |
| 668 uint16_t num_packets = ByteReader<uint16_t>::ReadBigEndian(&payload[10]); | |
| 669 base_time_ = ByteReader<int32_t, 3>::ReadBigEndian(&payload[12]); | |
| 670 feedback_seq_ = payload[15]; | |
| 671 size_t index = 16; | |
| 672 const size_t end_index = packet.payload_size_bytes(); | |
| 673 | |
| 674 if (num_packets == 0) { | |
| 675 LOG(LS_WARNING) << "Empty feedback messages not allowed."; | |
| 676 return false; | |
| 677 } | |
| 678 last_seq_ = base_seq_ + num_packets - 1; | |
| 679 | |
| 680 size_t packets_read = 0; | |
| 681 while (packets_read < num_packets) { | |
| 682 if (index + 2 > end_index) { | |
| 683 LOG(LS_WARNING) << "Buffer overflow while parsing packet."; | |
| 684 return false; | |
| 685 } | |
| 686 | |
| 687 PacketStatusChunk* chunk = | |
| 688 ParseChunk(&payload[index], num_packets - packets_read); | |
| 689 if (chunk == nullptr) | |
| 690 return false; | |
| 691 | |
| 692 index += 2; | |
| 693 status_chunks_.push_back(chunk); | |
| 694 packets_read += chunk->NumSymbols(); | |
| 695 } | |
| 696 | |
| 697 std::vector<StatusSymbol> symbols = GetStatusVector(); | |
| 698 | |
| 699 RTC_DCHECK_EQ(num_packets, symbols.size()); | |
| 700 | |
| 701 for (StatusSymbol symbol : symbols) { | |
| 702 switch (symbol) { | |
| 703 case StatusSymbol::kReceivedSmallDelta: | |
| 704 if (index + 1 > end_index) { | |
| 705 LOG(LS_WARNING) << "Buffer overflow while parsing packet."; | |
| 706 return false; | |
| 707 } | |
| 708 receive_deltas_.push_back(payload[index]); | |
| 709 ++index; | |
| 710 break; | |
| 711 case StatusSymbol::kReceivedLargeDelta: | |
| 712 if (index + 2 > end_index) { | |
| 713 LOG(LS_WARNING) << "Buffer overflow while parsing packet."; | |
| 714 return false; | |
| 715 } | |
| 716 receive_deltas_.push_back( | |
| 717 ByteReader<int16_t>::ReadBigEndian(&payload[index])); | |
| 718 index += 2; | |
| 719 break; | |
| 720 case StatusSymbol::kNotReceived: | |
| 721 continue; | |
| 722 } | |
| 723 } | |
| 724 | |
| 725 RTC_DCHECK_LE(index, end_index); | |
| 726 | |
| 727 return true; | |
| 728 } | 632 } |
| 729 | 633 |
| 730 std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom( | 634 void TransportFeedback::Clear() { |
| 731 const uint8_t* buffer, | 635 num_seq_no_ = 0; |
| 732 size_t length) { | 636 last_timestamp_us_ = GetBaseTimeUs(); |
| 733 CommonHeader header; | 637 packets_.clear(); |
| 734 if (!header.Parse(buffer, length)) | 638 encoded_chunks_.clear(); |
| 735 return nullptr; | 639 last_chunk_->Clear(); |
| 736 if (header.type() != kPacketType || header.fmt() != kFeedbackMessageType) | 640 size_bytes_ = kTransportFeedbackHeaderSizeBytes; |
| 737 return nullptr; | |
| 738 std::unique_ptr<TransportFeedback> parsed(new TransportFeedback); | |
| 739 if (!parsed->Parse(header)) | |
| 740 return nullptr; | |
| 741 return parsed; | |
| 742 } | 641 } |
| 743 | 642 |
| 744 TransportFeedback::PacketStatusChunk* TransportFeedback::ParseChunk( | 643 bool TransportFeedback::AddDeltaSize(DeltaSize delta_size) { |
| 745 const uint8_t* buffer, | 644 if (num_seq_no_ == kMaxReportedPackets) |
| 746 size_t max_size) { | 645 return false; |
| 747 if (buffer[0] & 0x80) { | 646 size_t add_chunk_size = last_chunk_->Empty() ? kChunkSizeBytes : 0; |
| 748 // First bit set => vector chunk. | 647 if (size_bytes_ + delta_size + add_chunk_size > kMaxSizeBytes) |
| 749 if (buffer[0] & 0x40) { | 648 return false; |
| 750 // Second bit set => two bits per symbol vector. | |
| 751 return TwoBitVectorChunk::ParseFrom(buffer); | |
| 752 } | |
| 753 | 649 |
| 754 // Second bit not set => one bit per symbol vector. | 650 if (last_chunk_->CanAdd(delta_size)) { |
| 755 return OneBitVectorChunk::ParseFrom(buffer); | 651 size_bytes_ += add_chunk_size; |
| 652 last_chunk_->Add(delta_size); |
| 653 ++num_seq_no_; |
| 654 return true; |
| 756 } | 655 } |
| 656 if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes) |
| 657 return false; |
| 757 | 658 |
| 758 // First bit not set => RLE chunk. | 659 encoded_chunks_.push_back(last_chunk_->Emit()); |
| 759 RunLengthChunk* rle_chunk = RunLengthChunk::ParseFrom(buffer); | 660 size_bytes_ += kChunkSizeBytes; |
| 760 if (rle_chunk->NumSymbols() > max_size) { | 661 last_chunk_->Add(delta_size); |
| 761 LOG(LS_WARNING) << "Header/body mismatch. " | 662 ++num_seq_no_; |
| 762 "RLE block of size " << rle_chunk->NumSymbols() | 663 return true; |
| 763 << " but only " << max_size << " left to read."; | |
| 764 delete rle_chunk; | |
| 765 return nullptr; | |
| 766 } | |
| 767 return rle_chunk; | |
| 768 } | 664 } |
| 769 | 665 |
| 770 } // namespace rtcp | 666 } // namespace rtcp |
| 771 } // namespace webrtc | 667 } // namespace webrtc |
| OLD | NEW |