前情
首先,要知道如何通过WebRTC建立简单的视频通话,首先得了解到底什么是WebRTC,可以先看下维基百科的说明:
WebRTC (Web Real-Time Communication) is a free, open-source project that provides web browsers and mobile applications with real-time communication (RTC) via simple application programming interfaces (APIs). It allows audio and video communication to work inside web pages by allowing direct peer-to-peer communication, eliminating the need to install plugins or download native apps.
当然了,WebRTC不仅广泛用于音视频通话,还可以结合其他场景用于视频会议、远程控制等。今天我们要做的就是搭建一套最简单的视频通话系统,包括前端以及后台(其实就是信令服务器),来熟悉WebRTC的整个通信流程。
在开始之前,建议读者先深入学习这篇来自WebRTC团队的入门教程Getting Started with WebRTC,
其中介绍了WebRTC的历史、WebRTC基本概念(RTCPeerConnection、RTCDataChannel、MediaStream)、信令、网络拓扑等。
熟悉上述的一些基本概念之后,便可以开始体验WebRTC的一些例子来深入地理解WebRTC的使用,推荐的还是官方出品的。WebRTC samples
展示的是基本API的使用,具体实现还需要点击到Github查看源码,需要一定的html基础。重点可看RTCPeerConnection这一部分。
WebRTC通信流程
通过上面的一些教程,我们知道建立一个通话,需要一个信令服务器(转发信令),一个STUN/TURN服务器(查找客户端的公网ip,如果穿透不成功则用转发),而具体这些服务器怎么联结在一起的呢,具体的操作流程到底是怎样子的呢?
1.通过信令服务器转发SDP
首先,可以参考MDN的Singal and video calling里面的这个流程图:
上述流程可以简单总结为:
- A.发起方(caller)创建pc(RTCPeerConnection),通过getUserMedia()采集麦克风/摄像头的音视频流(mediaStream),然后添加到pc上
- B.发起方通过pc.createOffer(),创建offer,然后调用setLocalDescription(offer)设为本地的描述
- C.发起方通过信令服务器(signaling server)发送offer给接收方(callee)。在这一过程中,如果接收方还没在线,信令服务器需要暂时保存offer,等接收方在线了,再发送
- D.接收方创建pc,然后采集音视频流,然后把mediaStream添加到pc上
- E.接收方把信令服务器传过来的offer,通过setRemoteDescription(offer),设为远端的描述
- F.接收方通过pc.createAnswew(),创建answer,然后调用setLocalDescription(answer)设为本地的描述
- G.接收方通过信令服务器发送answer给发起方,发起方通过setRemoteDescription(answer)设为远端的描述,
信令服务器在上述流程做的工作,其实就两个,转发offer还有转发answer,offer还有answer都属于SDP(Session Description Protocol)会话描述协议,具体详细内容通过查阅Anatomy of a WebRTC SDP来了解WebRTC里的SDP协议。
2.通过信令服务器转发candidate
在上图中,还有一个细节未提到的是,就是生成icecandidate并转发的流程。icecandiate是在调用createOffer()还有createAnswer()之后生成的,icecandidate代表客户端的候选地址,是通过ice机制获取当前客户端的候选地址,再借用MDN的流程图:

上述流程可以简单总结为:
- a.把发起方生成的icecandidate,通过信令服务器发送给接收方。如果这时接收方不在线的话,需要信令服务器缓存这些icecandidate,等待接收方在线时,再发送
- b.把接收方生成的icecandidate,通过信令服务器发送给发起方
所以信令服务器又多了项工作,就是转发icecandidate。
3.我们的STUN/TURN服务器呢?
如果两个客户端在同一内网的情况下,理论上是不需要STUN/TURN,只需要配置一台信令服务器,找到内网各自的地址,交换offer/answer,通过上述两个步骤,就能实现音视频通话。可现实生活中,很多时候我们的客户端是处于不同的内网下的,或者说处于不同的NAT下的,无法知道对方的公网地址,这时就需要STUN/TURN服务器啦。
在上一篇博客里面,提到过
可前面两个步骤中,没提到STUN/TURN服务器,我们的STUN/TURN服务器应该在哪配置呢?其实我们在一开始创建pc的时候,就需要把TURN/STUN服务器的地址配置进去
1 | const configuration = { iceServers: [{ |
配置完iceServers后,pc在createOffer或者createAnswer之后,就会通过iceServers即STUN/TURN服务器,查找自己的公网ip,并生成相应的candidate候选地址(包括内网以及外网的候选地址),然后通过信令服务器转发给对方,这样就可以互相知道对方的公网ip以及各自的内网ip。候选地址会生成多个,但最后会根据候选地址的优先级,最终选择最优的一对候选地址,形成通道,以传输音视频流。
更多关于ICE STUN TURN的相关内容,可查阅:Understanding WebRTC Media Connections: ICE, STUN and TURN