摘要:對于接收方來說,則必須實時解碼音頻和視頻流,并適應網絡抖動和時延。另外,由于主要是用來解決實時通信的問題,可靠性并不是很重要,因此,使用作為傳輸層協議低延遲和及時性才是關鍵。握手記錄嚴格按照協議規定的順序傳輸,順序不對就報錯。
Web Real-Time Communication(Web實時通信,WebRTC)由一組標準、協議和JavaScript API組成,用于實現瀏覽器之間(端到端)的音頻、視頻及數據共享。
WebRTC使得實時通信變成一種標準功能,任何Web應用都無需借助第三方插件和專有軟件,而是通過簡單地JavaScript API即可完成。
在WebRTC中,有三個主要的知識點,理解了這三個知識點,也就理解了WebRTC的底層實現原理。這三個知識點分別是:
MediaStream:獲取音頻和視頻流
RTCPeerConnection:音頻和視頻數據通信
RTCDataChannel:任意應用數據通信
MediaStream如上所說,MediaStream主要是用于獲取音頻和視頻流。其JS實現也比較簡單,代碼如下:
"use strict"; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; var constraints = { // 音頻、視頻約束 audio: true, // 指定請求音頻Track video: { // 指定請求視頻Track mandatory: { // 對視頻Track的強制約束條件 width: {min: 320}, height: {min: 180} }, optional: [ // 對視頻Track的可選約束條件 {frameRate: 30} ] } }; var video = document.querySelector("video"); function successCallback(stream) { if (window.URL) { video.src = window.URL.createObjectURL(stream); } else { video.src = stream; } } function errorCallback(error) { console.log("navigator.getUserMedia error: ", error); } navigator.getUserMedia(constraints, successCallback, errorCallback);
在JS中,我們通過getUserMedia函數來處理音頻和視頻,該函數接收三個參數,分別是音視頻的約束,成功的回調以及失敗的回調。
在底層,瀏覽器通過音頻和視頻引擎對捕獲的原始音頻和視頻流加以處理,除了對畫質和音質增強之外,還得保證音頻和視頻的同步。
由于音頻和視頻是用來傳輸的,因此,發送方還要適應不斷變化的帶寬和客戶端之間的網絡延遲調整輸出的比特率。
對于接收方來說,則必須實時解碼音頻和視頻流,并適應網絡抖動和時延。其工作原理如下圖所示:
如上成功回調的stream對象中攜帶者一個或多個同步的Track,如果你同時在約束中設置了音頻和視頻為true,則在stream中會攜帶有音頻Track和視頻Track,每個Track在時間上是同步的。
stream的輸出可以被發送到一或多個目的地:本地的音頻或視頻元素、后期處理的JavaScript代理,或者遠程另一端。如下圖所示:
RTCPeerConnection在獲取到音頻和視頻流后,下一步要做的就是將其發送出去。但這個跟client-server模式不同,這是client-client之間的傳輸,因此,在協議層面就必須解決NAT穿透問題,否則傳輸就無從談起。
另外,由于WebRTC主要是用來解決實時通信的問題,可靠性并不是很重要,因此,WebRTC使用UDP作為傳輸層協議:低延遲和及時性才是關鍵。
在更深入講解之前,我們先來思考一下,是不是只要打開音頻、視頻,然后發送UDP包就搞定了?
當然沒那么簡單,除了要解決我們上面說的NAT穿透問題之外,還需要為每個流協商參數,對用戶數據進行加密,并且需要實現擁塞和流量控制。
我們來看一張WebRTC的分層協議圖:
ICE、STUN和TURN是通過UDP建立并維護端到端連接所必需的;SDP 是一種數據格式,用于端到端連接時協商參數;DTLS用于保障傳輸數據的安全;SCTP和SRTP屬于應用層協議,用于在UDP之上提供不同流的多路復用、擁塞和流量控制,以及部分可靠的交付和其他服務。
ICE(Interactive Connectivity Establishment,交互連接建立):由于端與端之間存在多層防火墻和NAT設備阻隔,因此我們需要一種機制來收集兩端之間公共線路的IP,而ICE則是干這件事的好幫手。
ICE代理向操作系統查詢本地IP地址
如果配置了STUN服務器,ICE代理會查詢外部STUN服務器,以取得本地端的公共IP和端口
如果配置了TURN服務器,ICE則會將TURN服務器作為一個候選項,當端到端的連接失敗,數據將通過指定的中間設備轉發。
WebRTC使用SDP(Session Description Protocol,會話描述協議)描述端到端連接的參數。
SDP不包含媒體本身的任何信息,僅用于描述"會話狀況",表現為一系列的連接屬性:要交換的媒體類型(音頻、視頻及應用數據)、網絡傳輸協議、使用的編解碼器及其設置、帶寬及其他元數據。
DTLS對TLS協議進行了擴展,為每條握手記錄明確添加了偏移字段和序號,這樣就滿足了有序交付的條件,也能讓大記錄可以被分段成多個分組并在另一端再進行組裝。
DTLS握手記錄嚴格按照TLS協議規定的順序傳輸,順序不對就報錯。最后,DTLS還要處理丟包問題:兩端都是用計時器,如果預定時間沒有收到應答,就重傳握手記錄。
為保證過程完整,兩端都要生成自己簽名的證書,然后按照常規的TLS握手協議走。但這樣的證書不能用于驗證身份,因為沒有要驗證的信任鏈。因此,在必要情況下,
應用必須自己參與各端的身份驗證:
應用可以通過登錄來驗證用戶
每一端也可以在生成SDP提議/應答時指定各自的"身份頒發機構",等對端接收到SDP消息后,可以聯系指定的身份頒發機構驗證收到的證書
SRTP為通過IP網絡交付音頻和視頻定義了標準的分組格式。SRTP本身并不對傳輸數據的及時性、可靠性或數據恢復提供任何保證機制,
它只負責把數字化的音頻采樣和視頻幀用一些元數據封裝起來,以輔助接收方處理這些流。
SCTP是一個傳輸層協議,直接在IP協議上運行,這一點跟TCP和UDP類似。不過在WebRTC這里,SCTP是在一個安全的DTLS信道中運行,而這個信道又運行在UDP之上。
由于WebRTC支持通過DataChannel API在端與端之間傳輸任意應用數據,而DataChannel就依賴于SCTP。
以上講了這么多,終于到我們的主角RTCPeerConnection,RTCPeerConnection接口負責維護每一個端到端連接的完整生命周期:
RTCPeerConnection管理穿越NAT的完整ICE工作流
RTCPeerConnection發送自動(STUN)持久化信號
RTCPeerConnection跟蹤本地流
RTCPeerConnection跟蹤遠程流
RTCPeerConnection按需觸發自動流協商
RTCPeerConnection提供必要的API,以生成連接提議,接收應答,允許我們查詢連接的當前狀態,等等
我們來看一下示例代碼:
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() { ... }DataChannel
DataChannel支持端到端的任意應用數據交換,就像WebSocket一樣,但是是端到端的。
建立RTCPeerConnection連接之后,兩端可以打開一或多個信道交換文本或二進制數據。
其示例demo如下:
var ice = { "iceServers": [ {"url": "stun:stun.l.google.com:19302"}, // google公共測試服務器 // {"url": "turn:user@turnservera.com", "credential": "pass"} ] }; // var signalingChannel = new SignalingChannel(); var pc = new RTCPeerConnection(ice); navigator.getUserMedia({"audio": true}, gotStream, logError); function gotStream(stram) { pc.addStream(stram); pc.createOffer().then(function(offer){ pc.setLocalDescription(offer); }); } pc.onicecandidate = function(evt) { // console.log(evt); if(evt.target.iceGatheringState == "complete") { pc.createOffer().then(function(offer){ // console.log(offer.sdp); // signalingChannel.send(sdp); }) } } function handleChannel(chan) { console.log(chan); chan.onerror = function(err) {} chan.onclose = function() {} chan.onopen = function(evt) { console.log("established"); chan.send("DataChannel connection established."); } chan.onmessage = function(msg){ // do something } } // 以合適的交付語義初始化新的DataChannel var dc = pc.createDataChannel("namedChannel", {reliable: false}); handleChannel(dc); pc.onDataChannel = handleChannel; function logError(){ console.log("error"); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88764.html
摘要:為了使連接起作用,對等方必須獲取元數據的本地媒體條件例如,分辨率和編解碼器功能,并收集應用程序主機的可能網絡地址,用于來回傳遞這些關鍵信息的信令機制并未內置到中。所有特定于多媒體的元數據都使用協議傳遞。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 18 篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前面的章節,可以在這里...
摘要:實時通訊系統是最近互聯網應用的一個新領域。現在的問題是,開發一個優秀的系統需要具備哪些技術儲備呢先看終端方面。各個平臺,,,底層音頻系統也需要深入了解。互聯網不是一個可靠的實時音視頻傳輸網絡。現在我們知道開發一個系統需要什么技術了。 RTC(real time communication)實時通訊系統是最近互聯網應用的一個新領域。RTC系統的應用極其廣泛,我們常見的視頻電話,會議系統,...
閱讀 2120·2023-04-26 02:19
閱讀 1913·2021-11-19 09:40
閱讀 1703·2021-09-29 09:35
閱讀 3574·2021-09-29 09:34
閱讀 4296·2021-09-07 10:16
閱讀 5529·2021-08-11 11:14
閱讀 3578·2019-08-30 15:54
閱讀 1628·2019-08-30 15:53