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

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: Addressed comments, one bug fix with test case 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;
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698