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
尚未處理,通訊雙方尚未肯定最優的鏈接方式。markdown
應答方收到發起方發送的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 中文版》