WebRTC 前端实时通信技术

背景

随着Chrome、微软 Edge 和苹果 Safari 陆续宣布停止支持 Flash,Adobe 公司也正式宣布将在2020年年底停止对 Flash 的支持,这就使得国内大多数使用 Flash Player来支撑音视频等业务的公司面临着巨大的技术变革的考验。然而,在 Web 端技术不断向前发展,HTML5等标准逐渐成熟的大环境下,Web端开发者抛弃 Flash 来构建交互性更复杂的Web应用不再是一件困难的事情,反而会变得更加简单。

业务场景

目前,团队主要专注于直播、点播等视频相关的 P2P 业务上,客户端通过集成 SDK,能够获得更流畅播放体验并显著降低CDN分发成本,适用于互动直播、电视内容直播、赛事直播、在线视频、短视频等业务场景。支持 Android/iOS/OTT/Flash/HTML5 等系统平台,支持 arm/x86/mips 等架构。对于 HTML5 来说,团队要做的是应用WebRTC将已下载的音视频分片数据推送给订阅了该分片的对端用户,意在不影响用户播放体验的同时降低CDN的成本,同时拉开与竞品之间的距离,增大业务在价格方面的优势。

接下来,本文将从实战的角度来介绍如何使用 HTML5标准中 WebRTC相关 API 来实现 P2P 功能。

WebRTC

WebRTC(Web Real-Time Communications)是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。

纵观WebRTC建立P2P连接的过程主要是以下几步:

(1) 连接双方交换SDP(Session DescriptionProtocol,会话描述协议),用于描述“会话状态”,包含一系列的连接属性:要交换的媒体类型(音频、视频及应用数据)、网络传输协议、使用的编解码器及其设置、带宽及其他元数据;

(2) WebRTC内置了 ICE框架,负责候选项发现、连接检查、持久化等等,这部分工作对开发者是不可见的:开发者需要做的只是在初始化 RTCPeerConnection 对象时指定STUN 和 TURN 服务器;

(3) 若连接成功,最后就是 Peer 之间的数据分享过程了。

上述过程基本上就是进行实时通信需要经历的过程,整个过程说起来很简单,但实际上端与端之间通常存在有很多层的防火墙和 NAT 设备阻隔着,需要经过一系列繁琐的信令交换,网络地址转换、打洞等过程。幸运的是,WebRTC除了信令交换之外,其余的工作都已经帮我们实现好了,开发者可以将绝大多数的精力放在主要的业务逻辑上。

信令通道和会话协商

在建立连接和会话协商之前,我们需要一个信令(或信号)通道来交换信息,不幸的是,WebRTC 并没有为我们实现这部分的工作,而是将发送信号和协议的选择交给应用,无论是通过 HTTP、WebSocket还是其他任意的传递方式,只要能顺利到达对端即可。

在拥有了信令通道之后,就是会话协商的过程了,这个过程中交换的是会话描述协议信息,即 SDP 信息。当用户向对端用户发起 WebRTC 连接时,将创建一个称为提议的会话描述信息,该描述信息包含用户之间“对话”的配置信息,这有点像是在告诉对端用户:我将要去你家坐坐,你是不是得准备点茶点招待我啊?在对端用户收到提议方的会话描述信息后,将会回复一个应答的会话描述信息,告诉发起对话方:茶点准备好了,恭候您的大驾光临!

下述是具体的提议应答交换过程,如有 A 和 B 两个用户:

(1) A 调用 RTCPeerConnection.createOffer() 创建一个提议描述 SDP(A);

(2) A 调用 RTCPeerConnection.setLocalDescription() 设置得到的SDP(A) 信息;

(3) A 通过信令通道将SDP(A) 信息发送给 B;

(4) B 收到 A 的描述信息后调用RTCPeerConnection.setRemoteDescription() 记录对端用户的会话描述信息;

(5) B 调用RTCPeerConnection.createAnswer() 创建一个应答描述 SDP(B);

(6) B 调用RTCPeerConnection.setLocalDescription() 设置得到的 SDP(B) 信息;

(7) B 通过信令通道将SDP(B) 信息发送给 A;

(8) A 收到B 的描述信息后调用RTCPeerConnection.setRemoteDescription() 记录对端用户的会话描述信息;

ICE(Interactive Connectivity Establishment)

得到了对端用户的邀请确认后,双方此时就需要交换一下双方住址了,为了尽可能避免对方走错路错过了茶点最佳的品尝时间,双方都开始收集自己的详细地址信息,详细到走路怎么走,骑单车怎么走,打车又是怎么走,不得已时可能约上一个大家都熟知的地方相见。回到实际编码中来,要顺利的建立端到端的连接,两端之间必须能收发数据包,但通常端与端之间存在有很多层的防火墙和 NAT 设备阻隔着,需要经过一系列繁琐的网络地址转换、打洞等过程,总结来说这是一个寻找连接通道的过程,幸运的是,WebRTC 已经代替我们完成了这部分的工作。当需要连接的两端设置好本地和远端的会话描述后,本地 ICE 代理就会自动开始发现本地端所有可能的候选 IP 和端口的过程:

(1) 查询本地内网的 ip 地址;

(2) ICE 代理向 STUN 服务器查询,本地的外网 ip 和端口号;

(3) 如果端到端连接失败,数据将通过 TURN 服务器转发数据。

ICE 代理每发现一个新候选项就会自动回调 onicecandidate事件通知应用。此时,通过信令通道将该候选项 candidate 发送给对端 Peer,对端收到该候选项后则通过调用 RTCPeerConnection.addIceCandidate(candidate) 来增加端与端之间连接的通道方式,反之亦然。值得称赞的是,连接成功建立之后并不代表 ICE 代理的工作已经结束了,实际上此时 ICE 代理会继续收集本地候选项,意在找到一个更稳定的连接路径,这个过程对我们是不可见的。下图 ICE 代理的工作流程:

应用数据通道(DataChannel)

实际上 WebRTC 并不单单仅限于 Peer 之间分享音视频流,也支持任意应用数据交换(String,ArrayBuffer,Blob,File,Image等),而这仅仅只需要以下几步即可:

(1) 实例化一个 RTCPeerConnection 对象;

(2) 调用 RTCPeerConnection.createDataChannel(),实际上这一步只需在发起对话方创建即可;

(3) 接下来就是一系列的提议、应答和候选项通过信令通道交换的过程;

(4) 最终建立连接成功后,对端 Peer 会收到触发ondatachannel 的事件回调,其中事件中的 Event.channel 就是 Peer 间的数据通道,此时对话两端就可以通过这个“通道”来分享数据了。

初见 DataChannel 与 WebSocket 基本上是类似的,都支持 onopen、onmessage、onclose、onerror 事件回调,但两者之间仍然有一些区别,WebSocket 是在 TCP 的基础上构建的可靠有序的消息交付,而 DataChannel 是基于 UDP 的,当然也可以通过配置来指定是否有序和可靠性,提供了更多的灵活性配置,可自行搜索相关文章来了解。

现有 WebRTC 库

前文花了较多的篇幅来介绍 WebRTC 在建立端对端连接的相关过程,虽然没有贴出相关的代码,但相信大家在有了建连过程的基础后再自行搜索相关代码来看,会有事半功倍的效果!实际上,市面上已经有多家公司或组织已经封装了各自的 WebRTC 库,目前了解到的有:streamroot、webtorrent、peerjs、peer5等。

本文出现的初衷也正是为了了解这些库在实现 P2P 功能上有无独到之处,通过前文的描述我们知道,P2P 的核心要求就在于穿透 NAT 设备,只有穿越了它才能真正建立起端对端的连接,目前 NAT 设备有两种类型:对称型和锥型,而 P2P 需要的是锥型 NAT。从这些库对穿透这块的代码上来看并没有什么与众不同之处,更多的是在 STUN 无法穿透时配置了 TURN 来中转数据。但是十分幸运的是,根据 Google 提供的穿透数据来看:

  • 92%的时间可以直接连接(STUN)
  • 8%的时间要使用中继器(TURN)

在调研过程过程,也发现了一些比较有趣的网站,是基于 WebRTC 实现的在线视频通话和在线文字聊天 demo,有兴趣的可以在浏览器中打开一下的网站:

总结

在写这篇文章前花了一个星期来学习相关的知识包括: WebRTC API、NAT、信令服务、STUN 服务器、TURN 服务器等,但由于这部分的技术不是临时抱佛脚就能了解透彻的,是一个持续学习深入了解的过程。有点遗憾的是没在本文中介绍 NAT 的相关知识,实际上这部分内容可以单独拎出来讲解,等有空了再写一篇关于 NAT 的文章吧。

随着 Web 前端标准越来越成熟,浏览器能做到的东西越来越多,也许会逐渐替代客户端,这不得不说这很符合互联网的特点,相信有一天会出现一个标准,我们不再需要手机,不再需要安装软件,不再需要各种类型账号,实际上我们自身就是一个特定的 ID,将来所有的交互都是基于这个 ID 来提供不同的个性服务,无论我们走到哪都能得到所需的服务。想想都是满满的期待啊!

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

江天德的专栏

1 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jerry的SAP技术分享

SAP Cloud for Customer Price-计价简介

SAP Cloud for Customer(本文以下简称C4C)作为SAP新一代的CRM云产品,其Price功能实现虽不如以前的SAP ERP那么复杂,但是也...

942
来自专栏服务端思维

聊聊 Redis 使用场景

随着数据量的增长,MySQL 已经满足不了大型互联网类应用的需求。因此,Redis 基于内存存储数据,可以极大的提高查询性能,对产品在架构上很好的补充。在某些场...

583
来自专栏大宽宽的碎碎念

如何避免下重复订单为啥会下重了呢?用幂等防止重复订单客户端的流程后端数据表设计下单的实现技术搞定幂等就足够了吗?通知如果还拦不住……这么麻烦,有必要吗?结论

3057
来自专栏何俊林

关于直播,所有的技术细节都在这里了(四)

上篇《关于直播,所有的技术细节都在这里了(三)》我们讲述了直播后端系统的原理及优化,那么直播推流、播放端是否就没有可以优化的点呢? 答案是否定的。客户端的优化对...

1867
来自专栏Android小菜鸡

Android 8.0无法发送通知栏?通知栏适配通知渠道

  不得不说Andoird的通知栏相比于IOS在使用上有着明显的不足,不仅是体验上的差异,还有大量的非关注通知铺满了通知栏,导致通知栏混乱,杂多。   为什么...

601
来自专栏竹清助手

基于RTMP数据传输协议的实时流媒体技术研究

本文来自论文《基于 RTMP 协议的流媒体技术的原理与应用》,文中研究了基于 Flash 平台的流媒体系统中使用的 RTMP 协议的原理和应用,并对网络上实时流...

1584
来自专栏牛客网

京东金融一面+滴滴一面

1705
来自专栏何俊林

关于直播,所有的技术细节都在这里了(二)

上篇《关于直播,所有的技术细节都在这里了(一)》我们讲述了如何让直播内容以“最短”路径从主播到观众上,传输层面获得最低延迟,在本篇中我们会介绍直播应用层协议及传...

20310
来自专栏人人都是极客

物联网通信架构总结

本文从宏观上介绍IoT的通信架构,让大家都日渐频繁的物联网设备工作原理有一个初步的理解,主要分为了直连、网关、云三种模式。

773
来自专栏BaronTalk

观察者模式(ObserverPattern)

场景 我们接到一个来自气象局的需求:气象局需要我们构建一套系统,这系统有两个公告牌,分别用于显示当前的实时天气和未来几天的天气预报。当气象局发布新的天气数据(...

32110

扫码关注云+社区