美文网首页webrtc rtc/rtcp源码分析
WebRTC RTP/RTCP 源码分析(四):RTCP 的接收

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

作者: 酸辣粉多加辣椒 | 来源:发表于2019-07-15 20:51 被阅读0次

    基于 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<uint16_t>::ReadBigEndian(&payload[8]);
      uint16_t status_count = ByteReader<uint16_t>::ReadBigEndian(&payload[10]);
      base_time_ticks_ = ByteReader<int32_t, 3>::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 的接收

        本文链接:https://www.haomeiwen.com/subject/mviokctx.html