轉自:https://www.cnblogs.com/vipzhou/p/7994927.html
WebRTC介紹及簡單應用
WebRTC,即Web Real-Time Communication,web實時通信技術。簡單地說就是在web瀏覽器里面引入實時通信,包括音視頻通話等。
WebRTC實時通信技術介紹
如何使用
媒體介紹
信令
STUN和TURN介紹
對等連接和提議/應答協商
數據通道
NAT和防火牆穿透
簡單應用
其它
WebRTC實時通信技術介紹
WebRTC實現了基於網頁的語音對話或視頻通話,目的是無插件實現web端的實時通信的能力。
WebRTC提供了視頻會議的核心技術,包括音視頻的采集、編解碼、網絡傳輸、展示等功能,並且還支持跨平台,包括linux、windows、mac、android等。
-
WebRTC三角形
image -
WebRTC梯形
image -
WebRTC的多方會話
WebRTC支持多個瀏覽器參與的多方會話或會議會話,要建立這類會話有如下兩種模式:
image
image
- WebRTC新功能特性
image
如何使用WebRTC
WebRTC易於使用,只需極少步驟便可建立媒體會話。有些消息在瀏覽器和服務器之間流動,有些則直接在兩個瀏覽器(成為對等端)之間流動。
1、建立WebRTC會話
建立WebRTC連接需要如下幾個步驟:
獲取本地媒體(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三角形會話具體的調用流程:
image
說明:
SDP對象的傳輸可能是一個來回反復的過程,並且該過程采用的協議並未標准化
WebRTC梯形會話方式具體的調用流程:
image
說明:
此場景中,瀏覽器M和L直接交換媒體,只是它們運行的Web服務器不用而已。每個瀏覽器的會話描述對象都會映射至Jingle[XEP-0166]session-initiate消息和session-accept方法。
媒體介紹
先來看下WebRTC中的本地媒體:
1、WebRTC中的媒體
軌道(MediaStreamTrack,代表設備或錄制內容可返回的單一類型的媒體,唯一關聯一個“源”,WebRTC不能直接訪問或控制“源”,對“源”的一切控制都通過軌道實施;一個“源”可能對應多個軌道對象)
流(MediaStream,軌道對象的集合)
軌道和流的示意如下:
image
2、捕獲本地媒體
如下代碼展示了本地媒體的簡單獲取,並展示:
// 注意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等。
1、信令的作用
協商媒體功能和設置
標識和驗證會話參與者的身份(交換SDP對象中的信息:媒體類型、編解碼器、帶寬等元數據)
控制媒體會話、指示進度、更改會話、終止會話
雙占用分解
簡單地說,信令就是協調通訊的過程,一旦信令服務建立好了,兩個客戶端之間建立了連接,理論上它們就可以進行點對點通訊了。
2、信令的傳輸
WebRTC要求在兩個對等端建立雙向的信令通道,通常有三種方式來傳輸WebRTC信令:http、websocket、數據通道
http方式如下:
image
websocket代理信令傳輸:
image
3、WebRTC中的服務器
WebRTC提供了瀏覽器端的P2P通信,但並不意味着WebRTC不需要服務器。撇開應用服務器不說,至少以下兩種服務器是必須的:
瀏覽器之間建立通信前交換各種元數據(信令)的服務器(信令服務)
穿越NAT和防火牆的服務器(stun、turn、rsip等)
說明:
元數據是通過信令服務器中轉發給另一個客戶端,但是對於流媒體數據,一旦會話建立,首先嘗試使用點對點連接。簡單一點說就是:每個客戶端都有一個唯一的地址,他能用來和其他客戶端進行通訊和數據交換。
STUN服務器:用來取外網地址的。(見下節)
TURN服務器:在P2P失敗時進行轉發的。(見下節)
ICE:*Interactive Connectivity Establishment*,即交互式連通建立方式。並非一種新的協議,它通過綜合利用現有NAT穿透協議,以一種更有效的方式來組織會話建立過程,使之在不增加任何延遲同時比STUN等單一協議更具有健壯性、靈活性。
4、信令交互和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地址和端口號之間的映射表。
1、STUN服務器
STUN,Session Traversal Utilities for NAT,稱為NAT會話遍歷實用工具服務器。簡單地說,就是獲取內網設備的最外層NAT(公共ip地址)信息。
image
2、TURN服務器
TURN,Traversal Using Relay around NAT,稱為中繼型NAT遍歷服務器。
image
說明:
媒體中繼地址是一個公共地址,用於轉發接收到的包,或者將收到的數據包轉發給瀏覽器。如果兩個對等端因為NAT類型等原因不能直接建立P2P連接的話,那么可以使用中繼地址。
ps:相比較直接使用web服務器提供媒體中繼理想點。
對等連接和提議/應答協商
上一節中有簡單介紹對等連接和offer/answer交互流程,這節再說明下。
其實WebRTC定義了兩組主要的功能,分別是:媒體捕獲(getUserMedia(),前面已介紹)、媒體傳輸。對等連接和提議/應答協商的概念是媒體傳輸的核心。
1、對等連接
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()
}
2、提議/應答協商
要在二者之間建立連接,必須在二者之間建立會話。offer/answer是一種“一次性通過”型協商機制。實際中該過程可能會反復多次。
WebRTC使用RTCSessionDescription對象表示提議和應答。每個瀏覽器都將生成一個該對象。
3、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
}
4、測試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日
作者:西安-晁州
出處:https://vipzhou.cn
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。如有問題,可以郵件:caiya928@aliyun.com QQ:1419901425 聯系我
轉載