摘要:在處于使用了設備的私有網絡中的主機之間需要建立連接時需要使用穿越技術。目前已經有很多穿越技術,但沒有一項是完美的,因為的行為是非標準化的。
什么是WebRTC?
眾所周知,瀏覽器本身不支持相互之間直接建立信道進行通信,都是通過服務器進行中轉。比如現在有兩個客戶端,甲和乙,他們倆想要通信,首先需要甲和服務器、乙和服務器之間建立信道。甲給乙發送消息時,甲先將消息發送到服務器上,服務器對甲的消息進行中轉,發送到乙處,反過來也是一樣。這樣甲與乙之間的一次消息要通過兩段信道,通信的效率同時受制于這兩段信道的帶寬。同時這樣的信道并不適合數據流的傳輸,如何建立瀏覽器之間的點對點傳輸,一直困擾著開發者。WebRTC應運而生
WebRTC是一個開源項目,旨在使得瀏覽器能為實時通信(RTC)提供簡單的JavaScript接口。說的簡單明了一點就是讓瀏覽器提供JS的即時通信接口。這個接口所創立的信道并不是像WebSocket一樣,打通一個瀏覽器與WebSocket服務器之間的通信,而是通過一系列的信令,建立一個瀏覽器與瀏覽器之間(peer-to-peer)的信道,這個信道可以發送任何數據,而不需要經過服務器。并且WebRTC通過實現MediaStream,通過瀏覽器調用設備的攝像頭、話筒,使得瀏覽器之間可以傳遞音頻和視頻
WebRTC已經在我們的瀏覽器中這么好的功能,各大瀏覽器廠商自然不會置之不理。現在WebRTC已經可以在較新版的Chrome、Opera和Firefox中使用了,著名的瀏覽器兼容性查詢網站caniuse上給出了一份詳盡的瀏覽器兼容情況
另外根據36Kr前段時間的新聞Google推出支持WebRTC及Web Audio的Android 版Chrome 29@36kr和Android版Opera開始支持WebRTC,允許用戶在沒有任何插件的情況下實現語音和視頻聊天,Android也開始支持WebRTC
三個接口WebRTC實現了三個API,分別是:
* MediaStream:通過MediaStream的API能夠通過設備的攝像頭及話筒獲得視頻、音頻的同步流
* RTCPeerConnection:RTCPeerConnection是WebRTC用于構建點對點之間穩定、高效的流傳輸的組件
* RTCDataChannel:RTCDataChannel使得瀏覽器之間(點對點)建立一個高吞吐量、低延時的信道,用于傳輸任意數據
這里大致上介紹一下這三個API
MediaStream(getUserMedia)MediaStream API為WebRTC提供了從設備的攝像頭、話筒獲取視頻、音頻流數據的功能
W3C標準W3C標準傳送門
如何調用同門可以通過調用navigator.getUserMedia(),這個方法接受三個參數:
1. 一個約束對象(constraints object),這個后面會多帶帶講
2. 一個調用成功的回調函數,如果調用成功,傳遞給它一個流對象
3. 一個調用失敗的回調函數,如果調用失敗,傳遞給它一個錯誤對象
由于瀏覽器實現不同,他們經常會在實現標準版本之前,在方法前面加上前綴,所以一個兼容版本就像這樣
javacriptvar getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);一個超級簡單的例子
這里寫一個超級簡單的例子,用來展現getUserMedia的效果:
htmlGetUserMedia實例
將這段內容保存在一個HTML文件中,放在服務器上。用較新版本的Opera、Firefox、Chrome打開,在瀏覽器彈出詢問是否允許訪問攝像頭和話筒,選同意,瀏覽器上就會出現攝像頭所拍攝到的畫面了
注意,HTML文件要放在服務器上,否則會得到一個NavigatorUserMediaError的錯誤,顯示PermissionDeniedError,最簡單方法就是cd到HTML文件所在目錄下,然后python -m SimpleHTTPServer(裝了python的話),然后在瀏覽器中輸入http://localhost:8000/{文件名稱}.html
這里使用getUserMedia獲得流之后,需要將其輸出,一般是綁定到video標簽上輸出,需要使用window.URL.createObjectURL(localMediaStream)來創造能在video中使用src屬性播放的Blob URL,注意在video上加入autoplay屬性,否則只能捕獲到一張圖片
流創建完畢后可以通過label屬性來獲得其唯一的標識,還可以通過getAudioTracks()和getVideoTracks()方法來獲得流的追蹤對象數組(如果沒有開啟某種流,它的追蹤對象數組將是一個空數組)
約束對象(Constraints)約束對象可以被設置在getUserMedia()和RTCPeerConnection的addStream方法中,這個約束對象是WebRTC用來指定接受什么樣的流的,其中可以定義如下屬性:
* video: 是否接受視頻流
* audio:是否接受音頻流
* MinWidth: 視頻流的最小寬度
* MaxWidth:視頻流的最大寬度
* MinHeight:視頻流的最小高度
* MaxHiehgt:視頻流的最大高度
* MinAspectRatio:視頻流的最小寬高比
* MaxAspectRatio:視頻流的最大寬高比
* MinFramerate:視頻流的最小幀速率
* MaxFramerate:視頻流的最大幀速率
詳情見Resolution Constraints in Web Real Time Communications draft-alvestrand-constraints-resolution-00
RTCPeerConnectionWebRTC使用RTCPeerConnection來在瀏覽器之間傳遞流數據,這個流數據通道是點對點的,不需要經過服務器進行中轉。但是這并不意味著我們能拋棄服務器,我們仍然需要它來為我們傳遞信令(signaling)來建立這個信道。WebRTC沒有定義用于建立信道的信令的協議:信令并不是RTCPeerConnection API的一部分
信令既然沒有定義具體的信令的協議,我們就可以選擇任意方式(AJAX、WebSocket),采用任意的協議(SIP、XMPP)來傳遞信令,建立信道,比如我寫的demo,就是用的node的ws模塊,在WebSocket上傳遞信令
需要信令來交換的信息有三種:
* session的信息:用來初始化通信還有報錯
* 網絡配置:比如IP地址和端口啥的
* 媒體適配:發送方和接收方的瀏覽器能夠接受什么樣的編碼器和分辨率
這些信息的交換應該在點對點的流傳輸之前就全部完成,一個大致的架構圖如下:
通過服務器建立信道這里再次重申,就算WebRTC提供瀏覽器之間的點對點信道進行數據傳輸,但是建立這個信道,必須有服務器的參與。WebRTC需要服務器對其進行四方面的功能支持:
1. 用戶發現以及通信
2. 信令傳輸
3. NAT/防火墻穿越
4. 如果點對點通信建立失敗,可以作為中轉服務器
建立點對點信道的一個常見問題,就是NAT穿越技術。在處于使用了NAT設備的私有TCP/IP網絡中的主機之間需要建立連接時需要使用NAT穿越技術。以往在VoIP領域經常會遇到這個問題。目前已經有很多NAT穿越技術,但沒有一項是完美的,因為NAT的行為是非標準化的。這些技術中大多使用了一個公共服務器,這個服務使用了一個從全球任何地方都能訪問得到的IP地址。在RTCPeeConnection中,使用ICE框架來保證RTCPeerConnection能實現NAT穿越
ICE,全名叫交互式連接建立(Interactive Connectivity Establishment),一種綜合性的NAT穿越技術,它是一種框架,可以整合各種NAT穿越技術如STUN、TURN(Traversal Using Relay NAT 中繼NAT實現的穿透)。ICE會先使用STUN,嘗試建立一個基于UDP的連接,如果失敗了,就會去TCP(先嘗試HTTP,然后嘗試HTTPS),如果依舊失敗ICE就會使用一個中繼的TURN服務器。
我們可以使用Google的STUN服務器:stun:stun.l.google.com:19302,于是乎,一個整合了ICE框架的架構應該長這個樣子
瀏覽器兼容還是前綴不同的問題,采用和上面類似的方法:
javascriptvar PeerConnection = (window.PeerConnection || window.webkitPeerConnection00 || window.webkitRTCPeerConnection || window.mozRTCPeerConnection);創建和使用
javascript//使用Google的stun服務器 var iceServer = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] }; //兼容瀏覽器的getUserMedia寫法 var getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); //兼容瀏覽器的PeerConnection寫法 var PeerConnection = (window.PeerConnection || window.webkitPeerConnection00 || window.webkitRTCPeerConnection || window.mozRTCPeerConnection); //與后臺服務器的WebSocket連接 var socket = __createWebSocketChannel(); //創建PeerConnection實例 var pc = new PeerConnection(iceServer); //發送ICE候選到其他客戶端 pc.onicecandidate = function(event){ socket.send(JSON.stringify({ "event": "__ice_candidate", "data": { "candidate": event.candidate } })); }; //如果檢測到媒體流連接到本地,將其綁定到一個video標簽上輸出 pc.onaddstream = function(event){ someVideoElement.src = URL.createObjectURL(event.stream); }; //獲取本地的媒體流,并綁定到一個video標簽上輸出,并且發送這個媒體流給其他客戶端 getUserMedia.call(navigator, { "audio": true, "video": true }, function(stream){ //發送offer和answer的函數,發送本地session描述 var sendOfferFn = function(desc){ pc.setLocalDescription(desc); socket.send(JSON.stringify({ "event": "__offer", "data": { "sdp": desc } })); }, sendAnswerFn = function(desc){ pc.setLocalDescription(desc); socket.send(JSON.stringify({ "event": "__answer", "data": { "sdp": desc } })); }; //綁定本地媒體流到video標簽用于輸出 myselfVideoElement.src = URL.createObjectURL(stream); //向PeerConnection中加入需要發送的流 pc.addStream(stream); //如果是發送方則發送一個offer信令,否則發送一個answer信令 if(isCaller){ pc.createOffer(sendOfferFn); } else { pc.createAnswer(sendAnswerFn); } }, function(error){ //處理媒體流創建失敗錯誤 }); //處理到來的信令 socket.onmessage = function(event){ var json = JSON.parse(event.data); //如果是一個ICE的候選,則將其加入到PeerConnection中,否則設定對方的session描述為傳遞過來的描述 if( json.event === "__ice_candidate" ){ pc.addIceCandidate(new RTCIceCandidate(json.data.candidate)); } else { pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp)); } };實例
由于涉及較為復雜靈活的信令傳輸,故這里不做簡短的實例,可以直接移步到最后
RTCDataChannel既然能建立點對點的信道來傳遞實時的視頻、音頻數據流,為什么不能用這個信道傳一點其他數據呢?RTCDataChannel API就是用來干這個的,基于它我們可以在瀏覽器之間傳輸任意數據。DataChannel是建立在PeerConnection上的,不能多帶帶使用
使用DataChannel我們可以使用channel = pc.createDataCHannel("someLabel");來在PeerConnection的實例上創建Data Channel,并給與它一個標簽
DataChannel使用方式幾乎和WebSocket一樣,有幾個事件:
* onopen
* onclose
* onmessage
* onerror
同時它有幾個狀態,可以通過readyState獲取:
* connecting: 瀏覽器之間正在試圖建立channel
* open:建立成功,可以使用send方法發送數據了
* closing:瀏覽器正在關閉channel
* closed:channel已經被關閉了
兩個暴露的方法:
* close(): 用于關閉channel
* send():用于通過channel向對方發送數據
JavaScript已經提供了File API從input[type="file"]的元素中提取文件,并通過FileReader來將文件的轉換成DataURL,這也意味著我們可以將DataURL分成多個碎片來通過Channel來進行文件傳輸
一個綜合的DemoSkyRTC-demo,這是我寫的一個Demo。建立一個視頻聊天室,并能夠廣播文件,當然也支持單對單文件傳輸,寫得還很粗糙,后期會繼續完善
使用方式下載解壓并cd到目錄下
運行npm install安裝依賴的庫(express, ws, node-uuid)
運行node server.js,訪問localhost:3000,允許攝像頭訪問
打開另一臺電腦,在瀏覽器(Chrome和Opera,還未兼容Firefox)打開{server所在IP}:3000,允許攝像頭和話筒訪問
廣播文件:在左下角選定一個文件,點擊“發送文件”按鈕
廣播信息:左下角input框輸入信息,點擊發送
可能會出錯,注意F12對話框,一般F5能解決
功能視頻音頻聊天(連接了攝像頭和話筒,至少要有攝像頭),廣播文件(可多帶帶傳播,提供API,廣播就是基于多帶帶傳播實現的,可同時傳播多個,小文件還好說,大文件坐等內存吃光),廣播聊天信息
參考資料WebRTC官方網站
W3C-GetUserMedia
W3C-WebRTC
Capturing Audio & Video in HTML5@html5rocks
Getting Started with WebRTC@html5rocks
caniuse
ICE交互式連接建立
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87486.html
摘要:如果對和不太了解的同學,可以先閱讀如下文章的使用搭建前端視頻聊天室信令篇使用搭建前端視頻聊天室入門篇老劉和老姚當然服務器完全不參與其中,顯然是不可能的,用戶需要通過服務器上存儲的信息,才能確定需要和誰建立連接。 WebRTC給我們帶來了瀏覽器中的視頻、音頻聊天體驗。但個人認為,它最實用的特性莫過于DataChannel——在瀏覽器之間建立一個點對點的數據通道。在DataChannel之...
摘要:使用能使得狀態被保存在服務器上會話描述協議將客戶端之間傳遞的信令分為兩種信令和信令。他們主要內容的格式都遵循會話描述協議,簡稱。 博客原文地址 建議看這篇之前先看一下使用WebRTC搭建前端視頻聊天室——入門篇 如果需要搭建實例的話可以參照SkyRTC-demo:github地址 其中使用了兩個庫:SkyRTC(github地址)和SkyRTC-client(github地址) ...
摘要:官方資料官網儲備知識工具,推薦資料,使用方法,使用方法或基礎,推薦資料如下,官方資料項目沒用到,借鑒了的強類型,通過進行驗證核心,強烈推薦,推薦資料和需要多理解,項目的核心思想,推薦資料的使用搭建前端視頻聊天室信令篇使用搭建前端視頻聊天室入 官方資料 官網git 儲備知識 工具 Webpack,推薦資料webpack Babel,使用方法babel Flow,使用方法flow ...
摘要:最后,消息成功抵達并顯示在頁面上。在中,所有的數據都使用數據報傳輸層安全性。如果應用知識簡單的一對一文件傳輸,使用不可靠的數據通道將需要設計一定的響應重傳協議。目前建議的最大塊大小為。 本文翻譯自WebRTC data channels 在兩個瀏覽器中,為聊天、游戲、或是文件傳輸等需求發送信息是十分復雜的。通常情況下,我們需要建立一臺服務器來轉發數據,當然規模比較大的情況下,會擴展成...
摘要:前言本項目旨在從零到壹,制作一款界面精美的聊天軟件。因為本人是開發,設計功底欠缺,所以軟件設計的有點丑,如果有大神有更好的,歡迎。 Hola 前言 本項目旨在從零到壹,制作一款界面精美的聊天軟件。 Github 地址因為已工作,所以可能沒有多少時間來繼續跟進這個項目了,項目可優化的點已在下文列出,歡迎大家 Fork 或 Star。 ps: 征 logo 一枚。因為本人是開發,設計功底...
閱讀 2132·2023-04-26 03:06
閱讀 3580·2023-04-26 01:51
閱讀 2085·2021-11-24 09:38
閱讀 2452·2021-11-17 17:00
閱讀 2324·2021-09-28 09:36
閱讀 941·2021-09-24 09:47
閱讀 2586·2019-08-30 15:54
閱讀 1554·2019-08-30 15:44