一、總結
二、流程詳解
總流程可以參照 WEB-RTC 基礎概念和架構 的第二部分,本篇是對這個流程的 FE 代碼的一個梳理:
(一) 前期準備
- 首先發起端(以下統稱 Client A 或者 A)通過 mediaDevices 原生接口獲取當前設備的一些媒體輸入/輸出流(或者軌道,track),這一部分只是一個對媒體數據的前期注本工作,並沒有涉及 RTC 鏈接的相關內容,所以在上述文章的總流程中並沒有顯示。
- A 端初始化一個 RTC 鏈接對象(peerConnect-A),並掛載一系列的事件回調。
- 將本地的媒體軌道 track 添加到本地的 peerConnect-A 上,進入下一個流程。
(二) Client A 端鏈接操作
- peerConnect-A 在收集完媒體軌道 track 之後,創建 offer,這個 offer 中包含本地的一些信息,比如瀏覽器支持的編碼格式、ICE 候選服務、媒體軌道等等一些列的 RTC 需要的數據,這些數據經過信令(中繼)服務器的轉發,最終傳遞給需要進行 P2P 鏈接的接受端 Client B。
- 在 offer 創建之後,Client-A 需要做兩件事情(不嚴格需要前後順序):
- 把 offer 信息存儲到本地 peerConnect-A 中: peerConnect.setLocalDescription(offer) ;
- 把 offer 信息發送給信令(中繼)服務器;
(三) 信令服務器轉發數據
轉發 Client A 提供的 offer
(四) Client B 端鏈接操作
- Client B 端準備工作也沒啥,同樣也是初始化一個 RTC 鏈接對象(peerConnect-B),掛載一系列的事件回調,這個基本上和 A 端 RTC 鏈接對象的初始化一樣。當然,peerConnect-B 的初始化工作也可以在 Client B 接收到 A 端的 offer 再進行也不遲。
- Client B 收到服務器轉發過來的 offer 之後,會調用 setRemoteDescription 方法把 Client A 的 offer 信息存儲到本地的 peerConnect-B 中: peerConnect.setRemoteDescription(offer) 。
- 同時,Client B 創建一個 answer (在數據類型上,answer 與 offer 一致,只是爲了區分接收端還是發送端纔有不同的命名),並做了兩件事:
- 把 answer 信息存儲到本地 peerConnect-B 中: peerConnect.setLocalDescription(answer)
- 把 answer 信息發送給信令(中繼)服務器
- 把 answer 信息存儲到本地 peerConnect-B 中: peerConnect.setLocalDescription(answer)
(五) 信令服務器轉發數據
轉發 Client B 提供的 answer
(六) Client A 端鏈接操作
- 這一步就相當於步驟 (四) 中的第 2 小步,只不過是 Client A(peerConnect-A) 存儲 Client B 的 answer: peerConnect.setRemoteDescription(answer)
至此,主要的鏈接步驟已經完成,Client A 中的 peerConnect-A 與 Client B 中的 peerConnect-B 完成映射,即 peerConnect-A 等價於 peerConnect-B,兩臺終端的 P2P 鏈接完成。
三、RTC RTCPeerConnection 的一些主要事件
(一) onicecandidate
ice candidate,一個描述候選鏈接信息的數據,因爲有時候 P2P 並不能鏈接成功,就需要通過中間服務器(似乎與信令服務器不同)來鏈接,而 ice candidate,就是描述這個中間過程的數據。
按照 MDN 的描述,Client A(發起端) 獲取到這個信息後,把這個數據經過信令服務器轉發到 Client B,然後 Client B 會把這個信息通過調用 peerConnect.addIceCandidate(candidate) 方法存儲到 peerConnect-B 中去。那麼這裏有個問題:peerConnect-A 中需要存儲自身的 candidate 嗎? - 待實踐
(二) ontrack
發起端會把媒體軌道添加到 peerConnect 上,那麼對應地在接受端需要在 peerConnect 上添加這個事件回調來獲取傳過來的媒體數據,並把這些數據賦值給對應的 HTML 元素,所以,當 P2P 鏈接完成之後,FE 的大部分工作其實是在這個回調中進行的。