WebRTC (Web Real-Time Communications)
是一项实时通信技术,它容许网络应用或者站点,在不借助中间媒介的状况下,创建浏览器之间点对点(Peer-to-Peer
)的链接,实现视频流和(或)音频流或者其余任意数据的传输。WebRTC
包含的这些标准使用户在无需安装任何插件或者第三方的软件的状况下,建立点对点(Peer-to-Peer
)的数据分享和电话会议成为可能。javascript
本篇文章从自身实践出发,结合相关代码,总结WebRTC
实现的基本流程。java
首先咱们先看《WebRTC
权威指南》上给出的流程图,从这张图,咱们要明确两件事:git
而后咱们再介绍一下WebRTC
中的专有名词,方便读者对下文的理解。github
RTCPeerConnection
:核心对象,每个链接对象都须要新建该对象SDP
(Session Description Protocol
,会话描述协议):包含创建链接的一些必要信息,好比IP
地址等,sdp
由RTCPeerConnection
对象方法建立,咱们目前不须要知道该对象中的具体内容,使用黑盒传输便可ICE
(Interactive Connectivity Establishment
,交互式链接创建技术):用户之间创建链接的方式,用来选取用户之间最佳的链接方式如下代码不能直接运行,由于我这里并无实现信令服务器,如何实现信令服务器可自由选择(好比,socket.io、websocket等)。web
首先发起方获取视频流,若是成功,则新建RTCPeerConnection
对象,而后建立offer
,并发送给应答方。数组
addStream
方法将getUserMedia
方法中获取的流(stream
)添加到RTCPeerConnection
对象中,以进行传输onaddStream
事件用来监听通道中新加入的流,经过e.stream
获取onicecandidate
事件用来寻找合适的ICE
createOffer()
是RTCPeerConnection
对象自带的方法,用来建立offer
,建立成功后调用setLocalDescription
方法将localDescription
设置为offer
,localDescription
即为咱们须要发送给应答方的sdp
sendOffer
和sendCandidate
方法是自定义方法,用来将数据发送给服务器// 引入<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>脚本
// 提高浏览器兼容性
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
链接完成。websocket
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')
}
复制代码
数据通道datachannel
创建的过程略微不一样于创建视频流或音频流双向链接,offer、answer、ice
处理完毕以后,由一方发起请求便可。
localConnection = new RTCPeerConnection();
sendChannel = localConnection.createDataChannel("sendChannel");
sendChannel.onopen = handleSendChannelStatusChange;
sendChannel.onclose = handleSendChannelStatusChange;
复制代码
接收方此时并不须要再次调用createDataChannel
方法,只须要监听RTCPeerConnection
实例对象上的ondatachannel
事件就能够在回调中拿到发送方的请求,数据通道就创建起来了。
remoteConnection = new RTCPeerConnection();
remoteConnection.ondatachannel = receiveChannelCallback;
function receiveChannelCallback(event) {
receiveChannel = event.channel;
receiveChannel.onmessage = handleReceiveMessage;
receiveChannel.onopen = handleReceiveChannelStatusChange;
receiveChannel.onclose = handleReceiveChannelStatusChange;
}
复制代码
dataChannelOptions
传入的配置项是可选的,而且是一个普通的JavaScript
对象,这些配置项可使应用在UDP
或者TCP
的优点之间进行变化。
reliable
:设置消息是否进行担保ordered
:设置消息的接受是否须要按照发送时的顺序maxRetransmitTime
:设置消息发送失败时,多久从新发送maxRetransmits
:设置消息发送失败时,最多重发次数protocol
:设置强制使用其余子协议,但当用户代理不支持该协议时会报错negotiated
:设置开发人员是否有责任在两边建立数据通道,仍是浏览器自动完成这个步骤id
:设置通道的惟一标识目前,数据通道支持以下类型:
String
:JavaScript
基本的字符串Blob(binary large object)
:二进制大对象ArrayBuffer
:肯定数组长度的数据类型ArrayBufferView
:基础的数组视图其中,Blob
类型是一个能够存储二进制文件的容器,结合HTML5
相关文件读取API
,能够实现文件共享的功能。
MDN文档:>>>点我进入
WebRTC学习资料大全:>>>点我进入
官方Github地址:>>>点我进入
SDP字段解析:>>>点我进入
我的demo代码地址:>>>点我进入
书籍《WebRTC权威指南》,《Learning WebRTC 中文版》