LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtcp_packet - transport_feedback.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 359 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13