清華大作業指導:一人單刷雨課堂需要多少工作量?快手工程師詳解如何兩週搞定

機器之心發表於2020-04-23

昨天,清華自動化大一學生的 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 分發、質量監控、後端服務基礎架構等全鏈路對雨課堂進行了技術支援,確保了雨課堂大規模同時開課的穩定性和流暢度。

相關文章