首页 > 其他分享 >WebRTC研究:Transport-cc之RTP及RTCP

WebRTC研究:Transport-cc之RTP及RTCP

时间:2023-08-03 18:12:23浏览次数:57  
标签:sequence cc +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ nu

Transport-cc指的是Transport-wide Congestion Control。WebRTC最新的拥塞控制算法(Sendside BWE)基于Transport-cc,接收端记录数据包到达时间,构造相关RTCP包,然后反馈给发送端,在发送端做带宽估计,从而进行拥塞控制。之所以基于Transport-cc,放到发送端进行带宽估计,除了方便维护,也增加了相关算法的灵活性,因为大多数处理逻辑都放到了发送端。WebRTC中为了使用Transport-cc,需要用到RTP报头扩展以及增加新的RTCP类型。这里我们介绍下Transport-cc中的RTP以及RTCP。

RTP Header扩展

Transport sequence number

首先我们先来复习下RTP固定报头结构:

 0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|X|  CC   |M|     PT      |       sequence number         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           timestamp                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |            contributing source (CSRC) identifiers             |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

可以看到有一个sequence number字段,用于记录RTP包的序列号。一般情况下我们一个传输通道(PeerConnection)只包含一路视频流, 这个sequence number能满足大多数需求。但是在一些情况下,我们一个连接可能传输多个视频流,这些视频流复用一个传输通道,例如simulcast或者single PC场景,一个PeerConnection可能包含多个不同的视频流。在这些视频流中,RTP报头的sequence number是单独计数的。
这里举个例子,假设同一个PeerConnection下,我们传输两个视频流A与B,它们的RTP包记为Ra(n),Rb(n),n表示sequence number,这样我们观察同一个PeerConnection下,视频流按如下形式传输:
Ra(1),Ra(2),Rb(1),Rb(2),Ra(3),Ra(4),Rb(3),Rb(4)

在对某条PeerConnection进行带宽估计时,我们需要估计整条PeerConnection下所有视频流,而不是单独某个流。这样为了做一个RTP session(传输层)级别的带宽估计,原有各个流的sequence number就不能满足我们需要了。

为此Transport-cc中,使用了RTP报头扩展,用于记录transport sequence number,同一个PeerConnection连接下的所有流的transport sequence number,使用统一的计数器进行计数,方便进行同一个PeerConnection下的带宽估计。

这里我们使用前面的例子,视频流A与B,它们的RTP包记为Ra(n,m),Rb(n,m),n表示sequence number,m表示transport sequence number,这样同一个PeerConnection下,视频流按如下形式传输:
Ra(1,1),Ra(2,2),Rb(1,3),Rb(2,4),Ra(3,5),Ra(4,6),Rb(3,7),Rb(4,8)

这样进行带宽估计时,通过transport sequence number我们就能关心到这条传输通道下所有数据包的情况了。
RTP transport sequence number报头定义如下:

 0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |       0xBE    |    0xDE       |           length=1            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  ID   | L=1   |transport-wide sequence number | zero padding  |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

由于属于RTP报头扩展,所以可以看到以0xBEDE固定字段开头,表示One-Byte Header类型的扩展。
扩展头
transport sequence number占两个字节,存储在One-Byte Header的Extension data字段。由于按4字节对齐,所以还有值为0的填充数据。
对于同一个PeerConnection下的每个包,这个transport sequence number是从1开始递增的。这里我们看下Wireshark中对带transport sequence numberRTP报头扩展的解析:

One-Byte Header中Extension data字段为0x0028,可知该RTP包的transport sequence number为0x0028。

代码位置

void PacketRouter::SendPacket(std::unique_ptr<RtpPacketToSend> packet,
                              const PacedPacketInfo& cluster_info) {
  rtc::CritScope cs(&modules_crit_);
  // With the new pacer code path, transport sequence numbers are only set here,
  // on the pacer thread. Therefore we don't need atomics/synchronization.
  // 如果当前RTP包注册了TransportSequenceNumber扩展
  if (packet->HasExtension<TransportSequenceNumber>()) {
    packet->SetExtension<TransportSequenceNumber>((++transport_seq_) & 0xFFFF);
  }
}

TransportFeedback RTCP

报文格式

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |V=2|P|  FMT=15 |    PT=205     |           length              |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  0 |                     SSRC of packet sender                     |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4 |                      SSRC of media source                     |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  8 |      base sequence number     |      packet status count      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 12 |                 reference time                | fb pkt. count |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 16 |          packet chunk         |         packet chunk          |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    .                                                               .
    .                                                               .
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |         packet chunk          |  recv delta   |  recv delta   |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    .                                                               .
    .                                                               .
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |           recv delta          |  recv delta   | zero padding  |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1. FMT:5bits。Feedback message type(FMT)固定为15

  2. PT:8bits。由于属于传输层的Feedback Messages,所以payload type(PT)为205

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

  4. packet status count:2字节,表示这个TransportFeedback包记录了多少个RTP包信息,这些RTP的transport sequence number以base sequence number为基准

  5. ,比如记录的第一个RTP包的transport sequence number为base sequence number,那么记录的第二个RTP包transport sequence number为base sequence number+1

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

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

  8. packet chunk:2字节,记录RTP包的到达状态,记录的这些RTP包transport sequence number通过base sequence number计算得到

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

packet chunk

  1. 00-Packet not received
  2. 01-Packet received, small delta
  3. 10-Packet received, large or negative delta
  4. 11-[Reserved]

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

Run length chunk第一bit为0,后面跟着packet status以及run length。格式如下:


       0                   1
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |T| S |       Run Length        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

chunk type (T):1 bit,值为0
packet status symbol (S):2 bits,标识包状态
run length (L):13 bits,行程长度,标识有多少个连续包为相同状态

Status Vector Chunk

        0                   1
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |T|S|       symbol list         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Receive Delta

以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以及receive delta的使用是为了尽可能减小RTCP包大小。packet chunk用到了不同编码方式,对于收到的RTP包才添加到达时间信息,而且是通过时间间隔的方式记录到达时间。

代码导读

在RemoteEstimatorProxy中处理RTP包的到达时间,构造Transport-cc报文,反馈给发送端。大概函数调用流程如下:
发送端/媒体接收

RemoteEstimatorProxy::IncomingPacket
RemoteEstimatorProxy::Process
RemoteEstimatorProxy::SendPeriodicFeedbacks
RemoteEstimatorProxy::BuildFeedbackPacket

接收端/媒体发送

RTCPReceiver::IncomingPacket
RTCPReceiver::TriggerCallbacksFromRtcpPacket
TransportFeedbackObserver::OnTransportFeedback
RtpTransportControllerSend::OnTransportFeedback

标签:sequence,cc,+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+,nu
From: https://www.cnblogs.com/WillingCPP/p/17604039.html

相关文章

  • AddMvcCore,AddControllers,AddControllersWithViews,AddRazorPages的区别
    AddMvc/AddMvcCore/AddControllers等区别1.services.AddMvcCore()只注册运行 Controller/RazorPages 必要的核心服务,确保 Pipeline 程序可动作,其馀如像 DataAnnotationModelValidation、身分验证等服务要自己加挂,除有特殊客制需求,一般不太常用。2.services.AddControl......
  • 网工内推 | 云计算工程师专场,CCNP/HCIP认证优先
    01弧聚科技招聘岗位:网络工程师(云计算方向)职责描述:1、作为H3C初级云计算交付工程资源培养对象,需配合完成相关华三产品及服务规范培训。2、培训赋能后,安排到H3C云项目交付中进行项目交付及驻场支撑。3、按照公司项目需求,需动态进行出差支撑任职要求:1、大专学历及以上学历,IT相关专业......
  • CCPC Changchun 2020 D, Meaningless Sequence题解
    听说是签到题。不难看出设x为i二进制个数下1的个数(还是难的),则a_i=c^x。那么我们只需要考虑所有0到n的个数。当n为1111时,可以得到为(1+c)^n次方,那么我们把答案看成两部分一部分是1到111...和1000到n,那么当si位为1时,可以看成是n去掉前一位后再乘以c,递推得到每一个位置的答案,就是......
  • Lua script attempted to access a non local key in a cluster node 问题解决
    一、问题描述最近优化公司需要对不同的业务系统的缓存工具提供一个标准化的解决方案。各个业务系统将缓存数据通过map结构进行存储,然后在缓存系统中将这些map获取出来,然后保存在redis数据库中。技术经理想到的最好解决方案是将map集合直接存储在redis的hash表中。但是要求对hash......
  • Cisco CCNA——Internetworking
    InternetworkingInternetworkingBasics什么是网络?计算机网络:具有独立功能的多台计算机及其外部设备,通过通信线路连接起来网络设备Hub(集线器)优点:便宜、操作简单缺点:共享型、无法满足多人同时访问(目前基本淘汰出市场)接入设备越多冲突几率越大用CSMA/CD(载波侦听多路访问/冲突检测)技术......
  • C#中的System.AccessViolationException异常捕捉
    我们经常使用try-catch来捕捉异常,但从.NET4.0开始异常处理机制有所改变,导致AccessViolationException这类异常无法通过try-catch捕捉,而导致程序崩溃。官方解释AccessViolationException当代码尝试读取或写入尚未分配或无权访问的内存时,非托管或不安全代码中会发生访问冲突。这......
  • "account_id like '%':account_id||'%'", hasKey(p, "account_id&quot
    该SQL语句用于进行模糊查询,目标是根据传入的参数p中的account_id来查询sys_account表中的数据。解释如下:"account_idlike'%':account_id||'%'":这是SQL的查询条件部分,其中account_id是表sys_account的一个字段名。like是SQL中的模糊查询操作符,用于进行字符......
  • 浅谈-BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(Object targe
    BeanWrapper是SpringFramework中的一个接口,它提供了一种方便的方式来访问Java对象的属性,并允许对属性进行读取和设置操作。PropertyAccessorFactory.forBeanPropertyAccess(this)是一个工厂方法,用于创建一个BeanWrapper对象,以便访问指定的Java对象的属性。举个例子来......
  • k8s Service Accounts
    ServiceAccounts介绍服务帐户是一种非人类帐户,在Kubernetes中,它在Kubernetes集群中提供独特的身份。应用程序Pod、系统组件以及集群内部和外部的实体可以使用特定ServiceAccount的凭据来标识该ServiceAccount。此身份在各种情况下都很有用,包括向API服务器进行身份验......
  • 三菱plcCCLINK转profinet与西门子PLC通讯案例分析
    用三菱PLC的控制系统需要和西门子的PLC控制系统交互数据,捷米JM-PN-CCLK 是自主研发的一款 PROFINET 从站功能的通讯网关。该产品主要功能是将各种 CCLINK 总线和 PROFINET 网络连接起来。 捷米JM-PN-CCLK总线中做为从站使用,连接到 CCLINK 总线中做为从站使用。  三......