WebRTC的诞生背景
我们知道现在实时视频通信很普遍,基于FaceTime和Skype等视频通话工具,用户可以很方便地与他人进行视频对话。开发者们为了将用户体验优化到极致,通过大量的技术手段保障视频质量,比如减少丢包、断网恢复、即时响应用户网络变化等等。实时音视频通信对开发者的技术要求比较高,而且专利持有公司向开发者征收授权费,并构筑起巨大的技术壁垒。另一方面,对用户来说,需要去额外安装相应的插件或者应用程序,降低了用户体验,而且还有被捆绑流氓软件的风险。这时候一种叫WebRTC的技术应运而生了。
在讲WebRTC之前,我们先回顾一下Web通信的演化历史。在AJAX出现之前,也就是05年之前,如果需要更新内容,必须重载整个网页页面。AJAX出现之后,通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。但AJAX不能与服务器进行双工通信,因此服务器无法主动推消息给浏览器,只能通过浏览器进行轮询。Websocket的出现使这个局面得到改观,浏览器与服务器能进行全双工通信。不管是AJAX还是Websocket,都需要将数据发送给服务端。为了在两个用户间传送数据,开发者需要购买服务器网络,这方面的成本是非常庞大的。由谷歌支持的一项新技术——WebRTC彻底改变了这个局面。WebRTC是Web Real-Time Communication的缩写,实现了浏览器之间直接的实时通讯,而不再需要服务器中转,谷歌致力于让其成为HTML5的标准之一,目前大部分浏览器也已经支持。
WebRTC与P2P的结合
12年谷歌的chrome浏览器正式原生支持WebRTC,web开发者只需要几行javascript代码就可以开发出丰富的实时多媒体应用,而用户也无需安装插件,直接打开浏览器就可以与对方实时聊天。这时候有些嗅觉敏锐的开发者开始利用WebRTC的数据通道技术做P2P流媒体,例如国外一家公司叫做peer5。我们公司的创始人也从很早之前就投入到这方面的研究,但失望的发现用WebRTC做P2P流媒体还有一些问题难以解决,主要是支持的浏览器有限,互相之间也有很大的兼容问题。随后在13年和14年,Firefox和Opera也相继宣布支持WebRTC,更重要的是HLS这样的基于分片传输、适合P2P分发的协议越来越流行。这时我们发现时机已经越来越成熟了,只要某个直播流或者点播频道有足够的人在线(通常只要数十人在线就可以达到很好的P2P效果),加上良好设计的网络拓扑算法(比如网状拓扑,对节点的上下线并不敏感),就可以让P2P效果达到某个稳定的水平,并且可以跟HTTP源形成很好的互补。我们都知道在看视频期间,用户的上行带宽大部分时间是处于闲置状态,如果能把这些计算能力和网络带宽利用起来,这样相当于千家万户都是节点,你的邻居甚至你的舍友也许就在为你看视频提供加速,想想都是很酷的事情!因此我们成立了公司,开始持续数年的耕耘。
可能大家会有疑问,WebRTC将来真的会成为一种主流技术吗?我们用事实说话,看看各大浏览器的支持情况就知道了。从图中可以看出,大部分浏览器都已支持WebRTC,包括chrome、firefox和opera,微软基于chromium内核的edge浏览器也支持WebRTC。另外,苹果的safari也已经支持WebRTC。未来基于WebRTC的应用将越来越多,这是可以肯定的。
?
WebRTC媒体会话原理
我们假设现在有两个浏览器A和B要建立WebRTC对等连接,对等连接就是两个Web浏览器之间的直接媒体连接,如果A要主动联系B,需要先通过HTTP向信令服务器发送一个SDP,SDP可以理解为一个电脑名片,全称是Session Description Protocol,会话描述协议,用于描述对等连接的媒体特征。那么信令服务器又是什么呢?它就像一个红娘,帮两个互相不认识的人牵线。浏览器A发过来的SDP叫做offer,信令服务器将其传给浏览器B,后者收到后回应一个SDP对象,叫做answer,也通过信令服务器中转给A。交换完SDP后,两个对等端就开始尝试ICE打洞,打洞成功后开始协商密钥,之后就可以开始安全的媒体或数据会话了。
?
ICE打洞原理
由于IPv4提供的IP资源有限,IPv6还没有推广开来,大部分网络设备还处于内网中,需要通过NAT设备来与外部internet连接。NAT全称Network Address Translation,网络地址转换,装有NAT软件的路由器叫做NAT路由器,它至少有一个有效的外部全球IP地址。这样,所有使用本地地址的主机在和外界通信时,都要在NAT路由器上将其本地地址转换成全球IP地址,才能和因特网连接。当两个对等端处于不同的局域网中时,需要先知道对方的公网IP和端口。这时候可以先向STUN服务器发送测试数据包,后者做出响应,指示其在测试数据包中监测到的IP地址,此地址将成为潜在的候选地址返回。拿到候选地址的浏览器将其通过信令服务器发送给对等端,对等端也进行同样的操作,之后双方用所有得到的候选地址尝试连接,如果都没有成功的情况下,会用TURN服务器来作为中转服务器,TURN服务器是在所有替代方案都无效的情况下才有采取的,因为成本比较高昂。为了加速通话建立时间,有一个叫trickle ice的方案,其思想是客户端一边收集candidate一边发送给对方,比如local candidate 不需要通过stun获取直接就可以发起,这降低了了连通性检测完成的时间。
?
WebRTC数据通道
接下来介绍一个比较重要的概念——WebRTC data channel。我们基于WebRTC来做P2P流媒体,实际上就是用的data channel能力。那么data channel到底是什么呢?虽然有关WebRTC的宣传主要侧重于它对于实时音视频通讯的支持,但设计师一直都希望它也支持实时数据传输。相比Websocket和HTTP,数据通道支持流量大、延迟低的连接,具有稳定可靠等优点。而且data channel的接口和websocket一样,也是通过send来发送数据,通过ommessage来接收数据。那么如何对data channel数据传输的可靠性进行控制呢?通过刚才所讲的dataChannelOptions这个javascript对象,可以让data channel在UDP或者TCP的优势之间进行切换,比如让数据传输得更加稳定可靠,或者传输得更快。其中有几个比较重要的字段:ordered:设置数据的接受是否需要按照发送时的顺序,maxRetransmitTime:设置数据发送失败时,多久重新发送,maxRetransmits:设置数据发送失败时,最多重发次数。主要是配置ordered,当设置为true时数据通道表现更像TCP,false时表现更像UDP。
WebRTC与P2P流媒体
把WebRTC的data channel搞清楚后,我们就可以用用它来做P2P流媒体了。这方面已经有国外大神开发的知名开源项目:WebTorrent,在github上有1万多颗星。WebTorrent是一个开源的基于WebRTC 和BT协议的js框架,完全用javascript编写,可以同时运行于 Node.js 和浏览器,由于基于WebRTC,因此WebTorrent不需要安装任何插件,就可以跑在浏览器上。同时支持Chrome, Firefox 和 Opera浏览器。但是由于是基于BT协议,所以是一种pull-based的算法,这种算法是一种随机抓取的策略,随机抓取其它节点的buffer,但这样会存在一个问题:抓取的buffer不一定是目前需要的,也不一定是其他节点需要的,而且还会浪费下行带宽和其它节点的上行带宽,因此同时造成了“带宽饥饿”和“内容饥饿”问题。下面介绍一种改进版的pull-based算法——FirstAid算法。FirstAid是基于窗口滑动的,每隔一段时间触发一次窗口滑动,每个窗口又可以分成三段:urgent、normal和prefetch,urgent顾名思义,是离播放时间最近的buffer,所以优先级别最高,normal和prefetch优先级递减。当父节点为子节点传输buffer时,会优先满足urgent级别的要求,而暂停normal级别的,所以最紧迫的需求会优先得到满足,当子节点的urgent需求得到满足后,需要回过头来弥补他的竞争对手的需求,以达到一种互惠互利的状态。和刚才pull-based算法思想截然相反的是push-based算法,其中比较有代表性的是FashMesh算法,由港科大的学者提出来的一种P2P算法。FashMesh是基于一种叫Streaming Mesh的算法,将源节点的数据流分成多个子流,通过多棵生成树构成mesh来源源不断的传输给子节点,这种算法的优势是延迟低,带宽利用率高。Fast Mesh还可以根据每个子节点的上行带宽来动态的调整网络拓扑结构,让上行带宽大的节点更加接近源节点,从而充分利用网络的现有能力。根据一项对比试验,FastMesh可能是目前众多P2P算法中效果最好的。但这个算法也有缺点,当节点进入或离开网络时,都需要重新调整拓扑结构,因此不适合节点变化较大的情况。
我们自行研发的算法——Push-Pull算法则综合了push-based和pull-based两种算法的优势,用pull的方式从父节点获取优先级最高的buffer,由父节点以push的方式为其提供后续的buffer。另外,我们的算法混合HTTP、HTTPS、WebRTC等多种协议,在优先保证用户体验的前提下最大化P2P率。经过测试,Push-Pull算法具备低延迟、高带宽利用率、高P2P率、对网络拓扑结构变化鲁棒性强等优势。
SwarmCloud
SwarmCloud的web端SDK(hlsjs-p2p-engine,github地址:https://github.com/cdnbye/hlsjs-p2p-engine) 是完全用JavaScript写的HTML5流媒体加速SDK,实现了融合HTTP、WebRTC的多协议、多源、低延迟、高带宽利用率的无插件Web端流媒体加速能力。基于hls.js的MSE技术(Media Source Extension)将来自多个源节点的Buffer分块喂给播放器,再加上精心设计的算法来达到最优的调度策略及对各种边界条件的处理,hlsjs-p2p-engine能在保证用户流畅视频体验的前提下最大化P2P率。
集成我们的web端SDK也非常简单,只需要短短几行代码,把js文件引入到script标签中,像使用hls.js或者其他web播放器一样即可。Demo演示地址:https:// https://demo.cdnbye.com/,以下是代码示例:
<script src="//cdn.jsdelivr.net/npm/cdnbye@latest"></script>
<video id="video" controls></video>
<p id="version"></p>
<h3>download info:</h3>
<p id="info"></p>
<script>
document.querySelector('#version').innerText = `hls.js version: ${Hls.version} cdnbye version: ${Hls.engineVersion}`;
var video = document.getElementById('video');
var source = 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8';
if(Hls.isSupported()) {
var hls = new Hls({
p2pConfig: {
logLevel: false,
live: true, // set to false in VOD mode
// Other p2pConfig options provided by CDNBye
}
});
hls.loadSource(source);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
video.play();
});
hls.p2pEngine.on('stats', function ({totalHTTPDownloaded, totalP2PDownloaded, totalP2PUploaded}) {
var total = totalHTTPDownloaded + totalP2PDownloaded;
document.querySelector('#info').innerText = `p2p ratio: ${Math.round(totalP2PDownloaded/total*100)}%, saved traffic: ${totalP2PDownloaded}KB, uploaded: ${totalP2PUploaded}KB`;
});
}
// This is using the built-in support of the plain video element, without using hls.js.
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = source;
video.addEventListener('loadedmetadata',function() {
video.play();
});
}
</script>
结语
相对于传统的模式,SwarmCloud可以说是站在共享经济的风口上。我们知道传统的CDN厂商会先以批发价从ISP买进带宽,然后再以零售价卖给CP,CP买入带宽后进行内容分发,为终端用户提供CDN服务。我们则是基于Daas模式(Device as a Service),每个设备既是数据消耗者,同时又是分享者,从而在千家万户拥有了分布广泛的节点。不仅大幅提升了用户的播放流畅度,BGP机房、ISP骨干网的压力也得以缓解,从而实现多赢局面。
|