瀏覽器自己不支持相互之間直接創建信道進行通訊,都是經過服務器進行中轉。好比如今有兩個客戶端,甲和乙,他們倆想要通訊,首先須要甲和服務器、乙和服務器之間創建信道。甲給乙發送消息時,甲先將消息發送到服務器上,服務器對甲的消息進行中轉,發送到乙處,反過來也是同樣。這樣甲與乙之間的一次消息要經過兩段信道,通訊的效率同時受制於這兩段信道的帶寬。同時這樣的信道並不適合數據流的傳輸,如何創建瀏覽器之間的點對點傳輸,一直困擾着開發者。javascript
WebRTC 是一個開源項目,旨在使得瀏覽器能爲實時通訊(RTC)提供簡單的 JavaScript 接口。WebRTC 不只可傳輸視頻,也能夠傳輸其餘數據例如文本、圖片等。須要注意的是,WebRTC 並非瀏覽器的一個子集,瀏覽器只是根據 WebRTC 的標準協議實現了 WebRTC 的原生接口。Android 和 IOS 系統也支持 WebRTC 。html
WebRTC 應用包括下面四個主要的概念:java
信令服務器(Signalling servers)web
ICE 服務器(ICE servers)segmentfault
媒體服務器 (Media servers)瀏覽器
JavaScript 接口 (JavaScript API)服務器
信令服務器主要用於在兩個用戶之間交換信息。雖然 WebRTC 是點對點通訊,但仍是須要服務器來初始化鏈接,並傳遞一些信息。
WebRTC 沒有定義用於創建信道的信令的協議,所以可使用任意的傳輸方式,例如 WebSocket, XMPP, SIP, AJAX。網絡
你可使用實時的傳輸協議好比 WebSocket 來交換數據,也可使用簡單的 GET/POST 方式輪詢服務器來獲取數據。ide
信令服務器傳送的數據有:google
協商媒體功能和設置
標識和驗證會話參與者的身份
控制媒體會話、指示進度、更改會話和終止會話
其中只有第一項的必備功能。其餘均可以根據業務需求自由調整。
媒體協商最重要的功能在於,爲參與點對點通訊的兩個瀏覽器之間交換會話描述協議(SDP)。SDP 包含瀏覽器的 RTP 媒體棧配置所需的所有信息,包括媒體類型(音頻、視頻、數據)、所需的編解碼器,用於編解碼器的哥哥參數或設置,以及有關帶寬的信息。此外,信令通道還用於交換候選地址,以便進行 ICE 打洞。
實現點對點通訊的關鍵在於兩個瀏覽器之間能直接發送和接收數據包,但通常狀況下,瀏覽器或手機都是經過路由器訪問 Internet,因此存在網絡地址轉換(NAT)。位於 NAT 以內的 IP 地址是私有地址,外部沒法訪問。分配給 NAT 的 IP 地址纔是公共地址。NAT 每次從內部到外部轉發數據包時都使用公共地址。
交互式創建鏈接(ICE)是一種標準穿透協議,它利用 STUN 和 TURN 服務器來創建鏈接。
STUN 服務器能夠遍歷 NAT,獲取瀏覽器的候選地址,包括私有地址、外層 NAT 的公共 IP 地址等。通訊信令通道能夠交換候選地址,瀏覽器一旦發送並收到了候選項,就會開始進行鏈接檢查,若檢查成功,便使用該候選項發送媒體。
在大多狀況下,經過穿透能夠創建直接對等鏈接。可是,若 NAT 或防火牆限制很是嚴格,沒法創建鏈接,就只能經過 TURN 服務器中繼媒體。
媒體服務器不是必須的,但在多方會話或須要對媒體作額外處理的狀況下能夠考慮加入。對於有多個瀏覽器參與的會議,能夠採用一個集中式媒體服務器。在這種狀況下,美國瀏覽器都只需與媒體服務器創建單個鏈接便可,這種結構的優點是額可以擴展很是大的會話,同時能夠在最大限度上減小當有新加入者加入會話事美國瀏覽器所需的處理工做量。同時,媒體服務器也可對媒體進行分析、處理、保存等工做。
經過調用 navigator.getUserMedia() 能夠獲取視頻或音頻的數據,constraints 參數能夠選擇是否獲取視頻音頻。下面是一個簡單的示例
var constraints = { audio: false, video: true }; 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);
RTCPeerConnection 是 WebRTC 中最重要的一個接口,用於肯定 ICE 服務器、交換 SDP。鏈接過程以下:
建立 RTCPeerConnection 對象
RTCPeerConnection 的參數用於肯定 ICE 服務器,下面是使用了 google 開放的 STUN 服務器
let iceServer = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] }; let pc = new RTCPeerConnection(servers);
將媒體流放入 RTCPeerConnection 對象中
pc.addStream(localStream);
經過 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 打洞
當網絡候選可用時,經過信令服務器將其發送到對方瀏覽器
pc.onicecandidate = function(event) { if (event.candidate) { sendToServer(event.candidate) } };
當接受到對方網絡候選時,將其加入
let candidate = new RTCIceCandidate(candidate); pc.addIceCandidate(candidate);
監聽對方發送的媒體是否可用,並播放媒體
pc.onaddstream = event => { remoteVideo.src = window.URL.createObjectURL(event.stream); }
RTCDataChannel 是 RTCPeerConnection API 的一部分,只有在建立了 RTCPeerConnection 實例後才能建立數據通道。數據通道能夠用於發送文本或是文件。
pc = new RTCPeerConnection(); dc = pc.createDataChannel('dc'); dc.onmessage = event => console.log(event.data); dc.send('text'); dc.sed(new arraybuffer(32))
在另外一端可使用 ondatachannel 得到 RTCDataChannel 對象
pc.ondatachannel = event => dc = event.channel;
https://codelabs.developers.g...