WebRTC是爲了解決實時音視頻傳輸問題,致力於提供免安裝、免插件、免專利費,人人可用的高效便捷的實時流媒體傳輸。javascript
目前實時流媒體主流有三種實現方式:WebRTC、HLS、RTMP,當你看直播網站的時候會發現不少採用了HLS(HTTP Live Streaming,http直播),它是一種把流媒體拆分紅多個獨立小文件的技術,按照播放時間請求不一樣文件,把hls的文件進行解複用以後取出音視頻數據而後丟給video去播放(Safari和安卓版的Chrome能直接播放hls)。它的優勢是:使用了傳統http協議,因此兼容性和穩定都很是好,服務端能夠把hls文件上傳到cdn,進而可以應對百萬級別觀衆的直播,缺點是延時比較大,一般在10s以上,適合觀衆和主播沒有什麼交互的場景。由於一個hls文件時間長度一般在10s以上,再加上生成文件的時間就致使延遲很大。html
它是蘋果推出的一種標準,而另外一種RTMP是Adobe推出的,使用長鏈接,是一套完整的流媒體傳輸協議,使用flv視頻容器,原生瀏覽器不支持(flash插件支持),不過可使用websocket + MSE的方式,相關的類庫比較少,在Android/IOS客戶端上的直播應該用得比較多一點。相對於HLS請求分片的形式,RTMP因爲使用長鏈接,接收不間斷的數據流,它的延遲要比HLS小不少,一般是1~3秒,因此若是觀衆和主播之間有通話或者視頻交互,這種方式的延遲是能夠接受的。前端
第3種WebRTC(Web Real Time Communication)是谷歌在2012年推出的,到如今已經有6年的發展。今年2018年3月份WebRTC 1.0正式定稿,並獲得了Safari在內的全部主流瀏覽器的支持(Edge弄了一個ORTC),WebRTC致力於高效的實時音視頻通訊,作到比RTMP提供更低的延遲和更小的緩衝率。而且官方還提供了配套的native的Andorid/IOS的庫,不過實際的實現多是套一個webview,由webview啓動webrtc,再把數據給native層渲染。vue
先介紹下WebRTC的組成。java
WebRTC由三大塊組成,以下圖所示:git
(1)getUserMedia是負責獲取用戶本地的多媒體數據,如調起攝像頭錄像等。github
(2)RTCPeerConnection是負責創建P2P鏈接以及傳輸多媒體數據。web
(3)RTCDataChannel是提供的一個信令通道,在遊戲裏面信令是實現互動的重要元素。算法
getUserMedia負責獲取用戶本地的多媒體數據,包括調起麥克風錄音、攝像頭捕獲的視頻和屏幕錄製這三種,我已經在《如何實現前端錄音功能》用到了這個API——藉助WebRTC的getUserMedia實現錄音。調攝像頭錄製視頻也是相似,方法很簡單,以下代碼所示:vuex
window.navigator.mediaDevices
.getUserMedia({video: true})
.then(mediaStream => {
// 畫到一個video元素上面
$('video')[0].srcObject = mediaStream;
});複製代碼
若是想實現錄屏(屏幕共享)的話,就把獲取媒體的參數改一下,以下代碼把參數由默認的攝像頭改爲屏幕:
navigator.mediaDevices
.getUserMedia({video: {mediaSource: 'screen'}})
.then(stream => {
videoElement.srcObject = stream;
});複製代碼
而後就會彈一個框詢問要錄製的應用窗口,以下圖所示:
例如能夠選PPT應用,就能夠開始演講了。這個目前只有firefox支持,Edge有一個相似叫getDisplayMedia,Chrome還在開發之中,可是能夠裝一個官方提供的瀏覽器插件。可見這個demo。
經過getUserMedia調起以後拿到流對象mediaStream,這個流能夠在本地渲染,同時經過RTCPeerConnection能夠傳給對方。
爲了實現客戶端的點到點鏈接(數據不需通過服務器轉發),RTCPeerConnection作了不少工做。首先須要解決的問題是局域網穿透。
要創建一個鏈接須要知道對方的IP地址和端口號,在局域網裏面一臺路由器可能會鏈接着不少臺設備,例如家庭路由器接入寬帶的時候寬帶服務商會分配一個公網的IP地址,全部連到這個路由器的設備都共用這個公網IP地址。若是兩臺設備都用了同一個端口號建立套接字去鏈接服務,這個時候就會衝突,由於對外的IP是同樣的。所以路由器須要重寫IP地址/端口號進行區分,以下圖所示:
有兩臺設備分別用了相同的端口號創建鏈接,被路由器轉換成不一樣的端口,對外網表現爲相同IP地址不一樣端口號,當服務器給這兩個端口號發送數據的時候,路由器再根據地址轉換映射表把數據轉發給相應的主機。
因此當你在本地監聽端口號爲55020,可是對外的端口號並非這個,對方用55020這個端口號是連不到你的。這個時候有兩種解決方法,第一種是在路由器設置一下端口映射,以下圖所示:
上圖的配置是把全部發往8123端口的數據包到轉到192.168.123.20這臺設備上。
可是咱們不能要求每一個用戶都這麼配他們的路由器,所以就有了穿牆打洞,基本方法是先由服務器與其中一方(Peer)創建鏈接,這個時候路由器就會創建一個端口號內網和外網的映射關係並保存起來,如上面的外網1091就能夠打到電腦的55020的應用上,這樣就打了一個洞,這個時候服務器把1091端口加上IP地址告訴另外一方(Peer),讓它用這個打好洞的地址進行鏈接。這就是創建P2P鏈接穿牆打洞的原理,最先起源於網絡遊戲,由於打網絡遊戲常常要組網,WebRTC對NAT打洞進行了標準化。
這個的有效性受制於用戶的網絡拓撲結構,由於若是路由器的映射關係既取決於內網的IP + 端口號,也取決於服務器的IP加端口號,這個時候就打不了洞了,由於服務器打的那個洞不能給另一個外網的應用程序使用(會創建不一樣的映射關係)。相反若是地址映射表只取決於內網機器的IP和端口號那麼是可行的。打不了洞的狀況下WebRTC也提供瞭解決方法,即用一個服務器轉發多媒體數據。
這套打洞的機制叫ICE(Interactive Connectivity Establishment),幫忙打洞的服務器叫TURN服務,轉發多媒體數據的服務器叫STUN服務。谷歌提供了一個turn server,在我家的網絡下只能拿到局域網的地址:
爲此筆者寫了一個demo,可打開這個連接嘗試P2P聊天(能夠用兩個tab或者兩臺電腦),效果以下圖所示:
除了默認提供的TURN服務打洞以外,還須要有一個websocket服務交換互連雙方的信息。因此須要寫一個websocket服務,我用Node.js簡單寫了一個,代碼已經傳到github:webrtc-server-client-demo,包括瀏覽器端的代碼。
這個過程以下圖所示:
首先打開攝像頭獲取到本地的mediaStream,並把它添加到RTCPeerConnection的對象裏面,而後建立一個本地的offer,這個offer主要是描述本機的一些網絡和媒體信息,採用SDP( Session Description Protocol)格式,以下所示:
v=0
o=- 4809135116782128887 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS 6ReMVBFmnh4JhjzqjNO2AVBc26Ktg0R5jCFB
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...複製代碼
而後把這個offer經過websocket服務發送給要鏈接的對方,對方收到後建立一個answer,格式、做用和offer同樣,發送給呼叫方告知被呼叫方的一些信息。當任意一方收到對方的sdp信息後就會調setRemoteDescription記錄起來。而當收到默認的ice server發來的打洞信息candidate以後,把candidate發送給對方(在setRemoteDesc以後),讓對方發起鏈接,成功的話就會觸發onaddstream事件,把事件裏的event.stream畫到video上面便可獲得對方的影像。
這就是整一個鏈接過程。
若是鏈接成功就開始傳輸多媒體數據,這裏面WebRTC作了不少工做。
WebRTC總體的架構以下圖所示(可見官網):
主要的工做包括:
(1)音視頻的編解碼(VP8/VP9/AV1)
(2)抗丟包和擁塞控制
(3)回聲和噪音消除
WebRTC一個很大的做用就體如今這裏了——提供可靠的傳輸、優質的編解碼以及回聲問題消除,筆者曾經還用了一個叫h323 plus的包作了一個項目,也是P2P鏈接。而如今這種實時多媒體傳輸功能直接內嵌到瀏覽器裏面,對於開發人員來講無疑大大地提升了開發效率。
在實際的線上項目裏面,因爲P2P連通率和穩定性並非特別樂觀,因此更多地是採用P2SP的架構,S表明Server,以下圖所示:
一方面可以提升穩定性,另外一方面可以解決一對多和多對多視頻聊天的問題。由於WebRTC比較適用於一對一的,在一對多場景讓一個用戶的流推給幾個用戶不論是性能仍是上傳帶寬均可能會有問題。
能夠作一個兼容方案,當P2P不行的時候就切到P2SP.
關於RTCDataChannel這裏不展開討論,實際場景仍是使用WebSocket比較多。
WebRTC已經被W3C發佈了1.0標準,可是暫未成爲RFC標準。WebRTC也在逐漸地發展,包括:
(1)Chrome 69使用了新的回聲消除算法AEC3
(2)VP9編碼提高了35%的質量,新的AV1編碼能夠在Chrome裏面使用
(3)包括RTCRtpSender等更加豐富的操縱API
將來的RTC將會提供更多功能:
(1)直接操做媒體流數據的能力(如今得經過CaptureStream間接操做)
(2)自定義編解碼參數的能力RTCRtpEncodeingParameters(Chrome 70)
等等。
相信WebRTC的將來是很是光明的。
【人人網招聘中高級前端】
1. 項目背景: 咱們在作一個企業級海外的SAAS CRM(客戶管理系統)產品, 前端的技術挑戰很大, 好比在咱們的網站讓客戶直接打網絡電話(直接打手機那種), 發email, 自動根據用戶場景處理業務等。
2. 技術棧背景: 也是採用比較流行的vue, vuex等框架, 通信是WebRTC, 消息分發系統用Google的FCM和蘋果的APN。服務部署在亞馬遜或谷歌雲上。服務全球客戶。
3. 另外由於產品是一個企業級用戶產品因此個方面要求比較高(好比性能,安全,多任務處理等)。因此對候選人技術要求比較高,若是您對技術特別在乎,那麼咱們的空缺提供了很好的才能發揮空間和鍛鍊成長的機會。