头图

技术干货 | 基于标准 WebRTC 低延迟直播的开源实践

网易云信
English
导读:2020年,新冠疫情爆发并席卷全球,对包括中国在内的全球经济造成了巨大的冲击,同时深刻影响了社会生活。在这一背景下,以消费市场上轰轰烈烈的直播电商为引爆点,直播行业再次掀起热潮。在中国企业数字化转型的浪潮中发展了十年之久的企业直播服务市场,也顺势进入高速发展阶段。

图片

文|洪顺迪 网易云信流媒体 Server 端研发工程师

1 典型的直播架构

图片

在典型的直播架构中,左边是推流客户端,协议上才采用 RTMP 上行;右边是拉流客户端,支持不同的拉流协议拉流,比较常见的是:RTMP、FLV、HLS

1.1 现有架构的优点

这套框架很好的利用了 CDN 厂商或者说云厂商的能力。尽管拉流协议没有统一,rtmp/flv/hls 等拉流协议作为比较成熟的流媒体协议,经过多年的发展,得到了各 CDN 厂商广泛支持。在云端能力的支持下,服务端并发能力和拉流端加速能力大大增加了,直播行业蓬勃发展。

2 低延迟直播的现状

图片

在直播领域中卡顿和延迟就像是天平的两端。延迟做的越短,则卡顿越高;延迟越长,卡顿就越少。

一般场景下都是客户端用更大的 buffer 时长,牺牲延时来满足流畅性。随着行业的发展,某一些应用场景对延时时间的要求越来越苛刻,比如体育比赛直播,教育场景下老师与学生间的互动等,这些场景下常见的直播流媒体协议的缺点就体现出来了。

一般 rtmp 协议直播延时在 3-10s,如果经过层层 CDN 的缓存和转发,超过10秒也是常有的事,flv 和 hls 协议的延时更高。就拉流端来说,延迟的很大一部分源自网络传输:rtmp 在传输媒体前的 tcp 3次握手和 c0/c1/c2 握手协议,无端引入了好几个 RTT 的延迟;由于 rtmp/flv/hls 的传输层都是基于 tcp 协议,在网络不稳定的情况下,受限于 tcp 协议的拥塞控制不能充分利用网络带宽,客户端为了保持流畅性,只能加大缓存时间,因此更进一步加大了延迟。\
 

在认识到现有流媒体直播协议的局限性后,各大友商也纷纷推出了自己的低延时直播,较好的起到了对抗弱网和加快首屏的作用。但目前大都基于私有的信令协议和私有的 UDP 流媒体传输协议,各大云厂商无法互相兼容,这就限制了低延迟直播的大规模发展。

3 基于标准 WebRTC 的低延迟直播的开源实践

网易云信一直在探索如何做一个开放的低延时直播方案, 将来各家云厂商也能够比较方便的实现,就像现有的 rtmp/hls 协议一样,推动整个直播行业低延迟化。要实现这种方案需要做以下两件事情。

  1. 开放的信令协议: 信令协议需要满足绝大多数厂商的媒体协商需求,同时又能尽可能的简洁。
  2. 开放的媒体协议: 媒体传输协议需要满足在各大厂商间能够通用,在这之上的 QoS 能力也需要开放,不能是私有的。

依据上面的要求我们选择了 RTC 领域成熟的解决方案——WebRTC。下图是我们现在的实践架构。

图片

上图中 WE-CAN 是网易云信的全球加速 RTC 大网,媒体在 Server 间的网络传输依赖 WE-CAN。

边缘媒体服务器从 CDN 拉流到 WE-CAN 大网边缘节点,再从 WE-CAN 大网边缘节点发送给客户端。

3.1 开源的信令协议实现

信令协议上采用 HTTP+SDP 的方式,即客户端 POST 一个 SDP Offer。 

{
    ...
    "pull_stream": "nertc://your.domain.com/live/testname"
    "sdp": "v=0\r\no=4611731400430051336 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\n......",
    "type": "offer"
}

然后媒体服务器经过协商返回 SDP Answer。

{
    ...
    "code": 200
    "sdp": "v=0\r\no=4611731400430051336 10000 1 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=ice-lite\r\n......",
    "type": "answer"
    ...
}

3.2 标准的 WebRTC 媒体协议

客户端拿到 SDP Answer 后,就是标准的 WebRTC 媒体交互流程:ICE、 DTLS 加密连接,接收 RTP 流媒体。

下面是一个基本的 Web 端的拉流代码 Demo:

self.pc = new RTCPeerConnection(null);

self.pc.addTransceiver("audio", {direction: "recvonly"});
self.pc.addTransceiver("video", {direction: "recvonly"});

var offer = await self.pc.createOffer();
await self.pc.setLocalDescription(offer);

var session = await new Promise(function(resolve, reject) {
    var data = {
        pull_stream: streamId, 
        type: "offer", 
        sdp: offer.sdp
    };
    
    $.ajax({
        type: "POST", url: apiUrl, data: JSON.stringify(data),
        contentType:'application/json', dataType: 'json'
    }).done(function(data) {
        resolve(data);
    });
});

await self.pc.setRemoteDescription(
    new RTCSessionDescription({type: 'answer', sdp: session.sdp})
);

3.3 开源的 Native 媒体播放器

为了让 Native 客户端能够更方便的接入 WebRTC,我们同样开源了一个集成了标准 WebRTC 的低延迟直播播放器:We-Can-Player,只要输入流地址,就能实现接收 WebRTC 流播放。

3.4 客户端的架构:

图片

 

只要厂商实现了类似的协议,用这个播放器稍作修改就可以拉到 WebRTC 的流。从架构上可以看出媒体服务器和拉流客户端之间的交互大都是基于标准的 WebRTC,没有私有的 RTP 扩展和私有的 QoS 协议, CDN 厂商甚至可以没有自己的 RTC 大网,只需在 CDN 边缘节点实现标准的 WebRTC 网关+一个简单的 HTTP Server 就可以拥有同样的能力。

为了优化直播体验,我们还在 Server 端做了大量的优化。

4 优化直播体验

4.1 首屏优化

4.1.1 GOP 缓存首屏优化

直播领域有两大指标:首屏和流畅性。 假设用户推流端的 GOP 的是5秒,在某些情况下,拉流端要等接近5秒才能收到第一个 I 帧,首屏才能渲染。这对直播来说是不可接受的。

解决方案是在媒体服务器里做 Gop 缓存,缓存最近1-2个 Gop 的媒体包在 Server 端,当客户端和媒体器媒体连接成功以后,先发送 Gop 缓存里面的媒体包,再发送当前的媒体数据。客户端收到媒体包后,需要根据一定的策略对齐音视频包,再加速追帧。

在具体的实践过程中,要注意 Gop 缓存大小、客户端的 Jitter buffer 大小的配合、Gop 缓存里音视频的对齐、不同的推流端不同的 Gop 长度的适配等情况。

4.1.2 Pacer 平滑发送

如果推流端设置的 Gop 比较大,当拉流客户端媒体连接成功后,会一股脑的给客户端发送全部的 Gop 里数据,可能造成客户端缓冲溢出以及其他问题。这时候就需要 Server 的 Pacer 平滑发送发挥作用了。

在具体的实践过程中,要注意 Pacer 的追帧速率与客户端追帧速率的配合。

4.2 延迟优化

4.2.1 WE-CAN 大网

前文提到了直播行业之所以能蓬勃发展,在技术方面 CDN 厂商的云端能力起到了很大的推动作用。CDN 加快了边缘节点的回源速度,边缘节点又加快了拉流终端的接入速度。

从上面的架构图可以看到,为了加快回源速度,回源媒体服务的选择会尽可能的接近 CDN 的区域中心节点;为了优化客户端的接入性能,拉流媒体服务器也要尽可能的接近拉流客户端,因此媒体 如何迅速地从回源媒体服务传输给拉流媒体服务就至关重要。

而 WE-CAN 就承当了这个职责, 他是云信内部开发的一套高效全球传输大网,能加速全球任何两个媒体服务器之间的网络传输。从某种意义上来说,他起到了推动 CDN 加速传输的作用,不过 CDN 的原理是层层 cache,WE-CAN 靠的是路径优化。

4.2.2 全 SFU 架构的媒体服务器

设想两个主播的互动,如果我们加入 MCU 的话必然会引入缓存,导致首屏和延迟都加大,所以 RTC 大网内部都是基于 SFU 架构做的布局。

4.2.3 全链路延时监控

如何全链路的监控拉流测引入的延迟? 媒体流在 WE-CAN 大网里经过层层转发,如果任何一段路由引入不必要的延迟,就会影响最终的低延迟效果。我们的做法是在 RTP 头里加上一个 extension,记录 RTP 包到达每个机器的毫秒级的 NTP 时间后,在转发给客户端的最后一个媒体服务器上汇报每跳路由的时间消耗以及边缘服务器与客户端之间的 RTT 时间,在最终发给客户端的客户端 RTP 中再剥离这个 extension。尽管各机器的 NTP 时间没有绝对对齐,但依赖 WE-CAN 大网的全局 NTP 时间同步功能,差距能够控制在 1ms,这个精度足够在工程实践中发挥监控作用。

5 效果和后续工作

第一阶段在网络 QoS 方面暂时只支持 ARQ 和 Opus 的 inband-FEC 能力。由于 WebRTC 原生支持基于 XOR 的 FEC 能力,在抗连续丢包方面很弱,所以暂时没有开启 FEC,但较 RTMP 有了巨大的改进。实现了在 50% 丢包条件下,控制在2秒左右的延迟,200~400ms的首屏。

我们后面的计划包括:加入更多的 WebRTC 标准 Qos 能力(包括 FEC 在内);推流侧的 WebRTC 改造能力等,具体的开源内容可以持续关注【智企技术+】公众号,后续我们会持续更新开源相关内容及开源地址。

作者介绍

洪顺迪 ,网易云信流媒体 Server 端研发工程师,负责网易云信流媒体 Server 端的开发工作。

阅读 1k

网易云信技术小站
聊一聊网易云信在技术实践和架构优化上的那些事~

欢迎关注网易云信 GitHub:

572 声望
122 粉丝
0 条评论

欢迎关注网易云信 GitHub:

572 声望
122 粉丝
文章目录
宣传栏