一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

機器之心發佈

機器之心編輯部

昨天,清華自動化大一學生的 C++大作業霸佔了知乎榜首,該作業要求學生寫一個類似於「雨課堂」的網絡教學軟件(雷課堂),可以共享屏幕、語音直播、在線答題……其實現難度、工作量似乎都超出了大一學生的能力範圍,連清華特獎得主、阿里 P6 也表示無法單獨完成。離提交 deadline 只剩五六週,這個作業真能寫完嗎?

一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

在昨天的討論區,我們看到大部分評論都是對於這一作業的吐槽。不過也有人提醒大家,為什麼不試一試呢?畢竟,作業還是要交的。

一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

作為雨課堂的技術支持方,快手的音視頻工程師範威給出了自己的專業回答。範威有著十多年的工作經驗,在春節後深度參與了雨課堂和快手項目的聯合開發,為雨課堂提供了音視頻底層技術支持。

根據範威的介紹,總共需要 2 周開發時間,就能擁有一個雷課堂。當然,前提是「這些知識你都學過」,還要有「豐富的踩坑經驗」。

小夥伴們是不是心動了?下面來看具體分析。

一個人單擼一個雷課堂需要多少工作量?

雨課堂是清華大學研發的一款在線教育 APP,可以支持老師在線授課、分享 PPT,學生與老師進行語音互動。從音視頻角度來看,這種在線授課的形式其實就是一個標準的視頻會議場景。

要說如何從頭開始擼一個視頻會議軟件,需要分前端和後端來說。這裡前端指的是終端,後端指的是媒體服務器。前端的主要功能是負責音視頻通信,後端的主要功能是負責媒體流的轉發。

先說說前端。前端模塊包括音視頻採集、前處理、編解碼、收發包等功能模塊。目前開源的視頻會議項目以 webrtc 最為流行,其代碼裡有 80w+行之多。要想單手從頭擼一個視頻會議終端,雖說不需要 80w 行代碼那麼多,但是還是有其難度的。

採集模塊

首先是平臺的支持。iOS、Android、Windows、Mac、Linux,不同平臺提供的音視頻技術都不盡相同。音視頻的採集和前處理,需要根據不同的平臺和機型進行適配,有些算法可以採用平臺的能力,而有些算法需要通過軟件進行處理。

先來說一下采集和前處理模塊。視頻通過調用系統 API 完成攝像頭數據的採集,這裡不詳細說,感興趣的同學可以自行查閱官方文檔。視頻前處理包括各種美顏濾鏡算法,由於教育場景下這個功能不是剛需故而跳過。

這裡說一下音頻前處理。在實時語音通話時,從麥克風直接採集到的音頻是包含自己說話的聲音以及對方說話的聲音的。這是因為本地的揚聲器播放出對方的聲音也會被麥克風採集進去。如果不加任何處理就發送出去的話,對方會從揚聲器裡聽到自己說話,這種情況稱為聲學回聲(Echo)。為了得到一個比較自然的通話效果,需要對麥克風採集的音頻數據進行處理,消除掉對方說話的部分,只保留本地的聲音。這個過程叫做回聲消除(AEC,Acoustic Echo Cancellation)。AEC 算法最常用的方式是採用自適應濾波器來產生一個模擬回聲,然後再從麥克風採集信號中將這個模擬回聲抵消掉,達到消除回聲的目的。

一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

單線 AEC 架構

在實際項目中,還會對信號做一個 NLP(非線性濾波)來消除殘餘回聲,同時為了增強信噪比還會做聲學降噪和自動增益,統稱為 3A(AEC/AGC/ANS)。目前幾乎所有的智能手機和 Mac 平臺都有硬件的 3A 算法模塊,其中蘋果的設備調校的比較好,而 Android 手機的 3A 效果良莠不齊,通常需要通過軟件自己實現。最快的實現方式是採用系統提供的 3A 算法,這裡算 1 個人天。

編碼模塊

接下來是編解碼模塊。編解碼是將經過前處理的音視頻原始數據進行壓縮,以達到網絡傳輸的目的。由於網絡資源的限制,原始的音視頻數據量太大,不能直接在網絡上進行傳播,必須先經過壓縮。壓縮分為無損壓縮和有損壓縮。音視頻數據通常採用有損壓縮的方式,可以做到非常大的壓縮比。視頻編碼算法常用的有 H.264/H.265/VP8/VP9/AV1/AVS2 等等,音頻的壓縮算法有 AAC/Speex/Opus/G.711/G.729 等。現在通常採用的視頻壓縮算法是 H.264/H.265,而音頻算法則大都採用 Opus。

壓縮算法的細節非常繁雜,目前大多采用比較成熟的開源項目來實現,比如 x264,x265,ffmpeg 以及 libopus。蘋果設備也提供了內置的硬件視頻編解碼器 videotoolbox 可以支持 H.264/H.265 的實時編解碼,而 Android 則有 MediaCodec 提供相同的能力。在桌面平臺上,Intel 和 NVIDIA 的很多芯片提供了 qsv 和 nvenc 功能,用於實現桌面端的硬件視頻編解碼。有了編碼器之後,還需要對編碼參數進行正確的配置,以適合實時通信的場景。主要影響音視頻通話體驗的參數就是碼率,在其他參數不變的條件下,碼率越大音視頻質量就越好,而使用的網絡帶寬也越大。

這裡為了簡化實現,使用系統提供的編解碼器實現,算 1 個人天。

傳輸模塊

經過編碼之後的音視頻數據已經小了很多,可以進行網絡傳輸了。Internet 網絡傳輸協議分為 TCP 和 UDP 兩種方式。TCP 協議是可靠傳輸,保證數據的完整性和有序性,但是缺點是在公網傳輸時速度比較慢,延時比較大。而 UDP 協議是不可靠協議,數據只管發,不能保證一定能夠到達對方,但是優點是發送速度快,延時低。因此在實時音視頻通信裡,都會優先使用 UDP 協議進行數據發送。UDP 數據是以數據包為單位進行發送的,每次發送一個包,最大包大小不能超過 64K 字節。但是由於 IP 層的分片路由限制,通常一個 UDP 數據包的大小都會限制在一個 MTU(Max Transmission Unit)以內。以太網的 MTU 為 1500 字節,因此每個 UDP 包的大小大多都會限制在 1K 字節左右。而編碼後的視頻數據相對於這個大小還是太大了,需要對視頻數據進行進一步的分包才能進行發送。

由於 UDP 協議的特性是不可靠傳輸,因此數據包達到的先後順序也沒有保證。為了讓對方收到的音視頻數據的先後順序跟發送端一致,需要在接收端對 UDP 包進行排序。在視頻會議上,通常會採用 RTP 協議對分包之後的數據包進行一層封裝,每個 RTP 包都包含一個 RTP 頭,裡面為每個 RTP 包分配了一個序列號。這個序列號是有序遞增的,因此接收端可以通過收到的 RTP 包的序列號對數據包進行排序,同時也可以知道哪些序號的數據包沒有收到,從而向發送端請求重發。

上面提到 UDP 在網絡傳輸過程中可能會丟包。由於音視頻編碼後的數據需要完整接收才能進行正常解碼,因此採用 UDP 協議傳輸的 RTP 包需要能夠處理丟包恢復。丟包恢復的方式有兩種,一種是 FEC(前向糾錯),一種是 ARQ(自動重傳),通常項目上這兩個方法會同時採用。

FEC 是對一組 RTP 包進行冗餘編碼,產生出一些冗餘包,冗餘包包含了這一組 RTP 包的信息,在丟包的時候可以利用冗餘包裡的數據,恢復出這一組 RTP 包數據。常用的 FEC 算法包括 RS、卷積碼、噴泉碼等。FEC 的好處是不會引入額外的延時,冗餘包和數據包一起發送給對端,對端通過接收到的數據包和冗餘包嘗試恢復,沒有額外的交互時間,但由於網絡丟包的隨機性,並不是每一個 FEC 包都能夠被利用,這樣降低了整體的帶寬利用率

ARQ 則是精準的請求丟失的 RTP 包,讓發送端重新發送。在 RTP 協議裡,可以通過 NACK 來實現重傳請求,攜帶上請求重傳的 RTP 序列號。發送端接收到 NACK 請求後,會重新發送該序列號對應的 RTP 包到對端。NACK 和重傳包的傳輸引入了額外的延時,因此 ARQ 會導致音視頻通信的延時增加,但是帶寬利用率比較高。

對於差一些的網絡,網絡的帶寬並沒有那麼高,如果發送端編碼的音視頻數據超過了其發送的上行帶寬,就會導致網絡擁塞,產生丟包和卡頓。為了防止網絡擁塞的發生,發送端需要對自己的上行網絡帶寬進行預測,並反饋給編碼器,調整編碼器的碼率不要超過帶寬上限。這個算法叫做帶寬估計。帶寬估計是實時音視頻通信非常重要的一個算法,其準確性會很大程度上影響用戶體驗。帶寬估計算法的策略有很多,webrtc 中採用的是 google 提出的 GCC(Google Congestion Control)算法。

整個傳輸模塊沒有現成的開源項目可用,要麼自己擼要麼參考 webrtc 的實現,大概需要 3-5 天。

一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

緩衝隊列

到這裡,發送端模塊基本就介紹完了,下面說一些接收端要做的部分。接收端在接收到 RTP 數據包之後,首先根據 RTP 的序列號進行排序,如果有丟包,則通過 FEC 和 ARQ 進行恢復和重傳。得到完整有序的 RTP 包之後,對 RTP 包進行重組,組合成編碼後的音視頻數據。由於網絡傳輸的不穩定性,收到的數據並不是均勻的,有可能一會兒接收的快,一會兒接收的慢,造成數據接收的波動。這種現象被稱為網絡抖動(Jitter)。如果這時候直接進行解碼播放,那麼會導致視頻忽快忽慢,聲音出現變聲的現象。為了平滑這種網絡抖動,接收端需要有一個緩衝隊列,將接收到的音視頻數據放入到緩衝隊列中,然後再勻速的從隊列中取出,從而得到比較平滑的音視頻數據進行播放。

從緩衝隊列取出的數據就可以進行解碼了。解碼就是解壓縮的過程,將發送端壓縮的數據還原成原始的音視頻數據,才能在本地進行播放。一些編碼算法(例如 H.264/H.265/Opus)為了提高壓縮比,在壓縮時對於前後連續的兩幀音視頻數據做了參考,這樣就導致採用這類壓縮算法的編碼數據在解碼的時候存在參考關係的依賴,只有前一個數據被正確解碼,後一個數據才能也正確的解碼。但是由於網絡丟包,即使採用了 FEC 和 ARQ 等丟包恢復策略,仍然有部分音視頻數據無法完整的達到接收端。這時候如果強行解碼,那麼視頻會出現花屏,而聲音會出現爆音。為了解決這個問題,對於不連續的視頻數據,接收端需要向發送端請求編碼一個關鍵幀視頻數據。這個關鍵幀數據在解碼的時候不會參考其他視頻數據幀,同時可以被後續的編碼視頻幀參考,這樣可以解決後續視頻的參考關係問題。而音頻可以通過 PLC(Packet Loss Concealment)算法,根據波形產生出丟失的音頻數據。

這裡可以參考 webrtc 的 neteq 隊列來實現(沒錯,只有 webrtc 開源,所以同學們沒有別的參考),大概需要 3 天

本地播放

最後就是本地播放解碼出的音視頻數據。在播放的時候,音視頻數據在網絡傳輸上並不一定是相同的速度,因此可能會產生音畫不同步的問題。這裡還需要一個音視頻同步模塊,來控制音視頻播放的速度,保證聲音和視頻可以對齊。在對齊的時候,由於人耳對於音頻的快慢變化更加敏感,所以總是調整視頻的速度來對齊音頻。在每個音視頻數據中,都會帶一個時間戳(timestamp),這個時間戳是音頻和視頻數據採集時生成的,相同的時間戳的音視頻應該同時播放才能保證音畫同步。因此在播放視頻幀的時候,需要對比當前播放的音頻的時間戳,調整視頻播放的速度。

視頻在屏幕上播放的時候,其顯示的分辨率大小可能與實際編碼的分辨率大小不一致。視頻分辨率代表的是視頻像素點的個數,分辨率越高越清晰。對於現在的手機和顯示器來說,大多支持 HDPI,通過更加密集的像素點得到更加清晰細膩的圖像。而攝像頭採集和編碼的視頻分辨率並不會特別高,那麼在顯示的時候需要對視頻進行放大。不同的視頻放大算法對於清晰的影響比較大,默認的 linear 放大算法會導致圖像比較模糊,採用複雜的放大算法,比如 bicubic,lanzcos,spline 等,可以得到更加清晰的畫面,而一些特殊內容採用特定的算法會得到更好的視覺效果(比如人臉部分採用 softcubic 可以達到美顏效果)。

這裡不考慮實現效果的話,用最簡單的 opengl 渲染視頻,大概 2 天。

一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

這樣,一個簡簡單單的實時音視頻通信的終端部分就開發完了,再配上一個炫酷拉風的界面,就可以食用了。但是這裡只能實現兩個人之間的通信,而在線授課的場景可是一個老師對一群學生。如何實現多人之間的實時通信呢?這就需要後端的媒體服務器作中轉來實現。

媒體後端

這裡需要簡單介紹一下多人實時音視頻通信的網絡拓撲結構。對於三人以上的實時通信,由於接收端同時會接收多個人傳過來的音視頻數據,因此如果沒有服務器中轉的話,需要採用網狀拓撲結構,每個終端的音視頻流都需要同時發送給其他所有終端,網絡帶寬成倍增加。為了解決這個問題,就需要採用星型拓撲結構,所有的終端將自己的音視頻數據發送給中央服務器,再由服務器來做轉發。這個服務器就是視頻會議的後端,暨媒體服務器。

媒體服務器的實現方式有兩種。一種叫做 MCU 模式,一種叫 SFU 模式。

MCU 模式是服務器將所有人的音視頻數據在服務端進行解碼,然後合成為一個新的音視頻流。這個視頻流是由所有人的視頻組合出來的,而音頻則是將所有人的音頻混合,之後重新進行音視頻編碼,再發送給所有終端。這樣終端播放出來的音視頻流就是一個合併好的音視頻流。這種模式對於媒體服務器的性能消耗很大,因此一臺服務器並不能支持很多的終端。

SFU 模式則只是做 RTP 包的轉發,並不做解碼和合流的工作。每個終端同時會接收到多個人的音視頻流,每一組音視頻流需要獨立進行處理和解碼,然後在本地混合後播放出來。這種模式的 SFU 性能消耗比較低,能夠支持的併發很高。

如果不考慮高併發和架構設計,最簡單的實現大概 3 天。

一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

把這樣一個媒體服務器部署到網絡上,然後由它來轉發所有終端的音視頻數據包,這樣就可以實現多人之間的音視頻通信了。

總共需要 2 周開發時間,一個最最簡單的雷課堂就實現完成了。

當然,這裡只是為了完成作業從功能角度來實現。在實際項目中,需要考慮到性能和架構優化,增強穩定性和音視頻質量,服務端高併發和快速部署,各種算法參數調優和策略優化。沒有幾十人團隊精細打磨 2-3 年,以及專業的音視頻質量測試實驗室,不可能做到業界頂尖水準。

快手與雨課堂

為什麼快手對於雨課堂這麼熟悉?2 月 11 日,這家公司成為了清華大學慕課平臺「學堂在線」的獨家直播技術合作平臺,致力於以直播技術驅動優質教育課程更廣更快傳播。學堂在線旗下的雨課堂現在同時服務國內 500 所高校線上授課,涵蓋國內 90% 的 985 及 211 高校。

在疫情期間,全國大學有超過 100 萬堂課在雨課堂開課,近 4000 萬的大學生都在這裡上課,其中在武漢地區開播 14000 次。快手的直播技術給這些線上的課程提供技術支持,讓老師和學生們在線上開展教學時有良好的音視頻體驗。

一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

快手通過自身在直播平臺長期的技術積累,在推流工具、擁塞控制算法、智能 CDN 分發、質量監控、後端服務基礎架構等全鏈路對雨課堂進行了技術支持,確保了雨課堂大規模同時開課的穩定性和流暢度。


分享到:


相關文章: