RTC
RTC Server
流媒体服务器
媒体数据的传输,实现实时传输的最基本功能。
信令服务器
管理多路用户的逻辑,将多个通信用户组建房间进行权限控制和资源管理。
打洞服务器
为媒体传输提供更丰富的传输通道。
其他
CDN
提供就近接入和媒体缓存。
专线
复杂网络情况中提升各运营商之间传输质量。
NAT
NAT解决了IPv4资源不足问题,将端口和IP隐藏在内网,从而提高安全性
- 完全锥型
- IP限制型
- 端口限制型
- 对称型
组网的网关就像一道墙,阻隔着外部host和内网host直接访问。身处两个NAT后面的host不得不借助于打洞服务器来探测和协助两个host相互访问。因此,以上4种类型的组合情况有12种。
完全锥形比较容易理解,就是一个四元组:
{
内网IP,
内网端口,
映射的外网IP,
映射的外网端口
}
这个映射四元组就是墙上的“洞”,NAT通过查找这个映射表来转发数据。完全锥形没有任何限制,内网的任何host都可以通过这个“洞”和外界通信。
IP限制型,多加了一个元组:
被访问主机的IP
即限制了内网其他IP的host不能通过这个洞。
端口限制型,又多加了一个元组:
被访问主机的端口
即限制了内网同个host的其他端口不能通过这个洞。
最复杂和多变的对称型,对于同一个外网host访问内网host1和host2,它映射的IP和端口都是变化的,因此:对称型—对称型
和对称型—端口限制型
这两种情况在STUN中是无法穿越的。
NAT穿越为媒体传输通道提供了直连的选择,同一局域网应该首选直连通道。其他情况可根据业务需求和质量情况来判断选择哪种通道。
多对多通信
Mesh方案
思想基于一对一方案,将每个host之间都建立一个连接,且每个host之间都能打通直连通道。
局限性:
- 现实场景中,不一定每个host之间都能建立直连通道
- 共享媒体流的时候,将给每个对端发送一份数据,上行带宽很大
MCU方案
Multipoint Conferencing Unit
服务器进行多路混流和重新编码,视频会议场景等,对服务器硬件要求高。
优势很明显,场景体验好,节省带宽资源。
局限性也很明显,对服务器要求高,混流过程有一定的延时。
SFU方案
Selective Forwarding Unit
服务器对多路流根据实际场景进行转发。
传输质量
流媒体传输协议
传统直播推拉流架构的主要协议:HLS和RTMP协议。
由于WebRTC传输数据基于UDP协议,RTMP基于TCP协议,HLS基于HTTP协议的特点,传输实时性:WebRTC(RTCP/RTP) > RTMP > HLS
- WebRTC多用于实时音视频通信或互动场景
- RTMP多用于推拉流场景
- HLS多用于拉流端和点播场景
算法设计
在实时传输中,一般使用UDP协议,因此需要对抗丢包,乱序,抖动等质量问题。在实时和可靠之间做权衡,一切都是trade-off。
NACK
NACK receiver
目标: 既要做到及时快速的重传,又要避免过多过久的重传,减少带宽的使用。
思路1: 收到包时记录seq,定时检查最近1000个包里丢失了哪些,发送RTCP NACK请求。
问题:定时器间隔导致丢包不能快速请求。
思路2: 思路1+每次收到包都触发一次快速请求重传。
问题:乱序时误重传,浪费带宽。
思路3: 思路2+为避免即时和定时频繁发送NACK请求的问题,根据rtt推算是否在定时器触发时需要再次请求NACK,并记录包的重传次数,超过一定次数则停止再发重传请求。
弱网环境下的补充:若重传队列过长,可清理至上一个keyframe处的seq。若队列还是过长,可直接清空重传队列,并发送RTCP PLI请求。
NACK sender
sfu的sender应尽量减少包拷贝次数,多个发送端使用统一发包队列,只记录每个sender的索引。
RTC端到端
发送端
前处理
包括缩放、图像增强、美颜。编码
包括码控、预测、变换、量化、熵编码。
在 RTP 打包的时候是以 Slice 为单位 打包
的,而不是以帧为单位打包的。Slice 其实是为了并行编码设计的。将一帧图像划分成几个 Slice,并且 Slice 之间相互独立、互不依赖、独立编码。
在RTC视频通话场景下最好选择 CBR
的码控算法,从而保证输出码率能够比较好地贴合预估带宽。
如果编码器输出码率差网络带宽太多,也会导致 PacedSender
缓冲太多数据包,从而引起延时太长。码控和 PacedSender 都很重要,它们是一起协作来减少卡顿的。
接收端
Jitter Buffer
工作在接收端,主要功能就是在接收端收到包之后进行组帧,并判断帧的完整性、可解码性、发送丢包重传请求、发送关键帧请求以及估算网络抖动的。
判断帧完整性
结合发送端的打包特性:
- 在 RTP 打包的时候是以 Slice 为单位打包的,一帧是有可能有多个 Slice 的。
- 在 RTP 包里面,RTP 头有一个标志位 M,表示是一帧的结尾。因此只要收到这个标志位为 1 的包就代表收到了这一帧的最后一个包。
- 同一帧 RTP 序列号一直连续。
- 同一帧 RTP 时间戳相同。
- slice_header 的 first_mb_in_slice 字段为 0,就代表是帧的第一个 Slice 了。
方法一:
first_mb_in_slice 为0,序号连续,找到 M 为1的包。
方法二:
收包队列从 M 为1向前找序号连续的,直到找到RTP时间戳跳变为止为帧开头。
两种方法相同的都是用M标志位判断帧结尾,区别是如何找帧的开头。第一种方法更加灵活。
卡顿
一般的通话视频来说,帧之间间隔超过200ms会造成视觉卡顿。
发送端排查
- 帧率不够5fps,提高帧率。
- 机器性能不够,导致前处理或编码耗时过长。可以在高分辨率的时候尽量使用 GPU 做前处理,并使用硬件编码或者将软件编码设置为快速档加快处理的速度(压缩率会下降)。
- 编码器输出码率超过实际网络带宽。如果使用 VBR 码控算法,编码器的输出码率会随着画面的复杂程度变化,那就会有很大的概率因为画面复杂而出现输出码率超过预估带宽的情况,从而导致对端出现严重的卡顿。而 CBR 码控算法是你设置多少目标码率,编码器的输出码率就会接近于目标码率。
- 复杂帧编码后过大或者 I 帧比较大。为了能够减小这种大帧带来的瞬时网络波动,我们可以在编码打包之后、发送之前,加一个平滑发送的模块来平滑地发送视频包。这个模块在 WebRTC 中叫做 PacedSender(节奏发送器)。PacedSender 主要的工作原理就是编码输出的码流打包之后先放到它的缓冲区中,而不是直接发送。之后它再按照预估带宽大小对应的发送速度,将缓冲区中的数据发送到网络当中。
接收端排查
- 丢包重传策略应对网络丢包。
- 丢包重传仍然没有恢复,FIR请求,收到IDR帧强制关键帧(立即刷新帧)才可恢复。
花屏
基本上都是接收端的问题:
- 帧不完整。如果帧出现了丢包就送去解码的话,若能解码成功,那肯定会出现解码花屏的问题。
- 参考帧不完整。
- 渲染的时候 YUV 格式弄错了。
- Stride 问题会造成花屏。我们解码后渲染前一定要处理好 YUV 的 Stride 问题,不要和宽度弄混了。
后两者花屏的图像比较有辨识度。