• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MergeEventTypeAndTimestampForWireFormat(const CastLoggingEvent & event,const base::TimeDelta & time_delta)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 
EventTimestampLessThan(const RtcpReceiverEventLogMessage & lhs,const RtcpReceiverEventLogMessage & rhs)42 bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs,
43                             const RtcpReceiverEventLogMessage& rhs) {
44   return lhs.event_timestamp < rhs.event_timestamp;
45 }
46 
AddReceiverLogEntries(const RtcpReceiverLogMessage & redundancy_receiver_log_message,RtcpReceiverLogMessage * receiver_log_message,size_t * remaining_space,size_t * number_of_frames,size_t * total_number_of_messages_to_send)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:
NackStringBuilder()82   NackStringBuilder()
83       : frame_count_(0),
84         packet_count_(0),
85         last_frame_id_(-1),
86         last_packet_id_(-1),
87         contiguous_sequence_(false) {}
~NackStringBuilder()88   ~NackStringBuilder() {}
89 
Empty() const90   bool Empty() const { return frame_count_ == 0; }
91 
PushFrame(int frame_id)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 
PushPacket(int packet_id)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 
GetString()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 
RtcpBuilder(uint32 sending_ssrc)146 RtcpBuilder::RtcpBuilder(uint32 sending_ssrc)
147     : writer_(NULL, 0),
148       ssrc_(sending_ssrc),
149       ptr_of_length_(NULL) {
150 }
151 
~RtcpBuilder()152 RtcpBuilder::~RtcpBuilder() {}
153 
PatchLengthField()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.
AddRtcpHeader(RtcpPacketFields payload,int format_or_count)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 
Start()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 
Finish()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 
BuildRtcpFromReceiver(const RtcpReportBlock * report_block,const RtcpReceiverReferenceTimeReport * rrtr,const RtcpCastMessage * cast_message,const ReceiverRtcpEventSubscriber::RtcpEventMultiMap * rtcp_events,base::TimeDelta target_delay)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 
BuildRtcpFromSender(const RtcpSenderInfo & sender_info)216 PacketRef RtcpBuilder::BuildRtcpFromSender(const RtcpSenderInfo& sender_info) {
217   Start();
218   AddSR(sender_info);
219   return Finish();
220 }
221 
AddRR(const RtcpReportBlock * report_block)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 
AddReportBlocks(const RtcpReportBlock & report_block)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 
AddRrtr(const RtcpReceiverReferenceTimeReport * rrtr)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 
AddCast(const RtcpCastMessage * cast,base::TimeDelta target_delay)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 
AddSR(const RtcpSenderInfo & sender_info)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 */
AddDlrrRb(const RtcpDlrrReportBlock & dlrr)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 
AddReceiverLog(const ReceiverRtcpEventSubscriber::RtcpEventMultiMap & rtcp_events)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 
GetRtcpReceiverLogMessage(const ReceiverRtcpEventSubscriber::RtcpEventMultiMap & rtcp_events,RtcpReceiverLogMessage * receiver_log_message,size_t * total_number_of_messages_to_send)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