编者按: 随着互联网的发展、流量咨询费用的下降,直播互动越来越多的呈现在大众面前。直播带货、游戏主播,亦或者是大型网课,在直播中良好的网络环境与低延时是优质交互体验的关键。在这个各家云服务厂商标准不统一的年代,如何让低延时直播更加便捷稳定呢?本次LiveVideoStackCon 2022音视频技术大会上海站邀请到了毕伟老师为我们介绍网易云信的解决方案。
文/毕伟
整理/LiveVideoStack
大家下午好!我是网易云信资深音视频引擎研发工程师毕伟,今天为大家介绍云信开源低延时播放器的相关内容。云信开源播放器基于WebRTC二次开发,并且现在已经将代码上传到GitHub上,感兴趣的各位可以关注一下。
接下来我会从直播行业背景、低延时直播现状、低延时播放器框架、关键指标优化和未来展望5个方面逐步介绍。
一、直播行业背景
近几年直播发展非常迅速,已经渗透到各行各业。举两个非常典型的例子,一个是电商直播,另一个是在线教育。
电商直播中,存在主播直播和粉丝互动的环节,观众会通过下部的评论问主播相关的问题。如果延时很大,问完问题5到10秒才能听到主播的回答,会带来很差的交流体验,导致用户没有及时的收到反馈而直接退出直播间,成交转化率也较低。
因为疫情的原因,在线课堂十分火热,尤其是一个老师对应很多学生的大班课。老师在上课中也会和学生进行互动,高延时也会降低互动体验,影响课堂质量。
这两个典型场景的主要诉求都是低延时。现在市面上主流的仍然是标准CDN直播,即主播通过RTMP协议推流到CDN,CDN再进行分发,最后观看者通过HTTP-FLV、HLS、RTMP等协议进行拉流。整个方案基于TCP进行传输。因为TCP重传效率低,ACK反馈延迟导致数据积压,所以TCP方案的延时基本上在3到10秒。虽然HTTP-FLV/RTMP可以做到3秒左右,但是HLS因为切片的原因,会延长到10秒。综上所述,TCP方案并不适合用于低延时直播。
现在各大云厂商陆续推出了低延时直播的服务,主要是改造下行链路。通过把下行链路的RTMP转换成RTP,再进行UDP传输。整个直播过程包含主播端的采集、编码和发送、CDN分发、播放端接收、解码和渲染,主播端的延时相对较低,CDN内部走专网专线所以延时也是可控的。整个延时主要是下行TCP网络相对不太可控造成的,需要播放器加大缓冲区对抗网络抖动。正因如此,TCP方案端到端网络延时较大。事实上,改造下行网络带来的收益是最大化的。只需要将下行改为UDP传输,整个端到端延时就可以降低至1秒左右。现在市面上基于UDP的方案也有很多,例如QUIC、SRT、WebRTC等。目前WebRTC方案非常火热,大多数浏览器都支持,生态也很不错,所以云信也选择WebRTC作为低延时直播的基础。
云信也推出了自己的低延时直播服务。这张图是云信整个低延时直播的系统流程图。上行采用的是RTMP推流,通过改造下行链路,中间建立一张低延时传输网WE-CAN,主播推流到源站,源站再转推到WE-CAN进行分发。拉流端在边缘节点进行拉流。从云信传统的CDN直播转入到云信的低延时直播十分简便,只需要再重新申请一个低延时拉流的域名即可。
二、低延时直播现状
传统CDN直播能快速发展,和一些优秀的开源项目密不可分,例如FFMPEG、OBS、 VLC。目前的低延时直播仍然存在以下几个问题。首先各大云厂商采用的都是私有协议,没有标准化。另外,在使用这些协议时需要强绑定对应的SDK。在接入多家云厂商的服务时需要接入多个SDK。多个SDK对现阶段移动端APP的包大小十分不友好,不利于低延时直播的大规模推广。为此,云信推出一个开源的低延时播放器,开放信令交互,可以用一套SDK对接多家低延时云服务厂商。
三、低延时播放器框架
这是云信低延时播放器的框架。云信低延时播放器是一个传输层的SDK,最底层是WebRTC。因为我们意在打造一个通用版的SDK,所以我们将WebRTC全量包入,通过PeerConnection层接入,里面是一些主要模块,例如JitterBuffer、NetEQ、RTP/RTCP、Transport等。中间是RtdEngine层,主要作用是对WebRTC进行封装,包含API、引擎创建、信令建连、 媒体数据的接收回调等。最上层是FFMPEG插件。直播已近发展了数些年,各厂商都有一些存量的播放器,市面上大多数播放器都是基于FFMPEG开发,为了降低用户SDK接入门槛,云信将API封装成FFMPEG插件,扩展了输入流格式——ff\_rtd\_demuxer,对应的云信拉流地址协议头是“nertc://”。在FFMPEG插件里注册协议头,拉流地址替换以后就可以接入云信的低延时链路。如果要接入其他云厂商,只需要替换拉流协议头,同时将协议头添加到插件中即可,播放器代码不需要任何的改动。
下面介绍云信低延时播放器的交互流程。通过采用标准SDP+ICE的交互方式,以达到通用SDK的目的。客户端创建Offer SDP,通过HTTP POST到服务器,服务器响应Answer SDP,信令交互完成后进行ICE,ICE建连成功后服务器会发送媒体数据给播放器。
SDK的底层有一个Transport模块,建连成功后会收到服务器发送来的音视频数据,音视频数据包会分开传送。视频的数据包会送到JitterBuffer,音频数据包会送到NetEQ。视频的RTP包会在JitterBuffer中进行排序,组帧、重传等操作,之后会回调到RtdEngine。整个SDK内部不对视频进行解码,而是交由上层播放器做。视频数据组帧完成后回调时,为了不破坏原有的结构,云信模拟了一个解码线程,继承了WebRTC原来的VideoDecoder基类,模拟从JitterBuffer取数据的过程。取到的视频帧放在RtdEngine中,播放器通过插件从RtdEngine读取。音频在NetEQ中会被解码,之后回调PCM数据。同样,我们也在RtdEngine中模拟一个playout 线程,读取PCM数据到RtdEngine中,供播放器读取。大家可以注意到,我们只对音频做了解码,视频没有做。由于延时和缓冲区大小相关。播放器上层有一个缓冲区,JitterBuffer和NetEQ中也有缓冲区,多个缓冲区会对延时的控制带来难度,尤其是播放器上层的延时。我们希望将播放器上层的缓存区降为0,所有数据都在JitterBuffer和NetEQ中管理。这里音频解码是为了复用NetEQ中音频加减速的能力,更好地控制延时。
上面是传统CDN直播播放器的结构。通过FFMPEG从CDN中拉流,放到缓冲区中,然后进行解码、音画同步和渲染等。缓冲区一般设置为3到5秒。如果接入云信的低延时SDK,只要把云信的SDK编到FFMPEG中,作为FFMPEG的第三方插件,后续的整个流程不需要任何的改动,只需要把缓冲区降为0。所有的缓冲区都是由SDK中的JitterBuffer接管。拉流时只需要使用对应的低延时拉流地址,就可以接入到整个低延时拉流链路上。由此可见SDK的接入十分简便,同时可以复用原有FFMPEG拉流流程。原有播放器的业务不需要进行任何的改动。
下面具体介绍一下播放器的SDK接入。云信通过作为FFMPEG的插件,扩展AVInputformat格式,实现了如下接口rtd\_probe、 rtd\_read\_header、 rtd\_read\_packet、 rtd\_read\_close等。在rtd\_probe中添加nertc://的拉流协议头,FFEMPEG可以根据其中的分数探测最终的协议。如果需要接入其他低延时厂商的服务,就可以在rtd\_probe添加对应厂商的协议头。使用对应的拉流协议头就可以走进云信的低延时模块中。但仅仅走进模块还不够,后续还需要去和云厂商对接,了解其信令交互,自己进行一些对接上的调整即可。
我们提供了一个插件的源码,称之为rtd\_dec.c。只需要把rtd\_dec.c拷贝到FFMPEG的libavformat文件夹下,修改对应的脚本Makefile即可。另外,需要将生成的AVInputFormat类型ff\_rtd\_demuxer注册到FFMPEG中,使其能够认识。在allformats.c中添加AVInputFormat格式,FFMPEG重新编译。除此之外还有另外一种格式,即不编译FFMPEG ,直接调用FFMPEG接口av\_register\_input\_format()。这种方法仅对于低版本的FFMPEG支持,对于高版本的不太支持。所以我们统一采用allformats.c中添加libavformat格式,FFMPEG重新编译的方法。
还有一部分播放器是非FFMPEG播放器。云信也提供了一套API。具体操作可以参考rtd\_dec.c插件调用API的流程。
四、关键指标优化
下面来介绍关于直播指标的一些优化。分别是首帧优化、延迟优化和抗性优化。
1、首帧优化
首帧分为以下几个过程。用户点击播放之后进行建连,随后收到数据,再进行解码渲染。云信有一张WE-CAN传输网,在全球的主流国家和重点省市都进行了布点,大多数地区的用户都可以就近接入。同一地区的用户会尽量调度到同一个机房,减少回源。现阶段低延时拉流还是复用RTMP的上行,RTMP推流到CDN,再进行回源拉流。如果命中率较低,多次回源非常耗时,会大大影响首帧。
直播和RTC存在一些区别,直播在接入时没法请求关键帧等,如果服务器不缓存GOP,在订阅流时,服务器因为没有关键帧可以发,需要等待下一个关键帧到来才行。这会对首帧带来很大的影响。如果服务器缓存前一个GOP,订阅流时能立即发送数据。
以上都是服务器的优化。因为云信是一个通用的播放器,媒体建连会采用标准的ICE。ICE中存在DTLS,对于直播来说大部分场景不需要进行加密,可以关闭DTLS 减少建连耗时。
建连完成之后就可以收媒体数据包。网络中可能存在一些丢包的情况。检测丢包一般会通过序列号是否连续进行判断。但是当第一个关键帧最前面几个包丢掉,往往很难检测出来,或者能检测出丢包,但是不能判断前面丢了几个包,就不能确定如何重传。关键帧组帧不成功,会导致整个GOP都难以进行解码。有些用户的推流GOP很大,首个关键帧组帧失败会导致首帧时间非常长,这对用户体验影响很大。
有两个方法解决上述问题。第一个方法是拉流时服务器通过信令告知第一个序列号是多少,将拿到的序列号和收到的第一个包序列号进行比较,就能知道中间有没有包丢失,丢了几个包。就可以在收到包时立即进行重传。第二种方法,收到第一个RTP包,不管前面有没有丢包,直接往前重传10~20个包。
最后一个优化方式是首帧快速出帧。组帧完成以后出帧有一定的等待时间,为了快速出帧,将前面几帧等待时间设置为0,使得快速接触到视频包进行解码渲染。
通过以上几步的优化,整个首帧可以控制在200ms以内。
2、抗性优化
抗性优化第一个方面是NACK。WebRTC原生的重传效率较低,重传间隔在100ms左右,对于低延时直播来说,整个端到端延时也只有几百毫秒,因此这样的重传效率是不可接受的。我们对重传的间隔进行了优化,会根据实际的RTT进行重传。另外,对于重传的优先级,服务器会响应不同帧之间的优先级。
第二个方面是JitterBuffer、NetEQ。在整个播放过程中会实时监控网络质量,例如丢包率、RTT、Jitter等。有了丢包率就可以算出需要多少次重传才可以将这个包重传回来,根据重传次数和RTT,大致能估算出需要多少JitterBuffer来应对该次网络抖动,实时感知和调整。
第三种方式是添加冗余包。目前云信实现了标准RED。一开始我们打算做RSFEC,但RSFEC需要和服务器进行配合,对于我们的通用播放器不太适合。之后可能会把整个RSFEC链路流程建立好,具体实现通过插件的方式对接不同的云厂商。
3、延时优化
在起播阶段,服务器会发送GOPCache中的数据,导致起播阶段延时较大。整个播放过程中延时最高的时候就是在起播阶段。播放器通过加速播放来追赶延时,加速速度过快不仅会影响我们的感官体验,一些低端的机器还会因为解码速度不够导致无法加速,长时间处于高延时的状态,这样就违背了我们的低延时理念。为此云信采用了服务器丢帧的策略。假如在订阅流的时候是P帧,服务器发送缓存数据帧到某个P帧时,服务器收到了下一个关键帧,这个时候服务器会直接从当前P帧跳跃到下个关键帧,P帧和关键帧之间一段数据全部丢掉,重编关键帧及其后面帧的时间戳,保证时间戳连续。由于时间戳连续,所以播放器感知不到跳帧,只是起播阶段画面有一个小跳跃。通过上述的方法可以在起播阶段快速追赶上延时。
4、功能升级
WebRTC一开始并不是用来进行直播,它对直播有一些限制,比如音频只支持OPUS。现在低延时直播很多都是复用了RTMP上行,RTMP推流音频采用AAC。如果播放器不支持AAC,服务器就需要进行转码,例如AAC转OPUS。转码不仅会带来音质的损失,还会带来延时。所以我们在开源播放器中支持了AAC。
另外WebRTC不支持44.1K采样。云信也进行了44.1K采样的支持。
WebRTC不支持H265。现在分辨率越来越高,H265的压缩效率比H264高一些。云信也完成了对H265的支持。
WebRTC不支持多Slice。在播放Slice流时WebRTC在组帧时会出现帧完整性判断错误的情况,导致花屏现象的出现。云信也对多Slice进行了支持。
这是GitHub上开源播放器的DEMO。我们进行了一个测试。左边是OBS推流,利用OBS将其配置成低延时的模式,右边是拉流延时的对比。jitterBuffer配置成200ms,端到端延时在600ms左右。具体的延时可以根据自己的业务需求进行jitterBuffer调控,jitterBuffer下调一点,延时也会降低一点,反之亦然。
除了开源播放器,云信也有一个闭源的播放器。虽然闭源播放器也是基于WebRTC开发,但是因为不需要考虑通用,所以并没有使用整个WebRTC,只抽取其中的部分模块,例如JitterBuffer、NetEQ、Transport、NACK等模块。再进行相应的封装,包体积在iOS单架构增加550k,Android单架构增加1M。
信令协议方面,开源播放器使用的HTTP,HTTP在弱网环境下经常连接不上。我们采用KCP协议,增加冗余的方式,提升建连成功率。
首帧方面,我们简化了信令流程,提升建连速度。
弱网抗性中,得益于闭源包,会存在很多私有协议,QoS策略较为丰富。可以支持FEC、或者反馈支持不同分级的重传,可以抗住100ms+50%的丢包。
闭源播放器和RTC可以进行融合,支持连麦互动。
五、未来计划
5月份云信开源了windows端,之后我们将实现移动端的支持。移动端目前正在内测,内测结束后就会发布到GitHub上。未来我们也会持续优化各项播放指标,以及推行播放器标准化。也欢迎大家一起在开源播放器上开发,提供宝贵的意见。另外,云信正在构建一个低延时推流工具,未来也会开源,现阶段的方案是做成OBS插件,以提供全链路的解决方案。
谢谢大家!我的分享就到这里。