日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

开始使用WebRTC

發(fā)布時(shí)間:2024/3/13 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 开始使用WebRTC 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Get Started with WebRTC??機(jī)翻

原文:Get Started with WebRTC - HTML5 Rocks

無(wú)需插件即可進(jìn)行實(shí)時(shí)通信

想象一下,在這樣一個(gè)世界中,您的手機(jī)、電視和計(jì)算機(jī)可以在一個(gè)通用平臺(tái)上進(jìn)行通信。想象一下,將視頻聊天和對(duì)等數(shù)據(jù)共享添加到 Web 應(yīng)用很容易。這就是WebRTC的愿景。

想試試嗎?WebRTC可在桌面和移動(dòng)設(shè)備上使用Google Chrome,Safari,Firefox和Opera。一個(gè)好的起點(diǎn)是?appr.tc?的簡(jiǎn)單視頻聊天應(yīng)用程序:

  • 在瀏覽器中打開?appr.tc。
  • 單擊"加入"以加入聊天室,并讓應(yīng)用使用您的網(wǎng)絡(luò)攝像頭。
  • 在新選項(xiàng)卡中打開頁(yè)面末尾顯示的 URL,或者更好的是,在其他計(jì)算機(jī)上打開 URL。
  • 快速入門

    沒有時(shí)間閱讀本文或只想要代碼?

  • 要獲得WebRTC的概述,請(qǐng)觀看以下Google I / O視頻或查看這些幻燈片:

  • 如果尚未使用 API,請(qǐng)參閱在 HTML5 中捕獲音頻和視頻,simpl.info getUserMedia。getUserMedia
  • 若要了解 API,請(qǐng)參閱以下示例和?RTCPeerConnection simpl.info。RTCPeerConnection
  • 要了解 WebRTC 如何使用服務(wù)器進(jìn)行信令以及防火墻和 NAT 遍歷,請(qǐng)參閱?appr.tc?中的代碼和控制臺(tái)日志。
  • 迫不及待,現(xiàn)在只想嘗試WebRTC?嘗試?20 多個(gè)演示中的一些,這些演示演示了 WebRTC JavaScript API。
  • 您的機(jī)器和 WebRTC 遇到問(wèn)題?訪問(wèn)?WebRTC 疑難解答。
  • 或者,直接跳轉(zhuǎn)到WebRTC代碼實(shí)驗(yàn)室,這是一個(gè)分步指南,解釋了如何構(gòu)建一個(gè)完整的視頻聊天應(yīng)用程序,包括一個(gè)簡(jiǎn)單的信令服務(wù)器。

    WebRTC的非常短的歷史

    網(wǎng)絡(luò)面臨的最后一個(gè)主要挑戰(zhàn)之一是通過(guò)語(yǔ)音和視頻實(shí)現(xiàn)人類通信:實(shí)時(shí)通信或簡(jiǎn)稱RTC。RTC 在 Web 應(yīng)用中應(yīng)與在文本輸入中輸入文本一樣自然。沒有它,你創(chuàng)新和開發(fā)新互動(dòng)方式的能力就會(huì)受到限制。

    從歷史上看,RTC一直是企業(yè)和復(fù)雜的,需要昂貴的音頻和視頻技術(shù)在內(nèi)部許可或開發(fā)。將 RTC 技術(shù)與現(xiàn)有內(nèi)容、數(shù)據(jù)和服務(wù)集成既困難又耗時(shí),尤其是在 Web 上。

    Gmail視頻聊天在2008年開始流行,2011年,谷歌推出了使用Talk的Hangouts(Gmail也是如此)。谷歌收購(gòu)了GISP,該公司開發(fā)了RTC所需的許多組件,例如編解碼器和回聲消除技術(shù)。Google 開源了 GIPS 開發(fā)的技術(shù),并與互聯(lián)網(wǎng)工程任務(wù)組 (IETF) 和萬(wàn)維網(wǎng)聯(lián)盟 (W3C) 的相關(guān)標(biāo)準(zhǔn)機(jī)構(gòu)合作,以確保行業(yè)共識(shí)。2011年5月,愛立信構(gòu)建了WebRTC的第一個(gè)實(shí)現(xiàn)。

    WebRTC為實(shí)時(shí),無(wú)插件的視頻,音頻和數(shù)據(jù)通信實(shí)施了開放標(biāo)準(zhǔn)。需求是真實(shí)的:

    • 許多 Web 服務(wù)使用 RTC,但需要下載、本機(jī)應(yīng)用或插件。其中包括Skype,Facebook和Hangouts。
    • 下載,安裝和更新插件很復(fù)雜,容易出錯(cuò)并且很煩人。
    • 插件難以部署、調(diào)試、故障排除、測(cè)試和維護(hù),并且可能需要許可和與復(fù)雜、昂貴的技術(shù)集成。首先,通常很難說(shuō)服人們安裝插件!

    WebRTC項(xiàng)目的指導(dǎo)原則是,其API應(yīng)該是開源的,免費(fèi)的,標(biāo)準(zhǔn)化的,內(nèi)置于Web瀏覽器中,并且比現(xiàn)有技術(shù)更有效。

    我們現(xiàn)在在哪里?

    WebRTC用于各種應(yīng)用程序,例如Google Meet。WebRTC還與WebKitGTK+和Qt原生應(yīng)用程序集成。

    WebRTC實(shí)現(xiàn)了以下三個(gè)API:

    • MediaStream(也稱為getUserMedia)
    • RTCPeerConnection
    • RTCDataChannel

    API 定義在以下兩個(gè)規(guī)范中:

    • WebRTC
    • getUserMedia

    Chrome,Safari,Firefox,Edge和Opera在移動(dòng)設(shè)備和桌面上都支持這三個(gè)API。

    getUserMedia:有關(guān)演示和代碼,請(qǐng)參閱?WebRTC 示例或嘗試 Chris Wilson 用作 Web 音頻輸入的驚人示例。getUserMedia

    RTCPeerConnection:有關(guān)簡(jiǎn)單的演示和功能齊全的視頻聊天應(yīng)用程序,請(qǐng)參閱?WebRTC 示例分別對(duì)等連接和?appr.tc。這個(gè)應(yīng)用程序使用適配器.js,一個(gè)由谷歌在WebRTC社區(qū)的幫助下維護(hù)的JavaScript填充程序,以抽象出瀏覽器的差異和規(guī)格變化。

    RTCDataChannel:若要查看實(shí)際效果,請(qǐng)參閱?WebRTC 示例以查看其中一個(gè)數(shù)據(jù)通道演示。

    WebRTC codelab?展示了如何使用所有三個(gè) API 來(lái)構(gòu)建一個(gè)簡(jiǎn)單的應(yīng)用程序,用于視頻聊天和文件共享。

    您的第一個(gè) WebRTC

    WebRTC應(yīng)用程序需要做幾件事:

    • 獲取流式音頻、視頻或其他數(shù)據(jù)。
    • 獲取網(wǎng)絡(luò)信息,例如 IP 地址和端口,并將其與其他 WebRTC 客戶端(稱為對(duì)等方)交換以啟用連接,甚至通過(guò)?NAT?和防火墻。
    • 協(xié)調(diào)信令通信以報(bào)告錯(cuò)誤并啟動(dòng)或關(guān)閉會(huì)話。
    • 交換有關(guān)媒體和客戶端功能的信息,如分辨率和編解碼器。
    • 傳輸流式音頻、視頻或數(shù)據(jù)。

    為了獲取和通信流數(shù)據(jù),WebRTC 實(shí)現(xiàn)了以下 API:

    • MediaStream?可以訪問(wèn)數(shù)據(jù)流,例如來(lái)自用戶的攝像頭和麥克風(fēng)。
    • RTCPeerConnection?支持音頻或視頻通話,并提供加密和帶寬管理功能。
    • RTCDataChannel?支持通用數(shù)據(jù)的對(duì)等通信。

    (稍后將詳細(xì)討論WebRTC的網(wǎng)絡(luò)和信令方面。

    MediaStream接口(也稱為接口)getUserMedia

    MediaStream?API?表示同步的媒體流。例如,從攝像頭和麥克風(fēng)輸入中獲取的流具有同步的視頻和音頻軌道。(不要與<track>元素混淆,這是完全不同的東西。MediaStreamTrack

    理解API的最簡(jiǎn)單方法可能是在野外查看它:MediaStream

  • 在瀏覽器中,導(dǎo)航到?WebRTC 示例?getUserMedia。
  • 打開控制臺(tái)。
  • 檢查全局范圍內(nèi)的變量。stream
  • 每個(gè)都有一個(gè)輸入(可能是由 生成的),還有一個(gè)輸出(可能傳遞給視頻元素或 )。MediaStreamMediaStreamgetUserMedia()RTCPeerConnection

    該方法采用?MediaStreamConstraints?對(duì)象參數(shù),并返回解析為對(duì)象的 參數(shù)。getUserMedia()PromiseMediaStream

    每個(gè)都有一個(gè) ,例如 。由 and 方法返回 s 數(shù)組。MediaStreamlabel'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'MediaStreamTrackgetAudioTracks()getVideoTracks()

    對(duì)于?getUserMedia?示例,返回一個(gè)空數(shù)組(因?yàn)闆]有音頻),并且假設(shè)連接了一個(gè)工作正常的網(wǎng)絡(luò)攝像頭,則返回一個(gè)數(shù)組,該數(shù)組表示來(lái)自網(wǎng)絡(luò)攝像頭的流。每個(gè)都有一個(gè)種類 ( 或 ),a(類似于 ),并表示音頻或視頻的一個(gè)或多個(gè)通道。在這種情況下,只有一個(gè)視頻軌道,沒有音頻,但很容易想象用例中還有更多,例如從前置攝像頭,后置攝像頭,麥克風(fēng)獲取流的聊天應(yīng)用程序以及共享其屏幕的應(yīng)用程序。stream.getAudioTracks()stream.getVideoTracks()MediaStreamTrackMediaStreamTrack'video''audio'label'FaceTime HD Camera (Built-in)'

    可以通過(guò)設(shè)置?srcObject?屬性將 A?附加到視頻元素。以前,這是通過(guò)將屬性設(shè)置為使用 創(chuàng)建的對(duì)象 URL 來(lái)完成的,但這已被棄用。MediaStreamsrcURL.createObjectURL()

    正在主動(dòng)使用相機(jī),這會(huì)占用資源,并使相機(jī)保持打開狀態(tài)并打開相機(jī)燈亮。當(dāng)您不再使用軌道時(shí),請(qǐng)確保呼叫以關(guān)閉攝像機(jī)。MediaStreamTracktrack.stop()

    getUserMedia也可以用作 Web 音頻 API 的輸入節(jié)點(diǎn):

    <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的應(yīng)用程序和擴(kuò)展程序也可以合并。通過(guò)向清單添加和/或權(quán)限,只能在安裝時(shí)請(qǐng)求和授予一次權(quán)限。此后,不會(huì)要求用戶獲得相機(jī)或麥克風(fēng)訪問(wèn)權(quán)限。getUserMediaaudioCapturevideoCapture

    對(duì)于 , 只需授予一次權(quán)限。第一次,瀏覽器的信息欄中會(huì)顯示"允許"按鈕。Chrome 在 2015 年底棄用了 HTTP 訪問(wèn),因?yàn)樗粴w類為功能強(qiáng)大的功能。getUserMedia()getUserMedia()

    其意圖可能是為任何流數(shù)據(jù)源啟用 a,而不僅僅是攝像頭或麥克風(fēng)。這將允許從存儲(chǔ)的數(shù)據(jù)或任意數(shù)據(jù)源(如傳感器或其他輸入)進(jìn)行流式傳輸。MediaStream

    getUserMedia()真正與其他 JavaScript API 和庫(kù)結(jié)合使用:

    • 網(wǎng)絡(luò)攝像頭玩具是一個(gè)照相亭應(yīng)用程序,它使用WebGL為可以在本地共享或保存的照片添加奇怪而美妙的效果。
    • FaceKat是一款使用headtrackr.js構(gòu)建的面部跟蹤游戲。
    • ASCII 相機(jī)使用 Canvas API 生成 ASCII 圖像。

    正在上傳…重新上傳取消

    咕嚕咕嚕的藝術(shù)!

    約束

    約束可用于設(shè)置 的視頻分辨率值。這也允許支持其他約束,例如寬高比;對(duì)置模式(前置或后置攝像頭);幀速率,高度和寬度;和?applyConstraints()?方法。getUserMedia()

    有關(guān)示例,請(qǐng)參閱?WebRTC 示例?getUserMedia:選擇分辨率。

    一個(gè)陷阱:約束可能會(huì)影響共享資源的可用配置。例如,如果相機(jī)在 640 x 480 模式下通過(guò)一個(gè)選項(xiàng)卡打開,則另一個(gè)選項(xiàng)卡將無(wú)法使用約束以更高分辨率模式打開它,因?yàn)樗荒茉谝环N模式下打開。請(qǐng)注意,這是一個(gè)實(shí)現(xiàn)細(xì)節(jié)。可以讓第二個(gè)選項(xiàng)卡以更高分辨率的模式重新打開相機(jī),并使用視頻處理將第一個(gè)選項(xiàng)卡的視頻軌道縮小到640 x 480,但尚未實(shí)現(xiàn)。getUserMedia

    設(shè)置不允許的約束值會(huì)給出 a 或 a,例如,如果請(qǐng)求的分辨率不可用。若要查看此操作的實(shí)際效果,請(qǐng)參閱?WebRTC 示例?getUserMedia:為演示選擇分辨率。DOMExceptionOverconstrainedError

    屏幕和選項(xiàng)卡捕獲

    Chrome 應(yīng)用還允許通過(guò)?chrome.tabCapture 和 chrome.desktopCapture?API 共享單個(gè)瀏覽器標(biāo)簽頁(yè)或整個(gè)桌面的實(shí)時(shí)視頻。(有關(guān)演示和更多信息,請(qǐng)參閱使用 WebRTC 進(jìn)行屏幕共享。這篇文章已經(jīng)有幾年的歷史了,但它仍然很有趣。

    在 Chrome 中,也可以使用實(shí)驗(yàn)性約束將屏幕捕獲用作源。請(qǐng)注意,屏幕捕獲需要 HTTPS,并且只能用于開發(fā),因?yàn)樗峭ㄟ^(guò)命令行標(biāo)志啟用的,如本文所述。MediaStreamchromeMediaSource

    信令:會(huì)話控制、網(wǎng)絡(luò)和媒體信息

    WebRTC用于在瀏覽器(也稱為對(duì)等體)之間傳輸流數(shù)據(jù),但也需要一種機(jī)制來(lái)協(xié)調(diào)通信和發(fā)送控制消息,這一過(guò)程稱為信令。WebRTC未指定信令方法和協(xié)議。信令不是 API 的一部分。RTCPeerConnectionRTCPeerConnection

    相反,WebRTC應(yīng)用程序開發(fā)人員可以選擇他們喜歡的任何消息傳遞協(xié)議,例如SIP或XMPP,以及任何適當(dāng)?shù)碾p工(雙向)通信通道。appr.tc?示例使用 XHR 和通道 API 作為信令機(jī)制。代碼實(shí)驗(yàn)室使用在?Node?服務(wù)器上運(yùn)行的 Socket.io。

    信令用于交換三種類型的信息:

    • 會(huì)話控制消息:初始化或關(guān)閉通信并報(bào)告錯(cuò)誤。
    • 網(wǎng)絡(luò)配置:對(duì)外界來(lái)說(shuō),你電腦的IP地址和端口是什么?
    • 媒體功能:您的瀏覽器和要與之通信的瀏覽器可以處理哪些編解碼器和分辨率?

    通過(guò)信令進(jìn)行的信息交換必須已成功完成,然后才能開始對(duì)等流。

    例如,假設(shè)愛麗絲想和鮑勃交流。下面是?W3C WebRTC 規(guī)范中的代碼示例,其中顯示了運(yùn)行中的信令過(guò)程。該代碼假定存在該方法中創(chuàng)建的某些信令機(jī)制。另請(qǐng)注意,在 Chrome 和 Opera 上,當(dāng)前帶有前綴。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 交換網(wǎng)絡(luò)信息。(表達(dá)式查找候選項(xiàng)是指使用?ICE 框架查找網(wǎng)絡(luò)接口和端口的過(guò)程。

  • Alice 使用處理程序創(chuàng)建一個(gè)對(duì)象,該處理程序在網(wǎng)絡(luò)候選程序可用時(shí)運(yùn)行。RTCPeerConnectiononicecandidate
  • Alice 通過(guò) Bob 使用的任何信令通道(如 WebSocket 或其他機(jī)制)將序列化的候選數(shù)據(jù)發(fā)送給 Bob。
  • 當(dāng) Bob 收到來(lái)自 Alice 的應(yīng)聘者消息時(shí),他會(huì)打電話將應(yīng)聘者添加到遠(yuǎn)程對(duì)等描述中。addIceCandidate
  • WebRTC 客戶端(也稱為對(duì)等體,在本例中稱為 Alice 和 Bob)還需要確定和交換本地和遠(yuǎn)程音頻和視頻媒體信息,例如解析和編解碼器功能。通過(guò)會(huì)話描述協(xié)議 (SDP) 交換產(chǎn)品/服務(wù)和答案來(lái)發(fā)出信號(hào)以交換媒體配置信息:

  • Alice 運(yùn)行該方法。此返回的傳輸路徑為 —Alice 的本地會(huì)話描述。RTCPeerConnectioncreateOffer()RTCSessionDescription
  • 在回調(diào)中,Alice 使用設(shè)置本地描述,然后通過(guò)其信令通道將此會(huì)話描述發(fā)送給 Bob。請(qǐng)注意,在被調(diào)用之前不會(huì)開始收集候選項(xiàng)。這在JSEP IETF草案中得到了編纂。setLocalDescription()RTCPeerConnectionsetLocalDescription()
  • Bob 使用 將 Alice 發(fā)送給他的描述設(shè)置為遠(yuǎn)程描述。setRemoteDescription()
  • Bob 運(yùn)行該方法,將他從 Alice 那里獲得的遠(yuǎn)程描述傳遞給它,以便可以生成與她的會(huì)話兼容的本地會(huì)話。回調(diào)傳遞一個(gè) .Bob 將其設(shè)置為本地描述,并將其發(fā)送給 Alice。RTCPeerConnectioncreateAnswer()createAnswer()RTCSessionDescription
  • 當(dāng) Alice 獲取 Bob 的會(huì)話描述時(shí),她將其設(shè)置為帶有 的遠(yuǎn)程描述。setRemoteDescription
  • 乒!
  • 確保允許 在不再需要時(shí)通過(guò)調(diào)用來(lái)回收 垃圾回收。否則,線程和連接將保持活動(dòng)狀態(tài)。在WebRTC中可能會(huì)泄漏大量資源!RTCPeerConnectionclose()

    RTCSessionDescription對(duì)象是符合會(huì)話描述協(xié)議?SDP 的 Blob。序列化后,SDP 對(duì)象如下所示:

    <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>

    網(wǎng)絡(luò)和媒體信息的獲取和交換可以同時(shí)完成,但是在對(duì)等體之間的音頻和視頻流開始之前,這兩個(gè)過(guò)程必須已經(jīng)完成。

    前面描述的要約/答案體系結(jié)構(gòu)稱為?JavaScript 會(huì)話建立協(xié)議或 JSEP。(在愛立信的第一個(gè)WebRTC實(shí)現(xiàn)的演示視頻中,有一個(gè)很棒的動(dòng)畫解釋了信令和流式傳輸?shù)倪^(guò)程。

    JSEP 架構(gòu)

    一旦信令過(guò)程成功完成,數(shù)據(jù)就可以在呼叫者和被叫方之間直接對(duì)等流式傳輸,或者,如果失敗,則通過(guò)中間中繼服務(wù)器(稍后將詳細(xì)介紹)。流式傳輸是 的工作。RTCPeerConnection

    RTCPeerConnection

    RTCPeerConnection是 WebRTC 組件,用于處理對(duì)等體之間流數(shù)據(jù)的穩(wěn)定和高效通信。

    下面是一個(gè) WebRTC 體系結(jié)構(gòu)圖,顯示了 的作用。您會(huì)注意到,綠色部分很復(fù)雜!RTCPeerConnection

    正在上傳…重新上傳取消

    WebRTC架構(gòu)(來(lái)自?webrtc.org)

    從JavaScript的角度來(lái)看,從這張圖中要了解的主要內(nèi)容是,它保護(hù)Web開發(fā)人員免受潛伏在背后的無(wú)數(shù)復(fù)雜性的影響。WebRTC使用的編解碼器和協(xié)議做了大量的工作,使實(shí)時(shí)通信成為可能,即使在不可靠的網(wǎng)絡(luò)上也是如此:RTCPeerConnection

    • 丟包隱蔽
    • 回聲消除
    • 帶寬適應(yīng)性
    • 動(dòng)態(tài)抖動(dòng)緩沖
    • 自動(dòng)增益控制
    • 降噪和抑制
    • 圖像清理

    前面的 W3C 代碼從信令角度展示了 WebRTC 的簡(jiǎn)化示例。以下是兩個(gè)工作 WebRTC 應(yīng)用程序的演練。第一個(gè)是要演示的簡(jiǎn)單示例,第二個(gè)是完全可操作的視頻聊天客戶端。RTCPeerConnection

    沒有服務(wù)器的 RTCPeerConnection

    以下代碼取自?WebRTC 示例對(duì)等連接,該連接在一個(gè)網(wǎng)頁(yè)上具有本地和遠(yuǎn)程(以及本地和遠(yuǎn)程視頻)。這并不構(gòu)成任何非常有用的東西 - 調(diào)用方和被調(diào)用方在同一頁(yè)面上 - 但它確實(shí)使API的工作原理更加清晰,因?yàn)轫?yè)面上的對(duì)象可以直接交換數(shù)據(jù)和消息,而無(wú)需使用中間信令機(jī)制。RTCPeerConnectionRTCPeerConnectionRTCPeerConnection

    在此示例中,表示本地對(duì)等方(調(diào)用方)和遠(yuǎn)程對(duì)等方(被調(diào)用方)。pc1pc2

    訪客

  • 創(chuàng)建一個(gè)新流并從中添加流: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>
  • 創(chuàng)建產(chǎn)品/服務(wù)并將其設(shè)置為 的本地描述和 遠(yuǎn)程描述。這可以直接在代碼中完成,而無(wú)需使用信令,因?yàn)檎{(diào)用方和被調(diào)用方都在同一頁(yè)面上: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>
  • 被叫方

    創(chuàng)建并在添加來(lái)自 的流時(shí),將其顯示在視頻元素中: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 加服務(wù)器

    在現(xiàn)實(shí)世界中,WebRTC需要服務(wù)器,無(wú)論多么簡(jiǎn)單,因此可能會(huì)發(fā)生以下情況:

    • 用戶發(fā)現(xiàn)彼此并交換真實(shí)世界的詳細(xì)信息,例如名稱。
    • WebRTC客戶端應(yīng)用程序(對(duì)等體)交換網(wǎng)絡(luò)信息。
    • 對(duì)等方交換有關(guān)媒體的數(shù)據(jù),例如視頻格式和分辨率。
    • WebRTC 客戶端應(yīng)用程序遍歷?NAT 網(wǎng)關(guān)和防火墻。

    換句話說(shuō),WebRTC需要四種類型的服務(wù)器端功能:

    • 用戶發(fā)現(xiàn)和通信
    • 信號(hào)
    • NAT/防火墻遍歷
    • 對(duì)等通信失敗時(shí)的中繼服務(wù)器

    NAT 遍歷、對(duì)等網(wǎng)絡(luò)以及構(gòu)建用于用戶發(fā)現(xiàn)和信令的服務(wù)器應(yīng)用的要求超出了本文的討論范圍。可以說(shuō),ICE框架使用STUN協(xié)議及其擴(kuò)展名TURN來(lái)應(yīng)對(duì)NAT遍歷和其他網(wǎng)絡(luò)變幻莫測(cè)。RTCPeerConnection

    ICE 是用于連接對(duì)等方(如兩個(gè)視頻聊天客戶端)的框架。最初,ICE 嘗試通過(guò) UDP 以盡可能低的延遲直接連接對(duì)等方。在此過(guò)程中,STUN 服務(wù)器只有一個(gè)任務(wù):使 NAT 后面的對(duì)等方能夠查找其公共地址和端口。(有關(guān) STUN 和 TURN 的詳細(xì)信息,請(qǐng)參閱構(gòu)建 WebRTC 應(yīng)用所需的后端服務(wù)。

    查找連接候選項(xiàng)

    如果 UDP 失敗,ICE 將嘗試 TCP。如果直接連接失敗(特別是由于企業(yè) NAT 遍歷和防火墻),ICE 將使用中間(中繼)TURN 服務(wù)器。換句話說(shuō),ICE 首先將 STUN 與 UDP 結(jié)合使用來(lái)直接連接對(duì)等體,如果失敗,則回退到 TURN 中繼服務(wù)器。表達(dá)式查找候選項(xiàng)是指查找網(wǎng)絡(luò)接口和端口的過(guò)程。

    WebRTC數(shù)據(jù)路徑

    WebRTC工程師Justin Uberti在2013年Google I / O WebRTC演示中提供了有關(guān)ICE,STUN和TURN的更多信息。(演示幻燈片給出了 TURN 和 STUN 服務(wù)器實(shí)現(xiàn)的示例。

    一個(gè)簡(jiǎn)單的視頻聊天客戶端

    嘗試WebRTC的好地方,包括使用STUN服務(wù)器的信令和NAT /防火墻穿越,是?appr.tc?的視頻聊天演示。此應(yīng)用使用適配器.js、填充程序?qū)?yīng)用與規(guī)范更改和前綴差異隔離開來(lái)。

    代碼在其日志記錄中故意冗長(zhǎng)。檢查控制臺(tái)以了解事件的順序。下面是代碼的詳細(xì)演練。

    如果你覺得這有點(diǎn)令人困惑,你可能更喜歡 WebRTC codelab。本分步指南介紹了如何構(gòu)建完整的視頻聊天應(yīng)用程序,包括在 Node 服務(wù)器上運(yùn)行的簡(jiǎn)單信令 服務(wù)器。

    網(wǎng)絡(luò)拓?fù)?/span>

    目前實(shí)現(xiàn)的WebRTC僅支持一對(duì)一通信,但可用于更復(fù)雜的網(wǎng)絡(luò)場(chǎng)景,例如多個(gè)對(duì)等體直接或通過(guò)多點(diǎn)控制單元(MCU)相互通信,多點(diǎn)控制單元(MCU)是可以處理大量參與者并進(jìn)行選擇性流轉(zhuǎn)發(fā)的服務(wù)器,以及混合或錄制音頻和視頻。

    多點(diǎn)控制單元拓?fù)涫纠?/p>

    許多現(xiàn)有的WebRTC應(yīng)用程序僅演示W(wǎng)eb瀏覽器之間的通信,但網(wǎng)關(guān)服務(wù)器可以使在瀏覽器上運(yùn)行的WebRTC應(yīng)用程序與設(shè)備(如電話(也稱為PSTN))和VOIP系統(tǒng)進(jìn)行交互。2012年5月,Doubango Telecom開源了使用WebRTC和WebSocket構(gòu)建的sipml5 SIP客戶端,該客戶端(以及其他潛在用途)支持在iOS和Android上運(yùn)行的瀏覽器和應(yīng)用程序之間的視頻通話。在Google I / O上,Tethr和Tropo展示了一個(gè)使用OpenBTS單元在公文包中進(jìn)行災(zāi)難通信的框架,以通過(guò)WebRTC實(shí)現(xiàn)功能手機(jī)和計(jì)算機(jī)之間的通信。電話通信沒有運(yùn)營(yíng)商!

    Tethr/Tropo:公文包中的災(zāi)難通信

    RTCDataChannel應(yīng)用程序接口

    除了音頻和視頻,WebRTC還支持其他類型的數(shù)據(jù)的實(shí)時(shí)通信。

    該 API 支持以低延遲和高吞吐量對(duì)等方式交換任意數(shù)據(jù)。有關(guān)單頁(yè)演示以及如何構(gòu)建簡(jiǎn)單的文件傳輸應(yīng)用程序,請(qǐng)分別參閱?WebRTC 示例和?WebRTC 代碼實(shí)驗(yàn)室。RTCDataChannel

    該 API 有許多潛在的用例,包括:

    • 賭博
    • 遠(yuǎn)程桌面應(yīng)用
    • 實(shí)時(shí)文本聊天
    • 文件傳輸
    • 去中心化網(wǎng)絡(luò)

    該 API 具有多項(xiàng)功能,可充分利用并實(shí)現(xiàn)強(qiáng)大而靈活的對(duì)等通信:RTCPeerConnection

    • 利用會(huì)話設(shè)置RTCPeerConnection
    • 多個(gè)同時(shí)通道,優(yōu)先級(jí)
    • 可靠和不可靠的交付語(yǔ)義
    • 內(nèi)置安全性 (DTLS) 和擁塞控制
    • 能夠與音頻或視頻一起使用或不使用音頻或視頻

    語(yǔ)法有意類似于 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>

    通信直接發(fā)生在瀏覽器之間,因此即使當(dāng)打孔以應(yīng)對(duì)防火墻和 NAT 失敗時(shí)需要中繼 (TURN) 服務(wù)器,也可以比 WebSocket 快得多。RTCDataChannel

    RTCDataChannel可在 Chrome、Safari、Firefox、Opera 和 Samsung Internet 中使用。Cube Slam?游戲使用 API 來(lái)傳達(dá)游戲狀態(tài)。玩朋友或玩熊!創(chuàng)新平臺(tái)Sharefest通過(guò)peerCDN實(shí)現(xiàn)了文件共享,并提供了WebRTC如何實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)內(nèi)容分發(fā)的一瞥。RTCDataChannel

    有關(guān) 的更多信息,請(qǐng)查看 IETF?的協(xié)議規(guī)范草案。RTCDataChannel

    安全

    實(shí)時(shí)通信應(yīng)用程序或插件可能會(huì)通過(guò)多種方式危及安全性。例如:

    • 未加密的媒體或數(shù)據(jù)可能會(huì)在瀏覽器之間或?yàn)g覽器與服務(wù)器之間被截獲。
    • 應(yīng)用可能會(huì)在用戶不知情的情況下錄制和分發(fā)視頻或音頻。
    • 惡意軟件或病毒可能與明顯無(wú)害的插件或應(yīng)用程序一起安裝。

    WebRTC有幾個(gè)功能可以避免這些問(wèn)題:

    • WebRTC實(shí)現(xiàn)使用安全協(xié)議,如DTLS和SRTP。
    • 加密對(duì)于所有WebRTC組件都是強(qiáng)制性的,包括信令機(jī)制。
    • WebRTC不是一個(gè)插件。它的組件在瀏覽器沙箱中運(yùn)行,而不是在單獨(dú)的進(jìn)程中運(yùn)行。組件不需要單獨(dú)安裝,并且每當(dāng)瀏覽器更新時(shí)都會(huì)更新。
    • 必須顯式授予攝像頭和麥克風(fēng)訪問(wèn)權(quán)限,并且當(dāng)攝像頭或麥克風(fēng)運(yùn)行時(shí),用戶界面會(huì)清楚地顯示這一點(diǎn)。

    關(guān)于流媒體安全性的完整討論超出了本文的范圍。有關(guān)更多信息,請(qǐng)參閱 IETF?提議的 WebRTC 安全架構(gòu)。

    結(jié)語(yǔ)

    WebRTC的API和標(biāo)準(zhǔn)可以使內(nèi)容創(chuàng)建和通信工具民主化和分散化,包括電話,游戲,視頻制作,音樂(lè)制作和新聞采集。

    沒有比這更具顛覆性的技術(shù)了。

    正如博主菲爾·埃德霍爾姆(Phil Edholm)所說(shuō),"WebRTC和HTML5可能實(shí)現(xiàn)與原始瀏覽器對(duì)信息相同的實(shí)時(shí)通信轉(zhuǎn)換。

    開發(fā)人員工具

    • 正在進(jìn)行的會(huì)話的WebRTC統(tǒng)計(jì)數(shù)據(jù)可以在以下位置找到:

      chrome://webrtc-internals 屏幕截圖

      • 在 Chrome 瀏覽器中 chrome://webrtc-internals
      • 歌劇中的 opera://webrtc-internals
      • 關(guān)于:火狐中的webrtc
    • 跨瀏覽器互操作說(shuō)明
    • adapter.js是由Google在WebRTC社區(qū)的幫助下維護(hù)的WebRTC的JavaScript填充程序,它抽象了供應(yīng)商前綴,瀏覽器差異和規(guī)范更改。
    • 要了解有關(guān) WebRTC 信令過(guò)程的更多信息,請(qǐng)查看?appr.tc?日志輸出到控制臺(tái)。
    • 如果太多了,你可能更喜歡使用WebRTC框架,甚至是完整的WebRTC服務(wù)。
    • 錯(cuò)誤報(bào)告和功能請(qǐng)求始終受到贊賞:
      • WebRTC錯(cuò)誤
      • Chrome 錯(cuò)誤
      • 歌劇錯(cuò)誤
      • 火狐錯(cuò)誤
      • WebRTC演示錯(cuò)誤
      • 適配器.js錯(cuò)誤

    了解更多信息

    • Justin Uberti 在 Google I/O 2012 上的 WebRTC 會(huì)議
    • 艾倫·B·約翰斯頓(Alan B. Johnston)和丹尼爾·C·伯內(nèi)特(Daniel C. Burnett)在 webrtcbook.com 上以印刷版和電子書格式出版了一本W(wǎng)ebRTC書籍,現(xiàn)已推出第三版。
    • webrtc.org?是WebRTC所有內(nèi)容的所在地,包括演示,文檔和討論。
    • discuss-webrtc是一個(gè)用于WebRTC技術(shù)討論的Google Group。
    • @webrtc
    • Google Developers?Talk 文檔提供了有關(guān) NAT 遍歷、STUN、中繼服務(wù)器和候選者收集的更多信息。
    • WebRTC on GitHub
    • Stack Overflow是尋找答案并提出有關(guān)WebRTC問(wèn)題的好地方。

    標(biāo)準(zhǔn)和協(xié)議

    • WebRTC W3C 編輯草稿
    • W3C 編輯器草稿:媒體捕獲和流(也稱為getUserMedia)
    • IETF工作組章程
    • IETF WebRTC 數(shù)據(jù)通道協(xié)議草案
    • IETF JSEP Draft
    • IETF為ICE提出的標(biāo)準(zhǔn)
    • IETF RTCWEB工作組互聯(lián)網(wǎng)草案:Web實(shí)時(shí)通信用例和要求

    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 及更高版本
    • 三星互聯(lián)網(wǎng)4及更高版本

    RTCPeerConnection應(yīng)用程序接口

    • Chrome 桌面 20 及更高版本;適用于 Android 29 及更高版本的 Chrome 瀏覽器(無(wú)標(biāo)志)
    • Opera 18 及更高版本(默認(rèn)啟用);適用于 Android 20 及更高版本的 Opera(默認(rèn)情況下處于啟用狀態(tài))
    • Firefox 22 及更高版本(默認(rèn)啟用)
    • 微軟邊緣 16 及更高版本
    • iOS 上的 Safari 11.2 及更高版本,以及 MacOS 上的 11.1 及更高版本
    • 三星互聯(lián)網(wǎng)4及更高版本

    RTCDataChannel應(yīng)用程序接口

    • Chrome 25中的實(shí)驗(yàn)版本,但在Chrome 26及更高版本中更穩(wěn)定(并且具有Firefox互操作性);適用于安卓 29 及更高版本的 Chrome 瀏覽器
    • Opera 18及更高版本中的穩(wěn)定版本(以及Firefox互操作性);適用于安卓 20 及更高版本的 Opera
    • Firefox 22 及更高版本(默認(rèn)啟用)

    有關(guān) API 的跨平臺(tái)支持(例如 和)的更多詳細(xì)信息,請(qǐng)參閱?caniuse.com?和?Chrome 平臺(tái)狀態(tài)。getUserMediaRTCPeerConnection

    本機(jī) API 也可在有關(guān) webrtc.org 的文檔中找到。RTCPeerConnection

    總結(jié)

    以上是生活随笔為你收集整理的开始使用WebRTC的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。