diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc index d570a92c8c..bb1578fd8c 100644 --- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc +++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc @@ -116,6 +116,15 @@ void TransportFeedback::LastChunk::Add(DeltaSize delta_size) { has_large_delta_ = has_large_delta_ || delta_size == kLarge; } +void TransportFeedback::LastChunk::AddMissingPackets(size_t num_missing) { + RTC_DCHECK_EQ(size_, 0); + RTC_DCHECK(all_same_); + RTC_DCHECK(!has_large_delta_); + RTC_DCHECK_LT(num_missing, kMaxRunLengthCapacity); + absl::c_fill(delta_sizes_, DeltaSize(0)); + size_ = num_missing; +} + uint16_t TransportFeedback::LastChunk::Emit() { RTC_DCHECK(!CanAdd(0) || !CanAdd(1) || !CanAdd(2)); if (all_same_) { @@ -160,7 +169,8 @@ void TransportFeedback::LastChunk::AppendTo( if (all_same_) { deltas->insert(deltas->end(), size_, delta_sizes_[0]); } else { - deltas->insert(deltas->end(), delta_sizes_, delta_sizes_ + size_); + deltas->insert(deltas->end(), delta_sizes_.begin(), + delta_sizes_.begin() + size_); } } @@ -342,11 +352,13 @@ bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number, uint16_t last_seq_no = next_seq_no - 1; if (!IsNewerSequenceNumber(sequence_number, last_seq_no)) return false; - for (; next_seq_no != sequence_number; ++next_seq_no) { - if (!AddDeltaSize(0)) - return false; - if (include_lost_) + uint16_t num_missing_packets = sequence_number - next_seq_no; + if (!AddMissingPackets(num_missing_packets)) + return false; + if (include_lost_) { + for (; next_seq_no != sequence_number; ++next_seq_no) { all_packets_.emplace_back(next_seq_no); + } } } @@ -698,5 +710,38 @@ bool TransportFeedback::AddDeltaSize(DeltaSize delta_size) { return true; } +bool TransportFeedback::AddMissingPackets(size_t num_missing_packets) { + size_t new_num_seq_no = num_seq_no_ + num_missing_packets; + if (new_num_seq_no > kMaxReportedPackets) { + return false; + } + + if (!last_chunk_.Empty()) { + while (num_missing_packets > 0 && last_chunk_.CanAdd(0)) { + last_chunk_.Add(0); + --num_missing_packets; + } + if (num_missing_packets == 0) { + num_seq_no_ = new_num_seq_no; + return true; + } + encoded_chunks_.push_back(last_chunk_.Emit()); + } + RTC_DCHECK(last_chunk_.Empty()); + size_t full_chunks = num_missing_packets / LastChunk::kMaxRunLengthCapacity; + size_t partial_chunk = num_missing_packets % LastChunk::kMaxRunLengthCapacity; + size_t num_chunks = full_chunks + (partial_chunk > 0 ? 1 : 0); + if (size_bytes_ + kChunkSizeBytes * num_chunks > kMaxSizeBytes) { + num_seq_no_ = (new_num_seq_no - num_missing_packets); + return false; + } + size_bytes_ += kChunkSizeBytes * num_chunks; + // T = 0, S = 0, run length = kMaxRunLengthCapacity, see EncodeRunLength(). + encoded_chunks_.insert(encoded_chunks_.end(), full_chunks, + LastChunk::kMaxRunLengthCapacity); + last_chunk_.AddMissingPackets(partial_chunk); + num_seq_no_ = new_num_seq_no; + return true; +} } // namespace rtcp } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h index 22f384fe05..c580632337 100644 --- a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h +++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h @@ -11,6 +11,7 @@ #ifndef MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_ #define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_ +#include #include #include @@ -110,6 +111,7 @@ class TransportFeedback : public Rtpfb { class LastChunk { public: using DeltaSize = TransportFeedback::DeltaSize; + static constexpr size_t kMaxRunLengthCapacity = 0x1fff; LastChunk(); @@ -120,6 +122,8 @@ class TransportFeedback : public Rtpfb { bool CanAdd(DeltaSize delta_size) const; // Add `delta_size`, assumes `CanAdd(delta_size)`, void Add(DeltaSize delta_size); + // Equivalent to calling Add(0) `num_missing` times. Assumes `Empty()`. + void AddMissingPackets(size_t num_missing); // Encode chunk as large as possible removing encoded delta sizes. // Assume CanAdd() == false for some valid delta_size. @@ -133,7 +137,6 @@ class TransportFeedback : public Rtpfb { void AppendTo(std::vector* deltas) const; private: - static constexpr size_t kMaxRunLengthCapacity = 0x1fff; static constexpr size_t kMaxOneBitCapacity = 14; static constexpr size_t kMaxTwoBitCapacity = 7; static constexpr size_t kMaxVectorCapacity = kMaxOneBitCapacity; @@ -148,7 +151,7 @@ class TransportFeedback : public Rtpfb { uint16_t EncodeRunLength() const; void DecodeRunLength(uint16_t chunk, size_t max_size); - DeltaSize delta_sizes_[kMaxVectorCapacity]; + std::array delta_sizes_; size_t size_; bool all_same_; bool has_large_delta_; @@ -158,6 +161,8 @@ class TransportFeedback : public Rtpfb { void Clear(); bool AddDeltaSize(DeltaSize delta_size); + // Adds `num_missing_packets` deltas of size 0. + bool AddMissingPackets(size_t num_missing_packets); const bool include_lost_; uint16_t base_seq_no_;