webRTC是英文Web Real-Time Communication的缩写,中文翻译网页实时通信,是浏览器不需要服务器的中转,可以直接通信的技术
网上的很多教程都会包含实时视频的介绍,不过我感觉视频看起来很酷,不过却不是webRTC的使用难点,却明显增加webRTC的使用复杂度,可以略过
webRTC是客户端对客户端的单对单实时通信,但是还是需要服务器,就好比一个婚介所的作用
下面我们通过socket.io作为服务器端实现简单的聊天功能
实现步骤
发起方向服务器发出通知并初始化RTCPeerConnection
服务器接收到通知通知接收并初始化RTCPeerConnection
双方都监听onicecandidate
事件,并在回调里面把event.candidate
上传到服务器
双发都监听ondatachannel事件,并在回调里面给event.channel
监听onmessage
事件
发起方调用createOffer
方法,并在这个方法的回调中给自己的RTCPeerConnection
实例设置setLocalDescription
,并向服务器发送自己的Description
接收方在服务器推送给自己的消息里面把5中的Description
设置为自己的RTCPeerConnection
实例的RemoteDescription
,并调用createAnswer
方法,在此方法的回调之中设置setLocalDescription
,并把自己的Description
上传到服务器
发起方接收到服务器推送给自己的Description
,设置为LocalDescription
,至此双方连接建立
双方可以调用自己的channel的send方法发送文本消息
至于调用视频和音频,我觉着这部分使用起来比较简单,不绕
步骤就是一方的开启视频,获取视频流,添加到RTCPeerConnection实例中,连接的另外一方监听onaddstream事件,获取视频流,OK
多人会话的话,同一个RTCPeerConnection实例是不能够多人会话的。如果要多人会话,就要单对单建立多个连接。同样的步骤执行多次就可以了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table width="800px">
<tr>
<td>
<video id="myVideo"></video>
</td>
<td>
<div style="height: 200px;overflow: auto"></div>
</td>
</tr>
<tr>
<td></td>
<td>
<textarea style="height: 200px;width: 400px" id="textarea"></textarea>
</td>
</tr>
</table>
<button id="start">开始</button>
<button id="stop">结束</button>
<button id="send">发送</button>
<script src='/socket.io/socket.io.js'></script>
<script src="js/index.js"></script>
</body>
</html>
var video = document.getElementById('video')
var localPeerConnection, remotePeerConnection
var localChannel
var socket = io.connect('http://localhost:8181')
// 打开页面即开启等待模式
startWaiting()
function startWaiting() {
var servers = {
"iceServers": [{
"url": "stun:stun.l.google.com:19302"
}]
}
var pc_constraints = {
optional: [{
DtlsSrtpKeyAgreement: true
}]
}
localPeerConnection = new RTCPeerConnection(servers, pc_constraints)
localChannel = localPeerConnection.createDataChannel('sendDataChannel', { reliable: true })
localPeerConnection.onicecandidate = function(event) {
if (event.candidate) {
socket.emit('onicecandidate', event.candidate)
}
}
localChannel.onopen = function() {
console.log('open')
}
localChannel.onclose = function() {
console.log('close')
}
localPeerConnection.ondatachannel = function(event) {
console.log(event.channel)
event.channel.onmessage = function(msg) {
console.log('event msg', msg)
}
}
socket.on('offer', function(desc) {
console.log('offer: ', desc)
localPeerConnection.setRemoteDescription(desc)
setRemote = true
localPeerConnection.createAnswer(function(desc) {
localPeerConnection.setLocalDescription(desc)
socket.emit('answer', desc)
}, function(error){console.log(error)})
})
socket.on('answer', function(desc) {
console.log('answer: ', desc)
localPeerConnection.setRemoteDescription(desc)
console.log('answer end')
setRemote = true
})
socket.on('onicecandidate', function(icecandidate) {
localPeerConnection.addIceCandidate(icecandidate)
})
}
document.getElementById('start').onclick = function() {
localPeerConnection.createOffer(function(desc) {
localPeerConnection.setLocalDescription(desc)
socket.emit('offer', desc)
}, function(error){console.log(error)})
}
document.getElementById('send').onclick = function() {
var value = document.getElementById('textarea').value
localChannel.send(value)
}
var static = require('node-static')
var http = require('http')
var file = new(static.Server)()
var app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(8181);
var io = require('socket.io').listen(app)
io.sockets.on('connection', function(socket) {
socket.on('offer',function(desc) {
socket.broadcast.emit('offer', desc)
})
socket.on('answer',function(desc) {
socket.broadcast.emit('answer', desc)
})
socket.on('onicecandidate', function(candidate) {
socket.broadcast.emit('onicecandidate', candidate)
})
socket.on('message', function(message) {
socket.broadcast.to(message.channel).emit('message', message.message)
})
})