在上周落幕帷幕的多媒体领域技术盛会——LiveVideoStackCon音视频技术大会上,阿里云的高级技术专家李刚进行了《下一代低延时的直播CDN》技术分享。主讲人李刚,多年关注在CDN这个领域,早期主要研究和cache服务器缓存以及流媒体相关的技术, 专注CDN文件分发、图片与大文件下载等业务。从2015年开始负责全面构建阿里云CDN直播系统,对流式长连接的分发有很深刻的理解。今天主要分享内容是阿里云自研低延时直播系统在构建时,遇到的一些技术难点与实践。
分享从当下直播技术回顾、低延时直播技术思考、低延时直播技术实现、展望四个部分展开,本文为演讲原文,希望对直播CDN相关从业者有一定的帮助。
一、直播场景回顾
下图列举了当下存在的一些常见的直播场景。
- 秀场直播是国内最早出现的直播形式,在各个直播平台上是比较常见的。
- 游戏直播,像斗鱼、虎牙、战旗等直播平台都是比较典型的游戏直播平台,游戏直播对码率要求比较高,观看人数也多,所以它也是流量贡献最大的直播形式。
- 移动直播是最近一两年比较火的直播形式,比较明显的特点就是推流和播放比较容易, 通过手机APP就可以进行直播,所以手机直播一般也是推流数最多的直播形式。
- 活动赛事直播,像今年夏天的世界杯,这类直播一般对交互要求不高,所以一般都是HLS播放形式,延迟相对其他都会多一些。
- 答题直播是今年年初左右出现的新型直播形式,每场直播的时间不长,突发流量比较高。
这些直播场景,在国内主要用HTTP-FLV和RTMP这种传输形式,这两种传播形式一般延时在3-5秒,当然这也会受视频本身GOP影响, 移动直播一般是1-2秒时间间隔,所以控制在3-5秒是比较容易的。但是游戏直播关键帧延时一般在8-10秒,所以游戏直播的延时更大一些。而活动赛事直播一般不会强调互动性,对流畅度比较高,所以会一般选用HLS,延时在10秒以上。
二、低延时直播需求
3~5秒延时对于多数常见的直播形式一般问题不大, 但是对于某些场景效果会很差。
对于连麦场景影响是最明显的, 连麦超过1秒,对话可能就没办法维持下去了。现在一般直播平台的连麦直播需求都会借助第三方的连麦服务,然后再推给直播CDN厂商。
在答题直播场景下, 一般都要求在一段时间内用户提交答案,如果有各别用户延迟比较大,这样对用户是不公平的。虽然直播平台仍然使用FLV的传输形式完成答题直播,但是基本都会采用SEI插帧等方法来解决时间同步问题, 需要平台的端和直播CDN做一些配合来完成。
除了连麦、答题场景之外,像在线课堂、在线拍卖等场景因为涉及到实时性的互动,对延时的要求也比较高。
从对业务的支持层面来看, 仅仅有RTMP、FLV这种3~5秒延时以上的直播形式已经不够了, 需要对更低延迟的直播业务进行支持。从技术的角度来看,国内常用的FLV、RTMP这种直播手段,本身是Adobe自己的标准, 而且很快会停止对flash的维护, 另一方面WebRTC技术的兴起,Chrome、Safari等浏览器也都进行了支持,因此也需要对新的技术有一些调研和准备。
基于对于这些问题的思考, 阿里云CDN也开展了对低延时直播技术的研发。
三、短延时直播VS实时音视频通信
简单介绍下实时音视频通信和短延时直播的区别:
使用WebRTC主要用于解决实时音视频通话的需求,必然对延迟要求非常严格, 一个会议室中参与的多方可以进行视频通话, 每个参与者可以看到其他参与者,也能听到其他参与者说话。每个参与者既有推流,又有播放,数据是双向的。所以参与人数不会太多,一般不能超过20个。
短延时直播仍然是直播业务类型, 只是延时比较低, 短延时直播的业务模型相对简单, 数据单向传输,一个主播推流,参与的播放者人数没有限制,上百万都可以。
四、技术选型的思考
在做短延时直播项目的时候,我们在技术选型上做了一些思考。
首先,是必须要兼容已有直播业务和技术栈,因为阿里云直播CDN系统已经有了很多客户,短延时直播需要从现有直播的业务上慢慢衍生, 可以让客户在短延时和常规直播手段进行切换, 这也是处于业务稳定性的考虑。
第二,对于直播来讲, 秒开是一个很重要的指标,我们后面详细展开。当然卡顿也是重要的指标,因为WebRTC在移动端拥塞控制和重传方面有一些处理,所以卡顿率方面不会比TCP差。
第三,对齐到WebRTC会是最终的结果, 毕竟用户能够使用H5就可以直接推流或者观看直播, 更方便客户的接入和使用。但由于完整的支持WebRTC要解决加解密、打洞、音频格式等问题, 所以前期考虑只使用WebRTC中的一部分技术,完整支持WebRTC会是二期的工作。
五、TCP的可能性
已有的业务,无论是图片、大小文件、点播、直播,这些都是在TCP通信基础上实现的,所以短延时直播在开展的时候我们就思考了TCP的可能性。
我们对于短延时的目标定义为从端到端800毫秒以内,一场直播的延迟来自于推流端延迟、CDN产生的延迟、播放端延迟这三个方面,很多客户会关注CDN产生的延迟,我们也对数据进行过统计,CDN从入到出所产生的总延时,全网平均不到100毫秒,晚高峰平均也不超过200毫秒。而从经验角度来看,播放端的延迟会比较严重,主要是两方面,一方面是开播时候卡前一个关键帧所带来的延迟,另一方面如果CDN服务器到播放端有抖动,累积的延迟会越来越多。
之前有一个彩票直播业务的客户, 因为客户担心用户怀疑刮奖的时效性, 所以对延时要求就非常苛刻, 客户的端进行延迟优化, 延迟也可以做到1秒内。
所以,一开始我们有了这样一个结论,网络正常的情况下,使用现有的RTMP、FLV进行分发,延迟也可以做到1秒以内。
但是现实情况是网络是不可能出现不丢包的情况。当网络抖动出现丢包的时候,TCP是ACK确认机制的,也就是发送方发送一包之后,一定要等过对方回应,才会继续发。如果说网络一旦出现丢包,就会在一个RTO之后重传,RTO的值和RTT有关,并且RTO的最小值是200ms。如果想保证流畅性,你的播放端一定要至少能容忍200ms以上的抖动,但播放端的jitbuffer太多又无法满足低延时的要求。
这里对一下比WebRTC中RTP传输使用的NACK机制,NACK的丢包反馈更加及时,如果网络是偶然性抖动居多的时候, NACK机制效果更加好。这里我们也做了一个统计,全网平均RTT小于15ms,如果CDN节点覆盖足够好的情况下,延迟理论上会很低。以1.5Mbps码率的音视频流举例,每秒钟100个包,包和包之间就是10ms的间隔。如果当第二个丢包出现的时候,第三个包对方接收到了,就可以马上知道第二个包是丢掉了,就可以立刻返回一个NACK,进行重传。在这种极限情况下,重传间隔就是25ms,相比之前TCP的200ms是一个质的提升,想满足绝大部分播放延迟在800ms以内才有可能。
另外,使用TCP的话,无效传输没法避免,。TCP是采用socket buffer进行通信,数据也是从应用层先进入socket buffer再分发。对于RTMP或FLV的分发来说,假如某一帧的数据的一部分已经进入了socket缓冲区, 那么也必须将这一帧剩余的数据发送出去, 如果剩余的数据不发出去的话, 播放端会出现解析错误, 断开连接, 这个体验会很差。
而在网络在出现波动的时候, 有可能这socket buffer里面的数据很久之后才能传送到对方, 而在短延时直播的场景下, 这些socket buffer里面和应用层太久的数据再发送给播放端已经没有意义,也就是说会产生很多无效的传输。
六、自研短延时直播方案
基于这些考虑,我们最终采用了以下的方案。WebRTC是当下短延时流媒体的传输比较热门的技术, 所以在实现短延时直播的同时会考虑使用WebRTC相关的一些技术。原有的RTMP, FLV, HLS这些使用TCP,新增阿里自研私有ARTP短延时方案,最终会支持WebRTC,ARTP和WebRTC使用UDP传输。
在研发之前,我们会对各项部署做一些思考。
1.端口问题
WebRTC的默认工作方式SFU服务器会为每个参与者需要为其他每个参与者分配一个端口, 一定程度上来说是通过不同的端口来区分参与者。而CDN从安全的角度来考虑, 不会采取这种方式, 所以从一开始就认定在短延时直播这个场景下,我们会使用固定端口的方式来提供服务。下图是最终的方案,流媒体服务器会开几个端口分别支持不同播放形式的访问,允许用户的端进行的灵活控制。
2. 秒开问题
这里讲一下播放秒开的问题, 如果采用标准的WebRTC方式,那么需要经过下图这样几个环节。
这样下来对于直播秒开的体验来说就会很差,所以在实现低延时直播方案时针对这个问题需要进行优化处理, 去掉一些不必要的环节。
CDN服务器本身是有公网IP和端口的, 播放端没有独立的公网IP和端口,如果是像WebRTC这么实现的话, 服务器把数据直接传给播放端,那么必然涉及到打洞探测的问题,所以如果想要达到秒开效果的话,就不能使用WebRTC的这种方式, 需要让播放端先给服务器发送请求, 让自己所在的NAT网关建立起映射之后,服务器再把数据吐给客户端时就OK了。
上图就是最终的时序图,使用的是比较简单的应答模式。没有了TCP的三次握手环节,所以秒开效果一定比FLV、RTMP更好。同时,客户端直接发起播放请求,请求包长度尽量控制在一个UDP包内,不要出现一个请求两个包的情况。
国内直播平台大部分还是使用h264和AAC,所以我们也是首先支持这两种格式,其他音视频格式像HEVC等也是我们后续要支持的格式。
3.RTP报文
PT字段是载荷类型,sequence number是包序列号,发送端切片的时候,写好序列号,接收端依据这个序列号进行数据的还原。而且在重传发生的时候,还依靠这个序列号进行NACK的反馈。时间戳对流媒体传输非常重要,播放器依赖它进行解码和同步。SSRC用来识别不同的身份,同一个IP和端口被NAT重新分配的时候, SSRC识别出这是一个不同的连接。
前面讲过使用TCP传输的时候,网络抖动出现堆积时,需要丢帧,但是一定是丢完整的帧,不能丢片段。那为什么RTP场景下为什么没有这个问题?以H264为例,RTP在封装的时候,如果NAL单元小于MTU,那么我们认为一个RTP包可以完整封装一个NAL单元的,如果出现丢帧,那么我们认为缺少的是一个完整的NAL单元,对后面NAL单元解析是没有问题的,不会出现数据错乱。
如果一个NAL单元大于一个MTU的时候,假设一个NAL单元需要三个RTP包封装,不管丢到哪一个还是全部丢掉,接收端都可以标识出这个NAL单元,不会影响其他NAL单元的解析。
4.平滑发送机制
现在采用的混合拥塞算法,基于丢包率和基于延迟进行码率控制。标准的做法是,当播放卡顿时,会让发送端降码率。
从两个方面来看,当推流端上行出现抖动的时候,服务器会反馈数据包,把码率自动降下来。当播放端出现下行抖动的时候,一种是输出转码流,另一种是让主播推两路流上来,让播放卡顿的用户换到低码率。
5.播放端上的优化
第一阶段是开播阶段,获得GOP数据的时候,如果端不做处理的话,一定会有一个延迟。所以在这个阶段,播放端一定进行快进的操作,缩短延迟。第二阶段是当网络出现抖动的时候,会慢慢放大buffer的长度,来一定程度上适应抖动,提高流畅度。第三阶段,当网络恢复的时候,我们可以适当快进,减小buffer,把进度赶回来。也就是说这个buffer大小是动态变化的。
6.RTC内部打包机制
H264和AAC数据会在内部先进行切片,放到平滑发送队列再发送给对端,同时重传包也会进入平滑发送队列, 并且会放到平滑发送队列的队首位置。
7.FEC冗余传输
FEC是靠冗余传输,来提高容错率。关键帧10%冗余率, 非关键帧5%,根据丢包判断出网络状况,动态调整冗余度。
8.UDP传输注意事项
UDP无连接,也就没有TCP的连接断开时的挥手确认连接关闭的机制。那么对于主播来说,如果出现断开,然后短时间再重推的话就会遇到问题,因为CDN会认为前一个推流连接还在,新的推流连接推的是同名流,会拒绝掉新的连接,主播也会反馈无法推流。对于播放来说,虽然没有同名流问题,但是如果播放端不再观看,CDN服务器会仍然将数据发送给指定的IP和端口,这就产生了很多无效的传输。最终会反映到流量和计费日志上。所以采用RTCP报文的方式,对于播放和推流连接的断开进行通知,节省资源消耗, 流抢占等问题。
9.探活策略
除了对于正常关闭进行主动通知之外, 还需要对超时情况进行处理。即便是TCP传输的时候也有类似的问题,推流端发送了FIN结束报文,但是服务器未必收到,所以一定要有超时的机制来进行管理。我们采用数据及时反馈的机制,在下行播放端要求周期性的返回心跳,上行要求推流端在8或10秒内一定要有一些真实数据传输,否则我们就会断开。
这幅时序图更细致的展开了一下实现的逻辑,播放端和服务器。
Tengine是阿里开源的服务器软件, 阿里云CDN的文件、点播、直播功能都是在其基础上进行开发,而在短延时直播功能的实现我们也是把开源的WebRTC的库进行了一些改造。选择Tengine来做主要原因也是因为对其非常的熟悉,而且在其基础上也积累了很多配套的技术,包括配置下发管理、日志收集、业务处理等。
最后,我们来看下实际的数据情况。
目前短延时直播功能是在一些地区进行了部署和验证,还没到全网铺开的阶段。
秒开数据比原来FLV访问提升很大, UDP交互省去了三次握手环节。错误率和延迟都有了较大的提升。这里目前只对比了下行,从已经灰度的一些节点来看,上行卡顿数据要优于原有RTMP的推流。
七、后续展望
完整的支持WebRTC一定是目标, 毕竟直接通过浏览器就可以完成推流和播放对于用户的接入来说实在太方便, 对于CDN来讲控制接入一定是一个必须做的事情。
对于CDN要做的另一个事情就是优化传输,其实无论对于文件加速还是流媒体加速,传输永远都是最重要的,CDN这个分发网络本身就是为了优化传输而存在。
从实践来看,UDP传输比原来的TCP传输对资源消耗要多,而且重传、封包、FEC冗余计算等都会额外增加计算量,在多进程模式下可能还会遇到内存资源的过多消耗。