webrtc QOS方法四.4(Transport-wide Congestion Control协议笔记)

一、协议链接

https://tools.ietf.org/pdf/draft-holmer-rmcat-transport-wide-cc-extensions-01.pdf

二、协议定义

三、参数说明

version (V): 2 bits。固定是2。

padding (P): 1 bit。

feedback message type (FMT): 5 bits。TransportCC固定是15。

payload type (PT): 8 bits。TransportCC固定是205。

SSRC of packet sender: 32 bits。

SSRC of media source: 32 bits。

base sequence number: 16 bits。TransportFeedback包中记录的第一个RTP包的transport sequence number,在反馈的各个TransportFeedback RTCP包中,这个字段不一定是递增的,也有可能比之前的RTCP包小。

packet status count: 16 bits。表示这个TransportFeedback包记录了多少个RTP包信息,这些RTP的transport sequence number以base sequence number为基准。比如记录的第一个RTP包的transport sequence number为base sequence number,那么记录的第二个RTP包transport sequence number为base sequence number+1

reference time: 24 bits。表示参考时间,以64ms为单位,RTCP包记录的RTP包到达时间信息以这个reference time为基准进行计算。

feedback packet count: 8 bits。用于计数发送的每个TransportFeedback包,相当于RTCP包的序列号。可用于检测TransportFeedback包的丢包情况。

packet chunk: 16 bits。参见下面详细介绍。

recv delta: 8 bits For each "packet received" 状态的包,也就是收到的RTP包,在recv delta列表中添加对应的的到达时间间隔信息,用于记录RTP包到达时间信息。通过前面的reference time以及recv delta信息,我们就可以得到RTP包到达时间。

以250us(0.25ms)为单位,表示RTP包到达时间与前面一个RTP包到达时间的间隔,对于记录的第一个RTP包,该包的时间间隔是相对reference time的。

如果在packet chunk记录了一个"Packet received, small delta"状态的包,那么就会在receive delta列表中添加一个无符号1字节长度receive delta,无符号1字节取值范围[0,255],由于Receive Delta以0.25ms为单位,故此时Receive Delta取值范围[0, 63.75]ms
如果在packet chunk记录了一个"Packet received, large or negative delta"状态的包,那么就会在receive delta列表中添加一个有符号2字节长度的receive delta,范围[-8192.0, 8191.75] ms
如果时间间隔超过了最大限制,那么就会构建一个新的TransportFeedback RTCP包,由于reference time长度为3字节,所以目前的包中3字节长度能够覆盖很大范围了
以上说明总结起来就是:对于收到的RTP包在TransportFeedback RTCP receive delta列表中通过时间间隔记录到达时间,如果与前面包时间间隔小,那么使用1字节表示,否则2字节,超过最大取值范围,就另起新RTCP包了。

对于"Packet received, small delta"状态的包来说,receive delta最大值63.75ms,那么一秒时间跨度最少能标识1000/63.75~=16个包。由于receive delta为250us的倍数,所以一秒时间跨度最多能标识4000个包。

五、packet chunk

首先先了解下RTP包状态,目前定义了如下四种状态,每个状态值2bits,用来标识RTP包的到达状态,以及与前面RTP包的时间间隔大小信息:

packet chunk有两种类型,Run length chunk(行程长度编码数据块)与Status vector chunk(状态矢量编码数据块),对应packet chunk结构的两种编码方式。packet chunk的第一bit标识chunk类型。

Run length chunk:行程长度编码是一种简单的数据压缩算法,其基本思想是将重复且连续出现多次的字符使用“连续出现次数+字符”来描述,例如:aaabbbcdddd通过Run length编码就可以压缩为3a3bc4d。Run length chunk中就使用了Run length编码标识连续多个相同状态的包。

 

chunk type (T): 1 bit。Run length chunk时固定为0。

packet status symbol (S): 2 bits。包到达状态。 

 run length (L): 13 bits。行程长度,标识有多少个连续包为相同状态。

示例:

 Status Vector Chunk:

chunk type (T): 1 bit。Status Vector Chunk固定为1。

symbol size (S): 1 bit。为0表示只包含"packet not received" (0)以及"packet received"(1)状态,每个状态使用1bit表示,这样后面14bits的symbol list能标识14个包的状态。为1表示使用2bits来标识包状态,这样symbol list中我们只能标识7个包的状态。

symbol list: 14 bits。标识一系列包的状态, 总共能标识7或14个包的状态。

 symbol size为0,这样能标识14个包的状态。第一个包状态为"packet not received"(0),接着后面5个包状态为"packet received"(1),再接着三个包状态为"packet not received",再接着三个包状态为"packet received",最后两个包状态为"packet not received"。

symbol size为1,这样只能标识7个包的状态。第一个包为"packet not received"(00)状态,第二个包为 "packet received, w/o timestamp"(11)状态,再接着三个包为"packet received"(01)状态,最后两个包为"packet not received"(00)状态。

六、transport CC在webrtc上的使用

1、BWE根据TransportCC进行基于延时的码率估计用到该报文。

 2、GoogCcNetworkController::OnTransportPacketsFeedback 网络带宽探测也用到transportCC协议实现。

七、发送transport CC RTCP报文调用栈

RunPlatformThread
->ProcessThreadImpl::Process
->RemoteEstimatorProxy::Process
->RemoteEstimatorProxy::SendPeriodicFeedbacks---------周期调用,还有一处是立即返回
->PacketRouter::SendCombinedRtcpPacket
->ModuleRtpRtcpImpl2::SendCombinedRtcpPacket
->RTCPSender::SendCombinedRtcpPacket
->RTCPSender::PacketSender::AppendPacket
->rtcp::TransportFeedback::Create

八、发送带TransportSequenceNumber扩展头字段报文笔记

参见webrtc代码走读二十:extension扩展头协商及初始化流程_CrystalShaw的博客-CSDN博客

RtpPacket::AllocateRawExtension函数配置TransportSequenceNumber扩展头字段。

FindOrCreateExtensionInfo

VideoChannel::SetRemoteContent_w协商RTP扩展头

发送之前会记录两个时间:报文启动发送时间和报文实际发送时间。

启动发送的调用栈如下:

ProcessThreadImpl::Process
->PacedSender::Process
->PacingController::ProcessPackets
->PacketRouter::SendPacket
->ModuleRtpRtcpImpl2::TrySendPacket
->RtpSenderEgress::SendPacket
->RtpSenderEgress::AddPacketToTransportFeedback
->RtpTransportControllerSend::OnAddPacket

 实际发送时间,是udp socket一路发送信号量到Call::OnSentPacket函数。

ProcessThreadImpl::Process()
->PacedSender::Process()    
->PacingController::ProcessPackets()
->PacketRouter::SendPacket
->ModuleRtpRtcpImpl2::TrySendPacket
->RtpSenderEgress::SendPacket
->RtpSenderEgress::SendPacketToNetwork
->WebRtcVoiceMediaChannel::SendRtp
->MediaChannel::SendRtp
->MediaChannel::SendPacket
->MediaChannel::DoSendPacket
->BaseChannel::SendPacket
->SrtpTransport::SendRtpPacket
->RtpTransport::SendPacket
->DtlsTransport::SendPacket
->P2PTransportChannel::SendPacket
->ProxyConnection::Send
->UDPPort::SendTo
->AsyncUDPSocket::SendTo---后续参照下面调用关系,一路发送信号量到TransportFeedbackAdapter::ProcessSentPacket<-RtpTransportControllerSend::OnSentPacket

RtpTransportControllerSend::OnSentPacket
Call::OnSentPacket
RtpTransport::OnSentPacket(rtc::PacketTransportInternal * packet_transport, const rtc::SentPacket & sent_packet) 
DtlsTransport::OnSentPacket(rtc::PacketTransportInternal * transport, const rtc::SentPacket & sent_packet) 
P2PTransportChannel::OnSentPacket(const rtc::SentPacket & sent_packet)
OnSentPacket(rtc::AsyncPacketSocket * socket, const rtc::SentPacket & sent_packet) 
AsyncUDPSocket::SendTo(const void * pv, unsigned __int64 cb, const rtc::SocketAddress & addr, const rtc::PacketOptions & options) 
UDPPort::SendTo(const void * data, unsigned __int64 size, const rtc::SocketAddress & addr, const rtc::PacketOptions & options, bool payload) 
ProxyConnection::Send(const void * data, unsigned __int64 size, const rtc::PacketOptions & options) 
P2PTransportChannel::SendPacket(const char * data, unsigned __int64 len, const rtc::PacketOptions & options, int flags) 
DtlsTransport::SendPacket(const char * data, unsigned __int64 size, const rtc::PacketOptions & options, int flags) 
RtpTransport::SendPacket(bool rtcp, rtc::CopyOnWriteBuffer * packet, const rtc::PacketOptions & options, int flags) 
SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer * packet, const rtc::PacketOptions & options, int flags) 
BaseChannel::SendPacket(bool rtcp, rtc::CopyOnWriteBuffer * packet, const rtc::PacketOptions & options) 
Thread::QueuedTaskHandler::OnMessage(rtc::Message * msg) 
Thread::Dispatch(rtc::Message * pmsg) 
Thread::ProcessMessages(int cmsLoop) 
Thread::PreRun(void * pv) 

 

transport CC的RTCP报文的referenceTime时间戳是在AsyncUDPSocket::OnReadEvent函数获取

 RemoteEstimatorProxy::IncomingPacket获取到达时间

 

 八、参考

WebRTC研究:Transport-cc之RTP及RTCP - 剑痴乎

https://www.rfc-editor.org/rfc/rfc8888.pdf

参考:

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值