開始使用 WebRTC

WebRTC 是開放且無負擔的網路環境長期戰爭的新戰線。

JavaScript 發明者 Brendan Eich

不需外掛程式即可進行即時通訊

想像一下,如果手機、電視和電腦都能在同一個平台上溝通,想像一下,如果您可以輕鬆在網頁應用程式中加入視訊通話和點對點資料分享功能,那麼 WebRTC 就是您的不二之選。

想試試看嗎?WebRTC 可在 Google Chrome、Safari、Firefox 和 Opera 的電腦和行動裝置上使用。您可以從 appr.tc 提供的簡易視訊通話應用程式開始:

  1. 在瀏覽器中開啟 appr.tc
  2. 按一下「加入」即可加入聊天室,並允許應用程式使用你的網路攝影機。
  3. 在新分頁中開啟頁面結尾處顯示的網址,或是在其他電腦上開啟網址。

快速入門

沒有時間閱讀這篇文章,或只想取得程式碼?

或者,您也可以直接前往 WebRTC 程式碼研究室,這份逐步指南會說明如何建構完整的視訊通話應用程式,包括簡單的信號傳遞伺服器。

WebRTC 簡史

網路上最後一項重大挑戰,就是讓使用者透過語音和視訊進行即時通訊 (RTC)。在網頁應用程式中,RTC 的使用體驗應與在文字輸入欄位中輸入文字一樣自然。否則,您就無法創新,也無法開發讓使用者互動的全新方式。

以往,RTC 是企業級且複雜的技術,需要取得昂貴的音訊和視訊技術授權,或自行開發。將 RTC 技術與現有內容、資料和服務整合,是一項費時且困難的工作,尤其是在網路上。

Gmail 視訊通話在 2008 年開始流行,2011 年 Google 推出 Hangouts,並使用 Talk 服務 (與 Gmail 相同)。Google 收購了 GIPS,該公司開發了許多 RTC 所需的元件,例如編碼器和回音消除技術。Google 將 GIPS 開發的技術開放原始碼,並與網際網路工程工作小組 (IETF) 和全球資訊網協會 (W3C) 的相關標準機構合作,確保業界達成共識。2011 年 5 月,Ericsson 建構了第一個 WebRTC 實作

WebRTC 實作了即時、無外掛程式的影片、音訊和資料通訊開放標準。需求確實存在:

  • 許多網路服務都使用 RTC,但需要下載、原生應用程式或外掛程式。包括 Skype、Facebook 和 Hangouts。
  • 下載、安裝和更新外掛程式相當複雜、容易出錯且令人困擾。
  • 外掛程式難以部署、偵錯、排解問題、測試及維護,且可能需要授權,並整合複雜且昂貴的技術。畢竟要說服使用者安裝外掛程式,通常都很困難!

WebRTC 專案的指導原則是,其 API 應為開放原始碼、免費、標準化、內建於網路瀏覽器,且比現有技術更有效率。

我們目前處於哪個階段?

WebRTC 可用於各種應用程式,例如 Google Meet。WebRTC 也已與 WebKitGTK+ 和 Qt 原生應用程式整合。

WebRTC 實作以下三個 API: - MediaStream (也稱為 getUserMedia) - RTCPeerConnection - RTCDataChannel

這些 API 是在下列兩個規格中定義:

Chrome、Safari、Firefox、Edge 和 Opera 在行動裝置和電腦上都支援這三種 API。

getUserMedia:如需示範和程式碼,請參閱 WebRTC 範例,或試試 Chris Wilson 的精彩範例,該範例使用 getUserMedia 做為網路音訊的輸入內容。

RTCPeerConnection:如需簡單的示範和功能完整的視訊聊天應用程式,請分別參閱 WebRTC 範例 Peer connectionappr.tc。這個應用程式使用 adapter.js,這是 Google 在 WebRTC 社群的協助下維護的 JavaScript 遮罩,可用於抽象化瀏覽器差異和規格變更。

RTCDataChannel:如要瞭解實際運作情形,請參閱 WebRTC 範例,查看其中一個資料管道示範。

WebRTC 程式碼研究室會說明如何使用這三個 API 建構簡易的應用程式,用於進行視訊通話和檔案分享。

您的第一個 WebRTC

WebRTC 應用程式需要執行以下幾項操作:

  • 取得串流音訊、視訊或其他資料。
  • 取得 IP 位址和通訊埠等網路資訊,並與其他 WebRTC 用戶端 (稱為「對等端」) 交換資訊,以便建立連線,甚至可透過 NAT 和防火牆建立連線。
  • 協調信號通訊,以便回報錯誤,並啟動或關閉工作階段。
  • 交換媒體和用戶端功能的相關資訊,例如解析度和編解碼器。
  • 傳輸串流音訊、視訊或資料。

為了取得及傳輸串流資料,WebRTC 會實作下列 API:

  • MediaStream 可存取資料串流,例如來自使用者相機和麥克風的資料。
  • RTCPeerConnection 可啟用音訊或視訊通話功能,並提供加密和頻寬管理功能。
  • RTCDataChannel 可啟用一般資料的對等通訊。

(稍後會詳細討論 WebRTC 的網路和信號方面)。

MediaStream API (也稱為 getUserMedia API)

MediaStream API 代表媒體的同步串流。舉例來說,從相機和麥克風輸入取得的串流會同步處理影片和音訊軌道。(請勿將 MediaStreamTrack<track> 元素混淆,這兩者是完全不同的元素)。

如要瞭解 MediaStream API,最簡單的方法就是實際使用:

  1. 在瀏覽器中前往 WebRTC 範例 getUserMedia
  2. 開啟控制台。
  3. 檢查全域範圍中的 stream 變數。

每個 MediaStream 都有輸入內容,可能是由 getUserMedia() 產生的 MediaStream,以及輸出內容,可能會傳遞至影片元素或 RTCPeerConnection

getUserMedia() 方法會採用 MediaStreamConstraints 物件參數,並傳回會解析為 MediaStream 物件的 Promise

每個 MediaStream 都有一個 label,例如 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'getAudioTracks()getVideoTracks() 方法會傳回 MediaStreamTrack 陣列。

getUserMedia 為例,stream.getAudioTracks() 會傳回空陣列 (因為沒有音訊),假設已連上可用的網路攝影機,stream.getVideoTracks() 會傳回一個 MediaStreamTrack 陣列,代表網路攝影機的串流。每個 MediaStreamTrack 都有一種類型 ('video''audio') 和 label (類似 'FaceTime HD Camera (Built-in)'),並代表一個或多個音訊或影片管道。在本例中,只有一個影片軌道,沒有音訊,但不難想像會有更多用途,例如聊天應用程式會從前置鏡頭、後置鏡頭、麥克風取得串流,以及應用程式分享螢幕畫面。

您可以設定 srcObject 屬性,將 MediaStream 附加至影片元素。在過去,這項操作是透過將 src 屬性設為使用 URL.createObjectURL() 建立的物件網址來完成,但這項做法已淘汰

getUserMedia 也可以用來做為 Web Audio API 的輸入節點

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

以 Chromium 為基礎的應用程式和擴充功能也可以納入 getUserMedia。將 audioCapture 和/或 videoCapture 權限新增至資訊清單,即可在安裝時只要求及授予一次權限。之後,系統就不會要求使用者授予攝影機或麥克風存取權。

您只需要為 getUserMedia() 授予一次權限。首次使用時,瀏覽器的infobar會顯示「允許」按鈕。getUserMedia() 的 HTTP 存取權已在 2015 年底遭 Chrome 淘汰,因為該功能已歸類為強大功能

這項功能的用意可能是為任何串流資料來源啟用 MediaStream,而非僅限於攝影機或麥克風。這可讓您從儲存的資料或任意資料來源 (例如感應器或其他輸入內容) 串流資料。

getUserMedia() 搭配其他 JavaScript API 和程式庫使用時,才能發揮最大效益:

  • Webcam Toy 是相片沖印機應用程式,可使用 WebGL 為相片加上奇特又精彩的效果,並分享或儲存在本機。
  • FaceKat 是一款臉部追蹤遊戲,採用 headtrackr.js 建構而成。
  • ASCII 相機會使用 Canvas API 產生 ASCII 圖片。
由 idevelop.ro/ascii-camera 產生的 ASCII 圖像
gUM ASCII 藝術!

限制

限制條件可用於設定 getUserMedia() 的影片解析度值。這也讓您支援其他限制條件,例如顯示比例、鏡頭方向 (前置或後置鏡頭)、影格速率、高度和寬度,以及 applyConstraints() 方法。

如需範例,請參閱「WebRTC 範例 getUserMedia:選取解析度」。

設定不允許的限制值會產生 DOMExceptionOverconstrainedError,例如,如果要求的解析度無法使用。如要瞭解實際運作情形,請參閱 WebRTC 範例 getUserMedia:選取解析度,查看示範。

螢幕和分頁畫面擷取

Chrome 應用程式也能透過 chrome.tabCapturechrome.desktopCapture API 分享單一瀏覽器分頁或整個桌面的即時影像。(如需示範和更多資訊,請參閱「使用 WebRTC 共用螢幕畫面」)。雖然這篇文章已經發表多年,但仍值得一讀。)

您也可以使用實驗性的 chromeMediaSource 限制,在 Chrome 中將螢幕截圖用作 MediaStream 來源。請注意,螢幕截圖功能需要使用 HTTPS,且只能用於開發作業,因為這項功能是透過命令列旗標啟用,如這篇文章所述。

訊號:工作階段控制、網路和媒體資訊

WebRTC 會使用 RTCPeerConnection 在瀏覽器 (又稱為對等端) 之間傳輸串流資料,但也需要一種機制來協調通訊並傳送控制訊息,這項程序稱為信號傳送。WebRTC 不會指定訊號傳送方法和通訊協定。訊號傳送並非 RTCPeerConnection API 的一部分。

相反地,WebRTC 應用程式開發人員可以選擇所需的訊息通訊協定,例如 SIP 或 XMPP,以及任何適當的雙向通訊管道。appr.tc 範例使用 XHR 和 Channel API 做為信號機制。程式碼研究室使用在 Node 伺服器上執行的 Socket.io

信號用於交換三種資訊:

  • 工作階段控制訊息:用於初始化或關閉通訊,以及回報錯誤。
  • 網路設定:在外部世界中,你的電腦的 IP 位址和通訊埠為何?
  • 媒體功能:瀏覽器和要與其通訊的瀏覽器可以處理哪些編解碼和解析度?

透過訊號交換資訊後,才能開始進行點對點串流。

舉例來說,假設 Alice 想與 Bob 進行通訊,以下是 W3C WebRTC 規格的程式碼範例,說明信號傳送程序的運作方式。程式碼會假設 createSignalingChannel() 方法中已建立某些訊號機制。另請注意,在 Chrome 和 Opera 中,RTCPeerConnection 目前是前置字串。

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // Send the offer to the other peer.
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

首先,Alice 和 Bob 會交換網路資訊。(「尋找候選項目」一詞是指使用 ICE 架構尋找網路介面和通訊埠的程序)。

  1. Alice 會使用 onicecandidate 處理常式建立 RTCPeerConnection 物件,當網路候選項目可用時,就會執行這個物件。
  2. Alice 會透過所使用的任何信號通道 (例如 WebSocket 或其他機制),將序列化的候選資料傳送給 Bob。
  3. 當 Bob 收到 Alice 傳來的候選訊息時,他會呼叫 addIceCandidate,將候選訊息新增至遠端對等端描述。

WebRTC 用戶端 (也稱為對等端,或本例中的 Alice 和 Bob) 也需要確認及交換本機和遠端音訊和視訊媒體資訊,例如解析度和編解碼器功能。使用工作階段描述通訊協定 (SDP) 交換「出價」和「答覆」,即可傳送訊號交換媒體設定資訊:

  1. Alice 執行 RTCPeerConnection createOffer() 方法。此方法的傳回值會傳遞 RTCSessionDescription - Alice 的本機工作階段說明。
  2. 在回呼中,Alice 使用 setLocalDescription() 設定本機說明,然後透過信號通道將這個工作階段說明傳送給 Bob。請注意,RTCPeerConnection 必須等到 setLocalDescription() 呼叫後才會開始收集候選項目。這項規範已在 JSEP IETF 草案中編碼。
  3. Bob 使用 setRemoteDescription() 將 Alice 傳送的說明設為遠端說明。
  4. Bob 執行 RTCPeerConnection createAnswer() 方法,將從 Alice 取得的遠端說明傳遞給該方法,以便產生與 Alice 相容的本機工作階段。createAnswer() 回呼會傳遞 RTCSessionDescription。Bob 將其設為本機說明,並傳送給 Alice。
  5. 當阿莉取得志明的工作階段說明時,她會使用 setRemoteDescription 將其設為遠端說明。
  6. 連線偵測!

RTCSessionDescription 物件是符合會話描述協定 (SDP) 的 Blob。經過序列化的 SDP 物件如下所示:

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

取得和交換網路和媒體資訊的程序可以同時進行,但必須先完成這兩個程序,才能開始在對等端之間串流音訊和視訊。

先前所述的提供/回應架構稱為 JavaScript 會話建立通訊協定 (JSEP)。Ericsson 的示範影片中,有精彩的動畫說明信號和串流程序,這是 Ericsson 首次實作 WebRTC 的成果。

JSEP 架構圖
JSEP 架構

信號傳遞程序完成後,資料即可直接在呼叫端和被叫端之間進行點對點串流,如果失敗,則可透過中介轉送伺服器 (稍後會進一步說明) 進行串流。串流是 RTCPeerConnection 的工作。

RTCPeerConnection

RTCPeerConnection 是 WebRTC 元件,可處理點對點間穩定且有效率的串流資料通訊。

下圖為 WebRTC 架構圖,顯示 RTCPeerConnection 的角色。您會發現,綠色部分非常複雜!

WebRTC 架構圖
WebRTC 架構 (取自 webrtc.org)

從 JavaScript 的角度來看,這張圖表的主要重點是 RTCPeerConnection 可讓網頁開發人員不必面對潛藏在底層的複雜性。WebRTC 使用的編碼器和通訊協定可讓即時通訊順利進行,即使是在不穩定的網路上也一樣:

  • 封包遺失隱藏
  • 消除回音
  • 頻寬適應性
  • 動態抖動緩衝
  • 自動增益控制
  • 降噪和抑噪
  • 圖片清理

上述 W3C 程式碼顯示了從信號傳遞角度簡化的 WebRTC 範例。以下是兩個運作中的 WebRTC 應用程式示範。第一個是簡單的範例,用來示範 RTCPeerConnection;第二個是完整運作的視訊通訊用戶端。

不使用伺服器的 RTCPeerConnection

以下程式碼取自 WebRTC 範例 Peer connection,其中在一個網頁上有本機 遠端 RTCPeerConnection (以及本機和遠端影片)。這並沒有什麼實用之處,因為呼叫端和被呼叫端位於同一頁面,但這確實讓 RTCPeerConnection API 的運作方式更為清楚,因為網頁上的 RTCPeerConnection 物件可直接交換資料和訊息,不必使用中介訊號機制。

在本例中,pc1 代表本機端 (呼叫端),pc2 代表遠端 (被叫端)。

來電者

  1. 建立新的 RTCPeerConnection,並從 getUserMedia() 新增串流: ```js // Servers 是選用的設定檔。(請參閱稍後的 TURN 和 STUN 討論)。 pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. 建立優惠,並將其設為 pc1 的本地說明,以及 pc2 的遠端說明。由於呼叫端和被叫端位於同一頁面,因此您可以在程式碼中直接執行這項操作,而無需使用訊號: js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

被叫方

  1. 建立 pc2,並在新增 pc1 的串流時,在影片元素中顯示串流:js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

RTCPeerConnection API 加伺服器

在實際情況中,WebRTC 需要伺服器,即使是簡單的伺服器也一樣,因此可能會發生以下情況:

  • 使用者可以彼此互相認識,並交換真實世界中的詳細資料,例如姓名。
  • WebRTC 用戶端應用程式 (對等端) 交換網路資訊。
  • 同儕會交換媒體相關資料,例如影片格式和解析度。
  • WebRTC 用戶端應用程式會穿越 NAT 閘道和防火牆。

換句話說,WebRTC 需要四種伺服器端功能:

  • 使用者探索和通訊
  • 訊號
  • NAT/防火牆周遊功能
  • 在對等端對端通訊失敗時使用中繼伺服器

本文不討論 NAT 穿越、點對點網路,以及建構用於使用者探索和信號傳遞的伺服器應用程式所需的條件。簡單來說,STUN 通訊協定及其擴充功能 TURN 會由 ICE 架構使用,讓 RTCPeerConnection 能夠處理 NAT 穿越和其他網路變化。

ICE 是用於連線同儕 (例如兩個視訊通訊用戶端) 的架構。一開始,ICE 會嘗試透過 UDP 以盡可能低的延遲時間直接連線至對等端。在這項程序中,STUN 伺服器只有一項工作:讓 NAT 後方的對等端找出其公開位址和連接埠。(如要進一步瞭解 STUN 和 TURN,請參閱「建構 WebRTC 應用程式所需的後端服務」一文)。

尋找可連結的對象
尋找連線候選項目

如果 UDP 失敗,ICE 會嘗試使用 TCP。如果直接連線失敗 (特別是因為企業 NAT 穿越和防火牆),ICE 會使用中介 (轉送) TURN 伺服器。換句話說,ICE 會先使用 STUN 搭配 UDP 直接連線至對等端,如果失敗,就會改為使用 TURN 中繼伺服器。finding candidates 是指尋找網路介面和通訊埠的程序。

WebRTC 資料路徑
WebRTC 資料路徑

WebRTC 工程師 Justin Uberti 在 2013 年 Google I/O 大會的 WebRTC 簡報中,進一步說明 ICE、STUN 和 TURN。(簡報投影片提供 TURN 和 STUN 伺服器實作範例)。

簡易的視訊通話用戶端

appr.tc 的視訊通話示範是嘗試 WebRTC 的絕佳選擇,您可以使用 STUN 伺服器進行信號傳送和 NAT/防火牆穿越。這個應用程式使用 adapter.js,這是用來隔離應用程式與規格變更和前置字串差異的墊片。

程式碼會刻意在記錄中加入冗長的說明。請查看控制台,瞭解事件的順序。以下是程式碼的詳細操作說明。

網路拓撲

目前實作的 WebRTC 僅支援一對一通訊,但可用於更複雜的網路情境,例如多個對等端彼此直接或透過多點控制單元 (MCU) 進行通訊,MCU 是可處理大量參與者,並執行選取串流轉寄、混合或錄製音訊和影像的伺服器。

多點控制單元拓撲圖
多點控制單元拓撲範例

許多現有的 WebRTC 應用程式只會展示網路瀏覽器之間的通訊,但閘道伺服器可讓在瀏覽器上執行的 WebRTC 應用程式與裝置互動,例如電話 (也稱為 PSTN) 和VOIP 系統。2012 年 5 月,Doubango Telecom 將使用 WebRTC 和 WebSocket 建構的 sipml5 SIP 用戶端開放原始碼,除了其他潛在用途外,這項技術還可在 iOS 和 Android 裝置上,透過瀏覽器和應用程式進行視訊通話。在 Google I/O 大會上,Tethr 和 Tropo 展示了災難通訊架構 在公事包中,使用OpenBTS 小型基地台,透過 WebRTC 讓功能型手機和電腦之間進行通訊。不透過電信業者進行電話通訊!

2012 年 Google I/O 大會上的 Tethr/Tropo 示範
Tethr/Tropo:災難通訊隨身攜帶

RTCDataChannel API<

除了音訊和視訊,WebRTC 也支援其他類型的即時通訊。

RTCDataChannel API 可讓使用者以低延遲和高處理量,進行點對點的任意資料交換。如需單頁範例,以及瞭解如何建構簡單的檔案傳輸應用程式,請分別參閱 WebRTC 範例WebRTC 程式碼研究室

API 的用途相當多元,包括:

  • 遊戲
  • 遠端桌面應用程式
  • 即時文字即時通訊
  • 檔案傳輸
  • 去中心化網路

這個 API 提供多項功能,可充分運用 RTCPeerConnection,並提供強大且靈活的點對點通訊功能:

  • 利用 RTCPeerConnection 工作階段設定
  • 同時放送多個頻道,並設定優先順序
  • 可靠和不可靠的提交語意
  • 內建安全性 (DTLS) 和壅塞控制
  • 可在有或沒有音訊/視訊的情況下使用

我們刻意將語法設為類似 WebSocket,並搭配 send() 方法和 message 事件:

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

通訊會直接在瀏覽器之間進行,因此即使在透過洞檢測來因應防火牆和 NAT 失敗時,RTCDataChannel 的速度也比 WebSocket 快上許多,即使需要轉送 (TURN) 伺服器也一樣。

RTCDataChannel 可在 Chrome、Safari、Firefox、Opera 和 Samsung Internet 中使用。Cube Slam 遊戲會使用 API 傳達遊戲狀態。扮演朋友或熊!創新平台 Sharefest 可透過 RTCDataChannel 分享檔案,而 peerCDN 則讓我們一窺 WebRTC 如何啟用點對點內容分發功能。

如要進一步瞭解 RTCDataChannel,請參閱 IETF 的通訊協定規格草稿

安全性

即時通訊應用程式或外掛程式可能會透過多種方式危害安全性。例如:

  • 未加密的媒體或資料可能會在瀏覽器之間,或在瀏覽器與伺服器之間遭到攔截。
  • 應用程式可能會在使用者不知情的情況下錄製及發布影片或音訊。
  • 惡意軟體或病毒可能會與看似無害的外掛程式或應用程式一併安裝。

WebRTC 提供多項功能,可避免發生這些問題:

  • WebRTC 實作項目會使用安全的通訊協定,例如 DTLSSRTP
  • 所有 WebRTC 元件 (包括訊號機制) 都必須加密。
  • WebRTC 並非外掛程式。其元件會在瀏覽器沙箱中執行,而不是在獨立程序中執行。元件不需要另外安裝,且每次瀏覽器更新時都會更新。
  • 必須明確授予攝影機和麥克風存取權,並在使用者介面上清楚顯示攝影機或麥克風正在運作。

本文不會詳細討論串流媒體的安全性。詳情請參閱 IETF 提出的建議 WebRTC 安全性架構

總結

WebRTC 的 API 和標準可讓內容創作和通訊工具民主化和去中心化,包括電話、遊戲、影片製作、音樂製作和新聞收集。

這項技術的創新性,可說是前所未見。

正如網誌作者 Phil Edholm 所說:「WebRTC 和 HTML5 可能會為即時通訊啟用與原始瀏覽器相同的轉換資訊。」

開發人員工具

瞭解詳情

標準和通訊協定

WebRTC 支援摘要

MediaStreamgetUserMedia API

  • Chrome 電腦版 18.0.1008 以上版本;Chrome 適用於 Android 29 以上版本
  • Opera 18 以上版本;Android 版 Opera 20 以上版本
  • Opera 12、Opera Mobile 12 (採用 Presto 引擎)
  • Firefox 17 以上版本
  • Microsoft Edge 16 以上版本
  • iOS 上的 Safari 11.2 以上版本,以及 MacOS 上的 11.1 以上版本
  • Android 版 UC 11.8 以上版本
  • Samsung Internet 4 以上版本

RTCPeerConnection API

  • Chrome 電腦版 20 以上版本;Chrome 行動版 29 以上版本 (無標記)
  • Opera 18 以上版本 (預設為開啟);Android 版 Opera 20 以上版本 (預設為開啟)
  • Firefox 22 以上版本 (預設為開啟)
  • Microsoft Edge 16 以上版本
  • iOS 上的 Safari 11.2 以上版本,以及 MacOS 上的 11.1 以上版本
  • Samsung Internet 4 以上版本

RTCDataChannel API

  • Chrome 25 為實驗性版本,但 Chrome 26 以上版本更穩定 (且支援 Firefox 互通性);Android 版 Chrome 29 以上版本
  • Opera 18 以上版本的穩定版 (並支援 Firefox 互通性);Opera for Android 20 以上版本
  • Firefox 22 以上版本 (預設為開啟)

如要進一步瞭解 API 的跨平台支援功能 (例如 getUserMediaRTCPeerConnection),請參閱 caniuse.comChrome 平台狀態

RTCPeerConnection 的原生 API 也提供於 webrtc.org 上的說明文件