WebRTC介紹及簡單應用

WebRTC介紹及簡單應用


WebRTC,即Web Real-Time Communication,web實時通訊技術。簡單地說就是在web瀏覽器裏面引入實時通訊,包括音視頻通話等。javascript

  • WebRTC實時通訊技術介紹
  • 如何使用
  • 媒體介紹
  • 信令
  • STUN和TURN介紹
  • 對等鏈接和提議/應答協商
  • 數據通道
  • NAT和防火牆穿透
  • 簡單應用
  • 其它

WebRTC實時通訊技術介紹

WebRTC實現了基於網頁的語音對話或視頻通話,目的是無插件實現web端的實時通訊的能力。java

WebRTC提供了視頻會議的核心技術,包括音視頻的採集、編解碼、網絡傳輸、展現等功能,而且還支持跨平臺,包括linux、windows、mac、android等。linux

1. WebRTC三角形

image

2. WebRTC梯形

image

3. WebRTC的多方會話

WebRTC支持多個瀏覽器參與的多方會話或會議會話,要創建這類會話有以下兩種模式:android

image

image

4. WebRTC新功能特性

image


如何使用WebRTC

WebRTC易於使用,只需極少步驟即可創建媒體會話。有些消息在瀏覽器和服務器之間流動,有些則直接在兩個瀏覽器(成爲對等端)之間流動。git

一、創建WebRTC會話

創建WebRTC鏈接須要以下幾個步驟:github

  • 獲取本地媒體(getUserMedia()MediaStream API
  • 在瀏覽器和對等端(其它瀏覽器或終端)之間創建對等鏈接(RTCPeerConnection API
  • 將媒體和數據通道關聯至該鏈接
  • 交換會話描述(RTCSessionDescription

image

  • 瀏覽器M從Web服務器請求網頁
  • Web服務器向M返回帶有WebRTC js的網頁
  • 瀏覽器L從Web服務器請求網頁
  • Web服務器向L返回帶有WebRTC js的網頁
  • M決定與L通訊,經過M自身的js將M的會話描述對象(offer,提議)發送至Web服務器
  • Web服務器將M的會話描述對象發送至L上的js
  • L上的js將L的會話描述對象(answer,應答)發送至Web服務器
  • Web服務器轉發應答至M上的js
  • M和L開始交互,肯定訪問對方的最佳方式
  • 完成後,M和L開始協商通訊密鑰
  • M和L開始交換語音、視頻或數據

WebRTC三角形會話具體的調用流程:web

image

說明:
    SDP對象的傳輸多是一個來回反覆的過程,而且該過程採用的協議並未標準化

WebRTC梯形會話方式具體的調用流程:windows

image

說明:
    此場景中,瀏覽器M和L直接交換媒體,只是它們運行的Web服務器不用而已。每一個瀏覽器的會話描述對象都會映射至Jingle[XEP-0166]session-initiate消息和session-accept方法。

媒體介紹

先來看下WebRTC中的本地媒體:瀏覽器

一、WebRTC中的媒體

  • 軌道(MediaStreamTrack,表明設備或錄製內容可返回的單一類型的媒體,惟一關聯一個「源」,WebRTC不能直接訪問或控制「源」,對「源」的一切控制都經過軌道實施;一個「源」可能對應多個軌道對象)
  • 流(MediaStream,軌道對象的集合)

軌道和流的示意以下:服務器

image

二、捕獲本地媒體

以下代碼展現了本地媒體的簡單獲取,並展現:

// 注意getUserMedia()在各瀏覽器中的區別  
// Opera --> getUserMedia  
// Chrome --> webkitGetUserMedia  
// Firefox --> mozGetUserMedia  
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;  
  
// 只獲取video:  
var constraints = {audio: false, video: true};  
var video = document.querySelector("video");  
  
function successCallback(stream) {  
    // Note: make the returned stream available to console for inspection  
    window.stream = stream;  
      
if (window.URL) {  
        // Chrome瀏覽器
        video.srcObject = stream;  
    } else {  
        // Firefox和Opera: 能夠直接把視頻源設置爲stream  
        video.src = stream;  
    }  
    // 播放  
    video.play();  
}  
  
function errorCallback(error){  
    console.log("navigator.getUserMedia error: ", error);  
}  
  
navigator.getUserMedia(constraints, successCallback, errorCallback);

運行效果以下:

image

完整代碼查看:https://github.com/caiya/webrtc-demo.git


信令

在WebRTC中,信令起着舉足輕重的做用。但實現沒有標準化,好比http、websocket、xmpp等。

一、信令的做用

  • 協商媒體功能和設置
  • 標識和驗證會話參與者的身份(交換SDP對象中的信息:媒體類型、編解碼器、帶寬等元數據)
  • 控制媒體會話、指示進度、更改會話、終止會話
  • 雙佔用分解

簡單地說,信令就是協調通信的過程,一旦信令服務創建好了,兩個客戶端之間創建了鏈接,理論上它們就能夠進行點對點通信了。

二、信令的傳輸

WebRTC要求在兩個對等端創建雙向的信令通道,一般有三種方式來傳輸WebRTC信令:http、websocket、數據通道

http方式以下:

image

websocket代理信令傳輸:

image

三、WebRTC中的服務器

WebRTC提供了瀏覽器端的P2P通訊,但並不意味着WebRTC不須要服務器。撇開應用服務器不說,至少如下兩種服務器是必須的:

  • 瀏覽器之間創建通訊前交換各類元數據(信令)的服務器(信令服務)
  • 穿越NAT和防火牆的服務器(stun、turn、rsip等)
說明:
    元數據是經過信令服務器中轉發給另外一個客戶端,可是對於流媒體數據,一旦會話創建,首先嚐試使用點對點鏈接。簡單一點說就是:每一個客戶端都有一個惟一的地址,他能用來和其餘客戶端進行通信和數據交換。
    
    STUN服務器:用來取外網地址的。(見下節)
    
    TURN服務器:在P2P失敗時進行轉發的。(見下節)
    
    ICE:*Interactive Connectivity Establishment*,即交互式連通創建方式。並不是一種新的協議,它經過綜合利用現有NAT穿透協議,以一種更有效的方式來組織會話創建過程,使之在不增長任何延遲同時比STUN等單一協議更具備健壯性、靈活性。

四、信令交互和RTCPeerConnection的創建

WebRTC使用RTCPeerConnection創建鏈接傳送流數據,在創建RTCPeerConnection實例以後,想要創建點對點的信道,須要作兩件事:

  • 肯定本機上的媒體流的特性,好比分辨率、編解碼能力啥的(SDP描述符)
  • 鏈接兩端的主機的網絡地址(ICE Candidate)

經過offer和answer交換SDP描述符:

  • 甲和乙各自創建一個PC實例
  • 甲經過PC所提供的createOffer()方法創建一個包含甲的SDP描述符的offer信令
  • 甲經過PC所提供的setLocalDescription()方法,將甲的SDP描述符交給甲的PC實例
  • 甲將offer信令經過服務器發送給乙
  • 乙將甲的offer信令中所包含的的SDP描述符提取出來,經過PC所提供的setRemoteDescription()方法交給乙的PC實例
  • 乙經過PC所提供的createAnswer()方法創建一個包含乙的SDP描述符answer信令
  • 乙經過PC所提供的setLocalDescription()方法,將乙的SDP描述符交給乙的PC實例
  • 乙將answer信令經過服務器發送給甲
  • 甲接收到乙的answer信令後,將其中乙的SDP描述符提取出來,調用setRemoteDescripttion()方法交給甲本身的PC實例

經過ICE框架創建NAT/防火牆穿越的鏈接:

WebRTC使用ICE框架來得到這個外界能夠直接訪問的地址,RTCPeerConnection在創立的時候能夠將ICE服務器的地址傳遞進去,如:

var iceServer = {
    "iceServers": [{
        "url": "stun:stun.l.google.com:19302"
    }]
};
var pc = new RTCPeerConnection(iceServer);
  • 甲、乙各建立配置了ICE服務器的PC實例,併爲其添加onicecandidate事件回調
  • 當網絡候選可用時,將會調用onicecandidate函數
  • 在回調函數內部,甲或乙將網絡候選的消息封裝在ICE Candidate信令中,經過服務器中轉,傳遞給對方
  • 甲或乙接收到對方經過服務器中轉所發送過來ICE Candidate信令時,將其解析並得到網絡候選,將其經過PC實例的addIceCandidate()方法加入到PC實例中

這樣鏈接就創立完成了,能夠向RTCPeerConnection中經過addStream()加入流來傳輸媒體流數據。


STUN和TURN介紹

瀏覽器位於網絡地址轉換設備(NAT)以後是一種極爲廣泛的設計。舉個栗子:

image

再來看個圖,瞭解下「公共地址」和「私有地址」:

image

NAT主要負責維護內部ip地址和端口號與外部ip地址和端口號之間的映射表。

一、STUN服務器

STUN,Session Traversal Utilities for NAT,稱爲NAT會話遍歷實用工具服務器。簡單地說,就是獲取內網設備的最外層NAT(公共ip地址)信息。

image

二、TURN服務器

TURN,Traversal Using Relay around NAT,稱爲中繼型NAT遍歷服務器。

image

說明:
    媒體中繼地址是一個公共地址,用於轉發接收到的包,或者將收到的數據包轉發給瀏覽器。若是兩個對等端由於NAT類型等緣由不能直接創建P2P鏈接的話,那麼可使用中繼地址。
    
    ps:相比較直接使用web服務器提供媒體中繼理想點。

對等鏈接和提議/應答協商

上一節中有簡單介紹對等鏈接和offer/answer交互流程,這節再說明下。

其實WebRTC定義了兩組主要的功能,分別是:媒體捕獲(getUserMedia(),前面已介紹)、媒體傳輸。對等鏈接和提議/應答協商的概念是媒體傳輸的核心。

一、對等鏈接

RTCPeerConnection接口是WebRTC的主要API,用來在P2P端創建媒體鏈接及數據鏈接路徑。RTCPeerConnection對象的構造函數有一系列屬性,最主要的是iceServers屬性,表示服務器地址列表。用於幫助透過NAT和防火牆創建會話。

var pc = new RTCPeerConnection({
    iceServers: [{
        url: 'stun:stun.l.google.com:19302'
    },{
        url: 'turn:user@turn.myserver.com',
        credential: 'test'
    }]
})

getUserMedia({
    audio: true,
    video: true
}, successCB, failureCB)

function successCB(stream) {
    // 告知瀏覽器,我要發送MediaStream
    pc.addStream(stream)        // removeStream()
}

二、提議/應答協商

要在兩者之間創建鏈接,必須在兩者之間創建會話。offer/answer是一種「一次性經過」型協商機制。實際中該過程可能會反覆屢次。

WebRTC使用RTCSessionDescription對象表示提議和應答。每一個瀏覽器都將生成一個該對象。

三、JavaScript提議/應答協商控制

本地瀏覽器只關注兩個特定的調用:

// 將個人會話描述告知個人瀏覽器
pc.setLocalDescription(mySessionDescription)
...
// 將對等端的會話描述告知個人瀏覽器
pc.setRemoteDescription(yourSessionDescription)

生成提議、應答:

// 生成提議
pc.createOffer(gotOffer, didntGetOffer)

function gotOffer(aSessionDescription) {
    setLocalDescription(aSessionDescription)
    ...
    // 如今能夠將會話描述(提議offer)發送給對等端,以便對等端
    // a)、將提議傳遞給setRemoteDescription
    // b)、調用createAnswer
}

// 生成應答
pc.createAnswer(gotAnswer, didntGetAnswer)

function gotAnswer(aSessionDescription) {
    setLocalDescription(aSessionDescription)
    ...
    // 如今將會話描述(應答answer)發送給對等端,以便對等端
    // a)、將應答傳遞給setRemoteDescription
}

四、測試demo說明

如下測試demo展現在兩個瀏覽器中進行實時視頻通話,源碼地址:https://github.com/caiya/webrtc-p2p.git

image


數據通道

RTCDataChannel,數據通道是瀏覽器之間創建的非媒體的交互鏈接。即不傳遞媒體消息,繞過服務器直接傳遞數據。相比WebSocket、http消息,數據通道支持流量大、延遲低。

注意:
    單個對等鏈接中的多個數據通道底層共享一個流,因此只需一次offer、answer便可創建首個數據通道。以後再創建數據通道無需再次進行offer、answer交換。
    
    典型應用:遊戲實時狀態更新。

數據通道的使用

只有在建立完RTCPeerConnection實例以後才能建立數據通道,以下:

pc = new RTCPeerConnection()
dc = pc.createDataChannel('')

一端建立完數據通道後,另外一端只須要監聽ondatachannel事件便可:

pc = new RTCPeerConnection()
pc.ondatachannel = function(e) {
    dc = e.channel
}

此時,兩個對等端已經彼此創建數據通道,能夠直接相互發送消息:

dc.send('i am a text string for sending')
dc.send(new Blob(['i am a blob object'], {type: 'text/plain'}))
dc.send(new arrayBuffer(32))    // 發送arrayBuffer
dc.onmessage = function(e) {
    console.log('收到消息:', e.data)
}

加入數據通道後的測試demo

項目源代碼地址:https://github.com/caiya/webrtc-p2p-datachannel

部分截圖:

image


做者 @晁州 2017 年 11月 27日

相關文章
相關標籤/搜索