您好,登錄后才能下訂單哦!
上一篇文章《WebRTC 開發實踐:為什么你需要 SFU 服務器》我們了解了 WebRTC SFU 服務器的基本原理和必要性,解決了 What 和 Why,本文則更近一步,探究一下實現 SFU 服務器的關鍵技術點有哪些 ?重點解決一下 How
1 什么是 SFU ?
首先,我們再看一次 SFU 服務器的定義,什么是 SFU ?
SFU 的全稱是:Selective Forwarding Unit,是一種路由和轉發 WebRTC 客戶端音視頻數據流的服務端程序。
如圖所示,SFU 服務器最核心的功能就是與每一個 WebRTC Peer 客戶端建立鏈接,分別接收來自他們的音視頻數據,并實現?one-to-many 的能力(即把一個客戶端的流轉發到其他 WebRTC Peer 客戶端),那么,如果我們要實現這樣一臺 SFU 服務器,有哪些需要解決和處理的問題呢 ?
我們可以想象一下 Web 服務器和直播服務器的工作原理,瀏覽器/直播客戶端,要想完成與服務器之間的數據交換,通常離不開如下幾個步驟:
通過 DNS 解析,拿到服務器的 IP 地址;然后通過 “約定” 的端口(如:80 或者 1935)連接到服務器
客戶端使用 “約定” 的信令協議(如:HTTP,RTMP),發送請求給服務器,實現數據交換的準備工作
客戶端開始上行數據給服務器,或者服務器開始下發數據到客戶端,結束后,通過信令關閉連接
靜態的資源型的數據(文件、網頁),通常服務端是讀取磁盤上的數據拷貝一份給需要的客戶端
非靜態的實時數據(如:直播流),服務器則通過在 “內存” 中拷貝并轉發給需要的客戶端
同樣,WebRTC 客戶端與 SFU 服務器之間的交互,也是離不開這些步驟的,特別是 4/5,其實就是所謂的 one-to-many 能力。
2 ?信令和傳輸通道的建立
首先我們解決第一個問題,即 WebRTC 客戶端是如何跟 SFU 服務器建立數據傳輸通道的 ?
如圖,我們先看看瀏覽器與 Web 服務器的建聯過程:瀏覽器通過 DNS 解析 URL 中的域名,拿到 IP 后通過 80 端口連接上服務器(后續的數據傳輸均復用這條 TCP 鏈路)。
WebRTC 其實也是類似的,但是與標準的 HTTP 服務或者 RTMP 直播服務相比,還是有些區別的,如下:
信令和數據通道是 “分離” 的,信令目前沒有統一的實現方案,可以使用任何方案(如:HTTP、TCP 自定義協議、SIP 等等),但是數據并不走這條信令鏈路,而是走單獨的 UDP 端口
數據通道使用的 UDP 協議,不像 TCP?有 “連接” 的概念,客戶端僅僅知道服務器的 UDP 端口,但不 “連接” 是無法預判傳輸通道是否真的 OK(主要是部分 NAT 網關類型的限制,導致并不是所有 UDP 傳輸都能通),因此需要借助一些框架和協議來判斷 UDP 通道的可用性(即 ICE 協議)
上述內容分析完了,我們就可以看看如何實現 SFU 的信令和傳輸通道了:
實現 HTTP Web Server 服務(或者 SIP 或者基于 TCP 自定義協議),用于提供 “信令” 的支持(如:推流命令、拉流命令等)
通過 libnice 庫或者自己 coding 的方式,實現 ICE 協議,用于提供 UDP “數據通道” 的檢測和建聯
實現 UDP 數據監聽和發送,用于接收客戶端的數據,轉發其他客戶端的數據
3 需要實現哪些 “信令” ?
對于 HTTP 協議,實現的 “信令” 包括:GET,POST,DELETE 等等,定義了瀏覽器期望進行的行為。同理,對于 SFU,我們也要定義一系列必要的信令,以約定客戶端和服務器對應的行為,那具體有哪些呢 ?
其實 WebRTC 客戶端,與 SFU 服務器需要協商的事情,無外乎就是如下幾點:
ICE 建聯:交換 ICE 信息(用戶名、密碼、IP 地址、UDP 端口等)
發布流/取消發布流:客戶端通知服務器準備好接收數據
訂閱流/取消訂閱流:客戶端通知服務器準備好轉發數據
因此,SFU 服務器通過任意一種方式(HTTP/TCP 等),提供 ICE Connection/Publish/Subscribe 信令即可,SFU 在信令背后需要實現的邏輯分別如下:
1. ICE Connection:添加一路 UDP 通道
2. Publish:添加一個邏輯上的數據 Producer,通過 UDP 通道 recv 客戶端的數據,通知邏輯上的 Consumers
3. Subscribe:添加一個邏輯上的數據 Consumer,收到 Producer 通知后,通過 UDP 通道 send 給客戶端
4 如何實現 one-to-many ?
這是 SFU 最核心的功能,其實也不是 WebRTC SFU 特有,如前面所述,凡是非靜態資源型的服務(數據實時產生實時消費)均需要在服務端實現 one-to-many,比較典型的例子就是 RTMP 直播流服務器,需要將客戶端推流上來的數據,實時轉發給多個拉流的客戶端。
實現?one-to-many ,最重要的一點是需要把數據的生產者(Publisher)和數據的消費者(Subscriber)關聯起來,怎么關聯呢 ?
WebRTC 傳輸的音視頻數據,實際上是封裝在 RTP 包里面,RTP 包頭有個很重要的字段,叫做 ×××C(同步源標識),就是這路流的唯一標識,如圖:
數據的生產者(Publisher)和數據的消費者(Subscriber)即可通過 ×××C 來關聯,實現?one-to-many 的核心代碼邏輯抽象如下:
即:當 SFU 接收到?Publisher 發送上來的數據后,輪詢一下所有的?Subscribers,如果 ×××C 匹配成功,則將數據轉發給這個客戶端。
5 數據傳輸協議
WebRTC 采用的是標準的 RTP/RTCP 協議進行數據的封包和網絡狀態反饋,因此,SFU 服務器也需要支持?RTP/RTCP 的封包和解包,從而能夠 “理解” 客戶端的 UDP 數據包的含義,如:提取出 ×××C 或者 timestamp 等必要的信息,也能及時地向客戶端反饋網絡狀態(RTCP)。
關于 RTP/RTCP 傳輸協議,已經發展多年,是比較成熟的多媒體傳輸協議了,也有很多不錯的開源庫,這里就不再贅述了。
6 小結
以上就是關于如何實現 SFU 服務器最核心的知識點了,暫且就分享到這里了,如有疑問的小伙伴歡迎來信 lujun.hust@gmail.com 交流。另外,也歡迎大家關注我的新浪微博 @盧_俊 或者 微信公眾號 @Jhuster 獲取最新的文章和資訊。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。