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. 4 5 #include "media/cast/rtcp/rtcp_receiver.h" 6 7 #include "base/logging.h" 8 #include "media/cast/rtcp/rtcp_utility.h" 9 #include "media/cast/transport/cast_transport_defines.h" 10 11 namespace { 12 13 // A receiver frame event is identified by frame RTP timestamp, event timestamp 14 // and event type. 15 // A receiver packet event is identified by all of the above plus packet id. 16 // The key format is as follows: 17 // First uint64: 18 // bits 0-11: zeroes (unused). 19 // bits 12-15: event type ID. 20 // bits 16-31: packet ID if packet event, 0 otherwise. 21 // bits 32-63: RTP timestamp. 22 // Second uint64: 23 // bits 0-63: event TimeTicks internal value. 24 std::pair<uint64, uint64> GetReceiverEventKey( 25 uint32 frame_rtp_timestamp, const base::TimeTicks& event_timestamp, 26 uint8 event_type, uint16 packet_id_or_zero) { 27 uint64 value1 = event_type; 28 value1 <<= 16; 29 value1 |= packet_id_or_zero; 30 value1 <<= 32; 31 value1 |= frame_rtp_timestamp; 32 return std::make_pair( 33 value1, static_cast<uint64>(event_timestamp.ToInternalValue())); 34 } 35 36 } // namespace 37 38 namespace media { 39 namespace cast { 40 41 RtcpReceiver::RtcpReceiver(scoped_refptr<CastEnvironment> cast_environment, 42 RtcpSenderFeedback* sender_feedback, 43 RtcpReceiverFeedback* receiver_feedback, 44 RtcpRttFeedback* rtt_feedback, 45 uint32 local_ssrc) 46 : ssrc_(local_ssrc), 47 remote_ssrc_(0), 48 sender_feedback_(sender_feedback), 49 receiver_feedback_(receiver_feedback), 50 rtt_feedback_(rtt_feedback), 51 cast_environment_(cast_environment), 52 receiver_event_history_size_(0) {} 53 54 RtcpReceiver::~RtcpReceiver() {} 55 56 void RtcpReceiver::SetRemoteSSRC(uint32 ssrc) { remote_ssrc_ = ssrc; } 57 58 void RtcpReceiver::SetCastReceiverEventHistorySize(size_t size) { 59 receiver_event_history_size_ = size; 60 } 61 62 void RtcpReceiver::IncomingRtcpPacket(RtcpParser* rtcp_parser) { 63 RtcpFieldTypes field_type = rtcp_parser->Begin(); 64 while (field_type != kRtcpNotValidCode) { 65 // Each "case" is responsible for iterate the parser to the next top 66 // level packet. 67 switch (field_type) { 68 case kRtcpSrCode: 69 HandleSenderReport(rtcp_parser); 70 break; 71 case kRtcpRrCode: 72 HandleReceiverReport(rtcp_parser); 73 break; 74 case kRtcpSdesCode: 75 HandleSDES(rtcp_parser); 76 break; 77 case kRtcpByeCode: 78 HandleBYE(rtcp_parser); 79 break; 80 case kRtcpXrCode: 81 HandleXr(rtcp_parser); 82 break; 83 case kRtcpGenericRtpFeedbackNackCode: 84 HandleNACK(rtcp_parser); 85 break; 86 case kRtcpGenericRtpFeedbackSrReqCode: 87 HandleSendReportRequest(rtcp_parser); 88 break; 89 case kRtcpPayloadSpecificPliCode: 90 HandlePLI(rtcp_parser); 91 break; 92 case kRtcpPayloadSpecificRpsiCode: 93 HandleRpsi(rtcp_parser); 94 break; 95 case kRtcpPayloadSpecificFirCode: 96 HandleFIR(rtcp_parser); 97 break; 98 case kRtcpPayloadSpecificAppCode: 99 HandlePayloadSpecificApp(rtcp_parser); 100 break; 101 case kRtcpApplicationSpecificCastReceiverLogCode: 102 HandleApplicationSpecificCastReceiverLog(rtcp_parser); 103 break; 104 case kRtcpPayloadSpecificRembCode: 105 case kRtcpPayloadSpecificRembItemCode: 106 case kRtcpPayloadSpecificCastCode: 107 case kRtcpPayloadSpecificCastNackItemCode: 108 case kRtcpApplicationSpecificCastReceiverLogFrameCode: 109 case kRtcpApplicationSpecificCastReceiverLogEventCode: 110 case kRtcpNotValidCode: 111 case kRtcpReportBlockItemCode: 112 case kRtcpSdesChunkCode: 113 case kRtcpGenericRtpFeedbackNackItemCode: 114 case kRtcpPayloadSpecificFirItemCode: 115 case kRtcpXrRrtrCode: 116 case kRtcpXrDlrrCode: 117 case kRtcpXrUnknownItemCode: 118 rtcp_parser->Iterate(); 119 NOTREACHED() << "Invalid state"; 120 break; 121 } 122 field_type = rtcp_parser->FieldType(); 123 } 124 } 125 126 void RtcpReceiver::HandleSenderReport(RtcpParser* rtcp_parser) { 127 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType(); 128 const RtcpField& rtcp_field = rtcp_parser->Field(); 129 130 DCHECK(rtcp_field_type == kRtcpSrCode) << "Invalid state"; 131 132 // Synchronization source identifier for the originator of this SR packet. 133 uint32 remote_ssrc = rtcp_field.sender_report.sender_ssrc; 134 135 VLOG(2) << "Cast RTCP received SR from SSRC " << remote_ssrc; 136 137 if (remote_ssrc_ == remote_ssrc) { 138 transport::RtcpSenderInfo remote_sender_info; 139 remote_sender_info.ntp_seconds = 140 rtcp_field.sender_report.ntp_most_significant; 141 remote_sender_info.ntp_fraction = 142 rtcp_field.sender_report.ntp_least_significant; 143 remote_sender_info.rtp_timestamp = rtcp_field.sender_report.rtp_timestamp; 144 remote_sender_info.send_packet_count = 145 rtcp_field.sender_report.sender_packet_count; 146 remote_sender_info.send_octet_count = 147 rtcp_field.sender_report.sender_octet_count; 148 if (receiver_feedback_) { 149 receiver_feedback_->OnReceivedSenderReport(remote_sender_info); 150 } 151 } 152 rtcp_field_type = rtcp_parser->Iterate(); 153 while (rtcp_field_type == kRtcpReportBlockItemCode) { 154 HandleReportBlock(&rtcp_field, remote_ssrc); 155 rtcp_field_type = rtcp_parser->Iterate(); 156 } 157 } 158 159 void RtcpReceiver::HandleReceiverReport(RtcpParser* rtcp_parser) { 160 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType(); 161 const RtcpField& rtcp_field = rtcp_parser->Field(); 162 163 DCHECK(rtcp_field_type == kRtcpRrCode) << "Invalid state"; 164 165 uint32 remote_ssrc = rtcp_field.receiver_report.sender_ssrc; 166 167 VLOG(2) << "Cast RTCP received RR from SSRC " << remote_ssrc; 168 169 rtcp_field_type = rtcp_parser->Iterate(); 170 while (rtcp_field_type == kRtcpReportBlockItemCode) { 171 HandleReportBlock(&rtcp_field, remote_ssrc); 172 rtcp_field_type = rtcp_parser->Iterate(); 173 } 174 } 175 176 void RtcpReceiver::HandleReportBlock(const RtcpField* rtcp_field, 177 uint32 remote_ssrc) { 178 // This will be called once per report block in the Rtcp packet. 179 // We filter out all report blocks that are not for us. 180 // Each packet has max 31 RR blocks. 181 // 182 // We can calculate RTT if we send a send report and get a report block back. 183 184 // |rtcp_field.ReportBlockItem.ssrc| is the ssrc identifier of the source to 185 // which the information in this reception report block pertains. 186 187 const RtcpFieldReportBlockItem& rb = rtcp_field->report_block_item; 188 189 // Filter out all report blocks that are not for us. 190 if (rb.ssrc != ssrc_) { 191 // This block is not for us ignore it. 192 return; 193 } 194 VLOG(2) << "Cast RTCP received RB from SSRC " << remote_ssrc; 195 196 transport::RtcpReportBlock report_block; 197 report_block.remote_ssrc = remote_ssrc; 198 report_block.media_ssrc = rb.ssrc; 199 report_block.fraction_lost = rb.fraction_lost; 200 report_block.cumulative_lost = rb.cumulative_number_of_packets_lost; 201 report_block.extended_high_sequence_number = 202 rb.extended_highest_sequence_number; 203 report_block.jitter = rb.jitter; 204 report_block.last_sr = rb.last_sender_report; 205 report_block.delay_since_last_sr = rb.delay_last_sender_report; 206 207 if (rtt_feedback_) { 208 rtt_feedback_->OnReceivedDelaySinceLastReport( 209 rb.ssrc, rb.last_sender_report, rb.delay_last_sender_report); 210 } 211 } 212 213 void RtcpReceiver::HandleSDES(RtcpParser* rtcp_parser) { 214 RtcpFieldTypes field_type = rtcp_parser->Iterate(); 215 while (field_type == kRtcpSdesChunkCode) { 216 HandleSDESChunk(rtcp_parser); 217 field_type = rtcp_parser->Iterate(); 218 } 219 } 220 221 void RtcpReceiver::HandleSDESChunk(RtcpParser* rtcp_parser) { 222 const RtcpField& rtcp_field = rtcp_parser->Field(); 223 VLOG(2) << "Cast RTCP received SDES with cname " << rtcp_field.c_name.name; 224 } 225 226 void RtcpReceiver::HandleXr(RtcpParser* rtcp_parser) { 227 RtcpFieldTypes rtcp_field_type = rtcp_parser->FieldType(); 228 const RtcpField& rtcp_field = rtcp_parser->Field(); 229 230 DCHECK(rtcp_field_type == kRtcpXrCode) << "Invalid state"; 231 232 uint32 remote_ssrc = rtcp_field.extended_report.sender_ssrc; 233 rtcp_field_type = rtcp_parser->Iterate(); 234 235 while (rtcp_field_type == kRtcpXrDlrrCode || 236 rtcp_field_type == kRtcpXrRrtrCode || 237 rtcp_field_type == kRtcpXrUnknownItemCode) { 238 if (rtcp_field_type == kRtcpXrRrtrCode) { 239 HandleRrtr(rtcp_parser, remote_ssrc); 240 } else if (rtcp_field_type == kRtcpXrDlrrCode) { 241 HandleDlrr(rtcp_parser); 242 } 243 rtcp_field_type = rtcp_parser->Iterate(); 244 } 245 } 246 247 void RtcpReceiver::HandleRrtr(RtcpParser* rtcp_parser, uint32 remote_ssrc) { 248 if (remote_ssrc_ != remote_ssrc) { 249 // Not to us. 250 return; 251 } 252 const RtcpField& rtcp_field = rtcp_parser->Field(); 253 RtcpReceiverReferenceTimeReport remote_time_report; 254 remote_time_report.remote_ssrc = remote_ssrc; 255 remote_time_report.ntp_seconds = rtcp_field.rrtr.ntp_most_significant; 256 remote_time_report.ntp_fraction = rtcp_field.rrtr.ntp_least_significant; 257 258 if (receiver_feedback_) { 259 receiver_feedback_->OnReceiverReferenceTimeReport(remote_time_report); 260 } 261 } 262 263 void RtcpReceiver::HandleDlrr(RtcpParser* rtcp_parser) { 264 const RtcpField& rtcp_field = rtcp_parser->Field(); 265 if (remote_ssrc_ != rtcp_field.dlrr.receivers_ssrc) { 266 // Not to us. 267 return; 268 } 269 if (rtt_feedback_) { 270 rtt_feedback_->OnReceivedDelaySinceLastReport( 271 rtcp_field.dlrr.receivers_ssrc, 272 rtcp_field.dlrr.last_receiver_report, 273 rtcp_field.dlrr.delay_last_receiver_report); 274 } 275 } 276 277 void RtcpReceiver::HandleNACK(RtcpParser* rtcp_parser) { 278 const RtcpField& rtcp_field = rtcp_parser->Field(); 279 if (ssrc_ != rtcp_field.nack.media_ssrc) { 280 RtcpFieldTypes field_type; 281 // Message not to us. Iterate until we have passed this message. 282 do { 283 field_type = rtcp_parser->Iterate(); 284 } while (field_type == kRtcpGenericRtpFeedbackNackItemCode); 285 return; 286 } 287 std::list<uint16> nackSequenceNumbers; 288 289 RtcpFieldTypes field_type = rtcp_parser->Iterate(); 290 while (field_type == kRtcpGenericRtpFeedbackNackItemCode) { 291 HandleNACKItem(&rtcp_field, &nackSequenceNumbers); 292 field_type = rtcp_parser->Iterate(); 293 } 294 } 295 296 void RtcpReceiver::HandleNACKItem(const RtcpField* rtcp_field, 297 std::list<uint16>* nack_sequence_numbers) { 298 nack_sequence_numbers->push_back(rtcp_field->nack_item.packet_id); 299 300 uint16 bitmask = rtcp_field->nack_item.bitmask; 301 if (bitmask) { 302 for (int i = 1; i <= 16; ++i) { 303 if (bitmask & 1) { 304 nack_sequence_numbers->push_back(rtcp_field->nack_item.packet_id + i); 305 } 306 bitmask = bitmask >> 1; 307 } 308 } 309 } 310 311 void RtcpReceiver::HandleBYE(RtcpParser* rtcp_parser) { 312 const RtcpField& rtcp_field = rtcp_parser->Field(); 313 uint32 remote_ssrc = rtcp_field.bye.sender_ssrc; 314 if (remote_ssrc_ == remote_ssrc) { 315 VLOG(2) << "Cast RTCP received BYE from SSRC " << remote_ssrc; 316 } 317 rtcp_parser->Iterate(); 318 } 319 320 void RtcpReceiver::HandlePLI(RtcpParser* rtcp_parser) { 321 const RtcpField& rtcp_field = rtcp_parser->Field(); 322 if (ssrc_ == rtcp_field.pli.media_ssrc) { 323 // Received a signal that we need to send a new key frame. 324 VLOG(2) << "Cast RTCP received PLI on our SSRC " << ssrc_; 325 } 326 rtcp_parser->Iterate(); 327 } 328 329 void RtcpReceiver::HandleSendReportRequest(RtcpParser* rtcp_parser) { 330 if (receiver_feedback_) { 331 receiver_feedback_->OnReceivedSendReportRequest(); 332 } 333 rtcp_parser->Iterate(); 334 } 335 336 void RtcpReceiver::HandleRpsi(RtcpParser* rtcp_parser) { 337 const RtcpField& rtcp_field = rtcp_parser->Field(); 338 if (rtcp_parser->Iterate() != kRtcpPayloadSpecificRpsiCode) { 339 return; 340 } 341 if (rtcp_field.rpsi.number_of_valid_bits % 8 != 0) { 342 // Continue 343 return; 344 } 345 uint64 rpsi_picture_id = 0; 346 347 // Convert native_bit_string to rpsi_picture_id 348 uint8 bytes = rtcp_field.rpsi.number_of_valid_bits / 8; 349 for (uint8 n = 0; n < (bytes - 1); ++n) { 350 rpsi_picture_id += (rtcp_field.rpsi.native_bit_string[n] & 0x7f); 351 rpsi_picture_id <<= 7; // Prepare next. 352 } 353 rpsi_picture_id += (rtcp_field.rpsi.native_bit_string[bytes - 1] & 0x7f); 354 355 VLOG(2) << "Cast RTCP received RPSI with picture_id " << rpsi_picture_id; 356 } 357 358 void RtcpReceiver::HandlePayloadSpecificApp(RtcpParser* rtcp_parser) { 359 const RtcpField& rtcp_field = rtcp_parser->Field(); 360 uint32 remote_ssrc = rtcp_field.application_specific.sender_ssrc; 361 if (remote_ssrc_ != remote_ssrc) { 362 // Message not to us. Iterate until we have passed this message. 363 RtcpFieldTypes field_type; 364 do { 365 field_type = rtcp_parser->Iterate(); 366 } while (field_type == kRtcpPayloadSpecificRembCode || 367 field_type == kRtcpPayloadSpecificRembItemCode || 368 field_type == kRtcpPayloadSpecificCastCode || 369 field_type == kRtcpPayloadSpecificCastNackItemCode); 370 return; 371 } 372 373 RtcpFieldTypes packet_type = rtcp_parser->Iterate(); 374 switch (packet_type) { 375 case kRtcpPayloadSpecificRembCode: 376 packet_type = rtcp_parser->Iterate(); 377 if (packet_type == kRtcpPayloadSpecificRembItemCode) { 378 HandlePayloadSpecificRembItem(rtcp_parser); 379 rtcp_parser->Iterate(); 380 } 381 break; 382 case kRtcpPayloadSpecificCastCode: 383 packet_type = rtcp_parser->Iterate(); 384 if (packet_type == kRtcpPayloadSpecificCastCode) { 385 HandlePayloadSpecificCastItem(rtcp_parser); 386 } 387 break; 388 default: 389 return; 390 } 391 } 392 393 void RtcpReceiver::HandlePayloadSpecificRembItem(RtcpParser* rtcp_parser) { 394 const RtcpField& rtcp_field = rtcp_parser->Field(); 395 396 for (int i = 0; i < rtcp_field.remb_item.number_of_ssrcs; ++i) { 397 if (rtcp_field.remb_item.ssrcs[i] == ssrc_) { 398 // Found matching ssrc. 399 VLOG(2) << "Cast RTCP received REMB with received_bitrate " 400 << rtcp_field.remb_item.bitrate; 401 return; 402 } 403 } 404 } 405 406 void RtcpReceiver::HandleApplicationSpecificCastReceiverLog( 407 RtcpParser* rtcp_parser) { 408 const RtcpField& rtcp_field = rtcp_parser->Field(); 409 410 uint32 remote_ssrc = rtcp_field.cast_receiver_log.sender_ssrc; 411 if (remote_ssrc_ != remote_ssrc) { 412 // Message not to us. Iterate until we have passed this message. 413 RtcpFieldTypes field_type; 414 do { 415 field_type = rtcp_parser->Iterate(); 416 } while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode || 417 field_type == kRtcpApplicationSpecificCastReceiverLogEventCode); 418 return; 419 } 420 RtcpReceiverLogMessage receiver_log; 421 RtcpFieldTypes field_type = rtcp_parser->Iterate(); 422 while (field_type == kRtcpApplicationSpecificCastReceiverLogFrameCode) { 423 RtcpReceiverFrameLogMessage frame_log( 424 rtcp_field.cast_receiver_log.rtp_timestamp); 425 426 field_type = rtcp_parser->Iterate(); 427 while (field_type == kRtcpApplicationSpecificCastReceiverLogEventCode) { 428 HandleApplicationSpecificCastReceiverEventLog( 429 rtcp_field.cast_receiver_log.rtp_timestamp, 430 rtcp_parser, 431 &frame_log.event_log_messages_); 432 field_type = rtcp_parser->Iterate(); 433 } 434 435 if (!frame_log.event_log_messages_.empty()) 436 receiver_log.push_back(frame_log); 437 } 438 439 if (receiver_feedback_ && !receiver_log.empty()) { 440 receiver_feedback_->OnReceivedReceiverLog(receiver_log); 441 } 442 } 443 444 void RtcpReceiver::HandleApplicationSpecificCastReceiverEventLog( 445 uint32 frame_rtp_timestamp, 446 RtcpParser* rtcp_parser, 447 RtcpReceiverEventLogMessages* event_log_messages) { 448 const RtcpField& rtcp_field = rtcp_parser->Field(); 449 450 const uint8 event = rtcp_field.cast_receiver_log.event; 451 const CastLoggingEvent event_type = TranslateToLogEventFromWireFormat(event); 452 uint16 packet_id = event_type == PACKET_RECEIVED ? 453 rtcp_field.cast_receiver_log.delay_delta_or_packet_id.packet_id : 0; 454 const base::TimeTicks event_timestamp = 455 base::TimeTicks() + 456 base::TimeDelta::FromMilliseconds( 457 rtcp_field.cast_receiver_log.event_timestamp_base + 458 rtcp_field.cast_receiver_log.event_timestamp_delta); 459 460 // The following code checks to see if we have already seen this event. 461 // The algorithm works by maintaining a sliding window of events. We have 462 // a queue and a set of events. We enqueue every new event and insert it 463 // into the set. When the queue becomes too big we remove the oldest event 464 // from both the queue and the set. 465 ReceiverEventKey key = 466 GetReceiverEventKey( 467 frame_rtp_timestamp, event_timestamp, event, packet_id); 468 if (receiver_event_key_set_.find(key) != receiver_event_key_set_.end()) { 469 return; 470 } else { 471 receiver_event_key_set_.insert(key); 472 receiver_event_key_queue_.push(key); 473 474 if (receiver_event_key_queue_.size() > receiver_event_history_size_) { 475 const ReceiverEventKey oldest_key = receiver_event_key_queue_.front(); 476 receiver_event_key_queue_.pop(); 477 receiver_event_key_set_.erase(oldest_key); 478 } 479 } 480 481 RtcpReceiverEventLogMessage event_log; 482 event_log.type = event_type; 483 event_log.event_timestamp = event_timestamp; 484 event_log.delay_delta = base::TimeDelta::FromMilliseconds( 485 rtcp_field.cast_receiver_log.delay_delta_or_packet_id.delay_delta); 486 event_log.packet_id = 487 rtcp_field.cast_receiver_log.delay_delta_or_packet_id.packet_id; 488 event_log_messages->push_back(event_log); 489 } 490 491 void RtcpReceiver::HandlePayloadSpecificCastItem(RtcpParser* rtcp_parser) { 492 const RtcpField& rtcp_field = rtcp_parser->Field(); 493 RtcpCastMessage cast_message(remote_ssrc_); 494 cast_message.ack_frame_id_ = ack_frame_id_wrap_helper_.MapTo32bitsFrameId( 495 rtcp_field.cast_item.last_frame_id); 496 cast_message.target_delay_ms_ = rtcp_field.cast_item.target_delay_ms; 497 498 RtcpFieldTypes packet_type = rtcp_parser->Iterate(); 499 while (packet_type == kRtcpPayloadSpecificCastNackItemCode) { 500 const RtcpField& rtcp_field = rtcp_parser->Field(); 501 HandlePayloadSpecificCastNackItem( 502 &rtcp_field, &cast_message.missing_frames_and_packets_); 503 packet_type = rtcp_parser->Iterate(); 504 } 505 if (sender_feedback_) { 506 sender_feedback_->OnReceivedCastFeedback(cast_message); 507 } 508 } 509 510 void RtcpReceiver::HandlePayloadSpecificCastNackItem( 511 const RtcpField* rtcp_field, 512 MissingFramesAndPacketsMap* missing_frames_and_packets) { 513 514 MissingFramesAndPacketsMap::iterator frame_it = 515 missing_frames_and_packets->find(rtcp_field->cast_nack_item.frame_id); 516 517 if (frame_it == missing_frames_and_packets->end()) { 518 // First missing packet in a frame. 519 PacketIdSet empty_set; 520 std::pair<MissingFramesAndPacketsMap::iterator, bool> ret = 521 missing_frames_and_packets->insert(std::pair<uint8, PacketIdSet>( 522 rtcp_field->cast_nack_item.frame_id, empty_set)); 523 frame_it = ret.first; 524 DCHECK(frame_it != missing_frames_and_packets->end()) << "Invalid state"; 525 } 526 uint16 packet_id = rtcp_field->cast_nack_item.packet_id; 527 frame_it->second.insert(packet_id); 528 529 if (packet_id == kRtcpCastAllPacketsLost) { 530 // Special case all packets in a frame is missing. 531 return; 532 } 533 uint8 bitmask = rtcp_field->cast_nack_item.bitmask; 534 535 if (bitmask) { 536 for (int i = 1; i <= 8; ++i) { 537 if (bitmask & 1) { 538 frame_it->second.insert(packet_id + i); 539 } 540 bitmask = bitmask >> 1; 541 } 542 } 543 } 544 545 void RtcpReceiver::HandleFIR(RtcpParser* rtcp_parser) { 546 const RtcpField& rtcp_field = rtcp_parser->Field(); 547 548 RtcpFieldTypes field_type = rtcp_parser->Iterate(); 549 while (field_type == kRtcpPayloadSpecificFirItemCode) { 550 HandleFIRItem(&rtcp_field); 551 field_type = rtcp_parser->Iterate(); 552 } 553 } 554 555 void RtcpReceiver::HandleFIRItem(const RtcpField* rtcp_field) { 556 // Is it our sender that is requested to generate a new keyframe. 557 if (ssrc_ != rtcp_field->fir_item.ssrc) 558 return; 559 560 VLOG(2) << "Cast RTCP received FIR on our SSRC " << ssrc_; 561 } 562 563 } // namespace cast 564 } // namespace media 565