webRTC是Google在2010年收購GIP公司以後得到的一項技術。以下圖所示,它提供了音視頻的採集、處理(降噪,回聲消除等)、編解碼、傳輸等技術。html
webRTC的目標是實現無需安裝任何插件就能夠經過瀏覽器進行P2P的實時音視頻通話及文件傳輸,來看看Google的demo,是否是很酷?本文將帶你分析webRTC的原理,並逐步編寫一個簡單的demo。前端
如圖,瀏覽器之間媒體流的傳輸是P2P的,可是這並不意味着webRTC不須要服務器支持。創建P2P視頻鏈接須要的信息,如用來初始化通訊的session信息,雙方的ip、端口,視頻分辨率,編解碼格式等等,仍是須要經過服務器來傳輸的。webRTC沒有規定這些信息傳輸的機制,XHR、webSocket、Socket.io等都是能夠的,由於Socket.io自帶了房間的概念,便於雙向視頻的撮合,因此我在demo裏選擇了Socket.io。html5
固然,鏈接創建的過程不會這麼簡單。首先,提到P2P就繞不開NAT(Network Address Translation),webRTC使用ICE(Interactive Connectivity Establishment)框架,ICE是一種綜合性的NAT穿越技術,它整合了STUN、TURN。當穿越網絡時,ICE會先嚐試STUN,查出本身位於哪一種類型的NAT以後以及NAT爲某一個本地端口所綁定的Internet端端口從而創建UDP鏈接,若是失敗了ICE就會再嘗試TCP(先嚐試HTTP,再嘗試HTTPS),若是仍然失敗就使用中繼的TURN服務器。
ios
再來看看創建鏈接過程當中的具體步驟:git
var constraints = { audio: false, video: true }; navigator.mediaDevices.getUserMedia(constraints) .then(gotStream) .catch(function(e) { alert('getUserMedia() error: ' + e.name); }); function gotStream(stream) { localVideo.srcObeject = stream; localStream = stream; }
getUserMedia存在兼容性問題,須要在項目中引用webRTC官方給出的adapter.js。constraints還能夠配置video的分辨率、幀率、對移動端還能夠選擇先後攝像頭:github
var constraints = { video: { width: { min:640, ideal: 1280, max: 1920 }, height: { min: 480 ideal: 720, max: 1080 }, facingMode: 'user' // 前置攝像頭 } };
var serverConfig = { 'iceServers': [{ 'urls': 'stun:stun.l.google.com:19302' }] }; function createPeerConnection() { var pc = new RTCPeerConnection(serverConfig); pc.onicecandidate = function(e) { if (e.candidate) { pc.addIceCandidate(e.candidate); } }; // 添加對方的媒體流 pc.onaddstream = function(e) { remoteVideo.srcObeject = e.stream; remoteStream = stream; }; }
由STUN、TURN配置生成對應的RTCPeerConnection實例,再定義相關的事件處理函數,如onicecandidate、onaddstream、onremovestream等。web
function start() { pc.addstream(localStream); if (isCaller) { pc.createOffer(function(sessionDescription) { pc.setLocalDescription(sessionDescription); send(sessionDescription); // 根據不一樣的Signaling方式實現 }); if (receiveAnswer) { pc.setRemoteDescription(answer.sessionDescription); } } else { if (receiveOffer) { pc.setRemoteDescription(offer.sessionDescription); } pc.createAnswer(function(sessionDescription) { pc.setLocalDescription(sessionDescription); send(sessionDescription); }); } }
必須先getUserMedia後才能生成sessionDescription,而且只有在setLocalDescription後onicecandidate事件纔會觸發。上面代碼中的只是爲了說明大體流程,實際項目中結合socket.io的事件更容易實現。segmentfault
function stop() { pc.stop(); pc = null; }
關於socket.io有關的代碼本文沒有貼出,詳情可參考socket.io的用法。promise
按照上面的步驟能夠成功地搭建webRTC的小demo,可是可否將webRTC運用到實際項目中去呢?下面從瀏覽器兼容性和webRTC自己的性能兩個方面去分析。瀏覽器
誠然webRTC在回聲消除,圖像編解碼等方面已經作得十分出色,但它在性能上的問題仍是不可忽視的:
綜上所述,雖然webRTC具備不需安裝插件或者客戶端,開源免費,強大的網絡穿透能力,出色的音視頻處理技術等等優勢,但因爲兼容性及性能上的問題,要投入到生產中還須要時間,主要是IOS11的普及以及CPU佔用率和延時的問題。