在RFC3550中,除了定义了⽤来进⾏实时数据传输的 RTP 协议外,还定义了 RTCP 协议,⽤来反馈会话传输质量、⽤户源识别、控制 RTCP 传输间隔。在 Webrtc 中,通过 RTCP 我们可以实现发送数据/接收数据的反馈,传输控制如丢包重传、关键帧请求,⽹络指标 RTT、丢包率、抖动的计算及反馈,拥塞控制相关的带宽 反馈,以及⽤户体验相关的⾳视频同步等等。为了让开发者获取以上数据指标,Webrtc 提供了统⼀的接⼝调用,如在GoogleChrome中,可以通过 RTCPeerConnection.getStats()或者chrome://webrtc-internals/查看以上指标。
RTCP报文类型
⽬前 RTCP 主要定义了以下8种类型的报⽂,其中业务场景中主要⽤到 SR/RR/RTPFB/PSFB,接下来我们也将重点介绍这四种报⽂。未来如果有新类型的话,会继续从208-223中分配, 0/255⽬前禁⽌使⽤。
RTCP报文格式
在介绍报⽂类型之前,我们先看⼀下报⽂格式:
每个 RTCP 包都有⼀个和 RTP 类似的固定格式的头,⻓度为8,后⾯跟着⻓度不定的结构化数据,在不同 RTCP 类型时,这些结构化数据各不⼀样,但是它们必须都要 32-bit 对⻬。RTCP 的头部是定⻓的,⽽且在头部有⼀个字段来描述这个 RTCP 数据的⻓度,因此 RTCP 可以被复合成⼀组⼀同发送。
SR: Sender Report RTCP Packet
- SR 也叫发送者报告,发送端会周期性的发送 SR,携带的是会话开始到现在为⽌累计的发包数/字节数。
- SR 中携带的 NTP/RTP Timestamp 主要⽤来在接收端进⾏多个媒体流间的同步。
- SR 和后⾯的 RR 配合使⽤可以进⾏ RTT 的计算。
RR: Receiver Report RTCP Packet
与 SR 相对应,RR 也叫接收者报告,RR 中定义了更多的指标信息,即反应了收包状态,⼜反应了⽹络状态,因此我们有必要了解这些指标都是怎么计算的,来保证反馈的准确性。
Fraction lost
每个统计周期以 SR/RR 为间隔统计,fraction lost = (期望收包数-实际收包数)/期望收包数*255 在 RTP 传输中,收包、丢包计算都依赖于RtpHeader 中的 Sequence number,由于只被分配了16字节,即最⼤序号为65535,很容易⽤尽,所以需要我们做循环计数, 并在计算中转化为uint32这种取值范围更⼤的类型来表示。
Jitter
抖动的定义是信号在某特定时刻相对于其理想时间位置上的短期偏离。在⽹络传输中,数据包可能会经过不同的路由链路,当时的⽹络或拥塞或空闲,最终到达⽬的地时,与预期会有所偏差。通过数据包的到达情况,我们可以反过来估测⽹络的状态变化,⽤来对发送端进⾏指导。RFC3550中定义了相关计算公式。
DelaySinceLastSR
除了丢包、抖动以外,⽹络中我们最常关注的⼀个指标就是 RTT, 常⻅的操作是通过ping命令查看⽹络中的往返延迟。RTCP 中为了计算RTT,在 RR 中会携带上次收到的 SR 中的NTPTime,并计算其收到时在本机经历的时间,⽤ DelaySinceLastSR 表示。发送端收到后,剔除掉 DelaySinceLastSR 便是 RTT。
eg: 假设本次构造 RR 距离上次收到 SR 为 5250毫秒。
dlsr = 5250/1000 << 16 | 525000*65.535 => 0x0005:4000
RTT计算
音视频同步
在 RTP 传输中,携带的 timestmap 的初始值是随机产⽣的,另外⾳频、视频可以从不同的传输通道独⽴传输,虽然都是线性单调递增的,但是两者 RTP 的 timestmap 是没 有相互关系的,需要 RTCP 提供额外信息来进⾏同步。为了实现⾳视频同步, 发送端会定期发送 Sender Report, 携带 rtp timestmap、ntptime, 接收端把每路流收到的 rtp timestamp 都转换为 NTP 时间,实现同步。在实现同步之前需要知道,我们常说的采样率对应的时间单位是1秒。⾳频的timestamp ⼀般根据每帧的采样点数增加,如opus 48khz 代表每秒采样48000,如果每 20ms采样⼀次, 则每次采样为48000/(1000/20) = 960。由于⾳频采集频率⾼,不容易出现误差,所以程序实现中增⻓都是固定的960。
视频的采样率⼀般为90khz, 由于视频采样频率低,容易出现误差,实际计算时间戳时,会根据系统时间来计算,每帧之间增⻓不⼀定是固定的值,如图帧率为15fps, 每次增⻓不是固定值,约等于 90000/15。
RTP-FEEDBACK
RTP-FEEDBACK 主要⽤来在传输层进⾏反馈,实现数据包的丢包重传,码率控制,主要有以下⼏种类型:
NACK
在 RTP-FEEDBACK 中,最重要的当属NACK,区别于 TCP 中的 ACK,在 RTCP 中 NACK 代表否定应答,当接收⽅监测到数据包丢失时,发送⼀个 NACK 到发送⽅,表明⾃⼰没有收到某个报⽂。⽬前 NACK 可以认为是对抗弱⽹最主要的⼿段,报⽂格式如下:
- 4个字节(2字节 PID 代表第⼀个开始丢的包、2字节BLP代表紧随其后的16个包的丢包信息、bit1代表丢包);
- 可以同时携带多个nack block.
Transport-CC
- Transport-cc 是⽬前 Webrtc 中最新的拥塞控制算法,替代旧的 GCC 算法;
- Transport-CC 需要在 RTP 中增加扩展,接收端记录 RTP 包的到达时间、间隔并反馈给发送端,这⾥不做详细介绍,后期可以和 GCC ⼀起分享。
PAYLOAD-FEEDBACK
RTC 中,主要传输的是⾳频、视频,由于两种媒体有不同的特点,⾳频⼩包,前后帧⽆参考;视频帧具有前后参考关系,关键帧⼜是 GOP 中后续帧的主要参考对象,可以说是重中之重,需要 RTCP 针对具体的载荷类型进⾏更精细化的信息反馈。⽬前主要有以下类型:
- 当前的实现中,主要的反馈实现是PLI, 当⽹络出现丢包时,接收⽅反馈帧丢失,请求发送⽅重新编码关键帧发送;
- FIR 也是请求关键帧,主要⽤在新⽤户加⼊的场景中;
- ApplicationLayerFeeedbackMessage 中主要是 REMB 经常使⽤。
REMB
REMB 即接收端最⼤接收码率估测,需要配合rtp扩展abs-send-time⼀起使⽤,是接收端估算的本地最⼤带宽能⼒,发送端根据 REMB、丢包等进⾏拥塞控制。
REMB 估算的码率代表的是⼀个传输通道内所有 SSRC 的码率之和, ⽽不是针对于某⼀个特定的 SSRC。
XR
RTCP 在很早之前就定义了扩展报告,主要是在 SR/RR 基础之上携带补充信息,开发者可以基于其中更加详细的指标做更深层次的拥塞控制上的优化。包含以下七个报告块:
RRT/DLRR
上⾯讲到的 RTT 是发送⽅的计算逻辑,对于纯接收⽅,同样有必要知道⽹络 RTT,就需要⽤到该扩展。接收⽅发送 RRT 扩展后,发送⽅在下次的 RTCP 中携带 DLRR 扩展,计 算⽅式和 SR 计算 RTT 类似。
SS
可以看到,报⽂中携带了更加详细的指标信息,尤其是 Jitter 指标,对于带宽评估有很好的参考作⽤。
Chrome 指标查看
了解了指标的计算,如何确认指标计算是否正常,反馈是否准确,对于开发者同样重要。以 Chrome 浏览器为例,⽬前开发者想要查看底层统计指标有两种⽅式:
- 通过RTCPeerConnection.getStats() 接⼝调⽤;
- 通过chrome://webrtc-internals/查看, ⽬前Chrome处于两种getStats的过渡期,可以切换查看不同指标。
我们下⾯列举几个通过chrome://webrtc-internals/查看的指标:
以上我们对 RTCP 进⾏了简单的讲解,实际的开发场景中,对于 RTCP 的使⽤还有很多需要注意的点, 不同类型的报⽂采⽤不同的发送策略、发送周期、 触发时机等, 欢迎⼤家⼀起讨论。
腾讯云通信
一直致力于
让每个企业
都享受智慧服务带来的改变
END
未来可期
长按扫码关注腾讯云通信官方微信公众号
以获取更多更专业的云通信知识