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

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

Issue 1175263002: Add packetization and coding/decoding of feedback message format. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Updated parsing to match new spec Created 5 years, 5 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
(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;
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;
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;
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_)
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;
stefan-webrtc 2015/07/14 12:14:54 Have we not enumerated all cases here?
sprang_webrtc 2015/07/16 11:12:11 Yes, I just want to make sure we somehow capture a
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 // If symbol_vec only contains one kind of symbol, it may be RLE-coded.
418 bool rle_candidate = symbol_vec_.size() == first_symbol_cardinality_ ||
stefan-webrtc 2015/07/14 12:14:54 This is still hard for me to understand. Can we ex
sprang_webrtc 2015/07/16 11:12:10 I've added more comments, have a look.
stefan-webrtc 2015/07/27 11:49:28 A lot better
419 first_symbol_cardinality_ > capacity;
420 if (rle_candidate) {
421 if (symbol_vec_.back() == symbol) {
422 ++first_symbol_cardinality_;
423 if (first_symbol_cardinality_ <= capacity) {
424 // Only add to symbol_vec if we are not certain this will be RLE-coded.
425 symbol_vec_.push_back(symbol);
426 } else if (first_symbol_cardinality_ == kRunLengthCapacity) {
427 // Max length for an RLE-chunk reached.
428 EmitRunLengthChunk();
429 }
430 size_bytes_ += delta_size;
431 return true;
432 } else if (first_symbol_cardinality_ > capacity) {
stefan-webrtc 2015/07/14 12:14:54 Do we always end up in this else if if the express
sprang_webrtc 2015/07/16 11:12:11 Just breaking this out into a separate method does
433 // Symbols in symbol_vec can only be RLE-encoded but input symbol is of
434 // a different kind. Emit the RLE-chunk and re-add input.
435 EmitRunLengthChunk();
436 return Encode(symbol);
stefan-webrtc 2015/07/14 12:14:54 I assume there is no risk that this recursive call
sprang_webrtc 2015/07/16 11:12:11 No. Added comment.
437 }
438 }
439
440 // If this code point is reached, symbols in symbol_vec cannot be RLE-encoded.
441
442 if (is_two_bit && !vec_needs_two_bit_symbols_) {
443 // If the symbols in symbol_vec can be encoded using a one-bit chunk but
444 // the input symbol cannot, first check if we can simply change target type.
445 vec_needs_two_bit_symbols_ = true;
446 if (symbol_vec_.size() >= kTwoBitVectorCapacity) {
447 // symbol_vec contains more symbols than we can encode in a single
448 // two-bit chunk. Emit a new vector append to the remains, if any.
449 if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes)
450 return false;
451 EmitVectorChunk();
452 return Encode(symbol);
453 }
454 // symbol_vec symbols fit within a single two-bit vector chunk.
455 capacity = kTwoBitVectorCapacity;
456 }
457
458 symbol_vec_.push_back(symbol);
459 if (symbol_vec_.size() == capacity)
460 EmitVectorChunk();
461
462 size_bytes_ += delta_size;
463 return true;
464 }
465
466 // Upon packet completion, emit any remaining symbols in symbol_vec that have
467 // not yet been emitted in a status chunk.
468 void FeedbackPacket::EmitRemaining() {
469 if (symbol_vec_.empty())
470 return;
471
472 size_t capacity = vec_needs_two_bit_symbols_ ? kTwoBitVectorCapacity
473 : kOneBitVectorCapacity;
474 if (first_symbol_cardinality_ > capacity) {
475 EmitRunLengthChunk();
476 } else {
477 EmitVectorChunk();
478 }
479 }
480
481 void FeedbackPacket::EmitVectorChunk() {
482 if (vec_needs_two_bit_symbols_) {
483 status_chunks_.push_back(new TwoBitVectorChunk(&symbol_vec_));
484 } else {
485 status_chunks_.push_back(new OneBitVectorChunk(&symbol_vec_));
486 }
487 }
488
489 void FeedbackPacket::EmitRunLengthChunk() {
490 status_chunks_.push_back(
491 new RunLengthChunk(symbol_vec_.front(), first_symbol_cardinality_));
492 symbol_vec_.clear();
stefan-webrtc 2015/07/14 12:14:54 DCHECK that symbol_vec_.size() == 1 above?
sprang_webrtc 2015/07/16 11:12:11 No, it shouldn't be. Best I can do is DCHECK_GE(fi
stefan-webrtc 2015/07/27 11:49:28 Yes, I understand this better now, agree. :)
493 }
494
495 size_t FeedbackPacket::BlockLength() const {
496 return size_bytes_;
497 }
498
499 uint16_t FeedbackPacket::GetBaseSequence() const {
500 return base_seq_;
501 }
502
503 int32_t FeedbackPacket::GetBaseTime() const {
504 return static_cast<int32_t>(base_time_ & 0x00FFFFFF);
505 }
506
507 int64_t FeedbackPacket::GetBaseTimeUs() const {
508 return GetBaseTime() * kBaseScaleFactor;
509 }
510
511 std::vector<FeedbackPacket::StatusSymbol> FeedbackPacket::GetStatusVector()
512 const {
513 std::vector<FeedbackPacket::StatusSymbol> symbols;
514 for (PacketStatusChunk* chunk : status_chunks_)
515 chunk->AppendSymbolsTo(&symbols);
516 int64_t status_count = last_seq_ - base_seq_ + 1;
517 // If packet ends with a vector chunk, it may contain extraneous "packet not
518 // received"-symbols at the end. Crop any such symbols.
519 symbols.erase(symbols.begin() + status_count, symbols.end());
520 return symbols;
521 }
522
523 std::vector<int16_t> FeedbackPacket::GetReceiveDeltas() const {
524 return receive_deltas_;
525 }
526
527 std::vector<int64_t> FeedbackPacket::GetReceiveDeltasUs() const {
528 if (receive_deltas_.empty())
529 return std::vector<int64_t>();
530
531 std::vector<int64_t> us_deltas;
532 for (int16_t delta : receive_deltas_)
533 us_deltas.push_back(static_cast<int64_t>(delta) * kDeltaScaleFactor);
534
535 return us_deltas;
536 }
537
538 // Serialize packet.
539 bool FeedbackPacket::Create(uint8_t* packet,
540 size_t* position,
541 size_t max_length,
542 PacketReadyCallback* callback) const {
543 if (base_seq_ == -1)
544 return false;
545
546 while (*position + size_bytes_ > max_length) {
547 if (!OnBufferFull(packet, position, callback))
548 return false;
549 }
550
551 CreateHeader(kFeedbackMessageType, kPayloadType, HeaderLength(), packet,
552 position);
553 ByteWriter<uint32_t>::WriteBigEndian(&packet[*position], packet_sender_ssrc_);
554 *position += 4;
555 ByteWriter<uint32_t>::WriteBigEndian(&packet[*position], media_source_ssrc_);
556 *position += 4;
557
558 DCHECK_LE(base_seq_, 0xFFFF);
559 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_);
560 *position += 2;
561
562 int64_t status_count = last_seq_ - base_seq_ + 1;
563 DCHECK_LE(status_count, 0xFFFF);
564 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], status_count);
565 *position += 2;
566
567 ByteWriter<int32_t, 3>::WriteBigEndian(&packet[*position],
568 static_cast<int16_t>(base_time_));
569 *position += 3;
570
571 packet[(*position)++] = feedback_seq_;
572
573 // TODO(sprang): Get rid of this cast.
574 const_cast<FeedbackPacket*>(this)->EmitRemaining();
stefan-webrtc 2015/07/14 12:14:54 Is this going to be done somewhere else instead?
sprang_webrtc 2015/07/16 11:12:11 Can you elaborate on that statement? The alternat
stefan-webrtc 2015/07/27 11:49:28 I think I was mostly wondering about the TODO. Was
575 for (PacketStatusChunk* chunk : status_chunks_) {
576 chunk->WriteTo(&packet[*position]);
577 *position += 2;
578 }
579
580 for (int16_t delta : receive_deltas_) {
581 if (delta >= 0 && delta <= 0xFF) {
582 packet[(*position)++] = delta;
583 } else {
584 ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta);
585 *position += 2;
586 }
587 }
588
589 while ((*position % 4) != 0)
590 packet[(*position)++] = 0;
591
592 return true;
593 }
594
595 // De-serialize packet.
596 rtc::scoped_ptr<FeedbackPacket> FeedbackPacket::ParseFrom(const uint8_t* buffer,
597 size_t length) {
598 rtc::scoped_ptr<FeedbackPacket> packet(new FeedbackPacket());
599
600 if (length < kMinSizeBytes) {
601 LOG(LS_WARNING) << "Buffer too small (" << length
602 << " bytes) to fit a "
603 "FeedbackPacket. Minimum size = " << kMinSizeBytes;
604 return nullptr;
605 }
606
607 size_t packet_size_words =
608 ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) + 1;
609 if (length < (packet_size_words * 4)) {
stefan-webrtc 2015/07/14 12:14:54 Remove ()
sprang_webrtc 2015/07/16 11:12:11 Done.
610 LOG(LS_WARNING) << "Buffer too small (" << length
611 << " bytes) to fit a FeedbackPacket of "
612 << packet_size_words << " 32bit words.";
613 return nullptr;
614 }
615
616 // TODO(sprang): Break this out and generalize when implementing parsing of
617 // other RtcpPacket subclasses.
618
619 const uint8_t kRtcpVersion = 2;
620 uint8_t version = buffer[0] >> 6;
621 if (version != kRtcpVersion) {
622 LOG(LS_WARNING) << "Invalid RTCP header: Version must be " << kRtcpVersion
623 << " but was " << version;
624 return nullptr;
625 }
626
627 bool has_padding = (buffer[0] & 0x20) != 0;
628
629 uint8_t format = buffer[0] & 0x1F;
630 if (format != kFeedbackMessageType) {
631 LOG(LS_WARNING) << "Invalid RTCP header: FMT must be "
632 << kFeedbackMessageType << " but was " << format;
633 return nullptr;
634 }
635
636 uint8_t payload_type = buffer[1];
637 if (payload_type != kPayloadType) {
638 LOG(LS_WARNING) << "Invalid RTCP header: PT must be " << kPayloadType
639 << " but was " << payload_type;
640 return nullptr;
641 }
642
643 size_t payload_size = packet_size_words * 4;
644 if (has_padding) {
645 uint8_t padding_bytes = buffer[payload_size - 1];
646 if (payload_size - padding_bytes < kMinSizeBytes) {
stefan-webrtc 2015/07/14 12:14:54 I think you may have to verify that this subtracti
sprang_webrtc 2015/07/16 11:12:11 I'll rewrite it as payload_size < kMinSizeBytes
stefan-webrtc 2015/07/27 11:49:28 Acknowledged.
647 LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
648 << padding_bytes << ") for a packet size of "
649 << payload_size << "bytes.";
650 return nullptr;
651 }
652 payload_size -= padding_bytes;
653 }
654
655 packet->packet_sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
stefan-webrtc 2015/07/14 12:14:54 Maybe put a comment here with the header you are p
sprang_webrtc 2015/07/16 11:12:11 Added the message format overview on top. OK?
stefan-webrtc 2015/07/27 11:49:28 Acknowledged.
656 packet->media_source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
657 packet->base_seq_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]);
658 uint16_t num_packets = ByteReader<uint16_t>::ReadBigEndian(&buffer[14]);
659 packet->base_time_ = ByteReader<int32_t, 3>::ReadBigEndian(&buffer[16]);
660 packet->feedback_seq_ = buffer[19];
661 size_t index = 20;
662
663 if (num_packets == 0) {
664 LOG(LS_WARNING) << "Empty feedback messages not allowed.";
665 return nullptr;
666 }
667 packet->last_seq_ = packet->base_seq_ + num_packets - 1;
668
669 size_t packets_read = 0;
670 while (packets_read < num_packets) {
671 if (index + 2 > payload_size) {
672 LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
673 return nullptr;
674 }
675
676 PacketStatusChunk* chunk =
677 ParseChunk(&buffer[index], num_packets - packets_read);
678 if (chunk == nullptr)
679 return nullptr;
680
681 index += 2;
682 packet->status_chunks_.push_back(chunk);
683 packets_read += chunk->NumSymbols();
684 }
685
686 std::vector<StatusSymbol> symbols = packet->GetStatusVector();
687
688 DCHECK_EQ(num_packets, symbols.size());
689
690 for (StatusSymbol symbol : symbols) {
691 switch (symbol) {
692 case StatusSymbol::kReceivedSmallDelta:
693 if (index + 1 > payload_size) {
694 LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
695 return nullptr;
696 }
697 packet->receive_deltas_.push_back(buffer[index]);
698 ++index;
699 break;
700 case StatusSymbol::kReceivedLargeDelta:
701 if (index + 2 > payload_size) {
702 LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
703 return nullptr;
704 }
705 packet->receive_deltas_.push_back(
706 ByteReader<int16_t>::ReadBigEndian(&buffer[index]));
707 index += 2;
708 break;
709 default:
710 continue;
711 }
712 }
713
714 DCHECK_GE(index, payload_size - 3);
715 DCHECK_LE(index, payload_size);
716
717 return packet;
718 }
719
720 PacketStatusChunk* FeedbackPacket::ParseChunk(const uint8_t* buffer,
721 size_t max_size) {
722 if (buffer[0] & 0x80) {
723 // First bit set => vector chunk.
724 std::deque<StatusSymbol> symbols;
725 if (buffer[0] & 0x40) {
726 // Second bit set => two bits per symbol vector.
727 return TwoBitVectorChunk::ParseFrom(buffer);
728 }
729
730 // Second bit not set => one bit per symbol vector.
731 return OneBitVectorChunk::ParseFrom(buffer);
732 }
733
734 // First bit not set => RLE chunk.
735 RunLengthChunk* rle_chunk = RunLengthChunk::ParseFrom(buffer);
736 if (rle_chunk->NumSymbols() > max_size) {
737 LOG(LS_WARNING) << "Header/body mismatch. "
738 "RLE block of size " << rle_chunk->NumSymbols()
739 << " but only " << max_size << " left to read.";
740 delete rle_chunk;
741 return nullptr;
742 }
743 return rle_chunk;
744 }
745
746 } // namespace rtcp
747 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698