作者:陣圖
審校:泰一
來源:
WebRTC ICE 狀态與提名處理Scene
分析一個問題時候遇到這樣的場景:服務端一個 Candidate,用戶端三個不同優先級的 Candidate,但是最後居然選擇了一個優先級最低的 Pair。
服務端有一個 Relay Candidate,端口 50217。
a=candidate:3 1 udp 503316991 11.135.171.187 50217 typ relay raddr 10.101.107.25 rport 40821
用戶端有三個 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。
Remote selected pair: 1:1 592388294 UDP 11.135.171.187:50219 RELAYED
Candidate's Foundation
Candidate 的 Foundation: 這裡先提一下 Foundation,會涉及到 Frozen 狀态。
對于一條相同的信道,可能有不同的 Candidate,比如 Relay Candidate 被發現的時候,就可以生成一個新的 Server Reflexive 類型的 Candidate,但是他們都是基于相同的本地位址(IP,端口)和協定,則可以認為這些網絡是相似的,則他們就會有相同的 Foundation。其中 Foundation 在 SDP 中為第一個字段,即下面例子中的 '7'。
a=candidate:7 1 udp 503316991 11.178.68.36 51571 typ relay raddr 30.40.198.7 rport 55896
ICE States
ICE 主要有以下五種狀态,其中前四種是正常的狀态,第五種狀态 Frozen 涉及到
ICE Frozen Algorithm。
ICE 的五種狀态:
- Waiting: 當連通性檢查還沒有開始執行的時候(Binding Request 還沒發送)。
- In Progress: 當連通性檢查發送了,但是相應檢查的事務仍在執行中(Binding Request 已發送)。
- Successed: 連通性檢查執行完成且傳回結果成功(Binding Request 已完成)。
- Failed: 連通性檢查執行完成且結果失敗(Binding Request 已完成)。
- Frozen: ,所有 Candidate Pair 初始化完成以後就在這個狀态,對于相同的 Foundation(相似的 Candidate),會按照優先級依次選取一個 Pair,Unfreeze,并設定為 Waiting 狀态,其他則保持 Frozen。直到選取的 Pair 完成,才會繼續 Unfreeze 另一個 Pair。
ICE Nomination
ICE 有兩種提名方式:
1.Regular Nomination
對于正常提名,主要工作流程如下:
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 一端收到了,就接受這次提名。
2.Aggressive nomination
除了正常提名,還有一種比較激進的提名,正常提名中會新增一次握手。
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 作為實際的信道。
真實案例:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CNjdzMzEDZhZDNzMzYjRWO0YjY0ADZlVWMxMGNjZjMh9CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
Updating States When Nomination
原文參考當一個新的提名産生時,會對 ICE 内部狀态進行對應的變化。
當一端的 Binding Request 攜帶了 Use Candidate 的标志位時,則會産生一次提名(Nomination)。
不管 Controlling 或者 Controlled 模式下的 Agent,處理提名的狀态更新規則建議如下:
- 如果沒有提名的 Pair,則繼續進行連通性檢查的過程。
- 如果至少有一個有效的提名:
-
- Agent 必須删除該 Component 下的所有 Waiting 狀态和 Frozen 狀态的 Pair。
-
- 對于 In Progress 狀态下的 Pair,優先級低于目前提名 Pair 優先級的,停止重傳(取消)。
- 當某一個 Stream 的所有 Compont 都至少擁有一個提名時,且檢查仍然在進行時:
-
- Agent 必須将該 Stream 标記為已完成。
-
- Agent 可以開始傳輸媒體流。
-
- Agent 必須持續響應收到的消息。
-
- Agent 必須重傳目前仍然在 In Progress 的 Pair(優先級高于目前提名的,不然已經被删除或者取消)。
- 當檢查清單中的所有 Pair 都完成時:
-
- ICE 完成。
-
- Controlling Agent 根據優先級更新 Offer(貌似 WebRTC 沒有這一步)。
- 當檢查清單檢查有失敗時:
-
- 所有 Pair 都失敗時,關閉 ICE。
-
- 當有某個流的檢查成功時,Controlling Agent 移出失敗的 Pair,并更新 Offer。
-
- 如果有些檢查沒有完成,則 ICE 繼續。
Scheduling Checks
在描述提名時,還會涉及 ICE 對 Pair 的排程(當有效 Candidate 還在 In Progress 的時候但是其他 Candidate 的 Pair 已經收到 Binding Request)。
這裡隻讨論 Full,先不描述 Lite 模式。
ICE 的 Checks 分成兩種,Ordinary Checks And Triggered Checks。
- Ordinary Checks 是正常的 Pair 的檢查,表示這些 Pair 的檢查是從正常流程中切換過來的狀态的檢查。
- Triggered Check 是被動觸發的檢查,當這些 Pair 雖然還處在不可以開始檢查的狀态,但是這時候收到了對端的連通性檢查,這時候會對這個 Pair 進行提速,将其直接放入排程清單。
當 ICE 建立一個 Check List (每個 Stream 一個)後,會對每個 Check List 添加一個定時器,當定時器到來時,會進行如下排程:
注:這裡有點不能了解,整個流程看起來是串行的,激活速度有點慢。
- 首先排程 Triggered Check 并執行。
- 若無,排程優先級最高的 Waiting 狀态的 Pair,發送 Request,同時将狀态置為 In Progress。
- 若無,則從 Check List 中找出優先級最高的 Frozen 狀态的 Pair,Unfreeze 之,并發送 Request,狀态設定為 In Progress。
- 若無,終止排程。
Case Analyzed
簡單了解了 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。
「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。