WebRTC 筆記 --- 4 RTCPeerConnection,Stun,TURN

WebRTC 採用 RTCPeerConnection做browser與browser 之間的Streaming 與 data的溝通。但是需要一個訊息發送的機制把兩端的網路資訊與多媒體資訊做交換(可以當成一個傳送兩端基本資訊的server)。這個信號方法(Signaling methods)和protocols並沒有被明定在WebRTC裡面,所以信號方法並不在RTCPeerConnection API裡面。

而WebRTC的開發者可以選擇自己喜歡的交換訊息方式,例如: SIP、XMPP或是任何可以雙工(duplex  two-way)的溝通頻道(communication channel)。當交換的資訊完整成功之後才來開始做Stream的使用。

WebRTC 可以透過點對點(peer-to-peer)溝通,但是還是需要Server(通稱 Signaling server)原因是:
  1. 對Clients 交換 metadata做協調溝通這個過程叫做 signaling。
  2. 應對網路地址交換器(NATs)與防火牆


在Signaling server 主要對於兩個遠端browser交換的資訊為SDPICE candidate,因此這邊就簡單解釋一下SDP與ICE的功用是作什麼的了。

SDP:

主要描述多媒體 Session 通訊內容格式,用來發出Session 公告、Session 邀請跟參數協商。SDP本身不會在傳送任何多媒體本身但是在endpoints之間用於協商多媒體類型、格式和所有相關屬性

SDP 本身被設計比較彈性用來支援新的媒體類型與格式。起頭為SAP可以結合RTP、RTSP、SIP並且可以獨立成為多點傳送(multicast) 溝通的格式。

ICE: 

用來獲得與分享網路相關資訊,所以通常一開始會先用ICE framework來交換網路界面與ports。
不過很多時候因為NAT或是防火牆問題讓你無法直接連線,所以ICE靠著STUNTURN協定來處理NAT穿透與其他問題。

ICE一開始會用UDP方式連線到另一方,這邊stun server只有提供一個簡單的功能,就是在NAT中的client獲取自己的的公開IP與ports。如果UDP失敗了,ICE就會嘗試TCP的方式先試http若不行再試https。如果直接連線都失敗就改用TURN server作為中繼站,讓所有資料都透過TURN server來轉送。



Signaling Server: (mozilla)

簡單的說就是兩個裝置(或是browser)用來交換SDP與ICE的一個中間server。

以mozilla的說明為:傳送控制資訊於兩個裝置並且用來確定這兩個裝置互相溝通使用的協定(protocols)、頻道(channel)、媒體編碼(media codecs)與格式跟傳送資料的方法以及任何所需的路由信息。
最需要知道的是signling 並沒有被定義在WebRTC的標準中。
主要是因為兩個裝置並沒有辦法直接互相溝通而且WebRTC無法預測每一個可能使用WebRTC的目的。所以讓開發者選擇適合的網路技術與訊息協定是比較合理的。
尤其是當開發者已經有方法來連結兩個裝置還要他們使用其他方法來做連接是不合理的只是因為被定在WebRTC標準中。
開發者可以自由選擇傳送信令的方式與協定,例如:SIP、XMPP或任何可以進行雙向溝通的協定都可以。

在信令方法中主要交換的是下面三種資訊:

  • Session control message:
    用來初始化、建立、開啟或是關閉通訊並且處理錯誤。
  • Network configuration : (ICE)
    得到我們電腦的實際IP和port。
  • Media capabilities:  (SDP)
    我們的瀏覽器可以用的編碼和可使用的解析度跟溝通方式。

信令過程(The signaling process):

為了能夠讓WebRTC session開始運作,所以下列流程需要依序發生。

1. 每個點(peer)創造一個 RTCPeerConnection物件來代表他們的WebRTC session。

2. 每個點(peer)建立一個handler用來管理 signaling channel 傳送的candidates 到其他點的 icecandidate事件。

3. 每個點(peer)建立一個handler來管理遠端端點(peer)將track加到stream的這個track事件。
這部份程式要能將track連接到track的消耗者~例如: DOM裡的 video 元素

4. 呼叫者(caller)創建並且分享收到其他點的唯一識別碼或是能夠被signaling server區分彼此的token。詳細的識別碼內容與格式可以由自己來決定。

5.每個點(peer)連接到一個互相承認的signaling server~例如: WebSocket server 。知道如何透過這個server交換訊息。

6. 每個一點(peer)告訴signaling server 他們要加入到同一個WebRTC session。


Designing the signaling protocol:

我們已經建立了交換訊息的機制(websocket),現在我們需要定義protocol的樣式。這可以採用幾種方式來實做,這邊我們先使用JSON格式的內容來處理訊息與所需的正確額外資訊。

Exchanging ICE candidates:

在交換offer與answer之後,兩個參與者開始交換ICE candidates作為實際兩者對連的協商。每一個ICE candidate描述一個可用來對等傳送的通信。
每一個點會依序送他們找到的candidate直到送完推薦的candidate 甚至多媒體已經開始串流。一旦兩個點同意使用一個兼容的candidate 那這個candidate的sdp就被每一個點當作開啟連線的方式,如果之後又發現更有效率的candidate,串流也可能會改變格式如果有需要的話。

雖然目前不支援在candidate 接收後多媒體因為網路頻寬變小理論上是可以做downgrade傳送。


每個ICE message 建議通信的protocol(TCP or UDP)、IP位置、Port number、連線型態(例如:
不論指定的IP是自己還透過中繼server)以及將兩台電腦連線所需的其他資訊並且包含NAT或是其他的複雜網路。

備註:程式碼要注意的是透過onicecandidate handler的執行在ice協商時將ICE 層的candidate 透過signaling channel 連線送給其他的點並且接收來自signaling server傳來的ICE candidate message並且藉由RTCPeerConnection.addIceCandidate()交付給你的ICE 層。
至於SDP的內容通常我們都不用管。你的signaling server要做的就是送訊息,你的工作流程可能會需要登入/驗證的功能但是細節可能有所不同。



以下是一些會用到的API

RTCPeerConnection.createOffer():

初始化建立的SDP用來開始一個新的WebRTC與遠端連線。
他會建立一個RTCSessionDescription物件(包含多媒體相關的設定與資訊),物件建立實惠直接傳入第一個callback function( localDescCreated())

onicecandidate:

是個eventhandler 。主要是當icecandidate事件發生時觸發。每當 local ICE agent透過signaling server傳送訊息給其他點。會讓ICE agent不用透過與遠端的點協商。
簡單的說就是當有可用的ice candidate產生時候觸發這個事件並且在自己使用的signaling server將ice candidate 傳給其他點。

RTCPeerConnection.addIceCandidate():

當網頁或是app使用RTCPeerConnection接收到一個遠端signaling channel 傳來的新ICE candidate。藉由呼叫RTCPeerConnection.addIceCandidate()提供新的 ICE candidate 給瀏覽器的ICE agent。
這會新增一個遠端的candidate到RTCPeerConnection的 remote 作為當遠端結束連線時的狀態描述。

RTCIceCandidate:

WebRTC api interface的一部分,用來設定ICE作為連線選項之一可以用來建立RTCPeerConnection。我們會用它來產生ice candidate 然後使用 addIceCandidate() api 將 ice candidate加到local browser。


發起者(caller) 送sdp、ice candidate 到signaling server.
接收者(callee) 到signaling server收到sdp 後用setRemoteDescription 加入caller的sdp後才去getUserMedia找到並使用本地的視訊裝置接著使用 getTrack把track 跟stream加到 RTCPeerConnection。
完成後再去 createAnswer 做 setLocalDescription 把sdp丟回signaling server. 至於callee的 ice candidate 透過 onicecandidate event handler 在setLocalDescription api執行後會去trigger ice agent 產生 ice candidate 丟到signaling server上

ICE agent 會在當我們 setLocalDescription的時候產生 ICE candidate.


ICE restart: 通常用不太到

有時候在WebRTC session的生命週期中遇到網路連線改變。例如:使用者手機從基地台轉到WIFI或是網路變得擁擠。這個時候 ICE agent可以選擇執行ICE restart,這會讓網路重新協商連線,正確來說這跟初始化ICE 協商的方式是一樣的不過有個例外就是多媒體的傳送還是會走舊的網路連線直到新的連線可以使用並且平移到新的網路連線後要把舊的連線關閉。

note:
不同的瀏覽器支援的ICE restart條件不同,不是所有的瀏覽器會因為網路壅塞而執行ICE restart。

ICE restart分為兩種:
1. Full ICE restart 會讓所有在 session的 media stream 重新協定傳送。
2. Partial ICE restart 允許針對指定的media stream做重新協定傳送而非全部。但不是全部的瀏覽器支援Partial ICE restart。

如果有需要改變ice連線設定~例如:變更ICE server可以在restart ICE 呼叫之前使用 RTCPeerConnection.setConfiguration() 帶入RTCConfiguration 的設定值就可以了。

要如何明確地trigger ICE restart呢?透過呼叫 RTCPeerConnection.createOffer() 指定iceRestart選項值為true就可以了。這會產生一組新的ICE username fragment(ufrag)跟password用來做重新協定連線。
回應方的連線會在新的ICE ufrag 與 ICE password 拿到後自動執行ICE restart。


REF:

留言