webRTC實戰總結

前言

前段時間一直在忙一個基于WebRTC的PC和移動端雙向視頻的項目。第一次接觸webRTC,難免遇到了許多問題,比如:webRTC移動端兼容性檢測,如何配置MediaStreamConstraints, 信令(iceCandidate, sessionDescription)傳輸方式的選擇,iceCandidate和sessionDescription設置的先后順序,STUN和TURN的概念,如何實現截圖及錄制視頻及上傳圖片和視頻功能,如何高效跟蹤錯誤等等。好記性不如爛筆頭,特寫此文以記之。

移動端兼容性

對PC端來說,webRTC早已被各大瀏覽器支持了,Chrome 28,FF22,Edge…隨著不久之前發布的IOS11也宣布支持webRTC及getUserMedia,webRTC在移動端的應用前景也令人憧憬。

具體到實際項目中,經過測試,各大國產安卓手機自帶的瀏覽器基本不支持webRTC,但這些安卓手機的微信內置瀏覽器均能良好地支持webRTC,雖然Chrome及Firefox的移動端版本也能良好的支持webRTC,但國情決定了微信內置瀏覽器作為最佳切入點。另一方面。IOS11中微信內置瀏覽器還不支持webRTC(我堅信不久的將來就會支持),但在Safari中能夠完美支持。因此本項目選擇了微信公眾號為切入點,通過檢測userAgent引導IOS11用戶在Safari中打開頁面。

檢測webRTC的可行性,主要從getUserMedia和webRTC本身來入手:

function detectWebRTC() { const WEBRTC_CONSTANTS = ['RTCPeerConnection', 'webkitRTCPeerConnection', 'mozRTCPeerConnection', 'RTCIceGatherer']; const isWebRTCSupported = WEBRTC_CONSTANTS.find((item) => { return item in window; }); const isGetUserMediaSupported = navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia; if (!isWebRTCSupported || typeof isGetUserMediaSupported === 'undefined' ) { return false; } return true; }

如果返回false,再去檢測userAgent給予用戶不支持的具體提示。

配置MediaStreamConstraints

所謂MediaStreamConstraints,就是navigator.mediaDevices.getUserMedia(constraints)傳入的constraints,至于它的寫法及功能,參考MDN,本文不做贅述。我在這里想要強調的是,對于移動端來說控制好視頻圖像的大小是很重要的,例如本項目中想要對方的圖像占據全屏,這不僅是改變video元素的樣式或者屬性能做到的,首先要做的是改變MediaStreamConstraints中的視頻分辨率(width, height),使其長寬比例大致與移動端屏幕的類似,然后再將video元素的長和寬設置為容器的長和寬(例如100%)。

另外對于getUserMedia一定要捕獲可能出現的錯誤,如果是老的API,設置onErr回調,如果是新的(navigator.mediaDevices.getUserMedia),則catch異常。這樣做的原因:getUserMedia往往不會完全符合我們的預期,有時即使設置的是ideal的約束,仍然會報錯,如果不追蹤錯誤,往往一臉懵逼。這也是后文要提到的高效追蹤錯誤的方法之一。

搭建信令傳輸服務

要傳輸的信令包括兩個部分:sessionDescription和iceCandidate。為了便于傳輸可將其處理成字符串,另一端接收時還原并用對應的構造函數構造對應的實例即可。

webRTC并沒有規定信令的傳輸方式,而是完全由開發者自定義。常見的方式有短輪詢、webSocket(socket.io等),短輪詢的優點無非是簡單,兼容性強,但在并發量較大時,服務器負荷會很重。而webSocket就不存在這個問題,但webSocket搭建起來較為復雜,并不是所有的瀏覽器都支持websocket。綜合來說socket.io是個不錯的解決方案,事件機制和自帶的房間概念對撮合視頻會話都是天然有利的,并且當瀏覽器不支持websocket時可以切換為輪詢,也解決了兼容性的問題。

發起視頻會話的流程

可以看到無論是發起方還是接受方,第一步都是getUserMedia獲取本地媒體流,然后新建一個RTCPeerConnection實例,并指定好onicecandidate、onaddstream等回調:

// 指定TURN及STUN
const peerConnectionConfig = { 'iceServers': [ { 'urls': 'turn:numb.viagenie.ca', 'username': 'muazkh', 'credential': 'webrtc@live.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ], bundlePolicy: 'max-bundle', }; const pc = new RTCPeerConnection(peerConnectionConfig); pc.onicecandidate = ...; pc.onaddstream = ...;

然后addTrack指定要傳輸的視頻流

stream.getTracks().forEach((track) => { pc.addTrack(track, stream); });

發起方通過createOffer生成localDescription并傳給pc.setLocalDescription(),pc獲取了本地的sdp后開始獲取candidate,這里的candidate指的是網絡信息(ip、端口、協議),根據優先級從高到低分為三類:

  • host: 設備的ipv4或ipv6地址,即內網地址,一般會有兩個,分別對應udp和tcp,ip相同,端口不同;
  • srflx(server reflexive): STUN返回的外網地址;
  • relay: 當STUN不適用時(某些NAT會為每個連接分配不同的端口,導致獲取的端口和視頻連接端口并不一致),中繼服務器的地址;

三者之中只需要有一類連接成功即可,所以如果通信雙方在同一內網,不配置STUN和TURN也可以直接連接。其實這里隱藏著性能優化的點:如上圖所示,webRTC通信雙方在交換candidate時,首先由發起方先收集所有的candidate,然后在icegatheringstatechange事件中檢測iceGatheringState是否為’complete’,再發送給接收方。接收方設置了發送方傳來的sdp和candidate后,同樣要收集完自己所有的candidate,再發送給對方。如果這些candidate中有一對可以連接成功,則P2P通信建立,否則連接失敗。

問題來了,接受端要等待發起方收集完所有的candidate之后才開始收集自己的candidate,這其實是可以同時進行的;另外其實不一定需要所有的candidate才能建立連接,這也是可以省下時間的;最后如果網絡,STUN或者TURN出現問題,在上述傳輸模式下是非常致命的,會讓連接的時間變得很長不可接受。

解決方案就是IETF提出的Trickle ICE。即發起方每獲取一個candidate便立即發送給接收方,這樣做的好處在于第一類candidate即host,會立即發送給接收方,這樣接收方收到后可以立刻開始收集candidate,也就是發起方和接收方同時進行收集candidate的工作。另外,接收方每收到一個candidate會立即去檢查它的有效性,如果有效直接接通視頻,如果無效也不至于浪費時間。詳情可以參見ICE always tastes better when it trickles.

至于sessionDescription及iceCandidate的傳輸,因為JavaScript沒有處理sdp格式數據的方法,所以直接將其當做字符串處理,這樣做的壞處是難以改變sdp中的信息(如果非要改,通過正則匹配還是能改的)。

在掛斷視頻時,不僅要關閉peerConnection,也要停止本地及遠程的媒體流:


const tracks = localStream.getTracks().concat(remoteStream.getTracks()); tracks.forEach((track) => { track.stop(); }); peerConnection.close();

截圖&錄制視頻

截圖其實并不算什么新鮮的東西,無非是利用canvas的drawImage函數獲取video元素在某一幀的圖像,得到的是圖片的base64格式字符串,但要注意的是這樣得到的base64碼之前有這樣一串文本:

data:image/png;base64,

這是對數據協議,格式,編碼方式的聲明,是給瀏覽器看的。所以在將drawImage得到的字符串上傳給服務器時,最好將這串文本去掉,防止后端在轉換圖片時出現錯誤。

錄制視頻使用的是MediaRecorder API 詳情參考MDN MediaRecorder,目前僅支持錄制webm格式的視頻。可以在新建MediaRecorder實例的時候,設置mimeType、videoBitsPerSecond、audioBitsPerSecond:

const options = { mimeType: 'video/webm;codecs=vp8', // 視頻格式及編碼格式 videoBitsPerSecond: 2500000, // 視頻比特率,影響文件大小和質量  audioBitsPerSecond: 128000 // 音頻比特率,影響文件大小和質量 }; const recorder = new MediaRecorder(options);

在recorder的ondataavailable事件中拿到數據,將其轉換為Blob對象,再通過Formdata異步上傳至服務器。

錯誤追蹤

整個雙向視頻涉及到的步驟較多,做好錯誤追蹤是非常重要的。像getUserMedia時,一定要catch可能出現的異常。因為不同的設備,不同的瀏覽器或者說不同的用戶往往不能完全滿足我們設置的constraints。還有在實例化RTCPeerConnection時,往往會出現不可預期的錯誤,常見的有STUN、TURN格式不對,還有createOffer時傳遞的offerOptions格式不對,正確的應該為:

const offerOptions = { 'offerToReceiveAudio': true, 'offerToReceiveVideo': true };

CAVEAT

因為webRTC標準還在不斷地更新中,所以相關的API經常會有改動。

  • navigator.getUserMeida(已廢棄),現在改為navigator.mediaDevices.getUserMedia;
  • RTCPeerConnection.addStream被RTCPeerConnection.addTrack取代;
  • STUN,TURN配置里的url現被urls取代;

另外,對video元素也要特殊處理。設置autoPlay屬性,對播放本地視頻源的video還要設置muted屬性以去除回音。針對IOS播放視頻自動全屏的特性,還要設置playsinline屬性的值為true。

轉載于:https://www.cnblogs.com/liuhao-web/p/8706528.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/453070.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/453070.shtml
英文地址,請注明出處:http://en.pswp.cn/news/453070.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

程序員眼中的2007:尋找軟件開發利器

軟件開發生命周期包括需求分析、設計、開發、測試、交付部署等各個階段,以及貫穿在整個開發過程的軟件開發項目管理環節,2006年,在每一個階段都出現了令人眼花繚亂的技術與應用,同時這些技術還將進一步影響2007年的發展&#xff0…

谷歌虛擬服務器申請,【美國podserver.info】免費300M虛擬主機空間申請使用教程

【美國podserver.info】注冊使用教程:1、打開申請地址,點擊下圖位置中的“Sign Up”開始注冊。2、點擊“Sign Up”開始注冊后,進入到注冊檢查頁面,我們按下圖選擇“I’m a human.”然后點擊“Submit”進入到注冊信息填寫頁面。3、…

物理層協議有哪四大特性

1.機械特性 指明接口所用接線器的形狀和尺寸、引線數目和排列、固定和鎖定裝置等等。2.電氣特性 指明在接口電纜的各條線上出現的電壓的范圍。3.功能特性 指明某條線上出現的某一電平的電壓表示何種意義。4.過程特性 指明對于不同功能的各種可能事件的出現順序。

phpstudy中的mysql

1.進入mysql命令臺,執行 select version()即可 2status;

度量相似性數學建模_一種基于粒子群位置更新思想灰狼優化算法的K-Means文本分類方法與流程...

技術特征:1.一種基于粒子群位置更新思想灰狼優化算法的k-means文本分類方法,其特征在于:包括以下步驟:s1:對文本數據進行預處理,得到預處理后文本數據;s2:采用余弦角度為相似性度量,…

Overload重載和Override重寫的區別。Overloaded的方法是否可以改變返回值的類型?

Overload是重載的意思,Override是覆蓋的意思,也就是重寫。 重載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不同)。 重寫Override表示子類中的方法可以與父類中的…

web服務器文件管理,web文件管理服務器

web文件管理服務器 內容精選換一換該任務指導用戶在SSL證書管理平臺下載證書。證書狀態為已簽發或托管中。僅支持在證書有效期內,不限次數的下載證書,下載后即可在服務器(華為云的或非華為云的均可)上進行部署。證書請求文件選擇的是系統生成CSR&#xf…

簡單計算器 (關于棧的一種應用)

題目:簡單計算器讀入一個只包含 , -, *, / 的非負整數計算表達式,計算該表達式的值。Input測試輸入包含若干測試用例,每個測試用例占一行,每行不超過200個字符,整數和運算符之間用一個空格分隔。沒有非法表達式。當一行…

python中模運算_Python中的模運算

所謂取模運算&#xff0c;就是計算兩個數相除之后的余數&#xff0c;符號是%。如a % b就是計算a除以b的余數。用數學語言來描述&#xff0c;就是如果存在整數n和m&#xff0c;其中0 < m < b&#xff0c;使得$ a n * b m $&#xff0c;那么$ a \% b a - n * b m $。先…

偉大公司為什么需要技術型領導?

Facebook前工程總監黃易山撰寫了一系列文章&#xff0c;很好地總結了Facebook卓越研發文化中的寶貴經驗。本文是這一系列文章的第五篇&#xff0c;也是最后一篇。 何謂技術型領導 所有從外部聘用的管理人員包括技術部門負責人&#xff0c;都必須能夠編寫代碼&#xff0c;并且…

css樣式變 及實際用法

<html xmlns"http://www.w3.org/1999/xhtml"><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title>引入外部樣式</title><link rel" stylesheet" href"home.css&…

服務器部署的參數文檔,服務器參數配置

服務器參數配置 內容精選換一換源端服務器遷移至華為云后&#xff0c;最終將遷移到彈性云服務器上。因此在遷移前&#xff0c;您需要在華為云中創建一個或多個彈性云服務器。進入“彈性云服務器”頁面。關于參數的詳細信息&#xff0c;請參見購買彈性云服務器。Windows系統的目…

擴散法及其改進

擴散法是一種靜態路由算法,每一個輸入的分組都被從除輸入線路之外的所有其它線路上轉發出去.擴散法顯然會產生大量的分組副本,因此必須有一些辦法來抑制無限的轉發.1.一種辦法是在分組頭中攜帶一個跳數計數器,分組每到一個節點其跳數計數器就減1,當計數器為0時分組被丟棄.計數器…

h5頁 點擊返回時關閉_在微信、支付寶、百度錢包實現點擊返回按鈕關閉當前頁面和窗口...

最近在使用微信、支付寶、百度錢包實現網頁支付&#xff0c;對支付成功將自動關閉頁面&#xff0c;對于支付失敗&#xff0c;將顯示錯誤信息。當在錯誤頁面的時候&#xff0c;點擊返回或者Android物理按鍵上一步的時候&#xff0c;將關閉頁面。在微信、支付寶、百度錢包中&…

串操作指令

串操作指令可以方便對一組連續的數據進行操作。串操作后自動根據DF標志位修改ESI和EDI&#xff0c;DF 0時&#xff0c;ESI&#xff0c;EDI遞增&#xff0c;DF 1時&#xff0c;ESI&#xff0c;EDI遞減。串操作指令有2組&#xff0c;1組實現數據串傳送&#xff0c;另1組實現數據…

IS-IS基本配置

實驗內容&#xff1a;現在網絡中有4臺路由器&#xff0c;用戶希望利用這4臺路由器通過IS-IS協議實現網絡互聯&#xff0c;并且因為R1和R2性能相對較低&#xff0c;所以還要使這兩臺路由器處理的數據信息相對較少。 網絡拓撲&#xff1a; 實驗分析&#xff1a; 根據題意可知R1和…

高并發高流量網站架構

Web2.0的興起&#xff0c;掀起了互聯網新一輪的網絡創業大潮。以用戶為導向的新網站建設概念&#xff0c;細分了網站功能和用戶群&#xff0c;不僅成功的造就了一大批新生的網站&#xff0c;也極大的方便了上網的人們。但Web2.0以用戶為導向的理念&#xff0c;使得新生的網站有…

多處理機的進程調度方式

一.自調度方式 二.成組調度方式 三.專用處理機分配方式

枚舉類型用法_Mybatis-plus常見用法總結三

前面已經介紹了Mybatis-plus基本用法&#xff0c;今天為大家分享一些Mybatis-plus高級應用邏輯刪除自動注入枚舉類型處理Sql注入器多租戶表結構CREATE TABLE sys_role ( id varchar(64) NOT NULL COMMENT 主鍵, code varchar(64) NOT NULL DEFAULT COMMENT 角色編碼, name …