WebRTC-RTP/RTCP协议分析

协议汇总

RTP协议分析

RTP/RTCP协议诞生于1996年(RFC1889),在2004年有次大的改变(RFC3550),后来考虑到安全性变更为SRTP(RFC3711)。WebRTC用到SRTP,由于SRTP的对称秘钥需要走额外信道交换,所以WebRTC使用了DTLS,而DTLS依赖SDP的信息做校验,在P2P无法连接的场景需要用到TURN中继转发。RTP和RTCP是在一个协议里面描述的,RTCP是控制和反馈消息,比如如下知识点,都会用到RTCP

RTP消息头

下面的的字段均是从协议RFC3550中截取的,更详细的介绍请参见RFC3550,下面仅把个人的理解阐述出来。

主要字段说明

P(padding)

1 比特,若填充比特被设置,则此包包含一到多个附加在末端的填充比特,填充比特不算作负载的一部分。填充的最后一个字节指明可以忽略多少个填充字节。填充可能用于某些具有固定长度的加密算法,或者用于在底层数据单元中传输多个RTP包。由于Opus的包大小差不太多,但又不完全一样,所以会出现很多大小差不多却又不一样的小包,这对于服务器GSO发送这些包会带来很大的困难,所以通过增加几个字节的padding,可以让多个包一起GSO处理掉。

X(扩展标识)

1比特,若设置为1,固定头后面会跟随一个头扩展,扩展头4个字节,其中长度字段表示的是扩展项的个数,而非长度

CC(CSRC的个数)

4个比特,CSRC计数包含了跟在固定头后面的CSRC的数目

M(mark)

1个比特,标识的解释有具体协议规定。它用来允许在比特流中标识重要的事件,如帧边界等。

  1. Opus包,一般每个包的marker都设置为true
  2. Single NALU packet,也就是Payload就是264的NALU,帧的最后一个NALU的mark设置为true
  3. STAP-A包,用来打包SPS、PPS,一般都是IDR帧前会插入这个包,所以它属于IDR的一部分NALU,按照前面规则不是最后一个NALU设置marker为false,STAP-A设置为false。
  4. FU-A,最后一个包设置为true,其它设置为false

timestamp

rtp时间戳的定义和一般封装格式(比如TS、mp4)不一致,像TS、MP4音视频时间戳都是定义在一个时间轴上的,分别通过音视频时间戳即可保证音视频同步。

  1. rtp时间戳,音视频是单独计算的,不在一个时间轴上
  2. 时间戳单位:是采样率的倒数,比如视频采样率是90000,则单位是1/90000,音频是8000,则单位是1/8000。
  3. 如何保证音视频同步:在rtcp协议上会分别将音视频的时间戳和NTP时间一起传递,接收端处理逻辑则是依据NTP时间作为统一参照时间轴,做音视频同步。

SSRC和CSRC

在rtp协议上会有个混频器和转换器的东西,其作用是将多路rtp流混频成单一rtp流(比如重新转码,降低码率)这样从混频器出来的单一rtp流其SSRC是由混频器重新定义并且会话内唯一,但是为了标识混合后的音频隶属于哪路原始音频,则会在CSRC中标识多个原始SSRC。

注意,音频和视频的SSRC是不一样的。

RTP扩展头

defined by profile

具体解释后面header extension的格式,有one byte,和two byte,header extension是标准的TLV格式,one byte则标识T+L为1个字节,其中T和L各为4个比特。two byte含义类似,T+L为2个字节,其中T和L各位1个字节。

length

length的定义比较特殊,标识的是4字节为单位的个数,如果定义为2,则标识header extension总长度为2*4=8个字节。不够4字节的需要加0填充。

RTP PayLoad

负载类型

首先要说清楚一点,在rtp payload中可以存放多种媒体类型,具体类型由rtp header中的pt值决定,具体定义见RFC3551和https://www.ietf.org/assignments/rtp-parameters/rtp-parameters.xml定义。

以视频为例,RFC3551部分定义,>=96的动态自定义的部分,需要用户在SDP协议中定义。比如常见的H264 pt值定义为96,也有定义为97的。

负载存放形式

本文仅以最常见的H264为例具体说明,放入到RTP Payload的数据是H264的NALU包,但和H264标准定义有些差异。对于一个原始的 H.264 NALU 单元常由 [Start Code] [NALU Header][NALU Payload] 三部分组成, 其中 StartCode 用于标示这是一个NALU 单元的开始, 必须是 "00 00 00 01" 或 "00 0001", NALU 头仅一个字节, 其后都是NALU 单元内容.打包时去除 "00 0001" 或 "00 00 00 01" 的开始码, 把其他数据封包的 RTP 包即可。

宏观上看,打包的形式有3中模式,单一包模式、聚合包模式、分段包模式。同时又分有交织和不交织。

交织代表发包顺序不是解码顺序,这种方式比较适合对延时没有要求的场景,当然此种方式还需要为每个NALU包携带DON(docodeing order number)

NALU

h264详细定义在ISO_IEC_14496-10-AVC-2003.pdf。H.264的rtp payload定义在RFC6184,在RTP Payload部分的第一个字节是如下定义的NAL HDR,其中最重要的就是低5个比特,标识当前rtp包的NALU包的类型,也就是前面说的单一包模式、聚合模式、分段模式。

F: 1个比特. forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.禁止位,0表示正常,1表示错误,一般都是0;

NRI: 2个比特. nal_ref_idc. 取00~11,表示这个NALU的重要性,如00的NALU解码器可以丢弃它而不影响图像的回放.

Type: 5个比特,重要 nal_unit_type. 这个NALU单元的类型.简述如下:

NALU TYPE介绍

下面的截图分别取置ISO_IEC_14496-10-AVC-2003.pdf和RFC6184,后面RFC6184是rtp针对264做的扩展说明

RTP包中的nalu type介绍

  1. 1-23,这个是h264定义的nalu,里面全是媒体数据包
  2. 24,stap-a,single-time-aggregation packet,多个nalu的聚合包,他们时间戳相同。stap-a是没有DON(decoding order number)
  3. 25、stap-b,和stap-a一样包含多个nalu,他们时间戳相同,不同点在于stap-b包含DON
  4. 26、27,MTAP,也是存放聚合包,都需要有DON,但各个NALU时间戳不同。这种包由于时间戳不同,会在每个NALU包前面包含ts offset,而这个offset有16bit和24bit之分。
  5. 28、fu-a,fragmentation units,分片的包,比如一个idr帧可能有6000字节,作为一个udp包发那肯定超过mtu,一般mtu1500左右,有时候为了兼容mtu可能设置为500左右,fu-a也是不包含don的
  6. 29、fu-b,和fu-a一样是分片的nalu,包含don

在RTC应用场景中,由于对延时要求较高,一般不使用交织模式的打包方式,所以常用的分包模式是NAL unit、STAP-A、FU-A。像sps、pps这两个nalu由于很小,会用聚合的方式stap-a类型的rtp包来传输;针对idr帧,由于很大,会采用分片fu-a的方式来传输,同时在fu-a的起始rtp包和末尾rtp包均会带上标识。

DON

简单说下DON,全称是decoding order number,只用在交织包里面,非交织包发送顺序和解码顺序是一致的。

打包示例

协议RFC6184的打包示例如下,具体最好直接看协议会比较清楚一些。

Multiple Slices

一个帧可能是一个NALU,也可能有多个NALU,多个NALU叫多个slice(multiple slices)。打包时由于每个NALU的长度都没有超过最大长度,所以每个NALU都打成一个RTP包。这种打包方式有个问题,由于每个NALU都是一个包,如果丢包了之后,比较难处理。另外,优化UDP性能时,若使用GSO发送UDP包,这些包大小都不同,会让GSO难以处理。我们可以把这些NALU作为一个NALU打包,使用AnnexB的方式连接这些NALU,这样将小包合并为大包比较方便服务器处理。

nalu0 + 00 00 00 01 + nalu1 + 00 00 00 01 + nalu2

AnnexB一共有两种起始码:3字节的0x000001和4字节的0x00000001。3字节的0x000001只有一种场合下使用,就是一个完整的帧被编为多个slice的时候,包含这些slice的nalu使用3字节起始码。其余场合都是4字节的。

RTCP协议分析

RTCP和RTP混合一个通道传输

RTCP和RTP定义在一个RFC中,是反馈消息。可以完成预测和校正,便于WebRTC做到低延时。

RTCP和RTP可以bundle一个通道上传输,RFC协议考虑了如何区分它们,参考RFC1889.下面是RTP和RTCP的消息协议头,注意看RTP的M+PT和RTCP的PT均在第二字节。

因此,RTP和RTCP的关键区别,在于第二个字节也就是PT,RTCP的PT的定义,必须要能够避免和RTP的PT以及M被设置时冲突,参考(https://tools.ietf.org/html/rfc5761?spm=ata.13261165.0.0.19be4097vKwk13#section-4)中有详细定义。

RTP媒体的PT:[96,127]或[224,255](如果M标识位设置为1)

RTCP可用区间为:[0,95]或[128,223](如果M标识位设置为1),目前已经分配的区间有:

  • [64-65]([192,193]),FIR和NACK
  • [72-76]([200,204]),SR、RR、SDES、BYE
  • [77-78]([205,206]),RTPFB和PSFB
  • 79(207),XR
  • 80(208),RSI

所以未来RTCP的分片区间是[209,223],[194,199],所以判断是否是RTCP则判断PT值为[0,95]([128,223]),目前RTCP的PT值都是从64(192)开始,所以精确判断是在[64,95](192,223)。

主要协议

rtcp协议重要的两个协议SR和RR,一个是发送端信息统计和是接收端信息统计

SR

SR协议定义中有部分是RR协议定义的,刨除RR部分的最重要的NTP和RTP timestamp,这个部分是用于音视频同步用的。

RR

fraction lost:丢包率

packets lost:丢包数

扩展包序号(32bit):低16位为当前接收到的来自源的(用源SSRC标识)数据包的最大序列号;高16位表示RT包序列号的循环计数!我们都知道RTP数据包中,表示序列号的长度为2个字节,即最大的RTP序列号为65536,如果序列号超了65536,假设为65537,这个时候RTCP在扩展包序号中对其说明,如果没有超过65536,则高16位为0,如果超过65536,则为1,如果再来一圈,则为2。

间隔抖动(32bit):到达时间差值-发送时间插值

在WebRTC场景下,有用的部分主要是SR的NTP和RTP timestamp,用于音视频同步。RR中的丢包率和丢包数,用于发送端依据丢包率进行带宽估计。其他字段暂时未发现有用

WebRTC对RTCP的扩展

Transport Wide CC Feedback

具体协议参考:https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01

REMB

具体协议参考:https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值