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