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 "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
12
13 #include <algorithm>
14
15 #include "modules/include/module_common_types.h"
16 #include "modules/rtp_rtcp/source/byte_io.h"
17 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
18 #include "rtc_base/checks.h"
19 #include "rtc_base/logging.h"
20 #include "rtc_base/trace_event.h"
21
22 namespace webrtc {
23 namespace rtcp {
24 namespace {
25 // Header size:
26 // * 4 bytes Common RTCP Packet Header
27 // * 8 bytes Common Packet Format for RTCP Feedback Messages
28 // * 8 bytes FeedbackPacket header
29 constexpr size_t kTransportFeedbackHeaderSizeBytes = 4 + 8 + 8;
30 constexpr size_t kChunkSizeBytes = 2;
31 // TODO(sprang): Add support for dynamic max size for easier fragmentation,
32 // eg. set it to what's left in the buffer or IP_PACKET_SIZE.
33 // Size constraint imposed by RTCP common header: 16bit size field interpreted
34 // as number of four byte words minus the first header word.
35 constexpr size_t kMaxSizeBytes = (1 << 16) * 4;
36 // Payload size:
37 // * 8 bytes Common Packet Format for RTCP Feedback Messages
38 // * 8 bytes FeedbackPacket header.
39 // * 2 bytes for one chunk.
40 constexpr size_t kMinPayloadSizeBytes = 8 + 8 + 2;
41 constexpr int kBaseScaleFactor =
42 TransportFeedback::kDeltaScaleFactor * (1 << 8);
43 constexpr int64_t kTimeWrapPeriodUs = (1ll << 24) * kBaseScaleFactor;
44
45 // Message format
46 //
47 // 0 1 2 3
48 // 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
49 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 // |V=2|P| FMT=15 | PT=205 | length |
51 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 // 0 | SSRC of packet sender |
53 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54 // 4 | SSRC of media source |
55 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 // 8 | base sequence number | packet status count |
57 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58 // 12 | reference time | fb pkt. count |
59 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 // 16 | packet chunk | packet chunk |
61 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62 // . .
63 // . .
64 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 // | packet chunk | recv delta | recv delta |
66 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 // . .
68 // . .
69 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 // | recv delta | recv delta | zero padding |
71 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 } // namespace
73 constexpr uint8_t TransportFeedback::kFeedbackMessageType;
74 constexpr size_t TransportFeedback::kMaxReportedPackets;
75
76 // Keep delta_sizes that can be encoded into single chunk if it is last chunk.
77 class TransportFeedback::LastChunk {
78 public:
79 using DeltaSize = TransportFeedback::DeltaSize;
80
81 LastChunk();
82
83 bool Empty() const;
84 void Clear();
85 // Return if delta sizes still can be encoded into single chunk with added
86 // |delta_size|.
87 bool CanAdd(DeltaSize delta_size) const;
88 // Add |delta_size|, assumes |CanAdd(delta_size)|,
89 void Add(DeltaSize delta_size);
90
91 // Encode chunk as large as possible removing encoded delta sizes.
92 // Assume CanAdd() == false for some valid delta_size.
93 uint16_t Emit();
94 // Encode all stored delta_sizes into single chunk, pad with 0s if needed.
95 uint16_t EncodeLast() const;
96
97 // Decode up to |max_size| delta sizes from |chunk|.
98 void Decode(uint16_t chunk, size_t max_size);
99 // Appends content of the Lastchunk to |deltas|.
100 void AppendTo(std::vector<DeltaSize>* deltas) const;
101
102 private:
103 static constexpr size_t kMaxRunLengthCapacity = 0x1fff;
104 static constexpr size_t kMaxOneBitCapacity = 14;
105 static constexpr size_t kMaxTwoBitCapacity = 7;
106 static constexpr size_t kMaxVectorCapacity = kMaxOneBitCapacity;
107 static constexpr DeltaSize kLarge = 2;
108
109 uint16_t EncodeOneBit() const;
110 void DecodeOneBit(uint16_t chunk, size_t max_size);
111
112 uint16_t EncodeTwoBit(size_t size) const;
113 void DecodeTwoBit(uint16_t chunk, size_t max_size);
114
115 uint16_t EncodeRunLength() const;
116 void DecodeRunLength(uint16_t chunk, size_t max_size);
117
118 DeltaSize delta_sizes_[kMaxVectorCapacity];
119 size_t size_;
120 bool all_same_;
121 bool has_large_delta_;
122 };
123 constexpr size_t TransportFeedback::LastChunk::kMaxRunLengthCapacity;
124 constexpr size_t TransportFeedback::LastChunk::kMaxOneBitCapacity;
125 constexpr size_t TransportFeedback::LastChunk::kMaxTwoBitCapacity;
126 constexpr size_t TransportFeedback::LastChunk::kMaxVectorCapacity;
127
LastChunk()128 TransportFeedback::LastChunk::LastChunk() {
129 Clear();
130 }
131
Empty() const132 bool TransportFeedback::LastChunk::Empty() const {
133 return size_ == 0;
134 }
135
Clear()136 void TransportFeedback::LastChunk::Clear() {
137 size_ = 0;
138 all_same_ = true;
139 has_large_delta_ = false;
140 }
141
CanAdd(DeltaSize delta_size) const142 bool TransportFeedback::LastChunk::CanAdd(DeltaSize delta_size) const {
143 RTC_DCHECK_LE(delta_size, 2);
144 if (size_ < kMaxTwoBitCapacity)
145 return true;
146 if (size_ < kMaxOneBitCapacity && !has_large_delta_ && delta_size != kLarge)
147 return true;
148 if (size_ < kMaxRunLengthCapacity && all_same_ &&
149 delta_sizes_[0] == delta_size)
150 return true;
151 return false;
152 }
153
Add(DeltaSize delta_size)154 void TransportFeedback::LastChunk::Add(DeltaSize delta_size) {
155 RTC_DCHECK(CanAdd(delta_size));
156 if (size_ < kMaxVectorCapacity)
157 delta_sizes_[size_] = delta_size;
158 size_++;
159 all_same_ = all_same_ && delta_size == delta_sizes_[0];
160 has_large_delta_ = has_large_delta_ || delta_size == kLarge;
161 }
162
Emit()163 uint16_t TransportFeedback::LastChunk::Emit() {
164 RTC_DCHECK(!CanAdd(0) || !CanAdd(1) || !CanAdd(2));
165 if (all_same_) {
166 uint16_t chunk = EncodeRunLength();
167 Clear();
168 return chunk;
169 }
170 if (size_ == kMaxOneBitCapacity) {
171 uint16_t chunk = EncodeOneBit();
172 Clear();
173 return chunk;
174 }
175 RTC_DCHECK_GE(size_, kMaxTwoBitCapacity);
176 uint16_t chunk = EncodeTwoBit(kMaxTwoBitCapacity);
177 // Remove |kMaxTwoBitCapacity| encoded delta sizes:
178 // Shift remaining delta sizes and recalculate all_same_ && has_large_delta_.
179 size_ -= kMaxTwoBitCapacity;
180 all_same_ = true;
181 has_large_delta_ = false;
182 for (size_t i = 0; i < size_; ++i) {
183 DeltaSize delta_size = delta_sizes_[kMaxTwoBitCapacity + i];
184 delta_sizes_[i] = delta_size;
185 all_same_ = all_same_ && delta_size == delta_sizes_[0];
186 has_large_delta_ = has_large_delta_ || delta_size == kLarge;
187 }
188
189 return chunk;
190 }
191
EncodeLast() const192 uint16_t TransportFeedback::LastChunk::EncodeLast() const {
193 RTC_DCHECK_GT(size_, 0);
194 if (all_same_)
195 return EncodeRunLength();
196 if (size_ <= kMaxTwoBitCapacity)
197 return EncodeTwoBit(size_);
198 return EncodeOneBit();
199 }
200
201 // Appends content of the Lastchunk to |deltas|.
AppendTo(std::vector<DeltaSize> * deltas) const202 void TransportFeedback::LastChunk::AppendTo(
203 std::vector<DeltaSize>* deltas) const {
204 if (all_same_) {
205 deltas->insert(deltas->end(), size_, delta_sizes_[0]);
206 } else {
207 deltas->insert(deltas->end(), delta_sizes_, delta_sizes_ + size_);
208 }
209 }
210
Decode(uint16_t chunk,size_t max_size)211 void TransportFeedback::LastChunk::Decode(uint16_t chunk, size_t max_size) {
212 if ((chunk & 0x8000) == 0) {
213 DecodeRunLength(chunk, max_size);
214 } else if ((chunk & 0x4000) == 0) {
215 DecodeOneBit(chunk, max_size);
216 } else {
217 DecodeTwoBit(chunk, max_size);
218 }
219 }
220
221 // One Bit Status Vector Chunk
222 //
223 // 0 1
224 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
225 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
226 // |T|S| symbol list |
227 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228 //
229 // T = 1
230 // S = 0
231 // Symbol list = 14 entries where 0 = not received, 1 = received 1-byte delta.
EncodeOneBit() const232 uint16_t TransportFeedback::LastChunk::EncodeOneBit() const {
233 RTC_DCHECK(!has_large_delta_);
234 RTC_DCHECK_LE(size_, kMaxOneBitCapacity);
235 uint16_t chunk = 0x8000;
236 for (size_t i = 0; i < size_; ++i)
237 chunk |= delta_sizes_[i] << (kMaxOneBitCapacity - 1 - i);
238 return chunk;
239 }
240
DecodeOneBit(uint16_t chunk,size_t max_size)241 void TransportFeedback::LastChunk::DecodeOneBit(uint16_t chunk,
242 size_t max_size) {
243 RTC_DCHECK_EQ(chunk & 0xc000, 0x8000);
244 size_ = std::min(kMaxOneBitCapacity, max_size);
245 has_large_delta_ = false;
246 all_same_ = false;
247 for (size_t i = 0; i < size_; ++i)
248 delta_sizes_[i] = (chunk >> (kMaxOneBitCapacity - 1 - i)) & 0x01;
249 }
250
251 // Two Bit Status Vector Chunk
252 //
253 // 0 1
254 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
255 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
256 // |T|S| symbol list |
257 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
258 //
259 // T = 1
260 // S = 1
261 // symbol list = 7 entries of two bits each.
EncodeTwoBit(size_t size) const262 uint16_t TransportFeedback::LastChunk::EncodeTwoBit(size_t size) const {
263 RTC_DCHECK_LE(size, size_);
264 uint16_t chunk = 0xc000;
265 for (size_t i = 0; i < size; ++i)
266 chunk |= delta_sizes_[i] << 2 * (kMaxTwoBitCapacity - 1 - i);
267 return chunk;
268 }
269
DecodeTwoBit(uint16_t chunk,size_t max_size)270 void TransportFeedback::LastChunk::DecodeTwoBit(uint16_t chunk,
271 size_t max_size) {
272 RTC_DCHECK_EQ(chunk & 0xc000, 0xc000);
273 size_ = std::min(kMaxTwoBitCapacity, max_size);
274 has_large_delta_ = true;
275 all_same_ = false;
276 for (size_t i = 0; i < size_; ++i)
277 delta_sizes_[i] = (chunk >> 2 * (kMaxTwoBitCapacity - 1 - i)) & 0x03;
278 }
279
280 // Run Length Status Vector Chunk
281 //
282 // 0 1
283 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
284 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
285 // |T| S | Run Length |
286 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287 //
288 // T = 0
289 // S = symbol
290 // Run Length = Unsigned integer denoting the run length of the symbol
EncodeRunLength() const291 uint16_t TransportFeedback::LastChunk::EncodeRunLength() const {
292 RTC_DCHECK(all_same_);
293 RTC_DCHECK_LE(size_, kMaxRunLengthCapacity);
294 return (delta_sizes_[0] << 13) | static_cast<uint16_t>(size_);
295 }
296
DecodeRunLength(uint16_t chunk,size_t max_count)297 void TransportFeedback::LastChunk::DecodeRunLength(uint16_t chunk,
298 size_t max_count) {
299 RTC_DCHECK_EQ(chunk & 0x8000, 0);
300 size_ = std::min<size_t>(chunk & 0x1fff, max_count);
301 DeltaSize delta_size = (chunk >> 13) & 0x03;
302 has_large_delta_ = delta_size >= kLarge;
303 all_same_ = true;
304 // To make it consistent with Add function, populate delta_sizes_ beyound 1st.
305 for (size_t i = 0; i < std::min<size_t>(size_, kMaxVectorCapacity); ++i)
306 delta_sizes_[i] = delta_size;
307 }
308
TransportFeedback()309 TransportFeedback::TransportFeedback()
310 : base_seq_no_(0),
311 num_seq_no_(0),
312 base_time_ticks_(0),
313 feedback_seq_(0),
314 last_timestamp_us_(0),
315 last_chunk_(new LastChunk()),
316 size_bytes_(kTransportFeedbackHeaderSizeBytes) {}
317
~TransportFeedback()318 TransportFeedback::~TransportFeedback() {}
319
SetBase(uint16_t base_sequence,int64_t ref_timestamp_us)320 void TransportFeedback::SetBase(uint16_t base_sequence,
321 int64_t ref_timestamp_us) {
322 RTC_DCHECK_EQ(num_seq_no_, 0);
323 RTC_DCHECK_GE(ref_timestamp_us, 0);
324 base_seq_no_ = base_sequence;
325 base_time_ticks_ = (ref_timestamp_us % kTimeWrapPeriodUs) / kBaseScaleFactor;
326 last_timestamp_us_ = GetBaseTimeUs();
327 }
328
SetFeedbackSequenceNumber(uint8_t feedback_sequence)329 void TransportFeedback::SetFeedbackSequenceNumber(uint8_t feedback_sequence) {
330 feedback_seq_ = feedback_sequence;
331 }
332
AddReceivedPacket(uint16_t sequence_number,int64_t timestamp_us)333 bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number,
334 int64_t timestamp_us) {
335 // Convert to ticks and round.
336 int64_t delta_full = (timestamp_us - last_timestamp_us_) % kTimeWrapPeriodUs;
337 if (delta_full > kTimeWrapPeriodUs / 2)
338 delta_full -= kTimeWrapPeriodUs;
339 delta_full +=
340 delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2;
341 delta_full /= kDeltaScaleFactor;
342
343 int16_t delta = static_cast<int16_t>(delta_full);
344 // If larger than 16bit signed, we can't represent it - need new fb packet.
345 if (delta != delta_full) {
346 RTC_LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )";
347 return false;
348 }
349
350 uint16_t next_seq_no = base_seq_no_ + num_seq_no_;
351 if (sequence_number != next_seq_no) {
352 uint16_t last_seq_no = next_seq_no - 1;
353 if (!IsNewerSequenceNumber(sequence_number, last_seq_no))
354 return false;
355 for (; next_seq_no != sequence_number; ++next_seq_no)
356 if (!AddDeltaSize(0))
357 return false;
358 }
359
360 DeltaSize delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2;
361 if (!AddDeltaSize(delta_size))
362 return false;
363
364 packets_.emplace_back(sequence_number, delta);
365 last_timestamp_us_ += delta * kDeltaScaleFactor;
366 size_bytes_ += delta_size;
367 return true;
368 }
369
370 const std::vector<TransportFeedback::ReceivedPacket>&
GetReceivedPackets() const371 TransportFeedback::GetReceivedPackets() const {
372 return packets_;
373 }
374
GetBaseSequence() const375 uint16_t TransportFeedback::GetBaseSequence() const {
376 return base_seq_no_;
377 }
378
GetBaseTimeUs() const379 int64_t TransportFeedback::GetBaseTimeUs() const {
380 return static_cast<int64_t>(base_time_ticks_) * kBaseScaleFactor;
381 }
382
383 // De-serialize packet.
Parse(const CommonHeader & packet)384 bool TransportFeedback::Parse(const CommonHeader& packet) {
385 RTC_DCHECK_EQ(packet.type(), kPacketType);
386 RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
387 TRACE_EVENT0("webrtc", "TransportFeedback::Parse");
388
389 if (packet.payload_size_bytes() < kMinPayloadSizeBytes) {
390 RTC_LOG(LS_WARNING) << "Buffer too small (" << packet.payload_size_bytes()
391 << " bytes) to fit a "
392 "FeedbackPacket. Minimum size = "
393 << kMinPayloadSizeBytes;
394 return false;
395 }
396
397 const uint8_t* const payload = packet.payload();
398 ParseCommonFeedback(payload);
399
400 base_seq_no_ = ByteReader<uint16_t>::ReadBigEndian(&payload[8]);
401 uint16_t status_count = ByteReader<uint16_t>::ReadBigEndian(&payload[10]);
402 base_time_ticks_ = ByteReader<int32_t, 3>::ReadBigEndian(&payload[12]);
403 feedback_seq_ = payload[15];
404 Clear();
405 size_t index = 16;
406 const size_t end_index = packet.payload_size_bytes();
407
408 if (status_count == 0) {
409 RTC_LOG(LS_WARNING) << "Empty feedback messages not allowed.";
410 return false;
411 }
412
413 std::vector<uint8_t> delta_sizes;
414 delta_sizes.reserve(status_count);
415 while (delta_sizes.size() < status_count) {
416 if (index + kChunkSizeBytes > end_index) {
417 RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
418 Clear();
419 return false;
420 }
421
422 uint16_t chunk = ByteReader<uint16_t>::ReadBigEndian(&payload[index]);
423 index += kChunkSizeBytes;
424 encoded_chunks_.push_back(chunk);
425 last_chunk_->Decode(chunk, status_count - delta_sizes.size());
426 last_chunk_->AppendTo(&delta_sizes);
427 }
428 // Last chunk is stored in the |last_chunk_|.
429 encoded_chunks_.pop_back();
430 RTC_DCHECK_EQ(delta_sizes.size(), status_count);
431 num_seq_no_ = status_count;
432
433 uint16_t seq_no = base_seq_no_;
434 for (size_t delta_size : delta_sizes) {
435 if (index + delta_size > end_index) {
436 RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
437 Clear();
438 return false;
439 }
440 switch (delta_size) {
441 case 0:
442 break;
443 case 1: {
444 int16_t delta = payload[index];
445 packets_.emplace_back(seq_no, delta);
446 last_timestamp_us_ += delta * kDeltaScaleFactor;
447 index += delta_size;
448 break;
449 }
450 case 2: {
451 int16_t delta = ByteReader<int16_t>::ReadBigEndian(&payload[index]);
452 packets_.emplace_back(seq_no, delta);
453 last_timestamp_us_ += delta * kDeltaScaleFactor;
454 index += delta_size;
455 break;
456 }
457 case 3:
458 Clear();
459 RTC_LOG(LS_WARNING) << "Invalid delta_size for seq_no " << seq_no;
460 return false;
461 default:
462 RTC_NOTREACHED();
463 break;
464 }
465 ++seq_no;
466 }
467 size_bytes_ = RtcpPacket::kHeaderLength + index;
468 RTC_DCHECK_LE(index, end_index);
469 return true;
470 }
471
ParseFrom(const uint8_t * buffer,size_t length)472 std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom(
473 const uint8_t* buffer,
474 size_t length) {
475 CommonHeader header;
476 if (!header.Parse(buffer, length))
477 return nullptr;
478 if (header.type() != kPacketType || header.fmt() != kFeedbackMessageType)
479 return nullptr;
480 std::unique_ptr<TransportFeedback> parsed(new TransportFeedback);
481 if (!parsed->Parse(header))
482 return nullptr;
483 return parsed;
484 }
485
IsConsistent() const486 bool TransportFeedback::IsConsistent() const {
487 size_t packet_size = kTransportFeedbackHeaderSizeBytes;
488 std::vector<DeltaSize> delta_sizes;
489 LastChunk chunk_decoder;
490 for (uint16_t chunk : encoded_chunks_) {
491 chunk_decoder.Decode(chunk, kMaxReportedPackets);
492 chunk_decoder.AppendTo(&delta_sizes);
493 packet_size += kChunkSizeBytes;
494 }
495 if (!last_chunk_->Empty()) {
496 last_chunk_->AppendTo(&delta_sizes);
497 packet_size += kChunkSizeBytes;
498 }
499 if (num_seq_no_ != delta_sizes.size()) {
500 RTC_LOG(LS_ERROR) << delta_sizes.size() << " packets encoded. Expected "
501 << num_seq_no_;
502 return false;
503 }
504 int64_t timestamp_us = base_time_ticks_ * kBaseScaleFactor;
505 auto packet_it = packets_.begin();
506 uint16_t seq_no = base_seq_no_;
507 for (DeltaSize delta_size : delta_sizes) {
508 if (delta_size > 0) {
509 if (packet_it == packets_.end()) {
510 RTC_LOG(LS_ERROR) << "Failed to find delta for seq_no " << seq_no;
511 return false;
512 }
513 if (packet_it->sequence_number() != seq_no) {
514 RTC_LOG(LS_ERROR) << "Expected to find delta for seq_no " << seq_no
515 << ". Next delta is for "
516 << packet_it->sequence_number();
517 return false;
518 }
519 if (delta_size == 1 &&
520 (packet_it->delta_ticks() < 0 || packet_it->delta_ticks() > 0xff)) {
521 RTC_LOG(LS_ERROR) << "Delta " << packet_it->delta_ticks()
522 << " for seq_no " << seq_no
523 << " doesn't fit into one byte";
524 return false;
525 }
526 timestamp_us += packet_it->delta_us();
527 ++packet_it;
528 }
529 packet_size += delta_size;
530 ++seq_no;
531 }
532 if (packet_it != packets_.end()) {
533 RTC_LOG(LS_ERROR) << "Unencoded delta for seq_no "
534 << packet_it->sequence_number();
535 return false;
536 }
537 if (timestamp_us != last_timestamp_us_) {
538 RTC_LOG(LS_ERROR) << "Last timestamp mismatch. Calculated: " << timestamp_us
539 << ". Saved: " << last_timestamp_us_;
540 return false;
541 }
542 if (size_bytes_ != packet_size) {
543 RTC_LOG(LS_ERROR) << "Rtcp packet size mismatch. Calculated: "
544 << packet_size << ". Saved: " << size_bytes_;
545 return false;
546 }
547 return true;
548 }
549
BlockLength() const550 size_t TransportFeedback::BlockLength() const {
551 // Round size_bytes_ up to multiple of 32bits.
552 return (size_bytes_ + 3) & (~static_cast<size_t>(3));
553 }
554
555 // Serialize packet.
Create(uint8_t * packet,size_t * position,size_t max_length,PacketReadyCallback * callback) const556 bool TransportFeedback::Create(uint8_t* packet,
557 size_t* position,
558 size_t max_length,
559 PacketReadyCallback* callback) const {
560 if (num_seq_no_ == 0)
561 return false;
562
563 while (*position + BlockLength() > max_length) {
564 if (!OnBufferFull(packet, position, callback))
565 return false;
566 }
567 const size_t position_end = *position + BlockLength();
568
569 CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
570 position);
571 CreateCommonFeedback(packet + *position);
572 *position += kCommonFeedbackLength;
573
574 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_no_);
575 *position += 2;
576
577 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], num_seq_no_);
578 *position += 2;
579
580 ByteWriter<int32_t, 3>::WriteBigEndian(&packet[*position], base_time_ticks_);
581 *position += 3;
582
583 packet[(*position)++] = feedback_seq_;
584
585 for (uint16_t chunk : encoded_chunks_) {
586 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk);
587 *position += 2;
588 }
589 if (!last_chunk_->Empty()) {
590 uint16_t chunk = last_chunk_->EncodeLast();
591 ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk);
592 *position += 2;
593 }
594
595 for (const auto& received_packet : packets_) {
596 int16_t delta = received_packet.delta_ticks();
597 if (delta >= 0 && delta <= 0xFF) {
598 packet[(*position)++] = delta;
599 } else {
600 ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta);
601 *position += 2;
602 }
603 }
604
605 while ((*position % 4) != 0)
606 packet[(*position)++] = 0;
607
608 RTC_DCHECK_EQ(*position, position_end);
609 return true;
610 }
611
Clear()612 void TransportFeedback::Clear() {
613 num_seq_no_ = 0;
614 last_timestamp_us_ = GetBaseTimeUs();
615 packets_.clear();
616 encoded_chunks_.clear();
617 last_chunk_->Clear();
618 size_bytes_ = kTransportFeedbackHeaderSizeBytes;
619 }
620
AddDeltaSize(DeltaSize delta_size)621 bool TransportFeedback::AddDeltaSize(DeltaSize delta_size) {
622 if (num_seq_no_ == kMaxReportedPackets)
623 return false;
624 size_t add_chunk_size = last_chunk_->Empty() ? kChunkSizeBytes : 0;
625 if (size_bytes_ + delta_size + add_chunk_size > kMaxSizeBytes)
626 return false;
627
628 if (last_chunk_->CanAdd(delta_size)) {
629 size_bytes_ += add_chunk_size;
630 last_chunk_->Add(delta_size);
631 ++num_seq_no_;
632 return true;
633 }
634 if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes)
635 return false;
636
637 encoded_chunks_.push_back(last_chunk_->Emit());
638 size_bytes_ += kChunkSizeBytes;
639 last_chunk_->Add(delta_size);
640 ++num_seq_no_;
641 return true;
642 }
643
644 } // namespace rtcp
645 } // namespace webrtc
646