在學(xué)習(xí)WebRTC時(shí),網(wǎng)上的示例大多代碼較多,以下是參考那些代碼簡(jiǎn)化的一個(gè)WebRTC一對(duì)一的示例,在chrome 37下測(cè)試通過(guò)。其中iceServer可省略,沒(méi)有iceServer時(shí)在同一個(gè)局域網(wǎng)下仍可通訊。
客戶端代碼:
<html>
<body>
Local: <br>
<video id="localVideo" autoplay></video><br>
Remote: <br>
<video id="remoteVideo" autoplay></video>
<script>
// 僅僅用于控制哪一端的瀏覽器發(fā)起offer,#號(hào)后面有值的一方發(fā)起
var isCaller = window.location.href.split('#')[1];
// 與信令服務(wù)器的WebSocket連接
var socket = new WebSocket("ws://127.0.0.1:3000");
// stun和turn服務(wù)器
var iceServer = {
"iceServers": [{
"url": "stun:stun.l.google.com:19302"
}, {
"url": "turn:numb.viagenie.ca",
"username": "webrtc@live.com",
"credential": "muazkh"
}]
};
// 創(chuàng)建PeerConnection實(shí)例 (參數(shù)為null則沒(méi)有iceserver,即使沒(méi)有stunserver和turnserver,仍可在局域網(wǎng)下通訊)
var pc = new webkitRTCPeerConnection(iceServer);
// 發(fā)送ICE候選到其他客戶端
pc.onicecandidate = function(event){
if (event.candidate !== null) {
socket.send(JSON.stringify({
"event": "_ice_candidate",
"data": {
"candidate": event.candidate
}
}));
}
};
// 如果檢測(cè)到媒體流連接到本地,將其綁定到一個(gè)video標(biāo)簽上輸出
pc.onaddstream = function(event){
document.getElementById('remoteVideo').src = URL.createObjectURL(event.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
}
}));
};
// 獲取本地音頻和視頻流
navigator.webkitGetUserMedia({
"audio": true,
"video": true
}, function(stream){
//綁定本地媒體流到video標(biāo)簽用于輸出
document.getElementById('localVideo').src = URL.createObjectURL(stream);
//向PeerConnection中加入需要發(fā)送的流
pc.addStream(stream);
//如果是發(fā)起方則發(fā)送一個(gè)offer信令
if(isCaller){
pc.createOffer(sendOfferFn, function (error) {
console.log('Failure callback: ' + error);
});
}
}, function(error){
//處理媒體流創(chuàng)建失敗錯(cuò)誤
console.log('getUserMedia error: ' + error);
});
//處理到來(lái)的信令
socket.onmessage = function(event){
var json = JSON.parse(event.data);
console.log('onmessage: ', json);
//如果是一個(gè)ICE的候選,則將其加入到PeerConnection中,否則設(shè)定對(duì)方的session描述為傳遞過(guò)來(lái)的描述
if( json.event === "_ice_candidate" ){
pc.addIceCandidate(new RTCIceCandidate(json.data.candidate));
} else {
pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp));
// 如果是一個(gè)offer,那么需要回復(fù)一個(gè)answer
if(json.event === "_offer") {
pc.createAnswer(sendAnswerFn, function (error) {
console.log('Failure callback: ' + error);
});
}
}
};
</script>
</body>
</html>
實(shí)現(xiàn)WebRTC時(shí),信令服務(wù)器是必須的,它幫助客戶端之間進(jìn)行溝通。
這里使用Node.js的ws模塊來(lái)實(shí)現(xiàn)一個(gè)WebSocket服務(wù)作為信令服務(wù)器。另外使用express模塊讓它提供html頁(yè)面的訪問(wèn)。
server.js代碼如下:
var express = require('express'),
app = express(),
server = require('http').createServer(app);
server.listen(3000);
app.get('/', function(req, res) {
res.sendfile(__dirname + '/webrtc.html');
});
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({server: server});
// 存儲(chǔ)socket的數(shù)組,這里只能有2個(gè)socket,每次測(cè)試需要重啟,否則會(huì)出錯(cuò)
var wsc = [],
index = 1;
// 有socket連入
wss.on('connection', function(ws) {
console.log('connection');
// 將socket存入數(shù)組
wsc.push(ws);
// 記下對(duì)方socket在數(shù)組中的下標(biāo),因?yàn)檫@個(gè)測(cè)試程序只允許2個(gè)socket
// 所以第一個(gè)連入的socket存入0,第二個(gè)連入的就是存入1
// otherIndex就反著來(lái),第一個(gè)socket的otherIndex下標(biāo)為1,第二個(gè)socket的otherIndex下標(biāo)為0
var otherIndex = index--,
desc = null;
if (otherIndex == 1) {
desc = 'first socket';
} else {
desc = 'second socket';
}
// 轉(zhuǎn)發(fā)收到的消息
ws.on('message', function(message) {
var json = JSON.parse(message);
console.log('received (' + desc + '): ', json);
wsc[otherIndex].send(message, function (error) {
if (error) {
console.log('Send message error (' + desc + '): ', error);
}
});
});
});
使用npm安裝需要的模塊后使用node server.js啟動(dòng)服務(wù)。
測(cè)試時(shí)使用Chrome瀏覽器:
第一個(gè)瀏覽器窗口訪問(wèn)頁(yè)面:http://127.0.0.1:3000,在彈出的提示中允許使用攝像頭和麥克風(fēng)。
第二個(gè)瀏覽器窗口訪問(wèn)頁(yè)面:http://127.0.0.1:3000#true,#true表示它是一個(gè)發(fā)起方,在彈出的提示中同樣允許使用攝像頭和麥克風(fēng)。
這時(shí)頁(yè)面中應(yīng)當(dāng)可以看到2個(gè)畫面,一個(gè)是本地的,一個(gè)是遠(yuǎn)端的。
將代碼中的IP稍做調(diào)整后部署到外網(wǎng),即可在2個(gè)不同的地點(diǎn)訪問(wèn)這個(gè)頁(yè)面進(jìn)行實(shí)時(shí)通訊。
微信訂閱號(hào):
源文地址:http://blog.gopersist.com/2014/10/21/webrtc-simple/