RTC 弱網對抗之宂餘策略
動手點關注 乾貨不迷路 :point_down:
1. 背景
當下社會,實時音視頻通話已經成為人們生活、工作中重要的組成部分,如商務會談、親朋聊天等。而在通話過程中,總會存在着這樣那樣的意外情況:可能你坐在飛馳的高鐵上——信號時好時壞;又或者在會議途中離開辦公室——網絡從 wifi 切換到 4G……實現高質量的實時音視頻通話需要搭建一座無視距離連接人們的“橋樑”,而這座“橋樑”需要優秀的“基建技術”來保障網絡傳輸的穩定性和可靠性。
網絡傳輸鏈路上存在着許多不穩定的情況,造成所發出去的數據包出現丟包、延時或者抖動。不穩定的原因有很多,兩個通訊雙方在物理空間上存在距離,傳輸過程經過很多設備的處理,中途存在線路硬件故障、軟件驅動限制、或者鏈路數據擁塞等情況,都會導致發送出去的數據包在接收端沒有辦法收到或者延遲收到。
我們可以通過一些簡單基礎的工具檢測網絡是否處於波動情況,比如 ping 命令或者 Iperf 工具可以幫助統計丟包、延時以及單向抖動。我們用 ping 命令向一個遠端的主機發送 ICMP 消息,遠端主機會對你進行應答,這個過程中如果你發送出去的 ICMP 消息丟了,或者遠端服務器應答的消息丟了,在命令行界面上,對應的 icmp_seq 就會顯示超時未收到,這種情況就直觀地體現了丟包。
ping vs iPerf
帶寬分配和宂餘策略是弱網對抗核心模塊,隨着算法的演進迭代,我們能夠保證線上大部分場景的優質音視頻體驗。 對於一些小概率或特殊場景,如突發網損、擁塞恢復、PPT 翻頁等,我們還引入了多種宂餘策略,來兼顧流暢、恢復效率和低延時的需求。
2. 常用包恢復技術
通常,一個數據包在網絡傳輸鏈路中丟失了,主要有兩種方式將包進行恢復:一種是發送端利用接收端通知或者超時的機制,重新將這個包發送過來;另一種則是基於其他收到的宂餘包,在接收端將該包恢復出來。
第一種是我們熟知的自動重傳請求 ARQ 技術。與 TCP 協議中的 ACK 應答機制不同,實時音視頻場景使用的是 NACK 否定應答機制,通過接收端檢查包序號的連續性,主動將丟失的包信息通知給發送端進行重新發送。這種方式的優點是在低延時場景下的恢復效率高,帶寬利用率好,但在高延時場景下的效果比較差,存在重傳風暴等情況。
第二種是 Forward Error Correction (FEC) 即前向糾錯編碼,一種通過宂餘發送對抗網絡丟包的技術。它主要的技術原理就是分組編碼,組內進行宂餘恢復。假設每個分組由 k 個媒體包和 r 個宂餘包組成,一個分組中 k+r 個數據包中任意 k 個包可以用來重建 k 個原始媒體包。這種方式的優勢是根據先驗知識進行宂餘決策,不受延時影響。
3. 宂餘策略
在上述基本的包恢復技術下,為了使各種場景的整體抗弱網能力最大化,需要針對帶寬分配、抗丟包技術的組合配置等進行一系列的優化,從而達到抗丟包能力、端到端延時、卡頓率、宂餘率的平衡,達到“消耗最小的代價,實現最優的體驗”。
下面具體介紹我們在這方面做的幾項優化。
3.1 自適應調整策略
宂餘策略大致可以分為兩類,一類是前向宂餘,一類是被動宂餘。按照前文的描述,我們知道前向宂餘的優點是不需要交互,在高延時環境下更加適用,缺點是帶寬佔用過多。被動宂餘的優點是按需發送,佔用帶寬較少,缺點是高延時場景效果會急劇下滑。
我們的宂餘策略則是在尋找一個平衡點,通過被動宂餘和前向宂餘策略比例的調整,在保證丟包恢復率(比如 99.5%)的前提下,儘量的減小宂餘佔比,儘量的減小抗丟包恢復時間。所以,我們可以將當前問題抽象成如下一個數學場景:
-
假設 m 個媒體包,在重傳 k 次後,收到 i 個包的概率記為: P(m, i, k)
-
假設 n 個宂餘包,接收端收到 j 個包的概率記為: P(n, j, 0)
-
根據當前的 FEC 算法,這個 m + n 的分組在重傳 k 的情況下,接收端只需要接收到任意 m 個包,就能夠恢復全部的媒體包, 這個概率為:
-
Nack FEC 算法就是基於恢復概率大於 99% 的情況來計算當前最少需要配置的 FEC 宂餘度 n
基於上面的模型,在 m (平均幀分組大小), k (允許時間範圍內的重傳次數), i,j 是可以自變量。我們只要將 n 從 0 開始代入,上面求和的結果大於 99%,就可以將這個 n 作為 FEC 的宂餘率。
通過上面的算法,我們定義一個抗丟包恢復時間 resend_delay,就可以獲得被動重傳次數 k。通過參數 k,可以推導出為了達到恢復率 99%,還需要的 FEC 比例。
上述就是理論上的最優宂餘率計算邏輯。通過該算法邏輯,我們可以獲得一個自適應的宂餘調整策略,從而獲得最優的宂餘比例、最合適的延時損耗、以及最佳的丟包恢復率。
3.2 可靠重傳策略
在接收端媒體緩存中,對於 seq 最新和最老範圍內沒有接收到的數據,接收端會發送 Nack 請求,然後發送端接收 Nack 請求,將相應的包傳送過來。
正常工作狀態中,Pacer 優先發送 RTX 重傳數據,然後再發送媒體數據,這樣接收端這邊較老的丟失數據包,總能夠優先得到恢復。
但是在一些場景下,比如大丟包(70% 或以上的丟包率),或者突然限寬(4M ---> 300K)時,會出現大量的數據包被丟棄掉。這個數據包既包括原始包,也包括 Nack 重傳包,這樣會導致如下圖的一些問題。
如圖,如果丟包恢復效果比較差,比如上面 n + 3 的幀已經開始發送了,但是 n 幀還沒有被接收端全部接收到,這時,接收端生成的需要重傳的包列表 nack_list 就會很長。對於發送端來説,由於媒體數據還在繼續發送,理論上接收端請求的 nack 會越來愈多,這樣就會形成 nack 風暴。
Nack 風暴不但會導致大量的重傳流量擠佔媒體帶寬,導致帶寬分配模塊分配給媒體的碼率降低,也會導致 Pacer 擁堵,從而帶來更大的端到端延時。同時,由於不是選擇性的重傳某個幀的媒體包,導致接收端需要解碼的幀能夠被完整丟包恢復的概率比較低。
為了避免上述情況,我們引入了可靠重傳模塊:在檢測到上述情況後,及時暫停媒體發送,同時全力保障已經發送的幀數據能夠完全恢復。
我們通過 TccAck 和 Nack 請求的信息來確定某一個包處於什麼狀態,然後統計當前已經發送的數據中沒有被完整 ACK 的幀數量。如果這個數量過大,則會暫停媒體發送(同時暫停編碼器)。暫停媒體發送後,按照幀從老到新的順序,把 pacer 預算分配給最高優先級的幀,主動發送這些幀裏面沒有被 ACK 的數據。
通過上面的方式,我們有效解決了目標場景長時間卡死或者卡頓過多的問題。
3.3 擁塞恢復場景下快速抑制 FEC 碼率
我們 FEC 使用 loss 計算 FEC 宂餘率,為了防止抖動帶來的劇烈變化,這個 loss 值被平滑過。但是對於一些場景,比如帶寬突然掉落到較低的場景下,當擁塞狀態解除後,網絡丟包就會消失。這個時候,我們需要快速的抑制 FEC 碼率,讓出帶寬給到媒體,這樣可以儘快地提升畫面質量。
使用上面的狀態機,在接收到擁塞解除信號(擁塞狀態解除,並且瞬時 tcc loss 變為0)後,在平滑 loss 沒有變為 0 的情況下,使用瞬時 loss,可以快速取消掉 FEC 宂餘。
3.4 空餘帶寬利用優化
在共享場景下,宂餘策略會遇到進一步的挑戰。比如在 PPT 不翻頁的時候,空餘帶寬需要讓給視頻。但是在翻頁的時候共享流又會迅速佔據帶寬。這樣就會導致視頻碼率在翻頁時出現較大的波動。如果整體可用帶寬較低,就能夠看到視頻質量的明顯變化——卡頓率、延時上升。
如圖,在 PPT 翻頁場景,video 會使用 screen 空餘未被使用的帶寬。靜止畫面下,video 使用了大部分原本共享的預算。一旦 PPT 翻頁,共享的碼率瞬時提高,而 video 沒有及時把編碼碼率降下來,就會造成 pacer 模塊的擁堵,導致丟幀從而攝像頭流卡頓。
針對該場景,我們對帶寬分配策略進行了優化:
-
緩升快降
帶寬分配過程中對每個媒體流使用的上一層傳過來的空餘碼率進行緩升快降操作,防止高優先級碼流過快讓出空餘帶寬,導致低優先級碼流的分配碼率大幅波動。
-
關鍵幀檢測
當某個媒體流開始收到關鍵幀的時候,降低該流讓出空餘帶寬的量,使得整體輸出碼率的波動性降低。
-
波峯檢測
使用 300ms 統計窗口判斷波峯,出現較大的波峯數據時,降低該流讓出帶寬的量,減小整體輸出碼率的波動性。
4. 優化效果
在上述的宂餘策略優化下,飛書會議整體宂餘率大幅度降低(部分上漲是由於原有算法宂餘不足,出現大量卡頓,算法優化後,整體宂餘率調整為最佳值)。同時,在保證了音視頻整體效果的前提下,整體端到端延時也進一步下降,提升了飛書會議的整體音視頻體驗。
-
算法優化大幅度降低了低延時場景的宂餘率,高延時場景的宂餘率也趨於理論上的合理值。
-
解決了原有算法在高丟包場景下的問題,對於高延時,高丟包率的弱網場景下的體驗大幅提升。
-
解決了場景,網絡狀態變化過程中的收斂速度,提升了變化過程中的音視頻體驗。
在與同類產品的比較中,我們優化算法的宂餘度明顯低於同類產品,在流暢度對齊的情況下,消耗更小的帶寬。特別是在高丟包,高延時場景下,我們的宂餘率只相當於同類產品的 40%。
5. 未來展望
通過這些經優化的宂餘策略,當前飛書會議在弱網場景下的卡頓率、端到端延時、宂餘率等指標得到了大幅度的優化。在此基礎上,我們未來會在極端弱網支持,帶內宂餘聯動策略,智能場景識別等方面,進一步加大投入,增加飛書會議在各種弱網場景下的客户端體驗。
5.1 極端場景下的抗弱網能力支持
增加針對極高丟包、極高延時、丟包+延時,低帶寬+高丟包等場景的支持,配合宂餘策略以及帶寬分配策略,達到極端弱網場景下面的最佳音視頻體驗。
5.2 帶內宂餘聯動下的抗弱網策略
宂餘策略,除了前面提到的非音視頻編碼內的帶外宂餘(Nack,FEC 等),也包含音視頻編碼內的帶內宂餘。相比於帶外宂餘,帶內宂餘往往結合編碼自身的特點,使用更少的宂餘碼率代價,達到更高的抗弱網效果。
我們的宂餘策略也會進一步結合、更大化利用帶內宂餘算法,進一步提高抗弱網能力,降低整體延時和帶寬佔用。
5.3 場景識別下的抗弱網策略優化
後續,我們還將對當前的網絡環境進行識別,獲取到當前的網絡場景,從而可以進一步對宂餘策略以及編碼策略進行預判式的策略下發。
比如,我們識別到當前場景為高鐵場景,就可以在宂餘策略生成的時候偏向於抗連續丟包的策略,也可以預先增加默認前向宂餘來增加突發弱網的抗性。根據識別場景的特性,可以在實際發生弱網之前以及發生弱網之後,做出策略上的區別。
6. 加入我們
火山引擎 RTC,致力於提供全球互聯網範圍內高質量、低延時的實時音視頻通信能力,幫助開發者快速構建語音通話、視頻通話、互動直播、轉推直播等豐富場景功能,目前已覆蓋互娛、教育、會議、遊戲、汽車、金融、IoT 等豐富實時音視頻互動場景,服務數億用户。
我們是 RTC Lab 部門,負責 RTC 產品中音頻、視頻、網絡等基礎功能的研發,通過極致的工程和音視頻算法,打磨頂級的實時音視頻基礎體驗,期待優秀同學的加入!
:runner: 掃描上方二維碼,或點擊 閲讀原文 ,趕緊加入我們吧!
- 解鎖抖音世界盃的畫質優化實踐
- Kafka 架構、核心機制和場景解讀
- 頭條穩定性治理:ARC 環境中對 Objective-C 對象賦值的 Crash 隱患
- 字節跳動模型大規模部署實戰
- 「飛書績效」寬表SQL自動生成邏輯淺析
- Mybatis源碼主流程分析
- 推薦系統的Bias
- 抖音 Android 基礎技術大揭祕!| 字節跳動技術沙龍第十期
- 基於序列標註模型的主動學習實踐
- 加密技術科普
- 二維碼掃描優化
- 前端監控系列4 | SDK 體積與性能優化實踐
- 特效側用户體驗優化實戰 —— 包體積篇
- 深入理解 Android Studio Sync 流程
- 選擇 Go 還是 Rust?CloudWeGo-Volo 基於 Rust 語言的探索實踐
- 初探自然語言預訓練技術演進之路
- 高性能 RPC 框架 CloudWeGo-Kitex 內外統一的開源實踐
- 開源 1 週年突破 1w Star - CloudWeGo 開源社區實踐分享
- Go 語言官方依賴注入工具 Wire 使用指北
- prompt 綜述