1 // Copyright 2013 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.
5 #include "media/cast/rtcp/rtcp_receiver.h"
7 #include "base/logging.h"
8 #include "media/cast/rtcp/rtcp_utility.h"
9 #include "media/cast/transport/cast_transport_defines.h"
13 media::cast::CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event) {
16 return media::cast::kAudioAckSent;
18 return media::cast::kAudioPlayoutDelay;
20 return media::cast::kAudioFrameDecoded;
22 return media::cast::kAudioPacketReceived;
24 return media::cast::kVideoAckSent;
26 return media::cast::kVideoFrameDecoded;
28 return media::cast::kVideoRenderDelay;
30 return media::cast::kVideoPacketReceived;
32 return media::cast::kDuplicateAudioPacketReceived;
34 return media::cast::kDuplicateVideoPacketReceived;
36 // If the sender adds new log messages we will end up here until we add
37 // the new messages in the receiver.
38 VLOG(1) << "Unexpected log message received: " << static_cast<int>(event);
40 return media::cast::kUnknown;
44 media::cast::transport::RtcpSenderFrameStatus
45 TranslateToFrameStatusFromWireFormat(uint8 status) {
48 return media::cast::transport::kRtcpSenderFrameStatusUnknown;
50 return media::cast::transport::kRtcpSenderFrameStatusDroppedByEncoder;
52 return media::cast::transport::kRtcpSenderFrameStatusDroppedByFlowControl;
54 return media::cast::transport::kRtcpSenderFrameStatusSentToNetwork;
56 // If the sender adds new log messages we will end up here until we add
57 // the new messages in the receiver.
59 VLOG(1) << "Unexpected status received: " << static_cast<int>(status);
60 return media::cast::transport::kRtcpSenderFrameStatusUnknown;
64 // A receiver event is identified by frame RTP timestamp, event timestamp and
66 size_t HashReceiverEvent(uint32 frame_rtp_timestamp,
67 const base::TimeTicks& event_timestamp,
68 media::cast::CastLoggingEvent event_type) {
69 uint64 value1 = event_type;
71 value1 |= frame_rtp_timestamp;
72 return base::HashInts64(
73 value1, static_cast<uint64>(event_timestamp.ToInternalValue()));
81 RtcpReceiver::RtcpReceiver(scoped_refptr<CastEnvironment> cast_environment,
82 RtcpSenderFeedback* sender_feedback,
83 RtcpReceiverFeedback* receiver_feedback,
84 RtcpRttFeedback* rtt_feedback,
88 sender_feedback_(sender_feedback),
89 receiver_feedback_(receiver_feedback),
90 rtt_feedback_(rtt_feedback),
91 cast_environment_(cast_environment),
92 receiver_event_history_size_(0) {}
94 RtcpReceiver::~RtcpReceiver() {}
96 void RtcpReceiver::SetRemoteSSRC(uint32 ssrc) { remote_ssrc_ = ssrc; }
98 void RtcpReceiver::SetCastReceiverEventHistorySize(size_t size) {
99 receiver_event_history_size_ = size;
102 void RtcpReceiver::IncomingRtcpPacket(RtcpParser* rtcp_parser) {
103 RtcpFieldTypes field_type = rtcp_parser->Begin();
104 while (field_type != kRtcpNotValidCode) {
105 // Each "case" is responsible for iterate the parser to the next top
107 switch (field_type) {
109 HandleSenderReport(rtcp_parser);
112 HandleReceiverReport(rtcp_parser);
115 HandleSDES(rtcp_parser);
118 HandleBYE(rtcp_parser);
121 HandleXr(rtcp_parser);
123 case kRtcpGenericRtpFeedbackNackCode:
124 HandleNACK(rtcp_parser);
126 case kRtcpGenericRtpFeedbackSrReqCode:
127 HandleSendReportRequest(rtcp_parser);
129 case kRtcpPayloadSpecificPliCode:
130 HandlePLI(rtcp_parser);
132 case kRtcpPayloadSpecificRpsiCode:
133 HandleRpsi(rtcp_parser);
135 case kRtcpPayloadSpecificFirCode:
136 HandleFIR(rtcp_parser);
138 case kRtcpPayloadSpecificAppCode:
139 HandlePayloadSpecificApp(rtcp_parser);
141 case kRtcpApplicationSpecificCastReceiverLogCode:
142 HandleApplicationSpecificCastReceiverLog(rtcp_parser);
144 case kRtcpApplicationSpecificCastSenderLogCode:
145 HandleApplicationSpecificCastSenderLog(rtcp_parser);
147 case kRtcpPayloadSpecificRembCode:
148 case kRtcpPayloadSpecificRembItemCode:
149 case kRtcpPayloadSpecificCastCode:
150 case kRtcpPayloadSpecificCastNackItemCode:
151 case kRtcpApplicationSpecificCastReceiverLogFrameCode:
152 case kRtcpApplicationSpecificCastReceiverLogEventCode:
153 case kRtcpNotValidCode:
154 case kRtcpReportBlockItemCode:
155 case kRtcpSdesChunkCode:
156 case kRtcpGenericRtpFeedbackNackItemCode:
157 case kRtcpPayloadSpecificFirItemCode:
158 case kRtcpXrRrtrCode:
159 case kRtcpXrDlrrCode:
160 case kRtcpXrUnknownItemCode:
161 rtcp_parser->Iterate();
162 NOTREACHED() << "Invalid state";
165 field_type = rtcp_parser->FieldType();
169 void RtcpReceiver::HandleSenderReport(RtcpParser* rtcp_parser) {
170 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
171 const RtcpField& rtcp_field = rtcp_parser->Field();
173 DCHECK(rtcp_field_type == kRtcpSrCode) << "Invalid state";
175 // Synchronization source identifier for the originator of this SR packet.
176 uint32 remote_ssrc = rtcp_field.sender_report.sender_ssrc;
178 VLOG(2) << "Cast RTCP received SR from SSRC " << remote_ssrc;
180 if (remote_ssrc_ == remote_ssrc) {
181 transport::RtcpSenderInfo remote_sender_info;
182 remote_sender_info.ntp_seconds =
183 rtcp_field.sender_report.ntp_most_significant;
184 remote_sender_info.ntp_fraction =
185 rtcp_field.sender_report.ntp_least_significant;
186 remote_sender_info.rtp_timestamp = rtcp_field.sender_report.rtp_timestamp;
187 remote_sender_info.send_packet_count =
188 rtcp_field.sender_report.sender_packet_count;
189 remote_sender_info.send_octet_count =
190 rtcp_field.sender_report.sender_octet_count;
191 if (receiver_feedback_) {
192 receiver_feedback_->OnReceivedSenderReport(remote_sender_info);
195 rtcp_field_type = rtcp_parser->Iterate();
196 while (rtcp_field_type == kRtcpReportBlockItemCode) {
197 HandleReportBlock(&rtcp_field, remote_ssrc);
198 rtcp_field_type = rtcp_parser->Iterate();
202 void RtcpReceiver::HandleReceiverReport(RtcpParser* rtcp_parser) {
203 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
204 const RtcpField& rtcp_field = rtcp_parser->Field();
206 DCHECK(rtcp_field_type == kRtcpRrCode) << "Invalid state";
208 uint32 remote_ssrc = rtcp_field.receiver_report.sender_ssrc;
210 VLOG(2) << "Cast RTCP received RR from SSRC " << remote_ssrc;
212 rtcp_field_type = rtcp_parser->Iterate();
213 while (rtcp_field_type == kRtcpReportBlockItemCode) {
214 HandleReportBlock(&rtcp_field, remote_ssrc);
215 rtcp_field_type = rtcp_parser->Iterate();
219 void RtcpReceiver::HandleReportBlock(const RtcpField* rtcp_field,
220 uint32 remote_ssrc) {
221 // This will be called once per report block in the Rtcp packet.
222 // We filter out all report blocks that are not for us.
223 // Each packet has max 31 RR blocks.
225 // We can calculate RTT if we send a send report and get a report block back.
227 // |rtcp_field.ReportBlockItem.ssrc| is the ssrc identifier of the source to
228 // which the information in this reception report block pertains.
230 const RtcpFieldReportBlockItem& rb = rtcp_field->report_block_item;
232 // Filter out all report blocks that are not for us.
233 if (rb.ssrc != ssrc_) {
234 // This block is not for us ignore it.
237 VLOG(2) << "Cast RTCP received RB from SSRC " << remote_ssrc;
238 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
239 cast_environment_->Logging()->InsertGenericEvent(
240 now, kPacketLoss, rb.fraction_lost);
241 cast_environment_->Logging()->InsertGenericEvent(now, kJitterMs, rb.jitter);
243 transport::RtcpReportBlock report_block;
244 report_block.remote_ssrc = remote_ssrc;
245 report_block.media_ssrc = rb.ssrc;
246 report_block.fraction_lost = rb.fraction_lost;
247 report_block.cumulative_lost = rb.cumulative_number_of_packets_lost;
248 report_block.extended_high_sequence_number =
249 rb.extended_highest_sequence_number;
250 report_block.jitter = rb.jitter;
251 report_block.last_sr = rb.last_sender_report;
252 report_block.delay_since_last_sr = rb.delay_last_sender_report;
255 rtt_feedback_->OnReceivedDelaySinceLastReport(
256 rb.ssrc, rb.last_sender_report, rb.delay_last_sender_report);
260 void RtcpReceiver::HandleSDES(RtcpParser* rtcp_parser) {
261 RtcpFieldTypes field_type = rtcp_parser->Iterate();
262 while (field_type == kRtcpSdesChunkCode) {
263 HandleSDESChunk(rtcp_parser);
264 field_type = rtcp_parser->Iterate();
268 void RtcpReceiver::HandleSDESChunk(RtcpParser* rtcp_parser) {
269 const RtcpField& rtcp_field = rtcp_parser->Field();
270 VLOG(2) << "Cast RTCP received SDES with cname " << rtcp_field.c_name.name;
273 void RtcpReceiver::HandleXr(RtcpParser* rtcp_parser) {
274 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
275 const RtcpField& rtcp_field = rtcp_parser->Field();
277 DCHECK(rtcp_field_type == kRtcpXrCode) << "Invalid state";
279 uint32 remote_ssrc = rtcp_field.extended_report.sender_ssrc;
280 rtcp_field_type = rtcp_parser->Iterate();
282 while (rtcp_field_type == kRtcpXrDlrrCode ||
283 rtcp_field_type == kRtcpXrRrtrCode ||
284 rtcp_field_type == kRtcpXrUnknownItemCode) {
285 if (rtcp_field_type == kRtcpXrRrtrCode) {
286 HandleRrtr(rtcp_parser, remote_ssrc);
287 } else if (rtcp_field_type == kRtcpXrDlrrCode) {
288 HandleDlrr(rtcp_parser);
290 rtcp_field_type = rtcp_parser->Iterate();
294 void RtcpReceiver::HandleRrtr(RtcpParser* rtcp_parser, uint32 remote_ssrc) {
295 if (remote_ssrc_ != remote_ssrc) {
299 const RtcpField& rtcp_field = rtcp_parser->Field();
300 RtcpReceiverReferenceTimeReport remote_time_report;
301 remote_time_report.remote_ssrc = remote_ssrc;
302 remote_time_report.ntp_seconds = rtcp_field.rrtr.ntp_most_significant;
303 remote_time_report.ntp_fraction = rtcp_field.rrtr.ntp_least_significant;
305 if (receiver_feedback_) {
306 receiver_feedback_->OnReceiverReferenceTimeReport(remote_time_report);
310 void RtcpReceiver::HandleDlrr(RtcpParser* rtcp_parser) {
311 const RtcpField& rtcp_field = rtcp_parser->Field();
312 if (remote_ssrc_ != rtcp_field.dlrr.receivers_ssrc) {
317 rtt_feedback_->OnReceivedDelaySinceLastReport(
318 rtcp_field.dlrr.receivers_ssrc,
319 rtcp_field.dlrr.last_receiver_report,
320 rtcp_field.dlrr.delay_last_receiver_report);
324 void RtcpReceiver::HandleNACK(RtcpParser* rtcp_parser) {
325 const RtcpField& rtcp_field = rtcp_parser->Field();
326 if (ssrc_ != rtcp_field.nack.media_ssrc) {
327 RtcpFieldTypes field_type;
328 // Message not to us. Iterate until we have passed this message.
330 field_type = rtcp_parser->Iterate();
331 } while (field_type == kRtcpGenericRtpFeedbackNackItemCode);
334 std::list<uint16> nackSequenceNumbers;
336 RtcpFieldTypes field_type = rtcp_parser->Iterate();
337 while (field_type == kRtcpGenericRtpFeedbackNackItemCode) {
338 HandleNACKItem(&rtcp_field, &nackSequenceNumbers);
339 field_type = rtcp_parser->Iterate();
343 void RtcpReceiver::HandleNACKItem(const RtcpField* rtcp_field,
344 std::list<uint16>* nack_sequence_numbers) {
345 nack_sequence_numbers->push_back(rtcp_field->nack_item.packet_id);
347 uint16 bitmask = rtcp_field->nack_item.bitmask;
349 for (int i = 1; i <= 16; ++i) {
351 nack_sequence_numbers->push_back(rtcp_field->nack_item.packet_id + i);
353 bitmask = bitmask >> 1;
358 void RtcpReceiver::HandleBYE(RtcpParser* rtcp_parser) {
359 const RtcpField& rtcp_field = rtcp_parser->Field();
360 uint32 remote_ssrc = rtcp_field.bye.sender_ssrc;
361 if (remote_ssrc_ == remote_ssrc) {
362 VLOG(2) << "Cast RTCP received BYE from SSRC " << remote_ssrc;
364 rtcp_parser->Iterate();
367 void RtcpReceiver::HandlePLI(RtcpParser* rtcp_parser) {
368 const RtcpField& rtcp_field = rtcp_parser->Field();
369 if (ssrc_ == rtcp_field.pli.media_ssrc) {
370 // Received a signal that we need to send a new key frame.
371 VLOG(2) << "Cast RTCP received PLI on our SSRC " << ssrc_;
373 rtcp_parser->Iterate();
376 void RtcpReceiver::HandleSendReportRequest(RtcpParser* rtcp_parser) {
377 if (receiver_feedback_) {
378 receiver_feedback_->OnReceivedSendReportRequest();
380 rtcp_parser->Iterate();
383 void RtcpReceiver::HandleRpsi(RtcpParser* rtcp_parser) {
384 const RtcpField& rtcp_field = rtcp_parser->Field();
385 if (rtcp_parser->Iterate() != kRtcpPayloadSpecificRpsiCode) {
388 if (rtcp_field.rpsi.number_of_valid_bits % 8 != 0) {
392 uint64 rpsi_picture_id = 0;
394 // Convert native_bit_string to rpsi_picture_id
395 uint8 bytes = rtcp_field.rpsi.number_of_valid_bits / 8;
396 for (uint8 n = 0; n < (bytes - 1); ++n) {
397 rpsi_picture_id += (rtcp_field.rpsi.native_bit_string[n] & 0x7f);
398 rpsi_picture_id <<= 7; // Prepare next.
400 rpsi_picture_id += (rtcp_field.rpsi.native_bit_string[bytes - 1] & 0x7f);
402 VLOG(2) << "Cast RTCP received RPSI with picture_id " << rpsi_picture_id;
405 void RtcpReceiver::HandlePayloadSpecificApp(RtcpParser* rtcp_parser) {
406 const RtcpField& rtcp_field = rtcp_parser->Field();
407 uint32 remote_ssrc = rtcp_field.application_specific.sender_ssrc;
408 if (remote_ssrc_ != remote_ssrc) {
409 // Message not to us. Iterate until we have passed this message.
410 RtcpFieldTypes field_type;
412 field_type = rtcp_parser->Iterate();
413 } while (field_type == kRtcpPayloadSpecificRembCode ||
414 field_type == kRtcpPayloadSpecificRembItemCode ||
415 field_type == kRtcpPayloadSpecificCastCode ||
416 field_type == kRtcpPayloadSpecificCastNackItemCode);
420 RtcpFieldTypes packet_type = rtcp_parser->Iterate();
421 switch (packet_type) {
422 case kRtcpPayloadSpecificRembCode:
423 packet_type = rtcp_parser->Iterate();
424 if (packet_type == kRtcpPayloadSpecificRembItemCode) {
425 HandlePayloadSpecificRembItem(rtcp_parser);
426 rtcp_parser->Iterate();
429 case kRtcpPayloadSpecificCastCode:
430 packet_type = rtcp_parser->Iterate();
431 if (packet_type == kRtcpPayloadSpecificCastCode) {
432 HandlePayloadSpecificCastItem(rtcp_parser);
440 void RtcpReceiver::HandlePayloadSpecificRembItem(RtcpParser* rtcp_parser) {
441 const RtcpField& rtcp_field = rtcp_parser->Field();
443 for (int i = 0; i < rtcp_field.remb_item.number_of_ssrcs; ++i) {
444 if (rtcp_field.remb_item.ssrcs[i] == ssrc_) {
445 // Found matching ssrc.
446 VLOG(2) << "Cast RTCP received REMB with received_bitrate "
447 << rtcp_field.remb_item.bitrate;
453 void RtcpReceiver::HandleApplicationSpecificCastReceiverLog(
454 RtcpParser* rtcp_parser) {
455 const RtcpField& rtcp_field = rtcp_parser->Field();
457 uint32 remote_ssrc = rtcp_field.cast_receiver_log.sender_ssrc;
458 if (remote_ssrc_ != remote_ssrc) {
459 // Message not to us. Iterate until we have passed this message.
460 RtcpFieldTypes field_type;
462 field_type = rtcp_parser->Iterate();
463 } while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode ||
464 field_type == kRtcpApplicationSpecificCastReceiverLogEventCode);
467 RtcpReceiverLogMessage receiver_log;
468 RtcpFieldTypes field_type = rtcp_parser->Iterate();
469 while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode) {
470 RtcpReceiverFrameLogMessage frame_log(
471 rtcp_field.cast_receiver_log.rtp_timestamp);
473 field_type = rtcp_parser->Iterate();
474 while (field_type == kRtcpApplicationSpecificCastReceiverLogEventCode) {
475 HandleApplicationSpecificCastReceiverEventLog(
476 rtcp_field.cast_receiver_log.rtp_timestamp,
478 &frame_log.event_log_messages_);
479 field_type = rtcp_parser->Iterate();
482 if (!frame_log.event_log_messages_.empty())
483 receiver_log.push_back(frame_log);
486 if (receiver_feedback_ && !receiver_log.empty()) {
487 receiver_feedback_->OnReceivedReceiverLog(receiver_log);
491 void RtcpReceiver::HandleApplicationSpecificCastReceiverEventLog(
492 uint32 frame_rtp_timestamp,
493 RtcpParser* rtcp_parser,
494 RtcpReceiverEventLogMessages* event_log_messages) {
495 const RtcpField& rtcp_field = rtcp_parser->Field();
497 const CastLoggingEvent event_type =
498 TranslateToLogEventFromWireFormat(rtcp_field.cast_receiver_log.event);
499 const base::TimeTicks event_timestamp =
501 base::TimeDelta::FromMilliseconds(
502 rtcp_field.cast_receiver_log.event_timestamp_base +
503 rtcp_field.cast_receiver_log.event_timestamp_delta);
505 // The following code checks to see if we have already seen this event.
506 // The algorithm works by maintaining a sliding window of events. We have
507 // a queue and a set of events. We enqueue every new event and insert it
508 // into the set. When the queue becomes too big we remove the oldest event
509 // from both the queue and the set.
510 // Different events may have the same hash value. That's okay because full
511 // accuracy is not important in this case.
512 const size_t event_hash =
513 HashReceiverEvent(frame_rtp_timestamp, event_timestamp, event_type);
514 if (receiver_event_hash_set_.find(event_hash) !=
515 receiver_event_hash_set_.end()) {
518 receiver_event_hash_set_.insert(event_hash);
519 receiver_event_hash_queue_.push(event_hash);
521 if (receiver_event_hash_queue_.size() > receiver_event_history_size_) {
522 const size_t oldest_hash = receiver_event_hash_queue_.front();
523 receiver_event_hash_queue_.pop();
524 receiver_event_hash_set_.erase(oldest_hash);
528 RtcpReceiverEventLogMessage event_log;
529 event_log.type = event_type;
530 event_log.event_timestamp = event_timestamp;
531 event_log.delay_delta = base::TimeDelta::FromMilliseconds(
532 rtcp_field.cast_receiver_log.delay_delta_or_packet_id);
533 event_log.packet_id = rtcp_field.cast_receiver_log.delay_delta_or_packet_id;
534 event_log_messages->push_back(event_log);
537 void RtcpReceiver::HandleApplicationSpecificCastSenderLog(
538 RtcpParser* rtcp_parser) {
539 const RtcpField& rtcp_field = rtcp_parser->Field();
540 uint32 remote_ssrc = rtcp_field.cast_sender_log.sender_ssrc;
542 if (remote_ssrc_ != remote_ssrc) {
543 RtcpFieldTypes field_type;
544 // Message not to us. Iterate until we have passed this message.
546 field_type = rtcp_parser->Iterate();
547 } while (field_type == kRtcpApplicationSpecificCastSenderLogCode);
550 transport::RtcpSenderLogMessage sender_log;
552 RtcpFieldTypes field_type = rtcp_parser->Iterate();
553 while (field_type == kRtcpApplicationSpecificCastSenderLogCode) {
554 const RtcpField& rtcp_field = rtcp_parser->Field();
555 transport::RtcpSenderFrameLogMessage frame_log;
556 frame_log.frame_status =
557 TranslateToFrameStatusFromWireFormat(rtcp_field.cast_sender_log.status);
558 frame_log.rtp_timestamp = rtcp_field.cast_sender_log.rtp_timestamp;
559 sender_log.push_back(frame_log);
560 field_type = rtcp_parser->Iterate();
562 if (receiver_feedback_) {
563 receiver_feedback_->OnReceivedSenderLog(sender_log);
567 void RtcpReceiver::HandlePayloadSpecificCastItem(RtcpParser* rtcp_parser) {
568 const RtcpField& rtcp_field = rtcp_parser->Field();
569 RtcpCastMessage cast_message(remote_ssrc_);
570 cast_message.ack_frame_id_ = ack_frame_id_wrap_helper_.MapTo32bitsFrameId(
571 rtcp_field.cast_item.last_frame_id);
572 cast_message.target_delay_ms_ = rtcp_field.cast_item.target_delay_ms;
574 RtcpFieldTypes packet_type = rtcp_parser->Iterate();
575 while (packet_type == kRtcpPayloadSpecificCastNackItemCode) {
576 const RtcpField& rtcp_field = rtcp_parser->Field();
577 HandlePayloadSpecificCastNackItem(
578 &rtcp_field, &cast_message.missing_frames_and_packets_);
579 packet_type = rtcp_parser->Iterate();
581 if (sender_feedback_) {
582 sender_feedback_->OnReceivedCastFeedback(cast_message);
586 void RtcpReceiver::HandlePayloadSpecificCastNackItem(
587 const RtcpField* rtcp_field,
588 MissingFramesAndPacketsMap* missing_frames_and_packets) {
590 MissingFramesAndPacketsMap::iterator frame_it =
591 missing_frames_and_packets->find(rtcp_field->cast_nack_item.frame_id);
593 if (frame_it == missing_frames_and_packets->end()) {
594 // First missing packet in a frame.
595 PacketIdSet empty_set;
596 std::pair<MissingFramesAndPacketsMap::iterator, bool> ret =
597 missing_frames_and_packets->insert(std::pair<uint8, PacketIdSet>(
598 rtcp_field->cast_nack_item.frame_id, empty_set));
599 frame_it = ret.first;
600 DCHECK(frame_it != missing_frames_and_packets->end()) << "Invalid state";
602 if (rtcp_field->cast_nack_item.packet_id == kRtcpCastAllPacketsLost) {
603 // Special case all packets in a frame is missing.
606 uint16 packet_id = rtcp_field->cast_nack_item.packet_id;
607 uint8 bitmask = rtcp_field->cast_nack_item.bitmask;
609 frame_it->second.insert(packet_id);
612 for (int i = 1; i <= 8; ++i) {
614 frame_it->second.insert(packet_id + i);
616 bitmask = bitmask >> 1;
621 void RtcpReceiver::HandleFIR(RtcpParser* rtcp_parser) {
622 const RtcpField& rtcp_field = rtcp_parser->Field();
624 RtcpFieldTypes field_type = rtcp_parser->Iterate();
625 while (field_type == kRtcpPayloadSpecificFirItemCode) {
626 HandleFIRItem(&rtcp_field);
627 field_type = rtcp_parser->Iterate();
631 void RtcpReceiver::HandleFIRItem(const RtcpField* rtcp_field) {
632 // Is it our sender that is requested to generate a new keyframe.
633 if (ssrc_ != rtcp_field->fir_item.ssrc)
636 VLOG(2) << "Cast RTCP received FIR on our SSRC " << ssrc_;