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

本文详细介绍了WebRTC中RTCP包的接收过程,从Call::DeliverRtcp开始,经过VideoReceiveStream和RtpRtcp模块,最终在RTCPReceiver中解析不同类型如SR、RR、PLI等的RTCP包,并触发相应的回调函数,如GCC流程的启动。
摘要由CSDN通过智能技术生成

收到 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);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值