Remove Unused AsTextButtonBorder RTTI helper.
[chromium-blink-merge.git] / media / cast / rtcp / rtcp_receiver.cc
blob00b5ae6071862ccd89bd5241c9cc882c2825baea
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"
11 namespace {
13 media::cast::CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event) {
14 switch (event) {
15 case 1:
16 return media::cast::kAudioAckSent;
17 case 2:
18 return media::cast::kAudioPlayoutDelay;
19 case 3:
20 return media::cast::kAudioFrameDecoded;
21 case 4:
22 return media::cast::kAudioPacketReceived;
23 case 5:
24 return media::cast::kVideoAckSent;
25 case 6:
26 return media::cast::kVideoFrameDecoded;
27 case 7:
28 return media::cast::kVideoRenderDelay;
29 case 8:
30 return media::cast::kVideoPacketReceived;
31 case 9:
32 return media::cast::kDuplicatePacketReceived;
33 default:
34 // If the sender adds new log messages we will end up here until we add
35 // the new messages in the receiver.
36 VLOG(1) << "Unexpected log message received: " << static_cast<int>(event);
37 NOTREACHED();
38 return media::cast::kUnknown;
42 media::cast::transport::RtcpSenderFrameStatus
43 TranslateToFrameStatusFromWireFormat(uint8 status) {
44 switch (status) {
45 case 0:
46 return media::cast::transport::kRtcpSenderFrameStatusUnknown;
47 case 1:
48 return media::cast::transport::kRtcpSenderFrameStatusDroppedByEncoder;
49 case 2:
50 return media::cast::transport::kRtcpSenderFrameStatusDroppedByFlowControl;
51 case 3:
52 return media::cast::transport::kRtcpSenderFrameStatusSentToNetwork;
53 default:
54 // If the sender adds new log messages we will end up here until we add
55 // the new messages in the receiver.
56 NOTREACHED();
57 VLOG(1) << "Unexpected status received: " << static_cast<int>(status);
58 return media::cast::transport::kRtcpSenderFrameStatusUnknown;
62 } // namespace
64 namespace media {
65 namespace cast {
67 RtcpReceiver::RtcpReceiver(scoped_refptr<CastEnvironment> cast_environment,
68 RtcpSenderFeedback* sender_feedback,
69 RtcpReceiverFeedback* receiver_feedback,
70 RtcpRttFeedback* rtt_feedback,
71 uint32 local_ssrc)
72 : ssrc_(local_ssrc),
73 remote_ssrc_(0),
74 sender_feedback_(sender_feedback),
75 receiver_feedback_(receiver_feedback),
76 rtt_feedback_(rtt_feedback),
77 cast_environment_(cast_environment) {}
79 RtcpReceiver::~RtcpReceiver() {}
81 void RtcpReceiver::SetRemoteSSRC(uint32 ssrc) { remote_ssrc_ = ssrc; }
83 void RtcpReceiver::IncomingRtcpPacket(RtcpParser* rtcp_parser) {
84 RtcpFieldTypes field_type = rtcp_parser->Begin();
85 while (field_type != kRtcpNotValidCode) {
86 // Each "case" is responsible for iterate the parser to the next top
87 // level packet.
88 switch (field_type) {
89 case kRtcpSrCode:
90 HandleSenderReport(rtcp_parser);
91 break;
92 case kRtcpRrCode:
93 HandleReceiverReport(rtcp_parser);
94 break;
95 case kRtcpSdesCode:
96 HandleSDES(rtcp_parser);
97 break;
98 case kRtcpByeCode:
99 HandleBYE(rtcp_parser);
100 break;
101 case kRtcpXrCode:
102 HandleXr(rtcp_parser);
103 break;
104 case kRtcpGenericRtpFeedbackNackCode:
105 HandleNACK(rtcp_parser);
106 break;
107 case kRtcpGenericRtpFeedbackSrReqCode:
108 HandleSendReportRequest(rtcp_parser);
109 break;
110 case kRtcpPayloadSpecificPliCode:
111 HandlePLI(rtcp_parser);
112 break;
113 case kRtcpPayloadSpecificRpsiCode:
114 HandleRpsi(rtcp_parser);
115 break;
116 case kRtcpPayloadSpecificFirCode:
117 HandleFIR(rtcp_parser);
118 break;
119 case kRtcpPayloadSpecificAppCode:
120 HandlePayloadSpecificApp(rtcp_parser);
121 break;
122 case kRtcpApplicationSpecificCastReceiverLogCode:
123 HandleApplicationSpecificCastReceiverLog(rtcp_parser);
124 break;
125 case kRtcpApplicationSpecificCastSenderLogCode:
126 HandleApplicationSpecificCastSenderLog(rtcp_parser);
127 break;
128 case kRtcpPayloadSpecificRembCode:
129 case kRtcpPayloadSpecificRembItemCode:
130 case kRtcpPayloadSpecificCastCode:
131 case kRtcpPayloadSpecificCastNackItemCode:
132 case kRtcpApplicationSpecificCastReceiverLogFrameCode:
133 case kRtcpApplicationSpecificCastReceiverLogEventCode:
134 case kRtcpNotValidCode:
135 case kRtcpReportBlockItemCode:
136 case kRtcpSdesChunkCode:
137 case kRtcpGenericRtpFeedbackNackItemCode:
138 case kRtcpPayloadSpecificFirItemCode:
139 case kRtcpXrRrtrCode:
140 case kRtcpXrDlrrCode:
141 case kRtcpXrUnknownItemCode:
142 rtcp_parser->Iterate();
143 NOTREACHED() << "Invalid state";
144 break;
146 field_type = rtcp_parser->FieldType();
150 void RtcpReceiver::HandleSenderReport(RtcpParser* rtcp_parser) {
151 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
152 const RtcpField& rtcp_field = rtcp_parser->Field();
154 DCHECK(rtcp_field_type == kRtcpSrCode) << "Invalid state";
156 // Synchronization source identifier for the originator of this SR packet.
157 uint32 remote_ssrc = rtcp_field.sender_report.sender_ssrc;
159 VLOG(1) << "Cast RTCP received SR from SSRC " << remote_ssrc;
161 if (remote_ssrc_ == remote_ssrc) {
162 transport::RtcpSenderInfo remote_sender_info;
163 remote_sender_info.ntp_seconds =
164 rtcp_field.sender_report.ntp_most_significant;
165 remote_sender_info.ntp_fraction =
166 rtcp_field.sender_report.ntp_least_significant;
167 remote_sender_info.rtp_timestamp = rtcp_field.sender_report.rtp_timestamp;
168 remote_sender_info.send_packet_count =
169 rtcp_field.sender_report.sender_packet_count;
170 remote_sender_info.send_octet_count =
171 rtcp_field.sender_report.sender_octet_count;
172 if (receiver_feedback_) {
173 receiver_feedback_->OnReceivedSenderReport(remote_sender_info);
176 rtcp_field_type = rtcp_parser->Iterate();
177 while (rtcp_field_type == kRtcpReportBlockItemCode) {
178 HandleReportBlock(&rtcp_field, remote_ssrc);
179 rtcp_field_type = rtcp_parser->Iterate();
183 void RtcpReceiver::HandleReceiverReport(RtcpParser* rtcp_parser) {
184 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
185 const RtcpField& rtcp_field = rtcp_parser->Field();
187 DCHECK(rtcp_field_type == kRtcpRrCode) << "Invalid state";
189 uint32 remote_ssrc = rtcp_field.receiver_report.sender_ssrc;
191 VLOG(1) << "Cast RTCP received RR from SSRC " << remote_ssrc;
193 rtcp_field_type = rtcp_parser->Iterate();
194 while (rtcp_field_type == kRtcpReportBlockItemCode) {
195 HandleReportBlock(&rtcp_field, remote_ssrc);
196 rtcp_field_type = rtcp_parser->Iterate();
200 void RtcpReceiver::HandleReportBlock(const RtcpField* rtcp_field,
201 uint32 remote_ssrc) {
202 // This will be called once per report block in the Rtcp packet.
203 // We filter out all report blocks that are not for us.
204 // Each packet has max 31 RR blocks.
206 // We can calculate RTT if we send a send report and get a report block back.
208 // |rtcp_field.ReportBlockItem.ssrc| is the ssrc identifier of the source to
209 // which the information in this reception report block pertains.
211 const RtcpFieldReportBlockItem& rb = rtcp_field->report_block_item;
213 // Filter out all report blocks that are not for us.
214 if (rb.ssrc != ssrc_) {
215 // This block is not for us ignore it.
216 return;
218 VLOG(1) << "Cast RTCP received RB from SSRC " << remote_ssrc;
219 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
220 cast_environment_->Logging()->InsertGenericEvent(
221 now, kPacketLoss, rb.fraction_lost);
222 cast_environment_->Logging()->InsertGenericEvent(now, kJitterMs, rb.jitter);
224 transport::RtcpReportBlock report_block;
225 report_block.remote_ssrc = remote_ssrc;
226 report_block.media_ssrc = rb.ssrc;
227 report_block.fraction_lost = rb.fraction_lost;
228 report_block.cumulative_lost = rb.cumulative_number_of_packets_lost;
229 report_block.extended_high_sequence_number =
230 rb.extended_highest_sequence_number;
231 report_block.jitter = rb.jitter;
232 report_block.last_sr = rb.last_sender_report;
233 report_block.delay_since_last_sr = rb.delay_last_sender_report;
235 if (rtt_feedback_) {
236 rtt_feedback_->OnReceivedDelaySinceLastReport(
237 rb.ssrc, rb.last_sender_report, rb.delay_last_sender_report);
241 void RtcpReceiver::HandleSDES(RtcpParser* rtcp_parser) {
242 RtcpFieldTypes field_type = rtcp_parser->Iterate();
243 while (field_type == kRtcpSdesChunkCode) {
244 HandleSDESChunk(rtcp_parser);
245 field_type = rtcp_parser->Iterate();
249 void RtcpReceiver::HandleSDESChunk(RtcpParser* rtcp_parser) {
250 const RtcpField& rtcp_field = rtcp_parser->Field();
251 VLOG(1) << "Cast RTCP received SDES with cname " << rtcp_field.c_name.name;
254 void RtcpReceiver::HandleXr(RtcpParser* rtcp_parser) {
255 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType();
256 const RtcpField& rtcp_field = rtcp_parser->Field();
258 DCHECK(rtcp_field_type == kRtcpXrCode) << "Invalid state";
260 uint32 remote_ssrc = rtcp_field.extended_report.sender_ssrc;
261 rtcp_field_type = rtcp_parser->Iterate();
263 while (rtcp_field_type == kRtcpXrDlrrCode ||
264 rtcp_field_type == kRtcpXrRrtrCode ||
265 rtcp_field_type == kRtcpXrUnknownItemCode) {
266 if (rtcp_field_type == kRtcpXrRrtrCode) {
267 HandleRrtr(rtcp_parser, remote_ssrc);
268 } else if (rtcp_field_type == kRtcpXrDlrrCode) {
269 HandleDlrr(rtcp_parser);
271 rtcp_field_type = rtcp_parser->Iterate();
275 void RtcpReceiver::HandleRrtr(RtcpParser* rtcp_parser, uint32 remote_ssrc) {
276 if (remote_ssrc_ != remote_ssrc) {
277 // Not to us.
278 return;
280 const RtcpField& rtcp_field = rtcp_parser->Field();
281 RtcpReceiverReferenceTimeReport remote_time_report;
282 remote_time_report.remote_ssrc = remote_ssrc;
283 remote_time_report.ntp_seconds = rtcp_field.rrtr.ntp_most_significant;
284 remote_time_report.ntp_fraction = rtcp_field.rrtr.ntp_least_significant;
286 if (receiver_feedback_) {
287 receiver_feedback_->OnReceiverReferenceTimeReport(remote_time_report);
291 void RtcpReceiver::HandleDlrr(RtcpParser* rtcp_parser) {
292 const RtcpField& rtcp_field = rtcp_parser->Field();
293 if (remote_ssrc_ != rtcp_field.dlrr.receivers_ssrc) {
294 // Not to us.
295 return;
297 if (rtt_feedback_) {
298 rtt_feedback_->OnReceivedDelaySinceLastReport(
299 rtcp_field.dlrr.receivers_ssrc,
300 rtcp_field.dlrr.last_receiver_report,
301 rtcp_field.dlrr.delay_last_receiver_report);
305 void RtcpReceiver::HandleNACK(RtcpParser* rtcp_parser) {
306 const RtcpField& rtcp_field = rtcp_parser->Field();
307 if (ssrc_ != rtcp_field.nack.media_ssrc) {
308 RtcpFieldTypes field_type;
309 // Message not to us. Iterate until we have passed this message.
310 do {
311 field_type = rtcp_parser->Iterate();
312 } while (field_type == kRtcpGenericRtpFeedbackNackItemCode);
313 return;
315 std::list<uint16> nackSequenceNumbers;
317 RtcpFieldTypes field_type = rtcp_parser->Iterate();
318 while (field_type == kRtcpGenericRtpFeedbackNackItemCode) {
319 HandleNACKItem(&rtcp_field, &nackSequenceNumbers);
320 field_type = rtcp_parser->Iterate();
324 void RtcpReceiver::HandleNACKItem(const RtcpField* rtcp_field,
325 std::list<uint16>* nack_sequence_numbers) {
326 nack_sequence_numbers->push_back(rtcp_field->nack_item.packet_id);
328 uint16 bitmask = rtcp_field->nack_item.bitmask;
329 if (bitmask) {
330 for (int i = 1; i <= 16; ++i) {
331 if (bitmask & 1) {
332 nack_sequence_numbers->push_back(rtcp_field->nack_item.packet_id + i);
334 bitmask = bitmask >> 1;
339 void RtcpReceiver::HandleBYE(RtcpParser* rtcp_parser) {
340 const RtcpField& rtcp_field = rtcp_parser->Field();
341 uint32 remote_ssrc = rtcp_field.bye.sender_ssrc;
342 if (remote_ssrc_ == remote_ssrc) {
343 VLOG(1) << "Cast RTCP received BYE from SSRC " << remote_ssrc;
345 rtcp_parser->Iterate();
348 void RtcpReceiver::HandlePLI(RtcpParser* rtcp_parser) {
349 const RtcpField& rtcp_field = rtcp_parser->Field();
350 if (ssrc_ == rtcp_field.pli.media_ssrc) {
351 // Received a signal that we need to send a new key frame.
352 VLOG(1) << "Cast RTCP received PLI on our SSRC " << ssrc_;
354 rtcp_parser->Iterate();
357 void RtcpReceiver::HandleSendReportRequest(RtcpParser* rtcp_parser) {
358 if (receiver_feedback_) {
359 receiver_feedback_->OnReceivedSendReportRequest();
361 rtcp_parser->Iterate();
364 void RtcpReceiver::HandleRpsi(RtcpParser* rtcp_parser) {
365 const RtcpField& rtcp_field = rtcp_parser->Field();
366 if (rtcp_parser->Iterate() != kRtcpPayloadSpecificRpsiCode) {
367 return;
369 if (rtcp_field.rpsi.number_of_valid_bits % 8 != 0) {
370 // Continue
371 return;
373 uint64 rpsi_picture_id = 0;
375 // Convert native_bit_string to rpsi_picture_id
376 uint8 bytes = rtcp_field.rpsi.number_of_valid_bits / 8;
377 for (uint8 n = 0; n < (bytes - 1); ++n) {
378 rpsi_picture_id += (rtcp_field.rpsi.native_bit_string[n] & 0x7f);
379 rpsi_picture_id <<= 7; // Prepare next.
381 rpsi_picture_id += (rtcp_field.rpsi.native_bit_string[bytes - 1] & 0x7f);
383 VLOG(1) << "Cast RTCP received RPSI with picture_id " << rpsi_picture_id;
386 void RtcpReceiver::HandlePayloadSpecificApp(RtcpParser* rtcp_parser) {
387 const RtcpField& rtcp_field = rtcp_parser->Field();
388 uint32 remote_ssrc = rtcp_field.application_specific.sender_ssrc;
389 if (remote_ssrc_ != remote_ssrc) {
390 // Message not to us. Iterate until we have passed this message.
391 RtcpFieldTypes field_type;
392 do {
393 field_type = rtcp_parser->Iterate();
394 } while (field_type == kRtcpPayloadSpecificRembCode ||
395 field_type == kRtcpPayloadSpecificRembItemCode ||
396 field_type == kRtcpPayloadSpecificCastCode ||
397 field_type == kRtcpPayloadSpecificCastNackItemCode);
398 return;
401 RtcpFieldTypes packet_type = rtcp_parser->Iterate();
402 switch (packet_type) {
403 case kRtcpPayloadSpecificRembCode:
404 packet_type = rtcp_parser->Iterate();
405 if (packet_type == kRtcpPayloadSpecificRembItemCode) {
406 HandlePayloadSpecificRembItem(rtcp_parser);
407 rtcp_parser->Iterate();
409 break;
410 case kRtcpPayloadSpecificCastCode:
411 packet_type = rtcp_parser->Iterate();
412 if (packet_type == kRtcpPayloadSpecificCastCode) {
413 HandlePayloadSpecificCastItem(rtcp_parser);
415 break;
416 default:
417 return;
421 void RtcpReceiver::HandlePayloadSpecificRembItem(RtcpParser* rtcp_parser) {
422 const RtcpField& rtcp_field = rtcp_parser->Field();
424 for (int i = 0; i < rtcp_field.remb_item.number_of_ssrcs; ++i) {
425 if (rtcp_field.remb_item.ssrcs[i] == ssrc_) {
426 // Found matching ssrc.
427 VLOG(1) << "Cast RTCP received REMB with received_bitrate "
428 << rtcp_field.remb_item.bitrate;
429 return;
434 void RtcpReceiver::HandleApplicationSpecificCastReceiverLog(
435 RtcpParser* rtcp_parser) {
436 const RtcpField& rtcp_field = rtcp_parser->Field();
438 uint32 remote_ssrc = rtcp_field.cast_receiver_log.sender_ssrc;
439 if (remote_ssrc_ != remote_ssrc) {
440 // Message not to us. Iterate until we have passed this message.
441 RtcpFieldTypes field_type;
442 do {
443 field_type = rtcp_parser->Iterate();
444 } while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode ||
445 field_type == kRtcpApplicationSpecificCastReceiverLogEventCode);
446 return;
448 RtcpReceiverLogMessage receiver_log;
449 RtcpFieldTypes field_type = rtcp_parser->Iterate();
450 while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode) {
451 RtcpReceiverFrameLogMessage frame_log(
452 rtcp_field.cast_receiver_log.rtp_timestamp);
454 field_type = rtcp_parser->Iterate();
455 while (field_type == kRtcpApplicationSpecificCastReceiverLogEventCode) {
456 HandleApplicationSpecificCastReceiverEventLog(
457 rtcp_parser, &frame_log.event_log_messages_);
458 field_type = rtcp_parser->Iterate();
460 receiver_log.push_back(frame_log);
463 if (receiver_feedback_ && !receiver_log.empty()) {
464 receiver_feedback_->OnReceivedReceiverLog(receiver_log);
468 void RtcpReceiver::HandleApplicationSpecificCastReceiverEventLog(
469 RtcpParser* rtcp_parser,
470 RtcpReceiverEventLogMessages* event_log_messages) {
471 const RtcpField& rtcp_field = rtcp_parser->Field();
473 RtcpReceiverEventLogMessage event_log;
474 event_log.type =
475 TranslateToLogEventFromWireFormat(rtcp_field.cast_receiver_log.event);
476 event_log.event_timestamp =
477 base::TimeTicks() +
478 base::TimeDelta::FromMilliseconds(
479 rtcp_field.cast_receiver_log.event_timestamp_base +
480 rtcp_field.cast_receiver_log.event_timestamp_delta);
481 event_log.delay_delta = base::TimeDelta::FromMilliseconds(
482 rtcp_field.cast_receiver_log.delay_delta_or_packet_id);
483 event_log.packet_id = rtcp_field.cast_receiver_log.delay_delta_or_packet_id;
484 event_log_messages->push_back(event_log);
487 void RtcpReceiver::HandleApplicationSpecificCastSenderLog(
488 RtcpParser* rtcp_parser) {
489 const RtcpField& rtcp_field = rtcp_parser->Field();
490 uint32 remote_ssrc = rtcp_field.cast_sender_log.sender_ssrc;
492 if (remote_ssrc_ != remote_ssrc) {
493 RtcpFieldTypes field_type;
494 // Message not to us. Iterate until we have passed this message.
495 do {
496 field_type = rtcp_parser->Iterate();
497 } while (field_type == kRtcpApplicationSpecificCastSenderLogCode);
498 return;
500 transport::RtcpSenderLogMessage sender_log;
502 RtcpFieldTypes field_type = rtcp_parser->Iterate();
503 while (field_type == kRtcpApplicationSpecificCastSenderLogCode) {
504 const RtcpField& rtcp_field = rtcp_parser->Field();
505 transport::RtcpSenderFrameLogMessage frame_log;
506 frame_log.frame_status =
507 TranslateToFrameStatusFromWireFormat(rtcp_field.cast_sender_log.status);
508 frame_log.rtp_timestamp = rtcp_field.cast_sender_log.rtp_timestamp;
509 sender_log.push_back(frame_log);
510 field_type = rtcp_parser->Iterate();
512 if (receiver_feedback_) {
513 receiver_feedback_->OnReceivedSenderLog(sender_log);
517 void RtcpReceiver::HandlePayloadSpecificCastItem(RtcpParser* rtcp_parser) {
518 const RtcpField& rtcp_field = rtcp_parser->Field();
519 RtcpCastMessage cast_message(remote_ssrc_);
520 cast_message.ack_frame_id_ = ack_frame_id_wrap_helper_.MapTo32bitsFrameId(
521 rtcp_field.cast_item.last_frame_id);
523 RtcpFieldTypes packet_type = rtcp_parser->Iterate();
524 while (packet_type == kRtcpPayloadSpecificCastNackItemCode) {
525 const RtcpField& rtcp_field = rtcp_parser->Field();
526 HandlePayloadSpecificCastNackItem(
527 &rtcp_field, &cast_message.missing_frames_and_packets_);
528 packet_type = rtcp_parser->Iterate();
530 if (sender_feedback_) {
531 sender_feedback_->OnReceivedCastFeedback(cast_message);
535 void RtcpReceiver::HandlePayloadSpecificCastNackItem(
536 const RtcpField* rtcp_field,
537 MissingFramesAndPacketsMap* missing_frames_and_packets) {
539 MissingFramesAndPacketsMap::iterator frame_it =
540 missing_frames_and_packets->find(rtcp_field->cast_nack_item.frame_id);
542 if (frame_it == missing_frames_and_packets->end()) {
543 // First missing packet in a frame.
544 PacketIdSet empty_set;
545 std::pair<MissingFramesAndPacketsMap::iterator, bool> ret =
546 missing_frames_and_packets->insert(std::pair<uint8, PacketIdSet>(
547 rtcp_field->cast_nack_item.frame_id, empty_set));
548 frame_it = ret.first;
549 DCHECK(frame_it != missing_frames_and_packets->end()) << "Invalid state";
551 if (rtcp_field->cast_nack_item.packet_id == kRtcpCastAllPacketsLost) {
552 // Special case all packets in a frame is missing.
553 return;
555 uint16 packet_id = rtcp_field->cast_nack_item.packet_id;
556 uint8 bitmask = rtcp_field->cast_nack_item.bitmask;
558 frame_it->second.insert(packet_id);
560 if (bitmask) {
561 for (int i = 1; i <= 8; ++i) {
562 if (bitmask & 1) {
563 frame_it->second.insert(packet_id + i);
565 bitmask = bitmask >> 1;
570 void RtcpReceiver::HandleFIR(RtcpParser* rtcp_parser) {
571 const RtcpField& rtcp_field = rtcp_parser->Field();
573 RtcpFieldTypes field_type = rtcp_parser->Iterate();
574 while (field_type == kRtcpPayloadSpecificFirItemCode) {
575 HandleFIRItem(&rtcp_field);
576 field_type = rtcp_parser->Iterate();
580 void RtcpReceiver::HandleFIRItem(const RtcpField* rtcp_field) {
581 // Is it our sender that is requested to generate a new keyframe.
582 if (ssrc_ != rtcp_field->fir_item.ssrc)
583 return;
585 VLOG(1) << "Cast RTCP received FIR on our SSRC " << ssrc_;
588 } // namespace cast
589 } // namespace media