WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。
本篇文章从自身实践出发,结合相关代码,总结WebRTC实现的基本流程。
首先我们先看《WebRTC权威指南》上给出的流程图,从这张图,我们要明确两件事:
- 第一,通信双方需要先通过服务器交换一些信息
- 第二,完成信息交换后,通信双方将直接进行连接以传输数据
然后我们再介绍一下WebRTC中的专有名词,方便读者对下文的理解。
以下代码不能直接运行,因为我这里并没有实现信令服务器,如何实现信令服务器可自由选择。
首先发起方获取视频流,如果成功,则新建RTCPeerConnection对象,然后创建offer,并发送给应答方。
// 引入脚本
// 提升浏览器兼容性
var localConnection,
var constraints={
audio:false,
video:true
}
navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError)
function handleSuccess(stream) {
document.getElementById("video").srcObject = stream
localConnection=new RTCPeerConnection()
localConnection.addStream(stream)
localConnection.onaddStream=function(e) {
console.log('获得应答方的视频流' + e.stream)
}
localConnection.onicecandidate=function(event){
if(event.candidate){
sendCandidate(event.candidate)
}
}
localConnection.createOffer().then((offer)=>{
localConnection.setLocalDescription(offer).then(sendOffer)
})
}
同样的,接收方也需要新建一个RTCPeerConnection对象
var remoteConnection
var constraints={
audio:false,
video:true
}
}
navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError)
function handleSuccess(stream) {
document.getElementById("video").srcObject = stream
remoteConnection=new RTCPeerConnection()
remoteConnection.addStream(stream)
remoteConnection.onaddStream=function(e) {
console.log('获得发起方的视频流' + e.stream)
}
remoteConnection.onicecandidate=function(event){
if(event.candidate){
sendCandidate(event.candidate)
}
}
}
当应答方收到发起方发送的offer之后,调用setRemoteDescription设置RTCPeerConnection对象的remoteDescription属性,设置成功之后调用createAnswer方法,创建answer成功之后将其设置为localDescription,然后把answer发送给服务器
let desc=new RTCSessionDescription(sdp)
remoteConnection.setRemoteDescription(desc).then(function() {
remoteConnection.createAnswer().then((answer)=>{
remoteConnection.setLocalDescription(answer).then(sendAnswer)
})
})
当发起方收到应答方发送的answer之后,将其设置为remoteDescription,至此WebRTC连接完成。
let desc=new RTCSessionDescription(sdp)
localConnection.setRemoteDescription(desc).then(()=>{console.log('Peer Connection Success')})
此时虽然WebRTC连接已经完成,但是通信双方还不能直接通信,因为发送的ICE还没有处理,通信双方还没有确定最优的连接方式。
应答方收到发起方发送的ICE数据时,调用RTCPeerConnection对象的addIceCandidate方法。
remoteConnection.addIceCandidate(new RTCIceCandidate(ice))
发起方收到应答方发送的ICE数据时,同样调用RTCPeerConnection对象的addIceCandidate方法。
localConnection.addIceCandidate(new RTCIceCandidate(ice))
至此,一个最简单的WebRTC连接已经建立完成。
WebRTC擅长进行数据传输,不仅仅是音频和视频流,还包括我们希望的任何数据类型,相比于复杂的数据交换过程,创建一个数据通道这个主要功能已经在RTCDataConnection对象中实现了:
var peerConnection = new RTCPeerConnection();
var dataChannel = peerConnection.createDataChannel("label",dataChannelOptions);
WebRTC会处理好所有的事情,包括浏览器内部层。浏览器通过一系列的事件来通知应用程序,当前数据通道所处的状态。
ondatachannel事件会通知RTCPeerConnection对象,RTCDataChannel对象本身在开启、关闭、发生错误或者接收到消息时会触发对应的事件。
dataChannel.onerror = function (error){
console.log(error)
}
dataChannel.onmessage = function (event){
console.log(event.data)
}
dataChannel.onopen = function (error){
console.log('data channel opened')
// 当创建一个数据通道后,你必须等onopen事件触发后才能发送消息
dataChannel.send('Hello world')
}
dataChannel.onclose = function (error){
console.log('data channel closed')
}
dataChannelOptions传入的配置项是可选的,并且是一个普通的JavaScript对象,这些配置项可以使应用在UDP或者TCP的优势之间进行变化。
目前,数据通道支持如下类型:
其中,Blob类型是一个可以存储二进制文件的容器,结合H5相关文件读取API,可以实现文件共享的功能
MDN文档
博客WebRTC学习资料大全
书籍《WebRTC权威指南》,《Learning WebRTC 中文版》
Github地址