隨着互聯網高速發展,以及即將到來的5G時代,WebRTC做爲前端互動直播和實時音視頻的利器,也是將前端開發者們不可錯過的學習領域。若是你如今只是聽過而已,那你可能要好好學習一番。javascript
WebRTC 全稱是(Web browsers with Real-Time Communications (RTC)前端
大概2011年,谷歌收購了 GIPS,它是一個爲 RTC 開發出許多組件的公司,例如編解碼和回聲消除技術。Google 開源了 GIPS 開發的技術,並但願將其打造爲行業標準。java
收購花了一大筆錢,谷歌說開源就開源,確實不得不佩服,但顯然對於Googl來講,打造音視頻的開源生態有着更大的價值。「瀏覽器 + WebRTC」就是 Google 給出的一個答案。其願景就是能夠在瀏覽器之間快速地實現音視頻通訊。git
發展至今日,簡單來講:WebRTC是一個免費、開放的項目。使web瀏覽器經過簡單的JavaScript api接口實現實時通訊功能。github
通常談WebRTC架構都會拿出這張圖,WebRTC從上往下架構依次是:web
Web API層:面向開發者提供標準API(javascirpt),前端應用經過這一層接入使用WebRTC能力。ajax
C++ API層:面向瀏覽器開發者,使瀏覽器製造商可以輕鬆地實現Web API方案。api
音頻引擎(VoiceEngine):音頻引擎是一系列音頻多媒體處理的框架,包括從視頻採集卡到網絡傳輸端等整個解決方案。瀏覽器
視頻引擎(VideoEngine): 是一系列視頻處理的總體框架,從攝像頭採集視頻、視頻信息網絡傳輸到視頻顯示整個完整過程的解決方案。服務器
傳輸(Transport):傳輸 / 會話層,會話協商 + NAT穿透組件。
硬件模塊:音視頻的硬件捕獲以及NetWork IO相關。
這個類並不徹底屬於WebRTC的範疇,可是在本地媒體流獲取,及遠端流傳到vedio標籤播放都與WebRTC相關。 MS 由兩部分構成: MediaStreamTrack 和 MediaStream。
MediaStreamTrack 媒體軌,表明一種單類型數據流,能夠是音頻軌或者視頻軌。
MediaStream 是一個完整的音視頻流。它能夠包含 >=0 個 MediaStreamTrack。它主要的做用就是確保幾個媒體軌道是同步播放。
關於MediaStream,還有一個重要的概念叫作: Constraints(約束)。它是用來規範當前採集的數據是否符合須要,並能夠經過參數來設置。
// 基本
const constraint1 = {
"audio": true, // 是否捕獲音頻
"video": true // 是否捕獲視頻
}
// 詳細
const constraint2 = {
"audio": {
"sampleSize": 8,
"echoCancellation": true //回聲消除
},
"video": { // 視頻相關設置
"width": {
"min": "381", // 當前視頻的最小寬度
"max": "640"
},
"height": {
"min": "200", // 最小高度
"max": "480"
},
"frameRate": {
"min": "28", // 最小幀率
"max": "10"
}
}
}
複製代碼
其中本地媒體流獲取用到的是navigator.getUserMedia()
,它提供了訪問用戶本地相機/麥克風媒體流的手段。
var video = document.querySelector('video');
navigator.getUserMedia({
audio : true,
video : true
}, function (stream) {
//拿到本地媒體流
video.src = window.URL.creatObjectURL(stream);
}, function (error) {
console.log(error);
});
複製代碼
以上這段demo,就是經過getUserMedia
獲取stream
,瀏覽器彈窗向用戶索要權限,當容許後才能拿到stream
傳給video標籤進行播放。
getUserMedia
的第一個參數就是Constraint
,第二個參數傳入回調函數拿到視頻流。固然你可使用以下Promise的寫法:
navigator.mediaDevices.getUserMedia(constraints).
then(successCallback).catch(errorCallback);
複製代碼
RTCPeerConnection,用於實現peer跟peer之間的NAT穿透,繼而無需服務器就能傳輸音視頻數據流的鏈接通道。
這麼說過於抽象,爲了幫助理解,能夠用一個不太恰當但有助於理解的比喻:RTCPeerConnection
就是一個高級且功能強大的用於傳輸音視頻數據而創建相似Websocket連接通道,只不過它能夠用來創建瀏覽器
之因此說是高級且強大,是由於它做爲WebRTC web層核心API,讓你無須關注數據傳輸延遲抖動、音視頻編解碼,音畫同步等問題。直接使用PeerConnection 就能用上這些瀏覽器提供的底層封裝好的能力。
var pc = new RTCPeerConnection({
"iceServers": [
{ "url": "stun:stun.l.google.com:19302" }, //使用google公共測試服務器
{ "url": "turn:user@turnserver.com", "credential": "pass" } // 若有turn服務器,可在此配置
]
};);
pc.setRemoteDescription(remote.offer);
pc.addIceCandidate(remote.candidate);
pc.addstream(local.stream);
pc.createAnswer(function (answer) {
// 生成描述端鏈接的SDP應答併發送到對端
pc.setLocalDescription(answer);
signalingChannel.send(answer.sdp);
});
pc.onicecandidate = function (evt) {
// 生成描述端鏈接的SDP應答併發送到對端
if (evt.candidate) {
signalingChannel.send(evt.candidate);
}
}
pc.onaddstream = function (evt) {
//收到遠端流並播放
var remote_video = document.getElementById('remote_video');
remote_video.src = window.URL.createObjectURL(evt.stream);
}
複製代碼
你會疑問這裏ice Server配置是什麼? signalingChannel又是什麼? answer和offer又是什麼? candidate又是什麼?
咱們能夠經過new RTCPeerConnection()
建立RTCPeerConnection。以上代碼只是展現RTCPeerConnection的API和設置方法,但並不能運行。
要完成一個RTCPeerConnection須要設置ICE Server(STUN服務器或TURN服務器),在鏈接前還要交換信息,爲此須要藉助一個信令服務器(signaling server)來進行,主要交換SDP會話描述協議和ICE candidate,咱們後面段落介紹。
RTCDataChannel能夠創建瀏覽器之間的點對點通信。經常使用的通信方式有websocket, ajax和等方式。websocket雖然是雙向通信,可是不管是websocket仍是ajax都是客戶端和服務器之間的通信,你必須配置服務器才能夠進行通信。
而因爲RTCDATAChannel藉助RTCPeerConnection無需通過服務器,就能夠提供點對點之間的通信,無需/(避免)服務器了這個中間件。
var pc = new RTCPeerConnection();
var dc = pc.createDataChannel("my channel");
dc.onmessage = function (event) {
console.log("received: " + event.data);
};
dc.onopen = function () {
console.log("datachannel open");
};
dc.onclose = function () {
console.log("datachannel close");
};
複製代碼
咱們說WebRTC的RTCPeerConnection是能夠作到瀏覽器間(無服務)的通訊。
但這裏有個問題,當兩個瀏覽器不經過服務器創建PeerConnection時,它們怎麼知道彼此的存在呢?進一步講,它們該怎麼知道對方的網絡鏈接位置(IP/端口等)呢?支持何種編解碼器?甚至於何時開始媒體流傳輸、又該何時結束呢?
所以在創建WebRTC的RTCPeerConnection前,必須創建️另外一條通道來交這些協商信息,這些也被稱爲信令,這條通道成爲信令通道(Signaling Channel)。
兩個客戶端瀏覽器交換的信令具備如下功能:
其中主要涉及SDP(offer、answer)會話描述協議,以及ICE candidate的交換。
這裏須要注意的一點:
WebRTC標準自己沒有規定信令交換的通信方式,信令服務根據自身的狀況實現
通常會使用websocket通道來作信令通道,好比能夠基於socket.io來搭建信令服務。固然業界也有不少開源且穩定成熟的信令服務方案可供選擇。
在交換SDP後,webrtc就開始真正的鏈接來傳輸音視頻數據。這個創建鏈接的過程至關複雜,緣由是webrtc既要保證高效的傳輸性,又要保證穩定的連通性。
因爲瀏覽器客戶端之間所處的位置每每是至關複雜的,可能處於同一個內網段內,也可能處於兩個不一樣的位置,所處的NAT網關也可能很複雜。所以須要一種機制找到一條傳輸質量最優的道路,而WebRTC正具有這種能力。
首先簡單瞭解如下三個概念。
ICE鏈接大體的原理及步驟以下:
以上,WebRTC便能找到一條傳輸質量最優的鏈接道路。 固然實際狀況並非這麼簡單,整個過程包含着更復雜的底層細節。
經過以上了解了,結合WebRTC的API,信令服務,SDP協商、ICE鏈接等內容。咱們用一段代碼來講明WebRTC的使用流程步驟。
var signalingChannel = new SignalingChannel();
var pc = null;
var ice = {
"iceServers": [
{ "url": "stun:stun.l.google.com:19302" }, //使用google公共測試服務器
{ "url": "turn:user@turnserver.com", "credential": "pass" } // 若有turn服務器,可在此配置
]
};
signalingChannel.onmessage = function (msg) {
if (msg.offer) { // 監聽並處理經過發信通道交付的遠程提議
pc = new RTCPeerConnection(ice);
pc.setRemoteDescription(msg.offer);
navigator.getUserMedia({ "audio": true, "video": true }, gotStream, logError);
} else if (msg.candidate) { // 註冊遠程ICE候選項以開始鏈接檢查
pc.addIceCandidate(msg.candidate);
}
}
function gotStream(evt) {
pc.addstream(evt.stream);
var local_video = document.getElementById('local_video');
local_video.src = window.URL.createObjectURL(evt.stream);
pc.createAnswer(function (answer) { // 生成描述端鏈接的SDP應答併發送到對端
pc.setLocalDescription(answer);
signalingChannel.send(answer.sdp);
});
}
pc.onicecandidate = function (evt) {
if (evt.candidate) {
signalingChannel.send(evt.candidate);
}
}
pc.onaddstream = function (evt) {
var remote_video = document.getElementById('remote_video');
remote_video.src = window.URL.createObjectURL(evt.stream);
}
function logError() { ... }
複製代碼
一開始各個瀏覽器廠商,都會實現本身的一套API,諸如webkitRTCPeerConnection
和mozRTCPeerConnection
這樣的差別,對於前端開發者固然是苦不堪言。
而adapter.js正是爲了消除這種差別,幫助咱們能夠按照規範來寫咱們的WebRTC代碼。能夠參考 github.com/webrtcHacks…
關於標準的另外一個關鍵點是:W3C在2018年發佈的 WebRTC 1.0標準(candidate recommendation) www.w3.org/TR/webrtc 使得WebRTC也將成爲視頻通訊商業應用場景爆發的主要技術推進力。因此你能看到,目前絕大多數的實施通信廠商,在web瀏覽器側的方案基本都是WebRTC了。
標準的發展,必然推進兼容支持性的提高。 本人在大概2017年作H5在線夾娃娃的預研,當時發現不少瀏覽器,尤爲移動端和IOS徹底不可用的狀態,所以不得不放棄了WebRTC方案。
目前看來瀏覽器支持的很不錯了,除了IE仍然不支持外,PC瀏覽器基本已經支持。移動端上IOS在11以上已經支持。
這裏有個關鍵在於:別光看caniuse的瀏覽器,還要看移動端各定製瀏覽器是否支持,我這裏沒有普遍的兼容性測試數據。
但能夠給出一點結論,WebRTC在最新的IOS和安卓的手Q和微信都是可使用的。
上圖給的大體的學習攻略,能夠從webRTC核心API開始着手,按照demo實現諸如本地音視頻獲取及展現。 其次搭建簡單信令服務,在內網實現簡單的瀏覽器間的通信,是個不錯的嘗試。 當用起來後,再深刻李珏其鏈接穿越、傳輸的原理和相關協議,最後再嘗試深刻挖掘webrtc內部音視頻相關知識。
以上就是對於web前端而言比較容易理解且全面的webrtc基礎介紹。
參考文章