標准WebRTC連接建立流程
這里描述的是Trickle ICE過程,並且省略了通話發起與接受的信令部分。流程如下:
1) WebRTC A通過
Signal Server
轉發SDP OFFER到WebRTC B。WebRTC B做完本地處理以后,通過 Signal Server轉發SDP ANSWER到A。
2)A、B同時向STUN Server發送Binding request請求自身的外網地址,並從STUN Server回包的MAPPED-ADDRESS中
得到各自的外網地址
;
3)A、B收集完內外網ICE Candidate,並通過Signal Server發送給對方;
4)雙方開始做NAT穿越,互相給對方的ICE Candidate發送STUN Binding Request;
5)NAT穿越成功,A、B之間的
P2P連接建立
,進入媒體互通階段。在這個過程中,我們看到了有三個核心的部分,SDP協商、ICE Candidate交換、Stun Binding Req/Res的連通性檢查。
WebRTC網關連接建立流程
在了解了標准WebRTC的建連流程以后,我們來看看
WebRTC客戶端如何與網關建連
。
首先,我們網關的Media Server擁有公網IP,因此Server就不需要通過Stun Server收集自身的公網IP。WebRTC客戶端先與網關Signal Server協商SDP,包括ICE Candidate,Media Server分配IP和端口作為網關的ice candidate發送給客戶端。因為網關是公網IP,所以客戶端向這個IP發送STUN Binding Request會被服務器收到, 並回復Response。接着客戶端與網關媒體服務器進行DTLS握手與秘鑰協商,在此基礎上進一步進行SRTP的音視頻通信。至此,WebRTC客戶端與網關服務器建連成功。
WebRTC網關服務器媒體架構
最簡的服務器端端口方案是我們可以為每個客戶端分配一個端口,服務器上使用這個端口區分每個用戶,就像圖里描述的A、B、C、D四個人在WebRTC網關服務器上分別對應UDP端口10001~1004。這種方案邏輯上很簡單,
很多開源的服務器都采用這個方案
,如janus。另外一個原因是使用了libnice庫在服務器上來和客戶端做ice建連,類似的做法都是采用多端口的架構。
那么
多端口有什么不足呢?
1)很多的網絡出口防火牆對能夠通過的UDP端口是有限制的;
2)對於服務端來說開辟這么多端口,安全性本身也有一定的問題,特別是運維同學,更是拒絕;
3)開辟這么多的端口在Server端上,端口的開銷和性能均有一定的影響。那能否用單端口?使用單端口前,核心要解決的一個問題是:如何區分每一個RTP/RTCP包是屬於哪一個WebRTC客戶端。
為了解決這個問題,我們需要使用一些小技巧。首先,有幾個基礎知識點我們先了解一下。如下圖:
1)SDP offer和answer里配置的ice-ufrag字段里面內容,原來是用來作為stun數據包的鑒權的,因此STUN Binding Request里面的USERNAME字段就是由上Offer和answer的ice-ufrag內容拼接而成。
2)發送STUN Binding Request的客戶端本地udp fd,與ice建連成功后發送媒體數據的udp fd是同一個,也就是說Server上看到的ip port是同一個。
有了上面的背景知識,你肯定已經大致有一個方案了。我們來看看實現細節是怎么樣的:
1)在服務器給Web端的SDP Answer中設置 ice-ufrag為roomid/userid,其中RoomID和UserID是通話業務層分配的內容,用於區分每對通話以及參與者。接着做Ice candidate協商,Web端開始做連通性檢測,也就是stun binding request里的USERNAME為SDP local和remote的ice-ufrag指定內容。
2)服務器收到stun binding request的客戶端ip和端口,並正常回stun binding response。3)記錄客戶端地址與用戶的信息的映射關系。
4)服務器收到一個rtp/rtcp媒體數據包,通過包的源ip和端口,查詢映射表就可以識別這個包屬於哪個用戶。
WebRTC客戶端使用PeerConnection來表示不同的媒體連接,接下來我們將介紹如何選擇PeerConnection的方案。
在線體驗單端口直播與一對一視頻通話: https://github.com/starrtc/android-demo