Home | History | Annotate | Download | only in rtcp
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/cast/net/rtcp/rtcp_builder.h"
      6 
      7 #include <stdint.h>
      8 
      9 #include <algorithm>
     10 #include <vector>
     11 
     12 #include "base/logging.h"
     13 #include "media/cast/net/cast_transport_defines.h"
     14 #include "media/cast/net/rtcp/rtcp_defines.h"
     15 #include "media/cast/net/rtcp/rtcp_utility.h"
     16 
     17 namespace media {
     18 namespace cast {
     19 namespace {
     20 
     21 // Max delta is 4095 milliseconds because we need to be able to encode it in
     22 // 12 bits.
     23 const int64 kMaxWireFormatTimeDeltaMs = INT64_C(0xfff);
     24 
     25 uint16 MergeEventTypeAndTimestampForWireFormat(
     26     const CastLoggingEvent& event,
     27     const base::TimeDelta& time_delta) {
     28   int64 time_delta_ms = time_delta.InMilliseconds();
     29 
     30   DCHECK_GE(time_delta_ms, 0);
     31   DCHECK_LE(time_delta_ms, kMaxWireFormatTimeDeltaMs);
     32 
     33   uint16 time_delta_12_bits =
     34       static_cast<uint16>(time_delta_ms & kMaxWireFormatTimeDeltaMs);
     35 
     36   uint16 event_type_4_bits = ConvertEventTypeToWireFormat(event);
     37   DCHECK(event_type_4_bits);
     38   DCHECK(~(event_type_4_bits & 0xfff0));
     39   return (event_type_4_bits << 12) | time_delta_12_bits;
     40 }
     41 
     42 bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs,
     43                             const RtcpReceiverEventLogMessage& rhs) {
     44   return lhs.event_timestamp < rhs.event_timestamp;
     45 }
     46 
     47 void AddReceiverLogEntries(
     48     const RtcpReceiverLogMessage& redundancy_receiver_log_message,
     49     RtcpReceiverLogMessage* receiver_log_message,
     50     size_t* remaining_space,
     51     size_t* number_of_frames,
     52     size_t* total_number_of_messages_to_send) {
     53   RtcpReceiverLogMessage::const_iterator it =
     54       redundancy_receiver_log_message.begin();
     55   while (it != redundancy_receiver_log_message.end() &&
     56          *remaining_space >=
     57              kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) {
     58     receiver_log_message->push_front(*it);
     59     size_t num_event_logs = (*remaining_space - kRtcpReceiverFrameLogSize) /
     60                             kRtcpReceiverEventLogSize;
     61     RtcpReceiverEventLogMessages& event_log_messages =
     62         receiver_log_message->front().event_log_messages_;
     63     if (num_event_logs < event_log_messages.size())
     64       event_log_messages.resize(num_event_logs);
     65 
     66     *remaining_space -= kRtcpReceiverFrameLogSize +
     67                         event_log_messages.size() * kRtcpReceiverEventLogSize;
     68     ++number_of_frames;
     69     *total_number_of_messages_to_send += event_log_messages.size();
     70     ++it;
     71   }
     72 }
     73 
     74 // A class to build a string representing the NACK list in Cast message.
     75 //
     76 // The string will look like "23:3-6 25:1,5-6", meaning packets 3 to 6 in frame
     77 // 23 are being NACK'ed (i.e. they are missing from the receiver's point of
     78 // view) and packets 1, 5 and 6 are missing in frame 25. A frame that is
     79 // completely missing will show as "26:65535".
     80 class NackStringBuilder {
     81  public:
     82   NackStringBuilder()
     83       : frame_count_(0),
     84         packet_count_(0),
     85         last_frame_id_(-1),
     86         last_packet_id_(-1),
     87         contiguous_sequence_(false) {}
     88   ~NackStringBuilder() {}
     89 
     90   bool Empty() const { return frame_count_ == 0; }
     91 
     92   void PushFrame(int frame_id) {
     93     DCHECK_GE(frame_id, 0);
     94     if (frame_count_ > 0) {
     95       if (frame_id == last_frame_id_) {
     96         return;
     97       }
     98       if (contiguous_sequence_) {
     99         stream_ << "-" << last_packet_id_;
    100       }
    101       stream_ << ", ";
    102     }
    103     stream_ << frame_id;
    104     last_frame_id_ = frame_id;
    105     packet_count_ = 0;
    106     contiguous_sequence_ = false;
    107     ++frame_count_;
    108   }
    109 
    110   void PushPacket(int packet_id) {
    111     DCHECK_GE(last_frame_id_, 0);
    112     DCHECK_GE(packet_id, 0);
    113     if (packet_count_ == 0) {
    114       stream_ << ":" << packet_id;
    115     } else if (packet_id == last_packet_id_ + 1) {
    116       contiguous_sequence_ = true;
    117     } else {
    118       if (contiguous_sequence_) {
    119         stream_ << "-" << last_packet_id_;
    120         contiguous_sequence_ = false;
    121       }
    122       stream_ << "," << packet_id;
    123     }
    124     ++packet_count_;
    125     last_packet_id_ = packet_id;
    126   }
    127 
    128   std::string GetString() {
    129     if (contiguous_sequence_) {
    130       stream_ << "-" << last_packet_id_;
    131       contiguous_sequence_ = false;
    132     }
    133     return stream_.str();
    134   }
    135 
    136  private:
    137   std::ostringstream stream_;
    138   int frame_count_;
    139   int packet_count_;
    140   int last_frame_id_;
    141   int last_packet_id_;
    142   bool contiguous_sequence_;
    143 };
    144 }  // namespace
    145 
    146 RtcpBuilder::RtcpBuilder(uint32 sending_ssrc)
    147     : writer_(NULL, 0),
    148       ssrc_(sending_ssrc),
    149       ptr_of_length_(NULL) {
    150 }
    151 
    152 RtcpBuilder::~RtcpBuilder() {}
    153 
    154 void RtcpBuilder::PatchLengthField() {
    155   if (ptr_of_length_) {
    156     // Back-patch the packet length. The client must have taken
    157     // care of proper padding to 32-bit words.
    158     int this_packet_length = (writer_.ptr() - ptr_of_length_ - 2);
    159     DCHECK_EQ(0, this_packet_length % 4)
    160         << "Packets must be a multiple of 32 bits long";
    161     *ptr_of_length_ = this_packet_length >> 10;
    162     *(ptr_of_length_ + 1) = (this_packet_length >> 2) & 0xFF;
    163     ptr_of_length_ = NULL;
    164   }
    165 }
    166 
    167 // Set the 5-bit value in the 1st byte of the header
    168 // and the payload type. Set aside room for the length field,
    169 // and make provision for back-patching it.
    170 void RtcpBuilder::AddRtcpHeader(RtcpPacketFields payload, int format_or_count) {
    171   PatchLengthField();
    172   writer_.WriteU8(0x80 | (format_or_count & 0x1F));
    173   writer_.WriteU8(payload);
    174   ptr_of_length_ = writer_.ptr();
    175 
    176   // Initialize length to "clearly illegal".
    177   writer_.WriteU16(0xDEAD);
    178 }
    179 
    180 void RtcpBuilder::Start() {
    181   packet_ = new base::RefCountedData<Packet>;
    182   packet_->data.resize(kMaxIpPacketSize);
    183   writer_ = base::BigEndianWriter(
    184       reinterpret_cast<char*>(&(packet_->data[0])), kMaxIpPacketSize);
    185 }
    186 
    187 PacketRef RtcpBuilder::Finish() {
    188   PatchLengthField();
    189   packet_->data.resize(kMaxIpPacketSize - writer_.remaining());
    190   writer_ = base::BigEndianWriter(NULL, 0);
    191   PacketRef ret = packet_;
    192   packet_ = NULL;
    193   return ret;
    194 }
    195 
    196 PacketRef RtcpBuilder::BuildRtcpFromReceiver(
    197     const RtcpReportBlock* report_block,
    198     const RtcpReceiverReferenceTimeReport* rrtr,
    199     const RtcpCastMessage* cast_message,
    200     const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events,
    201     base::TimeDelta target_delay) {
    202   Start();
    203 
    204   if (report_block)
    205     AddRR(report_block);
    206   if (rrtr)
    207     AddRrtr(rrtr);
    208   if (cast_message)
    209     AddCast(cast_message, target_delay);
    210   if (rtcp_events)
    211     AddReceiverLog(*rtcp_events);
    212 
    213   return Finish();
    214 }
    215 
    216 PacketRef RtcpBuilder::BuildRtcpFromSender(const RtcpSenderInfo& sender_info) {
    217   Start();
    218   AddSR(sender_info);
    219   return Finish();
    220 }
    221 
    222 void RtcpBuilder::AddRR(const RtcpReportBlock* report_block) {
    223   AddRtcpHeader(kPacketTypeReceiverReport, report_block ? 1 : 0);
    224   writer_.WriteU32(ssrc_);
    225   if (report_block) {
    226     AddReportBlocks(*report_block);  // Adds 24 bytes.
    227   }
    228 }
    229 
    230 void RtcpBuilder::AddReportBlocks(const RtcpReportBlock& report_block) {
    231   writer_.WriteU32(report_block.media_ssrc);
    232   writer_.WriteU8(report_block.fraction_lost);
    233   writer_.WriteU8(report_block.cumulative_lost >> 16);
    234   writer_.WriteU8(report_block.cumulative_lost >> 8);
    235   writer_.WriteU8(report_block.cumulative_lost);
    236 
    237   // Extended highest seq_no, contain the highest sequence number received.
    238   writer_.WriteU32(report_block.extended_high_sequence_number);
    239   writer_.WriteU32(report_block.jitter);
    240 
    241   // Last SR timestamp; our NTP time when we received the last report.
    242   // This is the value that we read from the send report packet not when we
    243   // received it.
    244   writer_.WriteU32(report_block.last_sr);
    245 
    246   // Delay since last received report, time since we received the report.
    247   writer_.WriteU32(report_block.delay_since_last_sr);
    248 }
    249 
    250 void RtcpBuilder::AddRrtr(const RtcpReceiverReferenceTimeReport* rrtr) {
    251   AddRtcpHeader(kPacketTypeXr, 0);
    252   writer_.WriteU32(ssrc_);  // Add our own SSRC.
    253   writer_.WriteU8(4);       // Add block type.
    254   writer_.WriteU8(0);       // Add reserved.
    255   writer_.WriteU16(2);      // Block length.
    256 
    257   // Add the media (received RTP) SSRC.
    258   writer_.WriteU32(rrtr->ntp_seconds);
    259   writer_.WriteU32(rrtr->ntp_fraction);
    260 }
    261 
    262 void RtcpBuilder::AddCast(const RtcpCastMessage* cast,
    263                           base::TimeDelta target_delay) {
    264   // See RTC 4585 Section 6.4 for application specific feedback messages.
    265   AddRtcpHeader(kPacketTypePayloadSpecific, 15);
    266   writer_.WriteU32(ssrc_);              // Add our own SSRC.
    267   writer_.WriteU32(cast->media_ssrc);  // Remote SSRC.
    268   writer_.WriteU32(kCast);
    269   writer_.WriteU8(static_cast<uint8>(cast->ack_frame_id));
    270   uint8* cast_loss_field_pos = reinterpret_cast<uint8*>(writer_.ptr());
    271   writer_.WriteU8(0);  // Overwritten with number_of_loss_fields.
    272   DCHECK_LE(target_delay.InMilliseconds(),
    273             std::numeric_limits<uint16_t>::max());
    274   writer_.WriteU16(target_delay.InMilliseconds());
    275 
    276   size_t number_of_loss_fields = 0;
    277   size_t max_number_of_loss_fields = std::min<size_t>(
    278       kRtcpMaxCastLossFields, writer_.remaining() / 4);
    279 
    280   MissingFramesAndPacketsMap::const_iterator frame_it =
    281       cast->missing_frames_and_packets.begin();
    282 
    283   NackStringBuilder nack_string_builder;
    284   for (; frame_it != cast->missing_frames_and_packets.end() &&
    285              number_of_loss_fields < max_number_of_loss_fields;
    286        ++frame_it) {
    287     nack_string_builder.PushFrame(frame_it->first);
    288     // Iterate through all frames with missing packets.
    289     if (frame_it->second.empty()) {
    290       // Special case all packets in a frame is missing.
    291       writer_.WriteU8(static_cast<uint8>(frame_it->first));
    292       writer_.WriteU16(kRtcpCastAllPacketsLost);
    293       writer_.WriteU8(0);
    294       nack_string_builder.PushPacket(kRtcpCastAllPacketsLost);
    295       ++number_of_loss_fields;
    296     } else {
    297       PacketIdSet::const_iterator packet_it = frame_it->second.begin();
    298       while (packet_it != frame_it->second.end()) {
    299         uint16 packet_id = *packet_it;
    300         // Write frame and packet id to buffer before calculating bitmask.
    301         writer_.WriteU8(static_cast<uint8>(frame_it->first));
    302         writer_.WriteU16(packet_id);
    303         nack_string_builder.PushPacket(packet_id);
    304 
    305         uint8 bitmask = 0;
    306         ++packet_it;
    307         while (packet_it != frame_it->second.end()) {
    308           int shift = static_cast<uint8>(*packet_it - packet_id) - 1;
    309           if (shift >= 0 && shift <= 7) {
    310             nack_string_builder.PushPacket(*packet_it);
    311             bitmask |= (1 << shift);
    312             ++packet_it;
    313           } else {
    314             break;
    315           }
    316         }
    317         writer_.WriteU8(bitmask);
    318         ++number_of_loss_fields;
    319       }
    320     }
    321   }
    322   VLOG_IF(1, !nack_string_builder.Empty())
    323       << "SSRC: " << cast->media_ssrc
    324       << ", ACK: " << cast->ack_frame_id
    325       << ", NACK: " << nack_string_builder.GetString();
    326   DCHECK_LE(number_of_loss_fields, kRtcpMaxCastLossFields);
    327   *cast_loss_field_pos = static_cast<uint8>(number_of_loss_fields);
    328 }
    329 
    330 void RtcpBuilder::AddSR(const RtcpSenderInfo& sender_info) {
    331   AddRtcpHeader(kPacketTypeSenderReport, 0);
    332   writer_.WriteU32(ssrc_);
    333   writer_.WriteU32(sender_info.ntp_seconds);
    334   writer_.WriteU32(sender_info.ntp_fraction);
    335   writer_.WriteU32(sender_info.rtp_timestamp);
    336   writer_.WriteU32(sender_info.send_packet_count);
    337   writer_.WriteU32(static_cast<uint32>(sender_info.send_octet_count));
    338 }
    339 
    340 /*
    341    0                   1                   2                   3
    342    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
    343   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    344   |V=2|P|reserved |   PT=XR=207   |             length            |
    345   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    346   |                              SSRC                             |
    347   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    348   |     BT=5      |   reserved    |         block length          |
    349   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    350   |                 SSRC1 (SSRC of first receiver)               | sub-
    351   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
    352   |                         last RR (LRR)                         |   1
    353   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    354   |                   delay since last RR (DLRR)                  |
    355   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    356 */
    357 void RtcpBuilder::AddDlrrRb(const RtcpDlrrReportBlock& dlrr) {
    358   AddRtcpHeader(kPacketTypeXr, 0);
    359   writer_.WriteU32(ssrc_);  // Add our own SSRC.
    360   writer_.WriteU8(5);  // Add block type.
    361   writer_.WriteU8(0);  // Add reserved.
    362   writer_.WriteU16(3);  // Block length.
    363   writer_.WriteU32(ssrc_);  // Add the media (received RTP) SSRC.
    364   writer_.WriteU32(dlrr.last_rr);
    365   writer_.WriteU32(dlrr.delay_since_last_rr);
    366 }
    367 
    368 void RtcpBuilder::AddReceiverLog(
    369     const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events) {
    370   size_t total_number_of_messages_to_send = 0;
    371   RtcpReceiverLogMessage receiver_log_message;
    372 
    373   if (!GetRtcpReceiverLogMessage(rtcp_events,
    374                                  &receiver_log_message,
    375                                  &total_number_of_messages_to_send)) {
    376     return;
    377   }
    378 
    379   AddRtcpHeader(kPacketTypeApplicationDefined, kReceiverLogSubtype);
    380   writer_.WriteU32(ssrc_);  // Add our own SSRC.
    381   writer_.WriteU32(kCast);
    382 
    383   while (!receiver_log_message.empty() &&
    384          total_number_of_messages_to_send > 0) {
    385     RtcpReceiverFrameLogMessage& frame_log_messages(
    386         receiver_log_message.front());
    387 
    388     // Add our frame header.
    389     writer_.WriteU32(frame_log_messages.rtp_timestamp_);
    390     size_t messages_in_frame = frame_log_messages.event_log_messages_.size();
    391     if (messages_in_frame > total_number_of_messages_to_send) {
    392       // We are running out of space.
    393       messages_in_frame = total_number_of_messages_to_send;
    394     }
    395     // Keep track of how many messages we have left to send.
    396     total_number_of_messages_to_send -= messages_in_frame;
    397 
    398     // On the wire format is number of messages - 1.
    399     writer_.WriteU8(static_cast<uint8>(messages_in_frame - 1));
    400 
    401     base::TimeTicks event_timestamp_base =
    402         frame_log_messages.event_log_messages_.front().event_timestamp;
    403     uint32 base_timestamp_ms =
    404         (event_timestamp_base - base::TimeTicks()).InMilliseconds();
    405     writer_.WriteU8(static_cast<uint8>(base_timestamp_ms >> 16));
    406     writer_.WriteU8(static_cast<uint8>(base_timestamp_ms >> 8));
    407     writer_.WriteU8(static_cast<uint8>(base_timestamp_ms));
    408 
    409     while (!frame_log_messages.event_log_messages_.empty() &&
    410            messages_in_frame > 0) {
    411       const RtcpReceiverEventLogMessage& event_message =
    412           frame_log_messages.event_log_messages_.front();
    413       uint16 event_type_and_timestamp_delta =
    414           MergeEventTypeAndTimestampForWireFormat(
    415               event_message.type,
    416               event_message.event_timestamp - event_timestamp_base);
    417       switch (event_message.type) {
    418         case FRAME_ACK_SENT:
    419         case FRAME_PLAYOUT:
    420         case FRAME_DECODED:
    421           writer_.WriteU16(
    422               static_cast<uint16>(event_message.delay_delta.InMilliseconds()));
    423           writer_.WriteU16(event_type_and_timestamp_delta);
    424           break;
    425         case PACKET_RECEIVED:
    426           writer_.WriteU16(event_message.packet_id);
    427           writer_.WriteU16(event_type_and_timestamp_delta);
    428           break;
    429         default:
    430           NOTREACHED();
    431       }
    432       messages_in_frame--;
    433       frame_log_messages.event_log_messages_.pop_front();
    434     }
    435     if (frame_log_messages.event_log_messages_.empty()) {
    436       // We sent all messages on this frame; pop the frame header.
    437       receiver_log_message.pop_front();
    438     }
    439   }
    440   DCHECK_EQ(total_number_of_messages_to_send, 0u);
    441 }
    442 
    443 bool RtcpBuilder::GetRtcpReceiverLogMessage(
    444     const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
    445     RtcpReceiverLogMessage* receiver_log_message,
    446     size_t* total_number_of_messages_to_send) {
    447   size_t number_of_frames = 0;
    448   size_t remaining_space =
    449       std::min<size_t>(kMaxReceiverLogBytes, writer_.remaining());
    450   if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize +
    451                             kRtcpReceiverEventLogSize) {
    452     return false;
    453   }
    454 
    455   // We use this to do event timestamp sorting and truncating for events of
    456   // a single frame.
    457   std::vector<RtcpReceiverEventLogMessage> sorted_log_messages;
    458 
    459   // Account for the RTCP header for an application-defined packet.
    460   remaining_space -= kRtcpCastLogHeaderSize;
    461 
    462   ReceiverRtcpEventSubscriber::RtcpEventMultiMap::const_reverse_iterator rit =
    463       rtcp_events.rbegin();
    464 
    465   while (rit != rtcp_events.rend() &&
    466          remaining_space >=
    467              kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) {
    468     const RtpTimestamp rtp_timestamp = rit->first;
    469     RtcpReceiverFrameLogMessage frame_log(rtp_timestamp);
    470     remaining_space -= kRtcpReceiverFrameLogSize;
    471     ++number_of_frames;
    472 
    473     // Get all events of a single frame.
    474     sorted_log_messages.clear();
    475     do {
    476       RtcpReceiverEventLogMessage event_log_message;
    477       event_log_message.type = rit->second.type;
    478       event_log_message.event_timestamp = rit->second.timestamp;
    479       event_log_message.delay_delta = rit->second.delay_delta;
    480       event_log_message.packet_id = rit->second.packet_id;
    481       sorted_log_messages.push_back(event_log_message);
    482       ++rit;
    483     } while (rit != rtcp_events.rend() && rit->first == rtp_timestamp);
    484 
    485     std::sort(sorted_log_messages.begin(),
    486               sorted_log_messages.end(),
    487               &EventTimestampLessThan);
    488 
    489     // From |sorted_log_messages|, only take events that are no greater than
    490     // |kMaxWireFormatTimeDeltaMs| seconds away from the latest event. Events
    491     // older than that cannot be encoded over the wire.
    492     std::vector<RtcpReceiverEventLogMessage>::reverse_iterator sorted_rit =
    493         sorted_log_messages.rbegin();
    494     base::TimeTicks first_event_timestamp = sorted_rit->event_timestamp;
    495     size_t events_in_frame = 0;
    496     while (sorted_rit != sorted_log_messages.rend() &&
    497            events_in_frame < kRtcpMaxReceiverLogMessages &&
    498            remaining_space >= kRtcpReceiverEventLogSize) {
    499       base::TimeDelta delta(first_event_timestamp -
    500                             sorted_rit->event_timestamp);
    501       if (delta.InMilliseconds() > kMaxWireFormatTimeDeltaMs)
    502         break;
    503       frame_log.event_log_messages_.push_front(*sorted_rit);
    504       ++events_in_frame;
    505       ++*total_number_of_messages_to_send;
    506       remaining_space -= kRtcpReceiverEventLogSize;
    507       ++sorted_rit;
    508     }
    509 
    510     receiver_log_message->push_front(frame_log);
    511   }
    512 
    513   rtcp_events_history_.push_front(*receiver_log_message);
    514 
    515   // We don't try to match RTP timestamps of redundancy frame logs with those
    516   // from the newest set (which would save the space of an extra RTP timestamp
    517   // over the wire). Unless the redundancy frame logs are very recent, it's
    518   // unlikely there will be a match anyway.
    519   if (rtcp_events_history_.size() > kFirstRedundancyOffset) {
    520     // Add first redundnacy messages, if enough space remaining
    521     AddReceiverLogEntries(rtcp_events_history_[kFirstRedundancyOffset],
    522                           receiver_log_message,
    523                           &remaining_space,
    524                           &number_of_frames,
    525                           total_number_of_messages_to_send);
    526   }
    527 
    528   if (rtcp_events_history_.size() > kSecondRedundancyOffset) {
    529     // Add second redundancy messages, if enough space remaining
    530     AddReceiverLogEntries(rtcp_events_history_[kSecondRedundancyOffset],
    531                           receiver_log_message,
    532                           &remaining_space,
    533                           &number_of_frames,
    534                           total_number_of_messages_to_send);
    535   }
    536 
    537   if (rtcp_events_history_.size() > kReceiveLogMessageHistorySize) {
    538     rtcp_events_history_.pop_back();
    539   }
    540 
    541   DCHECK_LE(rtcp_events_history_.size(), kReceiveLogMessageHistorySize);
    542 
    543   VLOG(3) << "number of frames: " << number_of_frames;
    544   VLOG(3) << "total messages to send: " << *total_number_of_messages_to_send;
    545   return number_of_frames > 0;
    546 }
    547 
    548 }  // namespace cast
    549 }  // namespace media
    550