你們都知道奧斯卡有提名,其實在 WebRTC 的 ICE 中也有提名,有常規的提名,也有激進的提名,並且提名的候選人不必定是最優秀的候選人喔,本文就帶你一探其中玄妙。文章內容主要描述 RFC 5245 中 ICE 相關的狀態和 ICE 提名機制,並結合 libnice(0.14) 版本進行分析。html
做者:陣圖,阿里雲開發工程師
審校:泰一,阿里雲高級開發工程師網絡
分析一個問題時候遇到這樣的場景:服務端一個 Candidate,客戶端三個不一樣優先級的 Candidate,可是最後竟然選擇了一個優先級最低的 Pair。併發
服務端有一個 Relay Candidate,端口 50217。ide
a=candidate:3 1 udp 503316991 11.135.171.187 50217 typ relay raddr 10.101.107.25 rport 40821flex
客戶端有三個 Candidate,端口 50218(中間優先級),50219(最低優先級),50220(最高優先級)。阿里雲
Candidate 1: candidate:592388294 1 udp 47563391 11.135.171.187 50219 typ relay raddr 0.0.0.0 rport 0 generation 0 ufrag fO75 network-cost 50 Candidate 2: candidate:592388294 1 udp 48562623 11.135.171.187 50218 typ relay raddr 0.0.0.0 rport 0 generation 0 ufrag fO75 network-cost 50 Candidate 3: candidate:592388294 1 udp 49562879 11.135.171.187 50220 typ relay raddr 0.0.0.0 rport 0 generation 0 ufrag fO75 network-cost 50
可是最後選擇的倒是最低優先級的 Pair,50219。code
Remote selected pair: 1:1 592388294 UDP 11.135.171.187:50219 RELAYED
視頻
Candidate 的 Foundation: 這裏先提一下 Foundation,會涉及到 Frozen 狀態。htm
對於一條相同的信道,可能有不一樣的 Candidate,好比 Relay Candidate 被發現的時候,就能夠生成一個新的 Server Reflexive 類型的 Candidate,可是他們都是基於相同的本地地址(IP,端口)和協議,則能夠認爲這些網絡是類似的,則他們就會有相同的 Foundation。其中 Foundation 在 SDP 中爲第一個字段,即下面例子中的 '7'。blog
a=candidate:7 1 udp 503316991 11.178.68.36 51571 typ relay raddr 30.40.198.7 rport 55896
ICE 主要有如下五種狀態,其中前四種是正常的狀態,第五種狀態 Frozen 涉及到 ICE Frozen Algorithm。
ICE 的五種狀態:
Frozen: ,全部 Candidate Pair 初始化完成之後就在這個狀態,對於相同的 Foundation(類似的 Candidate),會按照優先級依次選取一個 Pair,Unfreeze,並設置爲 Waiting 狀態,其餘則保持 Frozen。直到選取的 Pair 完成,纔會繼續 Unfreeze 另外一個 Pair。
ICE 有兩種提名方式:
對於常規提名,主要工做流程以下:
L R - - STUN request -> \ L's <- STUN response / check <- STUN request \ R's STUN response -> / check STUN request + flag -> \ L's <- STUN response / check Regular Nomination
Controlling 模式下的 Agent 發起 Binding Request,而且收到對端的 Response,同時對端發起的 Connective Check 完成,Controling 一端會再次發出一個攜帶 USE_CANDIDATE 標誌位的 Binding Request,當 Controlled 一端收到了,就接受此次提名。
除了常規提名,還有一種比較激進的提名,常規提名中會新增一次握手。
L R - - STUN request + flag -> \ L's <- STUN response / check <- STUN request \ R's STUN response -> / check Figure 5: Aggressive Nomination
Controlling 模式下的 Agent 發起 Binding Request,可是在這個 Binding Request 中會直接攜帶 USE_CANDIDATE 的標誌位,Controlled 模式下的 Agent 收到了之後就接受此次提名。在激進提名模式下,能節約一次握手過程,可是當多個 Pair 同時接受提名時,會根據這些 Pair 各自的優先級進行選擇,選擇出優先級最高的 Pair 做爲實際的信道。
真實案例:
當一個新的提名產生時,會對 ICE 內部狀態進行對應的變化。
當一端的 Binding Request 攜帶了 Use Candidate 的標誌位時,則會產生一次提名(Nomination)。
無論 Controlling 或者 Controlled 模式下的 Agent,處理提名的狀態更新規則建議以下:
當某一個 Stream 的全部 Compont 都至少擁有一個提名時,且檢查仍然在進行時:
當檢查列表中的全部 Pair 都完成時:
當檢查列表檢查有失敗時:
在描述提名時,還會涉及 ICE 對 Pair 的調度(當有效 Candidate 還在 In Progress 的時候可是其餘 Candidate 的 Pair 已經收到 Binding Request)。
這裏只討論 Full,先不描述 Lite 模式。
ICE 的 Checks 分紅兩種,Ordinary Checks And Triggered Checks。
當 ICE 創建一個 Check List (每一個 Stream 一個)後,會對每一個 Check List 添加一個定時器,當定時器到來時,會進行以下調度:
注:這裏有點不能理解,整個流程看起來是串行的,激活速度有點慢。
若無,終止調度。
簡單瞭解了 ICE 的流程後,咱們迴歸最開始的 Case。
首先看 Add Candidate,三個 Remote Candidate 添加順序不一樣,依次爲 50219,50218,50220,注意,此時 50219 收到了對端的 Binding Request,激進提名,攜帶 USE_CANDIDATE,所以很快執行 Create Permission 並完成,這時候能夠開始發送 Binding Request 了,屬於 Triggered Checks 優先調度,發送 Binding Request,並進入 In Progress 狀態。
注:這裏除了本地 Relay 的 Pair,還有和 Turn 通訊的本地 Host 類型的 Candidate。
接着在 50219 在其餘兩個 Create Permission 還沒完成時候以迅雷不及掩耳之勢完成了 Check,根據 rfc 8.1.2 中的描述,對於不是在 In Progress 狀態的 Pair,都刪除,並不參考其優先級,故最後選擇了 50219 這個優先級最低的 Pair。
「視頻雲技術」你最值得關注的音視頻技術公衆號,每週推送來自阿里雲一線的實踐技術文章,在這裏與音視頻領域一流工程師交流切磋。