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