基於 Web 引擎擴充套件技術的 RTC 混合開發框架實踐

白玉蘭開源發表於2021-06-28

為什麼我們要獨立開發WEBRTC框架

在這裡插入圖片描述

  1. 現在市面上缺失好的基於WEBRTC的框架,我們希望做的框架能夠充分利用原生平臺的自由擴充能力、安全性、以及WEB的一些優良開發特性及生態等等。像傳統原生的音影片應用,一般在針對特定平臺系統的客戶端,都會做特殊的技術最佳化,比如window平臺會使用MFC或WCF等技術,能做到16/32/64路影片的高畫質解碼等等。像一些內容分發型應用,就需要突出內容更新及佈局擴充能力,比如我們經常使用的桌面版微信,就是利用了前面提到的特性,除了內容渲染,為了保證傳輸的安全性,在實現方面將網路通訊部分放在了原生平臺去做。

  2. 未來Web應用是什麼樣的呢?2007年穀歌CEO的對web3.0下定義的時候,他提到,希望未來的應用非常小,可以快速訪問,並且能夠支援跨平臺。今天,就像我們現在經常使用的微信、支付寶裡面的小程式,華為的快應用等,我們透過掃二維碼或者點選連結的方式,就直接可以跳轉到目標平臺的應用,這就是一些WEB應用的優勢,我們前端要發揚這些長處!

基於WebRTC的Web應用面臨的問題

在這裡插入圖片描述

目前,針對WebRTC來說,最大的問題就是使用體驗不理想,經常卡頓,主要問題我們可以簡單從下面三點分析:

  1. Web平臺碎片化嚴重。WebRTC官方正式標準一直到最近兩年才被確定下來,而且標準的迭代非常迅速,比如國外的chrome、Firefox,國內的360瀏覽器、QQ瀏覽器等等,都有基於自己想法上的可選性實現。

  2. WebRTC實現細節不可控。對於很多Web的開發者而言,我們往往比較關注的是Media、Vedio這些HTML5標籤本身,但比如我要想控制裡面的一些網路傳輸FEC、弱網對抗、頻寬估計、優先順序保障等演算法、使用特殊的編碼解碼,依賴純Web是做不到的,這不是瀏覽器的使命,如果想要做這種更底層的控制,就只能要想其他辦法參與到裡面去。

  3. 計算密集型演算法可選項少。我們很多時候需要對影片進行一些預處理的動作,比如美顏功能,現在通用的做法是首先需要獲取到使用者本地的一些原始的影片採集資料,然後繪製到canvas上,透過canvas介面獲取到imagedata,將imagedata傳遞到Web Assembly,然後再對它進行進一步的演算法運算,比如磨皮、提亮等等這些操作,然後重新繪製到canvas裡面,這個過程鏈路本身比較長。還有一點就是Web Assembly技術本身,也是一直在不停發展,他本身有自己的限制,比如Web Assembly的實現是基於chrome本身的一個render主執行緒驅動。雖然後續出現了Web worker的工作執行緒實現以及平行計算等,但是執行效能也不是特別好,如果我們希望能夠充分利用的計算資源,在這種情況下就很難實現。

另外,對於GPU部分,WebGl實現的細節上是有側重點的,因為瀏覽器WEB本身是要面向整個標籤頁的渲染,而不僅是影片視窗這一小塊,所以相比專業的影片渲染效能方面的表現並不太好。

聲網的一些實踐解決思路分享

在這裡插入圖片描述

  1. 統一渲染引擎。針對Web平臺碎片化問題,我們提供了一致的渲染引擎,讓使用者使用一個統一的執行渲染環境,以此來解決廠商、版本等差異引入的碎片化問題。

  2. 對於WebRTC的實現細節、演算法這一塊,屬於應用可擴充套件部分,我們會盡量想辦法,將這些能力封裝到原生平臺內部去實現。

PC端應用的框架選型

在這裡插入圖片描述

在最開始我們做技術評估的時候,可選框架有幾大類,Electron、CEF、Qt等等,但很多的開發框架,像CEF和Qt基礎技術棧比較偏向C、C++、Java等等,開發習慣和生態上和我們前端開發體驗不一致,尤其是它的開發工具鏈是需要獨立構建,所以最終我們選擇了Electorn,它是基於Nodejs的一個技術方案,前端在開發的時候,我們可以使用熟悉的開發環境,比如說Npm、yarn,還有包括後續的測試打包等整個構建過程。

擴充套件能力混合注入時的一些問題

在這裡插入圖片描述

  1. 原生擴充套件能力問題
    對於原生擴充套件能力的注入,我們將一些關鍵的業務邏輯的實現,透過用C++程式碼放到V8引擎裡與原生能力結合起來的,後續透過bridge,將能力暴露給上層。這裡最大的問題在於每一個V8引擎版本,底層C++的介面並不一致,並且,隨著nodejs版本的升級,每個版本里面的介面實現也略微不同的,這也是長期以來讓社群比較詬病問題。這裡我們的解決方案是,採用nodejs提供的node api實現,它是向後相容的,以此來保持底層介面一致性,解決開發外掛介面和node版本依賴的問題。

當我們的js層呼叫透過bridge注入到native後,驅動我們另外一個團隊開發的native SDK,包含了聲網主要的功能和演算法,比如我們的RTN網路接入、AI降噪演算法、背景分割、超分演算法等等。另外從前端開發體驗上,使用者只需要改動少量的程式碼,就可以完成基於agora sdk ng開發的自有APP的適配,這也是我們框架的初衷之一,保持外部開發使用者的體驗的基礎上,能夠提升它裡面的應用能力。

在這裡插入圖片描述

  1. 非同步事件驅動
    音影片應用的特點就是它的資料體積比較大,每一幀資料根據使用者影片解析度的不同,從幾K到幾十M都有可能,同時,我們還必須對這些資料進行解碼、編碼等等操作,這就要求我們能夠去充分使用使用者本地的計算能力,這裡就涉及到子執行緒相關的排程操作,透過非同步事件驅動,我們可以設計非同步事件的佇列管理,原生平臺生產、主執行緒消費的模式。另外因為單個資料體積比較大,如果渲染執行緒和非同步執行緒資料互動透過copy進行互動,記憶體開銷可想而知,這裡就必須使用到一些node api提供的external-ArrayBuffer技術,類似智慧指標引用的解決方案,我們只需要保證Buffer的生命週期即可,即在js層呼叫期間可用,指標銷燬時同時銷燬buffer,避免記憶體洩漏。

在這裡插入圖片描述

  1. 動態解析度問題
    受限於網路風暴等等問題,我們使用者很多時候解析度很難保持1080P不變,這個時候我們就需要一些平衡演算法,在幀率和解析度之間做平衡,這種情況下,影片寬窄就有可能發生變化,那我們就需要針對這種情況做一些特殊處理,canvas是可以透過更新texture的方式,適配影片資料幀的寬高、步長等,然後透過CSS樣式控制整體頁面渲染比例及佈局即可,不需要再做重取樣來保證寬高比,這個做法也是和傳統原生影片應用渲染方面有明顯差異的地方。

音訊播放

在這裡插入圖片描述

本地音訊採集完一般不需要本地回放,但在一些業務場景下,我們的使用者希望能夠根據自己的聲音反饋做一些特殊處理,比如使用者會希望可以透過直觀的聽到自己的音量來調整麥克風的相對位置等等。而且這也算是我們為了能夠保證與agora sdk ng這一致性功能。由於瀏覽器音訊播放是非同步執行的,即主執行緒將音訊資料轉發給音訊執行緒,音訊執行緒播放結束後通知主執行緒,主執行緒再處理下一個音訊資料段,這個過程本身是會有始終消耗的,所以在實時音訊播放場景中的直觀體驗就是,隨著時間增長,時延累加明顯,並且資料播放間隔出現有明顯噪音。

我們的解決方案比較簡單直接,採用audio workletprocessor介面,由我們來控制音訊傳遞給音訊播放執行緒的頻率,流式傳遞音訊資料到非同步執行緒,這樣就避免執行緒間反饋造成的時延累加,聽起來會很順滑,加上每次資料段比較短,約10ms左右,使用者聽起來就感覺自己的聲音變大了,沒有明顯的迴音感。

未來展望

在這裡插入圖片描述

未來我們希望能夠把更多聲網nativeSDK能力暴露到上層應用中,比如我們的桌面共享、AI降噪、美聲、vp9編碼解碼、背景分割、美顏、超分等等,我們聲網內部已經進入到測試環節,後續也希望能夠賦能給我們的使用者更加方便、強大的Web應用開發能力。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70001588/viewspace-2778572/,如需轉載,請註明出處,否則將追究法律責任。

相關文章