开始使用WebRTC
Get Started with WebRTC??機翻
原文:Get Started with WebRTC - HTML5 Rocks
無需插件即可進行實時通信
想象一下,在這樣一個世界中,您的手機、電視和計算機可以在一個通用平臺上進行通信。想象一下,將視頻聊天和對等數據共享添加到 Web 應用很容易。這就是WebRTC的愿景。
想試試嗎?WebRTC可在桌面和移動設備上使用Google Chrome,Safari,Firefox和Opera。一個好的起點是?appr.tc?的簡單視頻聊天應用程序:
快速入門
沒有時間閱讀本文或只想要代碼?
要獲得WebRTC的概述,請觀看以下Google I / O視頻或查看這些幻燈片:
或者,直接跳轉到WebRTC代碼實驗室,這是一個分步指南,解釋了如何構建一個完整的視頻聊天應用程序,包括一個簡單的信令服務器。
WebRTC的非常短的歷史
網絡面臨的最后一個主要挑戰之一是通過語音和視頻實現人類通信:實時通信或簡稱RTC。RTC 在 Web 應用中應與在文本輸入中輸入文本一樣自然。沒有它,你創新和開發新互動方式的能力就會受到限制。
從歷史上看,RTC一直是企業和復雜的,需要昂貴的音頻和視頻技術在內部許可或開發。將 RTC 技術與現有內容、數據和服務集成既困難又耗時,尤其是在 Web 上。
Gmail視頻聊天在2008年開始流行,2011年,谷歌推出了使用Talk的Hangouts(Gmail也是如此)。谷歌收購了GISP,該公司開發了RTC所需的許多組件,例如編解碼器和回聲消除技術。Google 開源了 GIPS 開發的技術,并與互聯網工程任務組 (IETF) 和萬維網聯盟 (W3C) 的相關標準機構合作,以確保行業共識。2011年5月,愛立信構建了WebRTC的第一個實現。
WebRTC為實時,無插件的視頻,音頻和數據通信實施了開放標準。需求是真實的:
- 許多 Web 服務使用 RTC,但需要下載、本機應用或插件。其中包括Skype,Facebook和Hangouts。
- 下載,安裝和更新插件很復雜,容易出錯并且很煩人。
- 插件難以部署、調試、故障排除、測試和維護,并且可能需要許可和與復雜、昂貴的技術集成。首先,通常很難說服人們安裝插件!
WebRTC項目的指導原則是,其API應該是開源的,免費的,標準化的,內置于Web瀏覽器中,并且比現有技術更有效。
我們現在在哪里?
WebRTC用于各種應用程序,例如Google Meet。WebRTC還與WebKitGTK+和Qt原生應用程序集成。
WebRTC實現了以下三個API:
- MediaStream(也稱為getUserMedia)
- RTCPeerConnection
- RTCDataChannel
API 定義在以下兩個規范中:
- WebRTC
- getUserMedia
Chrome,Safari,Firefox,Edge和Opera在移動設備和桌面上都支持這三個API。
getUserMedia:有關演示和代碼,請參閱?WebRTC 示例或嘗試 Chris Wilson 用作 Web 音頻輸入的驚人示例。getUserMedia
RTCPeerConnection:有關簡單的演示和功能齊全的視頻聊天應用程序,請參閱?WebRTC 示例分別對等連接和?appr.tc。這個應用程序使用適配器.js,一個由谷歌在WebRTC社區的幫助下維護的JavaScript填充程序,以抽象出瀏覽器的差異和規格變化。
RTCDataChannel:若要查看實際效果,請參閱?WebRTC 示例以查看其中一個數據通道演示。
WebRTC codelab?展示了如何使用所有三個 API 來構建一個簡單的應用程序,用于視頻聊天和文件共享。
您的第一個 WebRTC
WebRTC應用程序需要做幾件事:
- 獲取流式音頻、視頻或其他數據。
- 獲取網絡信息,例如 IP 地址和端口,并將其與其他 WebRTC 客戶端(稱為對等方)交換以啟用連接,甚至通過?NAT?和防火墻。
- 協調信令通信以報告錯誤并啟動或關閉會話。
- 交換有關媒體和客戶端功能的信息,如分辨率和編解碼器。
- 傳輸流式音頻、視頻或數據。
為了獲取和通信流數據,WebRTC 實現了以下 API:
- MediaStream?可以訪問數據流,例如來自用戶的攝像頭和麥克風。
- RTCPeerConnection?支持音頻或視頻通話,并提供加密和帶寬管理功能。
- RTCDataChannel?支持通用數據的對等通信。
(稍后將詳細討論WebRTC的網絡和信令方面。
MediaStream接口(也稱為接口)getUserMedia
MediaStream?API?表示同步的媒體流。例如,從攝像頭和麥克風輸入中獲取的流具有同步的視頻和音頻軌道。(不要與<track>元素混淆,這是完全不同的東西。MediaStreamTrack
理解API的最簡單方法可能是在野外查看它:MediaStream
每個都有一個輸入(可能是由 生成的),還有一個輸出(可能傳遞給視頻元素或 )。MediaStreamMediaStreamgetUserMedia()RTCPeerConnection
該方法采用?MediaStreamConstraints?對象參數,并返回解析為對象的 參數。getUserMedia()PromiseMediaStream
每個都有一個 ,例如 。由 and 方法返回 s 數組。MediaStreamlabel'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'MediaStreamTrackgetAudioTracks()getVideoTracks()
對于?getUserMedia?示例,返回一個空數組(因為沒有音頻),并且假設連接了一個工作正常的網絡攝像頭,則返回一個數組,該數組表示來自網絡攝像頭的流。每個都有一個種類 ( 或 ),a(類似于 ),并表示音頻或視頻的一個或多個通道。在這種情況下,只有一個視頻軌道,沒有音頻,但很容易想象用例中還有更多,例如從前置攝像頭,后置攝像頭,麥克風獲取流的聊天應用程序以及共享其屏幕的應用程序。stream.getAudioTracks()stream.getVideoTracks()MediaStreamTrackMediaStreamTrack'video''audio'label'FaceTime HD Camera (Built-in)'
可以通過設置?srcObject?屬性將 A?附加到視頻元素。以前,這是通過將屬性設置為使用 創建的對象 URL 來完成的,但這已被棄用。MediaStreamsrcURL.createObjectURL()
正在主動使用相機,這會占用資源,并使相機保持打開狀態并打開相機燈亮。當您不再使用軌道時,請確保呼叫以關閉攝像機。MediaStreamTracktrack.stop()
getUserMedia也可以用作 Web 音頻 API 的輸入節點:
<span style="color:white"><span style="background-color:#444444"><span style="color:#aeaeae"><em>// Cope with browser differences.</em></span><span style="color:#ffffff"> let audioContext</span><span style="color:#ffffff">;</span> <span style="color:#e28964">if</span> <span style="color:#ffffff">(</span><span style="color:#e28964">typeof</span> <span style="color:#89bdff">AudioContext</span> <span style="color:#ffffff">===</span> <span style="color:#65b042">'function'</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">audioContext </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span> <span style="color:#89bdff">AudioContext</span><span style="color:#ffffff">();</span> <span style="color:#ffffff">}</span> <span style="color:#e28964">else</span> <span style="color:#e28964">if</span> <span style="color:#ffffff">(</span><span style="color:#e28964">typeof</span><span style="color:#ffffff"> webkitAudioContext </span><span style="color:#ffffff">===</span> <span style="color:#65b042">'function'</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">audioContext </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span><span style="color:#ffffff"> webkitAudioContext</span><span style="color:#ffffff">();</span> <span style="color:#aeaeae"><em>// eslint-disable-line new-cap</em></span> <span style="color:#ffffff">}</span> <span style="color:#e28964">else</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">console</span><span style="color:#ffffff">.</span><span style="color:#ffffff">log</span><span style="color:#ffffff">(</span><span style="color:#65b042">'Sorry! Web Audio not supported.'</span><span style="color:#ffffff">);</span> <span style="color:#ffffff">}</span><span style="color:#aeaeae"><em>// Create a filter node.</em></span> <span style="color:#e28964">var</span><span style="color:#ffffff"> filterNode </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> audioContext</span><span style="color:#ffffff">.</span><span style="color:#ffffff">createBiquadFilter</span><span style="color:#ffffff">();</span> <span style="color:#aeaeae"><em>// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section</em></span><span style="color:#ffffff"> filterNode</span><span style="color:#ffffff">.</span><span style="color:#ffffff">type </span><span style="color:#ffffff">=</span> <span style="color:#65b042">'highpass'</span><span style="color:#ffffff">;</span> <span style="color:#aeaeae"><em>// Cutoff frequency. For highpass, audio is attenuated below this frequency.</em></span><span style="color:#ffffff"> filterNode</span><span style="color:#ffffff">.</span><span style="color:#ffffff">frequency</span><span style="color:#ffffff">.</span><span style="color:#ffffff">value </span><span style="color:#ffffff">=</span> <span style="color:#3387cc">10000</span><span style="color:#ffffff">;</span><span style="color:#aeaeae"><em>// Create a gain node to change audio volume.</em></span> <span style="color:#e28964">var</span><span style="color:#ffffff"> gainNode </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> audioContext</span><span style="color:#ffffff">.</span><span style="color:#ffffff">createGain</span><span style="color:#ffffff">();</span> <span style="color:#aeaeae"><em>// Default is 1 (no change). Less than 1 means audio is attenuated</em></span> <span style="color:#aeaeae"><em>// and vice versa.</em></span><span style="color:#ffffff"> gainNode</span><span style="color:#ffffff">.</span><span style="color:#ffffff">gain</span><span style="color:#ffffff">.</span><span style="color:#ffffff">value </span><span style="color:#ffffff">=</span> <span style="color:#3387cc">0.5</span><span style="color:#ffffff">;</span><span style="color:#ffffff">navigator</span><span style="color:#ffffff">.</span><span style="color:#ffffff">mediaDevices</span><span style="color:#ffffff">.</span><span style="color:#ffffff">getUserMedia</span><span style="color:#ffffff">({</span><span style="color:#ffffff">audio</span><span style="color:#ffffff">:</span> <span style="color:#e28964">true</span><span style="color:#ffffff">},</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">stream</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#aeaeae"><em>// Create an AudioNode from the stream.</em></span><span style="color:#e28964">const</span><span style="color:#ffffff"> mediaStreamSource </span><span style="color:#ffffff">=</span><span style="color:#ffffff">audioContext</span><span style="color:#ffffff">.</span><span style="color:#ffffff">createMediaStreamSource</span><span style="color:#ffffff">(</span><span style="color:#ffffff">stream</span><span style="color:#ffffff">);</span><span style="color:#ffffff">mediaStreamSource</span><span style="color:#ffffff">.</span><span style="color:#ffffff">connect</span><span style="color:#ffffff">(</span><span style="color:#ffffff">filterNode</span><span style="color:#ffffff">);</span><span style="color:#ffffff">filterNode</span><span style="color:#ffffff">.</span><span style="color:#ffffff">connect</span><span style="color:#ffffff">(</span><span style="color:#ffffff">gainNode</span><span style="color:#ffffff">);</span><span style="color:#aeaeae"><em>// Connect the gain node to the destination. For example, play the sound.</em></span><span style="color:#ffffff">gainNode</span><span style="color:#ffffff">.</span><span style="color:#ffffff">connect</span><span style="color:#ffffff">(</span><span style="color:#ffffff">audioContext</span><span style="color:#ffffff">.</span><span style="color:#ffffff">destination</span><span style="color:#ffffff">);</span> <span style="color:#ffffff">});</span></span></span>基于Chromium的應用程序和擴展程序也可以合并。通過向清單添加和/或權限,只能在安裝時請求和授予一次權限。此后,不會要求用戶獲得相機或麥克風訪問權限。getUserMediaaudioCapturevideoCapture
對于 , 只需授予一次權限。第一次,瀏覽器的信息欄中會顯示"允許"按鈕。Chrome 在 2015 年底棄用了 HTTP 訪問,因為它被歸類為功能強大的功能。getUserMedia()getUserMedia()
其意圖可能是為任何流數據源啟用 a,而不僅僅是攝像頭或麥克風。這將允許從存儲的數據或任意數據源(如傳感器或其他輸入)進行流式傳輸。MediaStream
getUserMedia()真正與其他 JavaScript API 和庫結合使用:
- 網絡攝像頭玩具是一個照相亭應用程序,它使用WebGL為可以在本地共享或保存的照片添加奇怪而美妙的效果。
- FaceKat是一款使用headtrackr.js構建的面部跟蹤游戲。
- ASCII 相機使用 Canvas API 生成 ASCII 圖像。
正在上傳…重新上傳取消
咕嚕咕嚕的藝術!
約束
約束可用于設置 的視頻分辨率值。這也允許支持其他約束,例如寬高比;對置模式(前置或后置攝像頭);幀速率,高度和寬度;和?applyConstraints()?方法。getUserMedia()
有關示例,請參閱?WebRTC 示例?getUserMedia:選擇分辨率。
一個陷阱:約束可能會影響共享資源的可用配置。例如,如果相機在 640 x 480 模式下通過一個選項卡打開,則另一個選項卡將無法使用約束以更高分辨率模式打開它,因為它只能在一種模式下打開。請注意,這是一個實現細節??梢宰尩诙€選項卡以更高分辨率的模式重新打開相機,并使用視頻處理將第一個選項卡的視頻軌道縮小到640 x 480,但尚未實現。getUserMedia
設置不允許的約束值會給出 a 或 a,例如,如果請求的分辨率不可用。若要查看此操作的實際效果,請參閱?WebRTC 示例?getUserMedia:為演示選擇分辨率。DOMExceptionOverconstrainedError
屏幕和選項卡捕獲
Chrome 應用還允許通過?chrome.tabCapture 和 chrome.desktopCapture?API 共享單個瀏覽器標簽頁或整個桌面的實時視頻。(有關演示和更多信息,請參閱使用 WebRTC 進行屏幕共享。這篇文章已經有幾年的歷史了,但它仍然很有趣。
在 Chrome 中,也可以使用實驗性約束將屏幕捕獲用作源。請注意,屏幕捕獲需要 HTTPS,并且只能用于開發,因為它是通過命令行標志啟用的,如本文所述。MediaStreamchromeMediaSource
信令:會話控制、網絡和媒體信息
WebRTC用于在瀏覽器(也稱為對等體)之間傳輸流數據,但也需要一種機制來協調通信和發送控制消息,這一過程稱為信令。WebRTC未指定信令方法和協議。信令不是 API 的一部分。RTCPeerConnectionRTCPeerConnection
相反,WebRTC應用程序開發人員可以選擇他們喜歡的任何消息傳遞協議,例如SIP或XMPP,以及任何適當的雙工(雙向)通信通道。appr.tc?示例使用 XHR 和通道 API 作為信令機制。代碼實驗室使用在?Node?服務器上運行的 Socket.io。
信令用于交換三種類型的信息:
- 會話控制消息:初始化或關閉通信并報告錯誤。
- 網絡配置:對外界來說,你電腦的IP地址和端口是什么?
- 媒體功能:您的瀏覽器和要與之通信的瀏覽器可以處理哪些編解碼器和分辨率?
通過信令進行的信息交換必須已成功完成,然后才能開始對等流。
例如,假設愛麗絲想和鮑勃交流。下面是?W3C WebRTC 規范中的代碼示例,其中顯示了運行中的信令過程。該代碼假定存在該方法中創建的某些信令機制。另請注意,在 Chrome 和 Opera 上,當前帶有前綴。createSignalingChannel()RTCPeerConnection
<span style="color:white"><span style="background-color:#444444"><span style="color:#aeaeae"><em>// handles JSON.stringify/parse</em></span> <span style="color:#e28964">const</span><span style="color:#ffffff"> signaling </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span> <span style="color:#89bdff">SignalingChannel</span><span style="color:#ffffff">();</span> <span style="color:#e28964">const</span><span style="color:#ffffff"> constraints </span><span style="color:#ffffff">=</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">audio</span><span style="color:#ffffff">:</span> <span style="color:#e28964">true</span><span style="color:#ffffff">,</span><span style="color:#ffffff"> video</span><span style="color:#ffffff">:</span> <span style="color:#e28964">true</span><span style="color:#ffffff">};</span> <span style="color:#e28964">const</span><span style="color:#ffffff"> configuration </span><span style="color:#ffffff">=</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">iceServers</span><span style="color:#ffffff">:</span> <span style="color:#ffffff">[{</span><span style="color:#ffffff">urls</span><span style="color:#ffffff">:</span> <span style="color:#65b042">'stuns:stun.example.org'</span><span style="color:#ffffff">}]};</span> <span style="color:#e28964">const</span><span style="color:#ffffff"> pc </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span> <span style="color:#89bdff">RTCPeerConnection</span><span style="color:#ffffff">(</span><span style="color:#ffffff">configuration</span><span style="color:#ffffff">);</span><span style="color:#aeaeae"><em>// Send any ice candidates to the other peer.</em></span><span style="color:#ffffff"> pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">onicecandidate </span><span style="color:#ffffff">=</span> <span style="color:#ffffff">({</span><span style="color:#ffffff">candidate</span><span style="color:#ffffff">})</span> <span style="color:#ffffff">=></span><span style="color:#ffffff"> signaling</span><span style="color:#ffffff">.</span><span style="color:#ffffff">send</span><span style="color:#ffffff">({</span><span style="color:#ffffff">candidate</span><span style="color:#ffffff">});</span><span style="color:#aeaeae"><em>// Let the "negotiationneeded" event trigger offer generation.</em></span><span style="color:#ffffff"> pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">onnegotiationneeded </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> async </span><span style="color:#ffffff">()</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#e28964">try</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">await pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">setLocalDescription</span><span style="color:#ffffff">(</span><span style="color:#ffffff">await pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">createOffer</span><span style="color:#ffffff">());</span><span style="color:#aeaeae"><em>// Send the offer to the other peer.</em></span><span style="color:#ffffff">signaling</span><span style="color:#ffffff">.</span><span style="color:#ffffff">send</span><span style="color:#ffffff">({</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">:</span><span style="color:#ffffff"> pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">localDescription</span><span style="color:#ffffff">});</span><span style="color:#ffffff">}</span> <span style="color:#e28964">catch</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">err</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">console</span><span style="color:#ffffff">.</span><span style="color:#ffffff">error</span><span style="color:#ffffff">(</span><span style="color:#ffffff">err</span><span style="color:#ffffff">);</span><span style="color:#ffffff">}</span> <span style="color:#ffffff">};</span><span style="color:#aeaeae"><em>// Once remote track media arrives, show it in remote video element.</em></span><span style="color:#ffffff"> pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">ontrack </span><span style="color:#ffffff">=</span> <span style="color:#ffffff">(</span><span style="color:#e28964">event</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#aeaeae"><em>// Don't set srcObject again if it is already set.</em></span><span style="color:#e28964">if</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">remoteView</span><span style="color:#ffffff">.</span><span style="color:#ffffff">srcObject</span><span style="color:#ffffff">)</span> <span style="color:#e28964">return</span><span style="color:#ffffff">;</span><span style="color:#ffffff">remoteView</span><span style="color:#ffffff">.</span><span style="color:#ffffff">srcObject </span><span style="color:#ffffff">=</span> <span style="color:#e28964">event</span><span style="color:#ffffff">.</span><span style="color:#ffffff">streams</span><span style="color:#ffffff">[</span><span style="color:#3387cc">0</span><span style="color:#ffffff">];</span> <span style="color:#ffffff">};</span><span style="color:#aeaeae"><em>// Call start() to initiate.</em></span><span style="color:#ffffff"> async </span><span style="color:#e28964">function</span><span style="color:#ffffff"> start</span><span style="color:#ffffff">()</span> <span style="color:#ffffff">{</span><span style="color:#e28964">try</span> <span style="color:#ffffff">{</span><span style="color:#aeaeae"><em>// Get local stream, show it in self-view, and add it to be sent.</em></span><span style="color:#e28964">const</span><span style="color:#ffffff"> stream </span><span style="color:#ffffff">=</span><span style="color:#ffffff">await navigator</span><span style="color:#ffffff">.</span><span style="color:#ffffff">mediaDevices</span><span style="color:#ffffff">.</span><span style="color:#ffffff">getUserMedia</span><span style="color:#ffffff">(</span><span style="color:#ffffff">constraints</span><span style="color:#ffffff">);</span><span style="color:#ffffff">stream</span><span style="color:#ffffff">.</span><span style="color:#ffffff">getTracks</span><span style="color:#ffffff">().</span><span style="color:#ffffff">forEach</span><span style="color:#ffffff">((</span><span style="color:#ffffff">track</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">=></span><span style="color:#ffffff">pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">addTrack</span><span style="color:#ffffff">(</span><span style="color:#ffffff">track</span><span style="color:#ffffff">,</span><span style="color:#ffffff"> stream</span><span style="color:#ffffff">));</span><span style="color:#ffffff">selfView</span><span style="color:#ffffff">.</span><span style="color:#ffffff">srcObject </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> stream</span><span style="color:#ffffff">;</span><span style="color:#ffffff">}</span> <span style="color:#e28964">catch</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">err</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">console</span><span style="color:#ffffff">.</span><span style="color:#ffffff">error</span><span style="color:#ffffff">(</span><span style="color:#ffffff">err</span><span style="color:#ffffff">);</span><span style="color:#ffffff">}</span> <span style="color:#ffffff">}</span><span style="color:#ffffff">signaling</span><span style="color:#ffffff">.</span><span style="color:#ffffff">onmessage </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> async </span><span style="color:#ffffff">({</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">,</span><span style="color:#ffffff"> candidate</span><span style="color:#ffffff">})</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#e28964">try</span> <span style="color:#ffffff">{</span><span style="color:#e28964">if</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#aeaeae"><em>// If you get an offer, you need to reply with an answer.</em></span><span style="color:#e28964">if</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">type </span><span style="color:#ffffff">===</span> <span style="color:#65b042">'offer'</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">await pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">setRemoteDescription</span><span style="color:#ffffff">(</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">);</span><span style="color:#e28964">const</span><span style="color:#ffffff"> stream </span><span style="color:#ffffff">=</span><span style="color:#ffffff">await navigator</span><span style="color:#ffffff">.</span><span style="color:#ffffff">mediaDevices</span><span style="color:#ffffff">.</span><span style="color:#ffffff">getUserMedia</span><span style="color:#ffffff">(</span><span style="color:#ffffff">constraints</span><span style="color:#ffffff">);</span><span style="color:#ffffff">stream</span><span style="color:#ffffff">.</span><span style="color:#ffffff">getTracks</span><span style="color:#ffffff">().</span><span style="color:#ffffff">forEach</span><span style="color:#ffffff">((</span><span style="color:#ffffff">track</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">=></span><span style="color:#ffffff">pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">addTrack</span><span style="color:#ffffff">(</span><span style="color:#ffffff">track</span><span style="color:#ffffff">,</span><span style="color:#ffffff"> stream</span><span style="color:#ffffff">));</span><span style="color:#ffffff">await pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">setLocalDescription</span><span style="color:#ffffff">(</span><span style="color:#ffffff">await pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">createAnswer</span><span style="color:#ffffff">());</span><span style="color:#ffffff">signaling</span><span style="color:#ffffff">.</span><span style="color:#ffffff">send</span><span style="color:#ffffff">({</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">:</span><span style="color:#ffffff"> pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">localDescription</span><span style="color:#ffffff">});</span><span style="color:#ffffff">}</span> <span style="color:#e28964">else</span> <span style="color:#e28964">if</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">type </span><span style="color:#ffffff">===</span> <span style="color:#65b042">'answer'</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">await pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">setRemoteDescription</span><span style="color:#ffffff">(</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">);</span><span style="color:#ffffff">}</span> <span style="color:#e28964">else</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">console</span><span style="color:#ffffff">.</span><span style="color:#ffffff">log</span><span style="color:#ffffff">(</span><span style="color:#65b042">'Unsupported SDP type.'</span><span style="color:#ffffff">);</span><span style="color:#ffffff">}</span><span style="color:#ffffff">}</span> <span style="color:#e28964">else</span> <span style="color:#e28964">if</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">candidate</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">await pc</span><span style="color:#ffffff">.</span><span style="color:#ffffff">addIceCandidate</span><span style="color:#ffffff">(</span><span style="color:#ffffff">candidate</span><span style="color:#ffffff">);</span><span style="color:#ffffff">}</span><span style="color:#ffffff">}</span> <span style="color:#e28964">catch</span> <span style="color:#ffffff">(</span><span style="color:#ffffff">err</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">console</span><span style="color:#ffffff">.</span><span style="color:#ffffff">error</span><span style="color:#ffffff">(</span><span style="color:#ffffff">err</span><span style="color:#ffffff">);</span><span style="color:#ffffff">}</span> <span style="color:#ffffff">};</span></span></span>首先,Alice 和 Bob 交換網絡信息。(表達式查找候選項是指使用?ICE 框架查找網絡接口和端口的過程。
WebRTC 客戶端(也稱為對等體,在本例中稱為 Alice 和 Bob)還需要確定和交換本地和遠程音頻和視頻媒體信息,例如解析和編解碼器功能。通過會話描述協議 (SDP) 交換產品/服務和答案來發出信號以交換媒體配置信息:
確保允許 在不再需要時通過調用來回收 垃圾回收。否則,線程和連接將保持活動狀態。在WebRTC中可能會泄漏大量資源!RTCPeerConnectionclose()
RTCSessionDescription對象是符合會話描述協議?SDP 的 Blob。序列化后,SDP 對象如下所示:
<span style="color:white"><span style="background-color:#444444"><span style="color:#ffffff">v</span><span style="color:#ffffff">=</span><span style="color:#3387cc">0</span><span style="color:#ffffff"> o</span><span style="color:#ffffff">=-</span> <span style="color:#3387cc">3883943731</span> <span style="color:#3387cc">1</span><span style="color:#ffffff"> IN IP4 </span><span style="color:#3387cc">127.0</span><span style="color:#ffffff">.</span><span style="color:#3387cc">0.1</span><span style="color:#ffffff"> s</span><span style="color:#ffffff">=</span><span style="color:#ffffff"> t</span><span style="color:#ffffff">=</span><span style="color:#3387cc">0</span> <span style="color:#3387cc">0</span><span style="color:#ffffff"> a</span><span style="color:#ffffff">=</span><span style="color:#e28964">group</span><span style="color:#ffffff">:</span><span style="color:#ffffff">BUNDLE audio video m</span><span style="color:#ffffff">=</span><span style="color:#ffffff">audio </span><span style="color:#3387cc">1</span><span style="color:#ffffff"> RTP</span><span style="color:#ffffff">/</span><span style="color:#ffffff">SAVPF </span><span style="color:#3387cc">103</span> <span style="color:#3387cc">104</span> <span style="color:#3387cc">0</span> <span style="color:#3387cc">8</span> <span style="color:#3387cc">106</span> <span style="color:#3387cc">105</span> <span style="color:#3387cc">13</span> <span style="color:#3387cc">126</span><span style="color:#aeaeae"><em>// ...</em></span><span style="color:#ffffff">a</span><span style="color:#ffffff">=</span><span style="color:#ffffff">ssrc</span><span style="color:#ffffff">:</span><span style="color:#3387cc">2223794119</span><span style="color:#ffffff"> label</span><span style="color:#ffffff">:</span><span style="color:#ffffff">H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810</span></span></span>網絡和媒體信息的獲取和交換可以同時完成,但是在對等體之間的音頻和視頻流開始之前,這兩個過程必須已經完成。
前面描述的要約/答案體系結構稱為?JavaScript 會話建立協議或 JSEP。(在愛立信的第一個WebRTC實現的演示視頻中,有一個很棒的動畫解釋了信令和流式傳輸的過程。
JSEP 架構
一旦信令過程成功完成,數據就可以在呼叫者和被叫方之間直接對等流式傳輸,或者,如果失敗,則通過中間中繼服務器(稍后將詳細介紹)。流式傳輸是 的工作。RTCPeerConnection
RTCPeerConnection
RTCPeerConnection是 WebRTC 組件,用于處理對等體之間流數據的穩定和高效通信。
下面是一個 WebRTC 體系結構圖,顯示了 的作用。您會注意到,綠色部分很復雜!RTCPeerConnection
正在上傳…重新上傳取消
WebRTC架構(來自?webrtc.org)
從JavaScript的角度來看,從這張圖中要了解的主要內容是,它保護Web開發人員免受潛伏在背后的無數復雜性的影響。WebRTC使用的編解碼器和協議做了大量的工作,使實時通信成為可能,即使在不可靠的網絡上也是如此:RTCPeerConnection
- 丟包隱蔽
- 回聲消除
- 帶寬適應性
- 動態抖動緩沖
- 自動增益控制
- 降噪和抑制
- 圖像清理
前面的 W3C 代碼從信令角度展示了 WebRTC 的簡化示例。以下是兩個工作 WebRTC 應用程序的演練。第一個是要演示的簡單示例,第二個是完全可操作的視頻聊天客戶端。RTCPeerConnection
沒有服務器的 RTCPeerConnection
以下代碼取自?WebRTC 示例對等連接,該連接在一個網頁上具有本地和遠程(以及本地和遠程視頻)。這并不構成任何非常有用的東西 - 調用方和被調用方在同一頁面上 - 但它確實使API的工作原理更加清晰,因為頁面上的對象可以直接交換數據和消息,而無需使用中間信令機制。RTCPeerConnectionRTCPeerConnectionRTCPeerConnection
在此示例中,表示本地對等方(調用方)和遠程對等方(被調用方)。pc1pc2
訪客
創建一個新流并從中添加流:RTCPeerConnectiongetUserMedia()
<span style="color:white"><span style="background-color:#444444"><span style="color:#aeaeae"><em>// Servers is an optional configuration file. (See TURN and STUN discussion later.)</em></span><span style="color:#ffffff"> pc1 </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span> <span style="color:#89bdff">RTCPeerConnection</span><span style="color:#ffffff">(</span><span style="color:#ffffff">servers</span><span style="color:#ffffff">);</span> <span style="color:#aeaeae"><em>// ...</em></span><span style="color:#ffffff"> localStream</span><span style="color:#ffffff">.</span><span style="color:#ffffff">getTracks</span><span style="color:#ffffff">().</span><span style="color:#ffffff">forEach</span><span style="color:#ffffff">((</span><span style="color:#ffffff">track</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#ffffff">pc1</span><span style="color:#ffffff">.</span><span style="color:#ffffff">addTrack</span><span style="color:#ffffff">(</span><span style="color:#ffffff">track</span><span style="color:#ffffff">,</span><span style="color:#ffffff"> localStream</span><span style="color:#ffffff">);</span> <span style="color:#ffffff">});</span></span></span>創建產品/服務并將其設置為 的本地描述和 遠程描述。這可以直接在代碼中完成,而無需使用信令,因為調用方和被調用方都在同一頁面上:pc1pc2
<span style="color:white"><span style="background-color:#444444"><span style="color:#ffffff">pc1</span><span style="color:#ffffff">.</span><span style="color:#ffffff">setLocalDescription</span><span style="color:#ffffff">(</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">).</span><span style="color:#e28964">then</span><span style="color:#ffffff">(()</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#ffffff">onSetLocalSuccess</span><span style="color:#ffffff">(</span><span style="color:#ffffff">pc1</span><span style="color:#ffffff">);</span><span style="color:#ffffff">},</span><span style="color:#ffffff">onSetSessionDescriptionError</span><span style="color:#ffffff">);</span><span style="color:#ffffff">trace</span><span style="color:#ffffff">(</span><span style="color:#65b042">'pc2 setRemoteDescription start'</span><span style="color:#ffffff">);</span><span style="color:#ffffff">pc2</span><span style="color:#ffffff">.</span><span style="color:#ffffff">setRemoteDescription</span><span style="color:#ffffff">(</span><span style="color:#ffffff">desc</span><span style="color:#ffffff">).</span><span style="color:#e28964">then</span><span style="color:#ffffff">(()</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#ffffff">onSetRemoteSuccess</span><span style="color:#ffffff">(</span><span style="color:#ffffff">pc2</span><span style="color:#ffffff">);</span><span style="color:#ffffff">},</span><span style="color:#ffffff">onSetSessionDescriptionError</span><span style="color:#ffffff">);</span></span></span>被叫方
創建并在添加來自 的流時,將其顯示在視頻元素中:pc2pc1
<span style="color:white"><span style="background-color:#444444"><span style="color:#ffffff">pc2 </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span> <span style="color:#89bdff">RTCPeerConnection</span><span style="color:#ffffff">(</span><span style="color:#ffffff">servers</span><span style="color:#ffffff">);</span><span style="color:#ffffff"> pc2</span><span style="color:#ffffff">.</span><span style="color:#ffffff">ontrack </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> gotRemoteStream</span><span style="color:#ffffff">;</span> <span style="color:#aeaeae"><em>//...</em></span> <span style="color:#e28964">function</span><span style="color:#ffffff"> gotRemoteStream</span><span style="color:#ffffff">(</span><span style="color:#ffffff">e</span><span style="color:#ffffff">){</span><span style="color:#ffffff">vid2</span><span style="color:#ffffff">.</span><span style="color:#ffffff">srcObject </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> e</span><span style="color:#ffffff">.</span><span style="color:#ffffff">stream</span><span style="color:#ffffff">;</span> <span style="color:#ffffff">}</span></span></span>RTCPeerConnectionAPI 加服務器
在現實世界中,WebRTC需要服務器,無論多么簡單,因此可能會發生以下情況:
- 用戶發現彼此并交換真實世界的詳細信息,例如名稱。
- WebRTC客戶端應用程序(對等體)交換網絡信息。
- 對等方交換有關媒體的數據,例如視頻格式和分辨率。
- WebRTC 客戶端應用程序遍歷?NAT 網關和防火墻。
換句話說,WebRTC需要四種類型的服務器端功能:
- 用戶發現和通信
- 信號
- NAT/防火墻遍歷
- 對等通信失敗時的中繼服務器
NAT 遍歷、對等網絡以及構建用于用戶發現和信令的服務器應用的要求超出了本文的討論范圍??梢哉f,ICE框架使用STUN協議及其擴展名TURN來應對NAT遍歷和其他網絡變幻莫測。RTCPeerConnection
ICE 是用于連接對等方(如兩個視頻聊天客戶端)的框架。最初,ICE 嘗試通過 UDP 以盡可能低的延遲直接連接對等方。在此過程中,STUN 服務器只有一個任務:使 NAT 后面的對等方能夠查找其公共地址和端口。(有關 STUN 和 TURN 的詳細信息,請參閱構建 WebRTC 應用所需的后端服務。
查找連接候選項
如果 UDP 失敗,ICE 將嘗試 TCP。如果直接連接失敗(特別是由于企業 NAT 遍歷和防火墻),ICE 將使用中間(中繼)TURN 服務器。換句話說,ICE 首先將 STUN 與 UDP 結合使用來直接連接對等體,如果失敗,則回退到 TURN 中繼服務器。表達式查找候選項是指查找網絡接口和端口的過程。
WebRTC數據路徑
WebRTC工程師Justin Uberti在2013年Google I / O WebRTC演示中提供了有關ICE,STUN和TURN的更多信息。(演示幻燈片給出了 TURN 和 STUN 服務器實現的示例。
一個簡單的視頻聊天客戶端
嘗試WebRTC的好地方,包括使用STUN服務器的信令和NAT /防火墻穿越,是?appr.tc?的視頻聊天演示。此應用使用適配器.js、填充程序將應用與規范更改和前綴差異隔離開來。
代碼在其日志記錄中故意冗長。檢查控制臺以了解事件的順序。下面是代碼的詳細演練。
如果你覺得這有點令人困惑,你可能更喜歡 WebRTC codelab。本分步指南介紹了如何構建完整的視頻聊天應用程序,包括在 Node 服務器上運行的簡單信令 服務器。網絡拓撲
目前實現的WebRTC僅支持一對一通信,但可用于更復雜的網絡場景,例如多個對等體直接或通過多點控制單元(MCU)相互通信,多點控制單元(MCU)是可以處理大量參與者并進行選擇性流轉發的服務器,以及混合或錄制音頻和視頻。
多點控制單元拓撲示例
許多現有的WebRTC應用程序僅演示Web瀏覽器之間的通信,但網關服務器可以使在瀏覽器上運行的WebRTC應用程序與設備(如電話(也稱為PSTN))和VOIP系統進行交互。2012年5月,Doubango Telecom開源了使用WebRTC和WebSocket構建的sipml5 SIP客戶端,該客戶端(以及其他潛在用途)支持在iOS和Android上運行的瀏覽器和應用程序之間的視頻通話。在Google I / O上,Tethr和Tropo展示了一個使用OpenBTS單元在公文包中進行災難通信的框架,以通過WebRTC實現功能手機和計算機之間的通信。電話通信沒有運營商!
Tethr/Tropo:公文包中的災難通信
RTCDataChannel應用程序接口
除了音頻和視頻,WebRTC還支持其他類型的數據的實時通信。
該 API 支持以低延遲和高吞吐量對等方式交換任意數據。有關單頁演示以及如何構建簡單的文件傳輸應用程序,請分別參閱?WebRTC 示例和?WebRTC 代碼實驗室。RTCDataChannel
該 API 有許多潛在的用例,包括:
- 賭博
- 遠程桌面應用
- 實時文本聊天
- 文件傳輸
- 去中心化網絡
該 API 具有多項功能,可充分利用并實現強大而靈活的對等通信:RTCPeerConnection
- 利用會話設置RTCPeerConnection
- 多個同時通道,優先級
- 可靠和不可靠的交付語義
- 內置安全性 (DTLS) 和擁塞控制
- 能夠與音頻或視頻一起使用或不使用音頻或視頻
語法有意類似于 WebSocket,具有方法和事件:send()message
<span style="color:white"><span style="background-color:#444444"><span style="color:#e28964">const</span><span style="color:#ffffff"> localConnection </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span> <span style="color:#89bdff">RTCPeerConnection</span><span style="color:#ffffff">(</span><span style="color:#ffffff">servers</span><span style="color:#ffffff">);</span> <span style="color:#e28964">const</span><span style="color:#ffffff"> remoteConnection </span><span style="color:#ffffff">=</span> <span style="color:#e28964">new</span> <span style="color:#89bdff">RTCPeerConnection</span><span style="color:#ffffff">(</span><span style="color:#ffffff">servers</span><span style="color:#ffffff">);</span> <span style="color:#e28964">const</span><span style="color:#ffffff"> sendChannel </span><span style="color:#ffffff">=</span><span style="color:#ffffff">localConnection</span><span style="color:#ffffff">.</span><span style="color:#ffffff">createDataChannel</span><span style="color:#ffffff">(</span><span style="color:#65b042">'sendDataChannel'</span><span style="color:#ffffff">);</span><span style="color:#aeaeae"><em>// ...</em></span><span style="color:#ffffff">remoteConnection</span><span style="color:#ffffff">.</span><span style="color:#ffffff">ondatachannel </span><span style="color:#ffffff">=</span> <span style="color:#ffffff">(</span><span style="color:#e28964">event</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#ffffff">receiveChannel </span><span style="color:#ffffff">=</span> <span style="color:#e28964">event</span><span style="color:#ffffff">.</span><span style="color:#ffffff">channel</span><span style="color:#ffffff">;</span><span style="color:#ffffff">receiveChannel</span><span style="color:#ffffff">.</span><span style="color:#ffffff">onmessage </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> onReceiveMessage</span><span style="color:#ffffff">;</span><span style="color:#ffffff">receiveChannel</span><span style="color:#ffffff">.</span><span style="color:#ffffff">onopen </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> onReceiveChannelStateChange</span><span style="color:#ffffff">;</span><span style="color:#ffffff">receiveChannel</span><span style="color:#ffffff">.</span><span style="color:#ffffff">onclose </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> onReceiveChannelStateChange</span><span style="color:#ffffff">;</span> <span style="color:#ffffff">};</span><span style="color:#e28964">function</span><span style="color:#ffffff"> onReceiveMessage</span><span style="color:#ffffff">(</span><span style="color:#e28964">event</span><span style="color:#ffffff">)</span> <span style="color:#ffffff">{</span><span style="color:#ffffff">document</span><span style="color:#ffffff">.</span><span style="color:#ffffff">querySelector</span><span style="color:#ffffff">(</span><span style="color:#65b042">"textarea#send"</span><span style="color:#ffffff">).</span><span style="color:#ffffff">value </span><span style="color:#ffffff">=</span> <span style="color:#e28964">event</span><span style="color:#ffffff">.</span><span style="color:#ffffff">data</span><span style="color:#ffffff">;</span> <span style="color:#ffffff">}</span><span style="color:#ffffff">document</span><span style="color:#ffffff">.</span><span style="color:#ffffff">querySelector</span><span style="color:#ffffff">(</span><span style="color:#65b042">"button#send"</span><span style="color:#ffffff">).</span><span style="color:#ffffff">onclick </span><span style="color:#ffffff">=</span> <span style="color:#ffffff">()</span> <span style="color:#ffffff">=></span> <span style="color:#ffffff">{</span><span style="color:#e28964">var</span><span style="color:#ffffff"> data </span><span style="color:#ffffff">=</span><span style="color:#ffffff"> document</span><span style="color:#ffffff">.</span><span style="color:#ffffff">querySelector</span><span style="color:#ffffff">(</span><span style="color:#65b042">"textarea#send"</span><span style="color:#ffffff">).</span><span style="color:#ffffff">value</span><span style="color:#ffffff">;</span><span style="color:#ffffff">sendChannel</span><span style="color:#ffffff">.</span><span style="color:#ffffff">send</span><span style="color:#ffffff">(</span><span style="color:#ffffff">data</span><span style="color:#ffffff">);</span> <span style="color:#ffffff">};</span></span></span>通信直接發生在瀏覽器之間,因此即使當打孔以應對防火墻和 NAT 失敗時需要中繼 (TURN) 服務器,也可以比 WebSocket 快得多。RTCDataChannel
RTCDataChannel可在 Chrome、Safari、Firefox、Opera 和 Samsung Internet 中使用。Cube Slam?游戲使用 API 來傳達游戲狀態。玩朋友或玩熊!創新平臺Sharefest通過peerCDN實現了文件共享,并提供了WebRTC如何實現點對點內容分發的一瞥。RTCDataChannel
有關 的更多信息,請查看 IETF?的協議規范草案。RTCDataChannel
安全
實時通信應用程序或插件可能會通過多種方式危及安全性。例如:
- 未加密的媒體或數據可能會在瀏覽器之間或瀏覽器與服務器之間被截獲。
- 應用可能會在用戶不知情的情況下錄制和分發視頻或音頻。
- 惡意軟件或病毒可能與明顯無害的插件或應用程序一起安裝。
WebRTC有幾個功能可以避免這些問題:
- WebRTC實現使用安全協議,如DTLS和SRTP。
- 加密對于所有WebRTC組件都是強制性的,包括信令機制。
- WebRTC不是一個插件。它的組件在瀏覽器沙箱中運行,而不是在單獨的進程中運行。組件不需要單獨安裝,并且每當瀏覽器更新時都會更新。
- 必須顯式授予攝像頭和麥克風訪問權限,并且當攝像頭或麥克風運行時,用戶界面會清楚地顯示這一點。
關于流媒體安全性的完整討論超出了本文的范圍。有關更多信息,請參閱 IETF?提議的 WebRTC 安全架構。
結語
WebRTC的API和標準可以使內容創建和通信工具民主化和分散化,包括電話,游戲,視頻制作,音樂制作和新聞采集。
沒有比這更具顛覆性的技術了。
正如博主菲爾·埃德霍爾姆(Phil Edholm)所說,"WebRTC和HTML5可能實現與原始瀏覽器對信息相同的實時通信轉換。
開發人員工具
- 正在進行的會話的WebRTC統計數據可以在以下位置找到:
chrome://webrtc-internals 屏幕截圖
- 在 Chrome 瀏覽器中 chrome://webrtc-internals
- 歌劇中的 opera://webrtc-internals
- 關于:火狐中的webrtc
- 跨瀏覽器互操作說明
- adapter.js是由Google在WebRTC社區的幫助下維護的WebRTC的JavaScript填充程序,它抽象了供應商前綴,瀏覽器差異和規范更改。
- 要了解有關 WebRTC 信令過程的更多信息,請查看?appr.tc?日志輸出到控制臺。
- 如果太多了,你可能更喜歡使用WebRTC框架,甚至是完整的WebRTC服務。
- 錯誤報告和功能請求始終受到贊賞:
- WebRTC錯誤
- Chrome 錯誤
- 歌劇錯誤
- 火狐錯誤
- WebRTC演示錯誤
- 適配器.js錯誤
了解更多信息
- Justin Uberti 在 Google I/O 2012 上的 WebRTC 會議
- 艾倫·B·約翰斯頓(Alan B. Johnston)和丹尼爾·C·伯內特(Daniel C. Burnett)在 webrtcbook.com 上以印刷版和電子書格式出版了一本WebRTC書籍,現已推出第三版。
- webrtc.org?是WebRTC所有內容的所在地,包括演示,文檔和討論。
- discuss-webrtc是一個用于WebRTC技術討論的Google Group。
- @webrtc
- Google Developers?Talk 文檔提供了有關 NAT 遍歷、STUN、中繼服務器和候選者收集的更多信息。
- WebRTC on GitHub
- Stack Overflow是尋找答案并提出有關WebRTC問題的好地方。
標準和協議
- WebRTC W3C 編輯草稿
- W3C 編輯器草稿:媒體捕獲和流(也稱為getUserMedia)
- IETF工作組章程
- IETF WebRTC 數據通道協議草案
- IETF JSEP Draft
- IETF為ICE提出的標準
- IETF RTCWEB工作組互聯網草案:Web實時通信用例和要求
WebRTC 支持摘要
MediaStream和 APIgetUserMedia
- Chrome 桌面版 18.0.1008 及更高版本;適用于安卓 29 及更高版本的 Chrome 瀏覽器
- 歌劇18及以上;適用于安卓 20 及更高版本的 Opera
- Opera 12,Opera Mobile 12(基于Presto引擎)
- 火狐 17 及更高版本
- 微軟邊緣 16 及更高版本
- iOS 上的 Safari 11.2 及更高版本,以及 MacOS 上的 11.1 及更高版本
- 安卓版上的 UC 11.8 及更高版本
- 三星互聯網4及更高版本
RTCPeerConnection應用程序接口
- Chrome 桌面 20 及更高版本;適用于 Android 29 及更高版本的 Chrome 瀏覽器(無標志)
- Opera 18 及更高版本(默認啟用);適用于 Android 20 及更高版本的 Opera(默認情況下處于啟用狀態)
- Firefox 22 及更高版本(默認啟用)
- 微軟邊緣 16 及更高版本
- iOS 上的 Safari 11.2 及更高版本,以及 MacOS 上的 11.1 及更高版本
- 三星互聯網4及更高版本
RTCDataChannel應用程序接口
- Chrome 25中的實驗版本,但在Chrome 26及更高版本中更穩定(并且具有Firefox互操作性);適用于安卓 29 及更高版本的 Chrome 瀏覽器
- Opera 18及更高版本中的穩定版本(以及Firefox互操作性);適用于安卓 20 及更高版本的 Opera
- Firefox 22 及更高版本(默認啟用)
有關 API 的跨平臺支持(例如 和)的更多詳細信息,請參閱?caniuse.com?和?Chrome 平臺狀態。getUserMediaRTCPeerConnection
本機 API 也可在有關 webrtc.org 的文檔中找到。RTCPeerConnection
總結
以上是生活随笔為你收集整理的开始使用WebRTC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: png怎么转换成jpg格式?如何转换照片
- 下一篇: 进神经网络的学习方式(译文)----中