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