WebRTC學習總結

WebRTC (Web Real-Time Communications) 是一項實時通信技術,它容許網絡應用或者站點,在不借助中間媒介的狀況下,創建瀏覽器之間點對點(Peer-to-Peer)的鏈接,實現視頻流和(或)音頻流或者其餘任意數據的傳輸。WebRTC包含的這些標準使用戶在無需安裝任何插件或者第三方的軟件的狀況下,建立點對點(Peer-to-Peer)的數據分享和電話會議成爲可能。javascript

本篇文章從自身實踐出發,結合相關代碼,總結WebRTC實現的基本流程。java

1. 引言

首先咱們先看《WebRTC權威指南》上給出的流程圖,從這張圖,咱們要明確兩件事:git

  • 第一,通訊雙方須要先經過服務器交換一些信息
  • 第二,完成信息交換後,通訊雙方將直接進行鏈接以傳輸數據

而後咱們再介紹一下WebRTC中的專有名詞,方便讀者對下文的理解。github

  • RTCPeerConnection:核心對象,每個鏈接對象都須要新建該對象
  • SDP(Session Description Protocol,會話描述協議):包含創建鏈接的一些必要信息,好比IP地址等,sdpRTCPeerConnection對象方法建立,咱們目前不須要知道該對象中的具體內容,使用黑盒傳輸便可
  • ICE(Interactive Connectivity Establishment,交互式鏈接創建技術):用戶之間創建鏈接的方式,用來選取用戶之間最佳的鏈接方式

2. WebRTC實現流程

如下代碼不能直接運行,由於我這裏並無實現信令服務器,如何實現信令服務器可自由選擇(好比,socket.io、websocket等)。web

首先發起方獲取視頻流,若是成功,則新建RTCPeerConnection對象,而後建立offer,併發送給應答方。數組

  • addStream方法將getUserMedia方法中獲取的流(stream)添加到RTCPeerConnection對象中,以進行傳輸
  • onaddStream事件用來監聽通道中新加入的流,經過e.stream獲取
  • onicecandidate事件用來尋找合適的ICE
  • createOffer()RTCPeerConnection對象自帶的方法,用來建立offer,建立成功後調用setLocalDescription方法將localDescription設置爲offerlocalDescription即爲咱們須要發送給應答方的sdp
  • sendOffersendCandidate方法是自定義方法,用來將數據發送給服務器
// 引入<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鏈接已經創建完成。

3. 數據通道

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:設置通道的惟一標識

4. 文件共享

目前,數據通道支持以下類型:

  • String:JavaScript基本的字符串
  • Blob(binary large object):二進制大對象
  • ArrayBuffer:肯定數組長度的數據類型
  • ArrayBufferView:基礎的數組視圖

其中,Blob類型是一個能夠存儲二進制文件的容器,結合HTML5相關文件讀取API,能夠實現文件共享的功能。

5.更多

MDN文檔:>>>點我進入

WebRTC學習資料大全:>>>點我進入

官方Github地址:>>>點我進入

SDP字段解析:>>>點我進入

我的demo代碼地址:>>>點我進入

書籍《WebRTC權威指南》,《Learning WebRTC 中文版》

相關文章
相關標籤/搜索