//使用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向對方發送數據
經過Data Channel發送文件大體思路
JavaScript已經提供了File API從input[type='file']
的元素中提取文件,並經過FileReader來將文件的轉換成DataURL,這也意味着咱們能夠將DataURL分紅多個碎片來經過Channel來進行文件傳輸
一個綜合的Demo
SkyRTC-demo,這是我寫的一個Demo。創建一個視頻聊天室,並可以廣播文件,固然也支持單對單文件傳輸,寫得還很粗糙,後期會繼續完善
使用方式
- 下載解壓並cd到目錄下
- 運行
npm install
安裝依賴的庫(express, ws, node-uuid) - 運行
node server.js
,訪問localhost:3000
,容許攝像頭訪問 - 打開另外一臺電腦,在瀏覽器(Chrome和Opera,還未兼容Firefox)打開
{server所在IP}:3000
,容許攝像頭和話筒訪問 - 廣播文件:在左下角選定一個文件,點擊「發送文件」按鈕
- 廣播信息:左下角input框輸入信息,點擊發送
- 可能會出錯,注意F12對話框,通常F5能解決
功能
視頻音頻聊天(鏈接了攝像頭和話筒,至少要有攝像頭),廣播文件(可單獨傳播,提供API,廣播就是基於單獨傳播實現的,可同時傳播多個,小文件還好說,大文件坐等內存吃光),廣播聊天信息