1、概述
通过语音和视频实现人工通信,即实时通信,简称RTC。RTC是指在应用程序中能像在文本输入中输入文本一样自然的语音视频通信技术。在早期,RTC一直被认为较为复杂,需要昂贵的音频和视频技术才能在开发。将RTC技术与现有内容,数据和服务集成起来非常困难且耗时,尤其是在Web上。Gmail的视频聊天在2008年开始流行,2011年,Google推出了使用Google Talk服务的Hangouts(与Gmail一样)。谷歌收购了GIPS,这家公司开发了许多RTC所需的组件,如编解码器和回声消除技术。现在谷歌开放了GIPS开发的技术,并与IETF和W3C的相关标准机构合作,以确保行业达成共识。2011年5月,爱立信建立了WebRTC的第一个实现。WebRTC实现了实时,无插件视频,音频和数据通信的开放标准。之前许多Web服务使用RTC,但需要下载本机应用程序或插件。其中包括Skype,Facebook和Google Hangouts。而下载,安装和更新插件很复杂,容易出错并且很烦人。插件很难部署,调试,故障排除,测试和维护,并且可能需要许可并且需要复杂,昂贵的技术集成。WebRTC项目的指导原则是其API应该是开源的,免费的,标准化的,内置于Web浏览器中并且比现有技术更有效。而对于移动端也是如此,在里面直接调用WebRTC的库就可以进行开发使用,而不需要安装底层插件。这篇文章主要讨论下WebRTC的一些基础情况和架构设计。
2、WebRTC APIs
WebRTC 有一些核心API,这边主要会讨论一些关于前端的API,有关移动端的API基本类似。这些API的核心逻辑也是WebRTC 开发的关键。WebRTC 替我们处理掉了大部分的复杂逻辑,通过调用这些API来提高开发者的开发效率,下面这张是WebRTC的体系结构:
WebRTC主要有3类API:
① 获取视频和音频
② 构建音视频的通信
③ 构建任意数据的通信
2.1 获取视频和音频
这部分API 用来访问输入设备,包括访问麦克风、摄像头或者来自其中任何一个的媒体流。与之对应的主要JavaScript APIs是 MediaStream。MediaStream代表一个同步的单一来源,比如视频、音频或者两者都有。每个MediaStream可以包含一个或多个MediaStream轨道(track)。比如说,一台笔记本电脑上有一个摄像头和一个麦克风同步提供视频和音频流。可以用getUserMedia()方法来访问这些设备。具体访问时可以增加一些约束(constraints),比如只要视频或者只要音频,或者指定本地设备的分辨率或帧率。同时可以添加进去设备获取成功或失败的回调。当设备获取成功,就能得到从这些设备中获取到的多媒体数据进行进一步的操作了。
2.2 构建音视频的通信
这部分API 主要用来与另一个WebRTC来建立连接,并且发送前面获取到的实时媒体流。与之对应的主要JavaScript APIs是 RTCPeerConnection。通过上一个APIs已经获取到了相关多媒体数据,这时候就可以通过这个APIs来和另一个对等方连接来将自己的数据传给对方,对方也可以用同样的方法将数据传过来。这样就能够做到一个最简单的视频通话了。
RTCPeerConnection这个模块主要做了以下这些事情:
① 信号处理: 用来对传入和传出的数据进行处理,主要用来消除音频和视频中的噪声
② 编码处理:对传入传出数据进行编解码,以及压缩和解压缩源音视频。
③ 建立点对点通信:找到真实的通过防火墙和NAT的对等路由地址,进而建立点对点连接。具体这块会遇到的问题之后会详细讨论。
④ 数据加密:加密传输的多媒体数据,以便用户数据得到充分保护。
⑤ 带宽管理:根据实际的带宽来进行传输策略。
从上面这些可以感受到,RTCPeerConnection这个模块是整个WebRTC的核心模块,几乎囊括了所有音视频通信需要关注和处理的点。
这个模块API主要有获取远端流gotRemoteStream(),这个API主要用来将远端的流和视频元素附加进来。同时提供创建Offer的API,这个API 用来提供自己这端的相关信息,包括自己这边有关媒体的信息,编解码器的信息等。并把这个信息作为本地描述,同时向远方对等端发送出去。远方对等端收到这个描述就将其作为远端描述存储起来。并可以通过getAnswer()方法来获取到对面传来的这个远端描述。注意由于WebRTC通信双方是对等的。也就是说比如有一对WebRTC通信对A和B。A的本地描述描述的是自己本地的一些情况,从A的角度是将这些信息打包成一个Offer发送给了B。而从B的角度,其实相当于A发来了一个Answer,里面保存了A的相关信息,所以这些相关信息从B的角度来看是远端描述,B对A同理。
2.3 构建任意数据的通信
WebRTC的 的通信其实不止于音视频,理论上说他可以传输任意类型的数据。与之对应的主要APIs是 RTCDataChannel。通过上面的RTCPeerConnection,其实是已经可以建立点对点的链接了,这时候两边其实是可以发送任意数据的。发送音视频数据需要用到MediaStream模块,而发送其他数据就需要用到RTCDataChannel模块了。这个模块比较适合游戏领域,尤其是电竞游戏。因为电竞游戏需要实时不停的和其他对等端交换数据。WebRTC的RTCDataChannel模块正好满足了这一需求。这个模块有些像WebSockets,并且WebSockets对这个模块的API的设计也是类似于WebSockets的为了方便习惯了WebSockets开发的开发者使用。而其相较于WebSocket的优势在于更低的延迟。并且WebRTC同时支持可靠(TCP)和不可靠(UDP)通信。玩过电竞游戏的应该知道,延迟对于游戏体验会有多大的影响。同时WebRTC在传输过程中已经对数据进行了标准DTLS加密,所以信息是非常安全的。通过数据通道(DataChannel)发送的包是完整的,而会在前往目的地的途中进行加密。从前面MediaStream模块用来传输音视频,也可以想象到,RTCDataChannel对于数据量较大的文件或者图片传输也是不在话下的。
使用这个模块的时候需要搭配RTCPeerConnection一起使用。通过RTCPeerConnection来创建一个对等连接。一旦连接成功,就会在成功回调处收到一个数据通道,这时就可以保存这个数据通道,并对其设置当收到对方数据是的处理回调。同时RTCPeerConnection可以创建一个数据通道,然后本地就可以通过这个数据通道来发送数据给对方。
3、服务和协议
虽说WebRTC主要是用来进行点对点通信,但是有些地方还是需要有后台服务器来进行支撑的。下面来讨论下其需要后台服务的部分。
3.1 信令(Signaling)
在WebRTC中信令是一个非常抽象的存在,或者可以理解为WebRTC官方根本就没有规定具体的规范。只要开发者实现了会话描述(session description)对象的交换就好了。会话描述里面一般来说需要包含编解码器,用什么安全策略及要使用的密匙,用于设置的网络信息。两边需要在建立连接前先互相发送给对方这些信息,这样才方便双方进行WebRTC连接。而具体通过什么方式同步倒无所谓,不觉得麻烦通过书信也可以,不过这样发起一次连接前置时间就久了。一般来说是采用WebSockets或者HTTP轮训的方式。对协议格式也没有要求,一般用JSON就好。
入上图所示,两个WebRTC对等体之间的多媒体数据是直接点对点连接的,而信令一般是通过后端服务器来进行数据通信的。整个流程可以理解为应用程序先获取到自己的会话描述,通过云端或后台服务发送到另一侧,一旦它从另一侧收到对面的会话描述。这时候它就有两个会话描述。这个会话描述其实就是上一节所说的本地描述和远端描述,只是讨论的角度不同,两者是一个东西。WebRTC获取到了这两个会话描述就可以建立点对点的媒体连接了。
3.2 STUN、TURN和ICE
除了需要后端服务来进行信令通信以外。这边还有需要后端服务的地方。要实际获得完全路由的对等会话,在很早以前很简单,因为每一个端都有一个自己的公共IP地址,直接通过IP地址就可以直接在彼此之间建立连接。
3.2.1 STUN
但是后来由于IP地址不够用了,于是使用了NAT技术来缓解IP耗尽的问题。NAT(Network Address Translation,网络地址转换)是1994年提出的。当在专用网内部的一些主机本来已经分配到了本地IP地址(即仅在本专用网内使用的专用地址),但现在又想和因特网上的主机通信(并不需要加密)时,可使用NAT方法。这种方法需要在专用网连接到因特网的路由器上安装NAT软件。装有NAT软件的路由器叫做NAT路由器,它至少有一个有效的外部全球IP地址。这样,所有使用本地地址的主机在和外界通信时,都要在NAT路由器上将其本地地址转换成全球IP地址,才能和因特网连接。
NAT的出现使得情况变得复杂了,NAT会分发所谓的本地IP地址,也就是说现在每个端实际上只知道NAT给自己的私有地址,而不知道自己向外链接的全球IP地址,这样就无法成点对点之间的通信。这时候就需要STUN服务器来解决这个问题了,通过webRTC来请求STUN服务器获取外部全球地址。STUN服务器获取到该请求,解析出它的全球地址,然后给予一个应答。至此WebRTC就能知道它自己的全球IP地址。然后两个知道了自己全球地址的WebRTC端就能进行流数据的通信了。
3.2.2 TURN
有了上面的STUN技术基本上能保证点对点之间的数据正常流动了,但有时也会出现一些例外情况使得无法完成点对点之间的通信,这时候就要采用TURN技术了。这个技术通过提供云回落的来保证当点对点通信失败时也能实现数据的有效传输。TURN 相当于提供一个云中接力。其实TURN相当于一个数据中继,当点对点连接失败时,可以通过这个中继服务器来进行传输。因为端的公共IP地址其实不一定一直固定,尤其在移动端,很有可能在车上和人视频从而导致IP地址随着位置的变化而变化。但是TURN服务器的IP地址基本时固定的,任何端和它建立连接相对来说比较稳定。它的缺点就是中继服务器中继的是各种多媒体流,需要较高的运营成本。
3.2.3 ICE
前面两种技术各有优劣STUN相对来说成本较低,但是没有那么稳定。而TURN成本较高但较为稳定。这时候就需要一种技术来根据实际情况能够动态的来选择采用那种方案了。WebRTC在这里采用的就是ICE技术。ICE能同时感知STUN和TURN,并分别进行尝试,计算出通信的最佳策略。如果能用STUN解决就用STUN,不然就采用TURN。下图是官方统计的关于两种策略采用概率统计图
从上图可以看到一般两者的比例约为6:1。
4、安全
webRTC同时考虑了数据的安全问题。它会强制加密媒体和数据。WebRTC发送的所有数据都会采用标准AES加密进行加密,音频和视频会通过SRTP加密。信令方面的传输可以采用HTTPS协议来进行加密。
5、多方通话
两方通话可以如上面所说进行即可,但是当是一个多对多的通话,就会复杂许多。首先能想到的就是建立多方彼此之间的点对点通信,这也是一种解决方案。好处就是处理处理简单,除了上面所述的一些功能服务器没有其他服务器。但缺点在于每个对等端都必须发送和复制这些数据给所有其他对等端,这样无疑就加大了对等端的CPU压力和带宽成本。
处理上面这种网状架构外,还有一种星形架构。这种架构推荐由一个多点控制单元(MCU)来进行中继。MCU是一个为大中继而定制的服务器。它可以做有选择的流转发、混合音频或视频数据、录音等事情。如果一个对等端退出,MCU不会打断整个会议。