摘要:使用了集成了的來進行雙方的數據通信。四加入視頻流現在我們已經有了一個可靠的視頻數據傳輸通道了,下一步只需要向這個通道加入數據流即可。
歡迎關注我的知乎專欄:https://zhuanlan.zhihu.com/starkwang
在傳統的 Web 應用中,瀏覽器與瀏覽器之間是無法直接相互通信的,必須借助服務器的幫助,但是隨著 WebRTC 在各大瀏覽器中的普及,這一現狀得到了改變。
WebRTC(Web Real-Time Communication,Web實時通信),是一個支持網頁瀏覽器之間進行實時數據傳輸(包括音頻、視頻、數據流)的技術,谷歌于2011年5月開放了工程的源代碼,目前在各大瀏覽器的最新版本中都得到了不同程度的支持。
這篇文章里我們采用 WebRTC 來構建一個簡單的視頻傳輸應用。
一、關于 WebRTC 的一些基本概念傳統的視頻推流的技術實現一般是這樣的:客戶端采集視頻數據,推流到服務器上,服務器再根據具體情況將視頻數據推送到其他客戶端上。
但是 WebRTC 卻截然不同,它可以在客戶端之間直接搭建基于 UDP 的數據通道,經過簡單的握手流程之后,可以在不同設備的兩個瀏覽器內直接傳輸任意數據。
這其中的流程包括:
采集視頻流數據,創建一個 RTCPeerConnection
創建一個 SDP offer 和相應的回應
為雙方找到 ICE 候選路徑
成功創建一個 WebRTC 連接
下面我們介紹這其中涉及到的一些關鍵詞:
RTCPeerConnection 對象是 WebRTC API 的入口,它負責創建、維護一個 WebRTC 連接,以及在這個連接中的數據傳輸。目前新版本的瀏覽器大都支持了這一對象,但是由于目前 API 還不穩定,所以需要加入各個瀏覽器內核的前綴,例如 Chrome 中我們使用 webkitRTCPeerConnection 來訪問它。
為了連接到其他用戶,我們必須要對其他用戶的設備情況有所了解,比如音頻視頻的編碼解碼器、使用何種編碼格式、使用何種網絡、設備的數據處理能力,所以我們需要一張“名片”來獲得用戶的所有信息,而 SDP 為我們提供了這些功能。
一個 SDP 的握手由一個 offer 和一個 answer 組成。
通信的兩側可能會處于不同的網絡環境中,有時會存在好幾層的訪問控制、防火墻、路由跳轉,所以我們需要一種方法在復雜的網絡環境中找到對方,并且連接到相應的目標。WebRTC 使用了集成了 STUN、TURN 的 ICE 來進行雙方的數據通信。
二、創建一個 RTCPeerConnection首先我們的目標是在同一個頁面中創建兩個實時視頻,一個的數據直接來自你的攝像頭,另一個的數據來自本地創建的 WebRTC 連接??雌饋硎沁@樣的:
圖圖圖。。。。。。。
首先我們創建一個簡單的 HTML 頁面,含有兩個 video 標簽:
下面我們創建一個 main.js 文件,先封裝一下各瀏覽器的 userMedia 和 RTCPeerConnection 對象:
function hasUserMedia() { navigator.getUserMedia = navigator.getUserMedia || navigator.msGetUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; return !!navigator.getUserMedia; } function hasRTCPeerConnection() { window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection; return !!window.RTCPeerConnection; }
然后我們需要瀏覽器調用系統的攝像頭 API getUserMedia 獲得媒體流,注意要打開瀏覽器的攝像頭限制。Chrome由于安全的問題,只能在 https 下或者 localhost 下打開攝像頭。
var yourVideo = document.getElementById("yours"); var theirVideo = document.getElementById("theirs"); var yourConnection, theirConnection; if (hasUserMedia()) { navigator.getUserMedia({ video: true, audio: false }, stream => { yourVideo.src = window.URL.createObjectURL(stream); if (hasRTCPeerConnection()) { // 稍后我們實現 startPeerConnection startPeerConnection(stream); } else { alert("沒有RTCPeerConnection API"); } }, err => { console.log(err); } ) }else{ alert("沒有userMedia API") }
沒有意外的話,現在應該能在頁面中看到一個視頻了。
下一步是實現 startPeerConnection 方法,建立傳輸視頻數據所需要的 ICE 通信路徑,這里我們以 Chrome 為例:
function startPeerConnection(stream) { //這里使用了幾個公共的stun協議服務器 var config = { "iceServers": [{ "url": "stun:stun.services.mozilla.com" }, { "url": "stun:stunserver.org" }, { "url": "stun:stun.l.google.com:19302" }] }; yourConnection = new RTCPeerConnection(config); theirConnection = new RTCPeerConnection(config); yourConnection.onicecandidate = function(e) { if (e.candidate) { theirConnection.addIceCandidate(new RTCIceCandidate(e.candidate)); } } theirConnection.onicecandidate = function(e) { if (e.candidate) { yourConnection.addIceCandidate(new RTCIceCandidate(e.candidate)); } } }
我們使用這個函數創建了兩個連接對象,在 config 里,你可以任意指定 ICE 服務器,雖然有些瀏覽器內置了默認的 ICE 服務器,可以不用配置,但還是建議加上這些配置。下面,我們進行 SDP 的握手。
由于是在同一頁面中進行的通信,所以我們可以直接交換雙方的 candidate 對象,但在不同頁面中,可能需要一個額外的服務器協助這個交換流程。
三、建立 SDP Offer 和 SDP Answer瀏覽器為我們封裝好了相應的 Offer 和 Answer 方法,我們可以直接使用。
function startPeerConnection(stream) { var config = { "iceServers": [{ "url": "stun:stun.services.mozilla.com" }, { "url": "stun:stunserver.org" }, { "url": "stun:stun.l.google.com:19302" }] }; yourConnection = new RTCPeerConnection(config); theirConnection = new RTCPeerConnection(config); yourConnection.onicecandidate = function(e) { if (e.candidate) { theirConnection.addIceCandidate(new RTCIceCandidate(e.candidate)); } } theirConnection.onicecandidate = function(e) { if (e.candidate) { yourConnection.addIceCandidate(new RTCIceCandidate(e.candidate)); } } //本方產生了一個offer yourConnection.createOffer().then(offer => { yourConnection.setLocalDescription(offer); //對方接收到這個offer theirConnection.setRemoteDescription(offer); //對方產生一個answer theirConnection.createAnswer().then(answer => { theirConnection.setLocalDescription(answer); //本方接收到一個answer yourConnection.setRemoteDescription(answer); }) }); }
和 ICE 的連接一樣,由于我們是在同一個頁面中進行 SDP 的握手,所以不需要借助任何其他的通信手段來交換 offer 和 answer,直接賦值即可。如果需要在兩個不同的頁面中進行交換,則需要借助一個額外的服務器來協助,可以采用 websocket 或者其它手段進行這個交換過程。
四、加入視頻流現在我們已經有了一個可靠的視頻數據傳輸通道了,下一步只需要向這個通道加入數據流即可。WebRTC 直接為我們封裝好了加入視頻流的接口,當視頻流添加時,另一方的瀏覽器會通過 onaddstream 來告知用戶,通道中有視頻流加入。
yourConnection.addStream(stream); theirConnection.onaddstream = function(e) { theirVideo.src = window.URL.createObjectURL(e.stream); }
以下是完整的 main.js 代碼:
function hasUserMedia() { navigator.getUserMedia = navigator.getUserMedia || navigator.msGetUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; return !!navigator.getUserMedia; } function hasRTCPeerConnection() { window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection; return !!window.RTCPeerConnection; } var yourVideo = document.getElementById("yours"); var theirVideo = document.getElementById("theirs"); var yourConnection, theirConnection; if (hasUserMedia()) { navigator.getUserMedia({ video: true, audio: false }, stream => { yourVideo.src = window.URL.createObjectURL(stream); if (hasRTCPeerConnection()) { startPeerConnection(stream); } else { alert("沒有RTCPeerConnection API"); } }, err => { console.log(err); }) } else { alert("沒有userMedia API") } function startPeerConnection(stream) { var config = { "iceServers": [{ "url": "stun:stun.services.mozilla.com" }, { "url": "stun:stunserver.org" }, { "url": "stun:stun.l.google.com:19302" }] }; yourConnection = new RTCPeerConnection(config); theirConnection = new RTCPeerConnection(config); yourConnection.onicecandidate = function(e) { if (e.candidate) { theirConnection.addIceCandidate(new RTCIceCandidate(e.candidate)); } } theirConnection.onicecandidate = function(e) { if (e.candidate) { yourConnection.addIceCandidate(new RTCIceCandidate(e.candidate)); } } theirConnection.onaddstream = function(e) { theirVideo.src = window.URL.createObjectURL(e.stream); } yourConnection.addStream(stream); yourConnection.createOffer().then(offer => { yourConnection.setLocalDescription(offer); theirConnection.setRemoteDescription(offer); theirConnection.createAnswer().then(answer => { theirConnection.setLocalDescription(answer); yourConnection.setRemoteDescription(answer); }) }); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79888.html
摘要:最后,消息成功抵達并顯示在頁面上。在中,所有的數據都使用數據報傳輸層安全性。如果應用知識簡單的一對一文件傳輸,使用不可靠的數據通道將需要設計一定的響應重傳協議。目前建議的最大塊大小為。 本文翻譯自WebRTC data channels 在兩個瀏覽器中,為聊天、游戲、或是文件傳輸等需求發送信息是十分復雜的。通常情況下,我們需要建立一臺服務器來轉發數據,當然規模比較大的情況下,會擴展成...
摘要:下面我們就看一下具體如何申請權限靜態權限申請在項目中的中增加以下代碼動態權限申請隨著的發展,對安全性要求越來越高。其定義如下通過上面的代碼我們就將顯示視頻的定義好了。當發送消息,并收到服務端的后,其狀態變為。 作者:李超,如遇到相關問題,可以點擊這里與作者直接交流。 前言 在學習 WebRTC 的過程中,學習的一個基本步驟是先通過 JS 學習 WebRTC的整體流程,在熟悉了整體流程之后,...
摘要:而現在我們可以利用多種工具框架進行跨平臺開發。實現視頻會議的幾種思路如何利用實現一個視頻會議應用這主要取決于使用什么技術來實現作為業務核心的部分。通過與技術結合,實現了網頁端多方音視頻通訊,可以快速實現部分的開發。 作者簡介:張乾澤,聲網 Agora Web 研發工程師 對于在線教育、醫療、視頻會議等場景來講,開發面向 Windows、Mac 的跨平臺客戶端是必不可少的一步。在過去,每...
摘要:為了使連接起作用,對等方必須獲取元數據的本地媒體條件例如,分辨率和編解碼器功能,并收集應用程序主機的可能網絡地址,用于來回傳遞這些關鍵信息的信令機制并未內置到中。所有特定于多媒體的元數據都使用協議傳遞。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 18 篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前面的章節,可以在這里...
閱讀 3091·2023-04-25 15:44
閱讀 1875·2019-08-30 13:11
閱讀 2830·2019-08-30 11:11
閱讀 3003·2019-08-29 17:21
閱讀 1306·2019-08-29 15:38
閱讀 897·2019-08-29 12:49
閱讀 1792·2019-08-28 18:19
閱讀 3221·2019-08-26 14:01