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