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 |