WebRTC RTP/RTCP 源码分析(四):RTCP 的接收和解析

基于 Chromium M69版本

收到 RTCP 包后分音频视频传递给相应 ReceiveStream 处理。

// /call/call.cc
PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type,
                                                 const uint8_t* packet,
                                                 size_t length) {
  // media_type == MediaType::VIDEO
  video_receive_stream_->DeliverRtcp(packet, length);
  // media)type == MediaType::AUDIO
  audio_receive_stream->DeliverRtcp(packet, length);
}

这里主要关注视频流,继续向下传递 RTCP 包。

// /video/video_receive_stream.cc
bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
  return rtp_video_stream_receiver_.DeliverRtcp(packet, length);
}

RtpVideoStreamReceiver 通知 RtpRtcp 类解析 RTCP 包后,获得 RTT 等信息。

// /video/rtp_video_stream_receiver.cc
bool RtpVideoStreamReceiver::DeliverRtcp(const uint8_t* rtcp_packet,
                                         size_t rtcp_packet_length) {

  rtp_rtcp_->IncomingRtcpPacket(rtcp_packet, rtcp_packet_length);
}

ModuleRtpRtcpImpl 类实现了 RtpRtcp,相应上面的调用,通知 RTCPReceiver 解析 RTCP 包。

// /modules/rtp_rtcp/source/rtp_rtcp_impl.cc
void ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet,
                                           const size_t length) {
  rtcp_receiver_.IncomingPacket(rtcp_packet, length);
}

RTCPReceiver 类负责分解复合 RTCP 包,并触发相应回调函数。

// /modules/rtp_rtcp/souce/rtcp_receiver.cc
void RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) {
  PacketInformation packet_information;
  if (!ParseCompoundPacket(packet, packet + packet_size, &packet_information))
    return;
  TriggerCallbacksFromRtcpPacket(packet_information);
}

RTCP 包的类型有:SR/RR/SDE/PLI/REMB/FIR等等,具体见 RFC3550。

bool RTCPReceiver::ParseCompoundPacket(const uint8_t* packet_begin,
                                       const uint8_t* packet_end,
                                       PacketInformation* packet_information) {
    switch (rtcp_block.type()) {
      case rtcp::SenderReport::kPacketType:
        HandleSenderReport(rtcp_block, packet_information);
        break;
      case rtcp::ReceiverReport::kPacketType:
        HandleReceiverReport(rtcp_block, packet_information);
        break;
      case rtcp::Sdes::kPacketType:
        HandleSdes(rtcp_block, packet_information);
        break;
      case rtcp::ExtendedReports::kPacketType:
        HandleXr(rtcp_block, packet_information);
        break;
      case rtcp::Bye::kPacketType:
        HandleBye(rtcp_block);
        break;
      case rtcp::Rtpfb::kPacketType:
        switch (rtcp_block.fmt()) {
          case rtcp::Nack::kFeedbackMessageType:
            HandleNack(rtcp_block, packet_information);
            break;
          case rtcp::Tmmbr::kFeedbackMessageType:
            HandleTmmbr(rtcp_block, packet_information);
            break;
          case rtcp::Tmmbn::kFeedbackMessageType:
            HandleTmmbn(rtcp_block, packet_information);
            break;
          case rtcp::RapidResyncRequest::kFeedbackMessageType:
            HandleSrReq(rtcp_block, packet_information);
            break;
          case rtcp::TransportFeedback::kFeedbackMessageType:
            HandleTransportFeedback(rtcp_block, packet_information);
            break;
          default:
            ++num_skipped_packets_;
            break;
        }
        break;
      case rtcp::Psfb::kPacketType:
        switch (rtcp_block.fmt()) {
          case rtcp::Pli::kFeedbackMessageType:
            HandlePli(rtcp_block, packet_information);
            break;
          case rtcp::Fir::kFeedbackMessageType:
            HandleFir(rtcp_block, packet_information);
            break;
          case rtcp::Remb::kFeedbackMessageType:
            HandlePsfbApp(rtcp_block, packet_information);
            break;
          default:
            ++num_skipped_packets_;
            break;
        }
        break;
      case rtcp::App::kPacketType:
          switch (rtcp_block.fmt()) {
          case rtcp::App::kNtpSyncResponseType:
              HandleSyncNtp(rtcp_block, packet_information);
              break;

          default:
              ++num_skipped_packets_;
              break;
          }
          break;
      default:
        ++num_skipped_packets_;
        break;
    }
}

例如:GCC 输入就来自 TransportFeedback 类型的 RTCP 包,上面的函数传给 TransportFeedback 来解读 RTCP 包携带的信息(序列号、时间戳等)。

// /modules/rtp_rtcp/source/rtcp_receiver.cc
void RTCPReceiver::HandleTransportFeedback(
    const CommonHeader& rtcp_block,
    PacketInformation* packet_information) {
    transport_feedback->Parse(rtcp_block);
}
// /modules/rtp_rtcp/souce/rtcp_packet/transport_feedback.cc
bool TransportFeedback::Parse(const CommonHeader& packet) {

  const uint8_t* const payload = packet.payload();
  ParseCommonFeedback(payload);

  base_seq_no_ = ByteReader::ReadBigEndian(&payload[8]);
  uint16_t status_count = ByteReader::ReadBigEndian(&payload[10]);
  base_time_ticks_ = ByteReader::ReadBigEndian(&payload[12]);
  feedback_seq_ = payload[15];
  Clear();
  size_t index = 16;
  const size_t end_index = packet.payload_size_bytes();
  // ...
}

分解了复合包之后就触发相应的回调函数。比如 TransportFeedback包就回调 TransportFeedbackObserver 来使用 RTCP 包的信息,开始 GCC 的流程。

// /modules/rtp_rtcp/source/rtcp_receiver.cc
void RTCPReceiver::TriggerCallbacksFromRtcpPacket(
    const PacketInformation& packet_information) {

  if (transport_feedback_observer_ &&
      (packet_information.packet_type_flags & kRtcpTransportFeedback)) {
    uint32_t media_source_ssrc =
        packet_information.transport_feedback->media_ssrc();
    if (media_source_ssrc == local_ssrc ||
        registered_ssrcs.find(media_source_ssrc) != registered_ssrcs.end()) {
      transport_feedback_observer_->OnTransportFeedback(
          *packet_information.transport_feedback);
    }
  }
}

你可能感兴趣的:(WebRTC RTP/RTCP 源码分析(四):RTCP 的接收和解析)