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