Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc

Issue 2616343003: Refactor TransportFeedback ensuring it's consistency: (Closed)
Patch Set: -unused headers Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698