開始使用 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 年開始受到歡迎。Google 在 2011 年推出了 Hangouts,這項服務則使用 Talk (與 Gmail 一樣)。Google 收購了 GIPS,GIPS 該公司開發了 RTC 所需的許多元件,例如轉碼器和回音消除技術。Google 提供由 GIPS 開發的技術,並與網際網路工程任務部 (IETF) 和全球資訊網協會 (World Wide Web Consortium,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 Sample Peer connectionappr.tc。這個應用程式使用了 adapter.js,這是 Google 維護的 JavaScript 輔助程式,在 WebRTC 社群的協助下,去除瀏覽器差異和規格變更。

RTCDataChannel:如要查看實際做法,請參閱 WebRTC 範例,前往 Data-channel 示範的其中一個例子。

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 物件參數,並傳回 Promise,該參數會解析為 MediaStream 物件。

每個 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()」授予權限一次。在此情況下,瀏覽器的資訊列中會顯示 [允許] 按鈕。由於 getUserMedia() 的 HTTP 存取權屬於強大功能,因此已在 2015 年底淘汰。

此意圖可能是為任何串流資料來源啟用 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 做為信號機制。程式碼研究室會使用在節點伺服器上執行的 Socket.io

信號可用於交換下列三種資訊:

  • 工作階段控制訊息:初始化或關閉通訊並回報錯誤。
  • 網路設定:對外公開,電腦的 IP 位址和通訊埠為何?
  • 媒體功能:瀏覽器和想要與其通訊的瀏覽器,能處理哪些轉碼器和解析度?

必須透過信號傳送資訊交換作業,系統才能開始進行點對點串流。

例如,假設小艾想要與志明溝通,以下為 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);
  }
};

首先,麗麗和小柏會交換網路資訊。(運算式「尋找候選項目」是指使用 ICE 架構尋找網路介面和通訊埠的程序)。

  1. Alice 會建立 RTCPeerConnection 物件,其中包含 onicecandidate 處理常式,在候選網路可用時執行。
  2. Alice 會透過 WebSocket 等所使用的任何信號管道,將序列化的候選資料傳送給 Bob。
  3. 當小明收到來自 Alice 的候選人訊息時,會呼叫 addIceCandidate,將候選對象加入遠端同類應用程式說明中。

WebRTC 用戶端 (在本範例中也稱為「同業」,或稱「Alice」和「Bob」) 也需要確認及交換本機和遠端音訊和視訊媒體資訊,例如解析度和轉碼器功能。使用會話說明通訊協定 (SDP) 交換 方案答案,指示交換媒體設定資訊的動作:

  1. Alice 會執行 RTCPeerConnection createOffer() 方法。此回應會傳回 RTCSessionDescription,也就是 Alice 的本機工作階段說明。
  2. 在回呼中,Alice 使用 setLocalDescription() 設定本機說明,然後透過信號管道,將此工作階段說明傳送給 Bob。請注意,只有在呼叫 setLocalDescription() 後,RTCPeerConnection 才會開始收集候選項目。並在 JSEP IETF 草稿中編寫而成。
  3. Bob 使用 setRemoteDescription() 將說明設為遠端說明,
  4. Bob 執行 RTCPeerConnection createAnswer() 方法,並傳遞他從 Alice 取得的遠端說明,以便產生與她相容的本機工作階段。createAnswer() 回呼會傳遞 RTCSessionDescription。接著,他將這段文字設為當地說明,並傳送給 Alice。
  5. 她在取得 Bob 的工作階段說明時,將這段說明設為 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。(有一部非常出色的動畫,能針對首次導入 WebRTC 的 Ericsson 示範影片說明信號和串流程序。)

JSEP 架構圖
JSEP 架構

信號傳送程序順利完成後,資料可在呼叫端與受呼叫端之間直接對點對點串流;如果失敗,也可以透過中介轉發伺服器 (稍後會詳細說明)。串流是 RTCPeerConnection 的工作。

RTCPeerConnection

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

以下是顯示 RTCPeerConnection 角色的 WebRTC 架構圖。如您所見,綠色部分相當複雜!

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

從 JavaScript 的角度來看,這張圖表的主要重點在於 RTCPeerConnection 能協助網頁開發人員免於潛藏在各種複雜複雜的工作上。即使 WebRTC 使用的轉碼器和通訊協定不穩定,也能執行大量的即時通訊,實現即時通訊:

  • 封包遺失率隱藏功能
  • 消除回聲
  • 頻寬調整
  • 動態抖動緩衝處理
  • 自動增益控制
  • 雜訊抑制和抑制
  • 圖片清理

先前的 W3C 程式碼從信號的角度來看,簡化了 WebRTC 的簡化範例。以下是兩個運作中的 WebRTC 應用程式的逐步操作說明。第一個用於示範 RTCPeerConnection 的簡單範例,第二個則是功能完整的視訊通訊用戶端。

RTCPeerConnection (不使用伺服器)

以下程式碼擷取自 WebRTC 對等互連範例對等互連,這個連線在單一網頁上包含本機「和」遠端 RTCPeerConnection (以及本機和遠端影片)。這並不算什麼有用,例如呼叫者和受呼叫者是在同一個頁面上,但其實 RTCPeerConnection API 的運作更加清楚,因為頁面上的 RTCPeerConnection 物件可以直接交換資料和訊息,而不必使用中介信號機制。

在本例中,pc1 代表本機對等點 (呼叫端),pc2 代表遠端對等點 (受呼叫端)。

來電者

  1. 建立新的 RTCPeerConnection,並從 getUserMedia() 新增串流: ```js // 伺服器是選用的設定檔。(稍後請參閱 TURN 和 STUN 的討論)。 pc1 = 新的 RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) =&gt; { 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) 週遊、點對點網路,以及建構伺服器應用程式以協助使用者探索及傳送信號時須滿足的需求。您可以說明 ICE 架構使用 STUN 通訊協定及其擴充功能 TURN,讓 RTCPeerConnection 能因應 NAT 遍歷和其他網路變遷。

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

尋找候選連線
尋找候選連線

如果 UDP 失敗,ICE 就會嘗試 TCP。如果直接連線失敗,特別是因為企業 NAT 週遊和防火牆,ICE 會使用中介 (relay) TURN 伺服器。也就是說,ICE 會先使用 STUN 搭配 UDP 直接連結對等點,如果失敗,則會改回使用 TURN 轉發伺服器。「尋找候選項目」運算式指的是尋找網路介面和通訊埠的程序。

WebRTC 資料路徑
WebRTC 資料路徑

WebRTC 工程師 Justin Uberti 在 2013 年 Google I/O WebRTC 簡報中提供了 ICE、STUN 和 TURN 的詳細資訊。(如需 TURN 和 STUN 伺服器實作範例,請參閱簡報投影片)。

簡單的視訊通訊用戶端

前往 appr.tc 觀看示範影片,即可透過 STUN 伺服器發出訊號和 NAT/防火牆週遊等 WebRTC。這個應用程式會使用 adapter.js,在規格變更和前置字元差異的情況下,插入應用程式的填充碼。

程式碼在記錄中刻意詳細。請前往控制台瞭解事件順序。以下是程式碼的詳細逐步操作說明。

網路拓撲

目前實作的 WebRTC 僅支援一對一通訊,但也可用於較複雜的網路情境,例如與多個對等節點直接互相通訊,或透過多點控制單元 (MCU) 使用;這個伺服器可處理大量參與者並進行選擇性串流轉送,以及混和或錄製音訊和影片。

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

許多現有的 WebRTC 應用程式都只會展示網路瀏覽器之間的通訊,但閘道伺服器可讓瀏覽器上執行的 WebRTC 應用程式與電話 (也稱為 PSTN) 和 VOIP 系統等裝置互動。Doubango Telecom 於 2012 年 5 月以 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);
};

瀏覽器會直接通訊,因此 RTCDataChannel 速度可能比 WebSocket 快得多,即使需要轉送 (TURN) 伺服器才能應付防火牆和 NAT 無法正常運作,亦然。

RTCDataChannel」支援 Chrome、Safari、Firefox、Opera 和 Samsung Internet。Cube Slam 遊戲會使用這個 API 通訊遊戲狀態。與好友玩遊戲或玩小熊!透過 RTCDataChannelpeerCDN 的創新平台 Sharefest 分享檔案功能,有助於一窺 WebRTC 如何啟用點對點內容發布功能。

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

安全性

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

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

WebRTC 具備幾項功能可避免這些問題:

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

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

總結

WebRTC 的 API 和標準可將內容製作與通訊 (包括電話通訊、遊戲、影片製作、音樂製作和新聞收集) 等工具去中心化,使人人受惠。

科技並未嚴重造成乾擾

以 Blogger Phil Edholm 安裝的例子來說,「WebRTC 和 HTML5 也能像原始瀏覽器那樣促成即時通訊,透過相同的方式進行即時通訊。」

開發人員工具

瞭解詳情

標準和通訊協定

WebRTC 支援摘要

MediaStreamgetUserMedia API

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

RTCPeerConnection API

  • Chrome 電腦版 20 以上版本;Android 29 以上版本的 Chrome (無旗標)
  • Opera 18 以上版本 (預設為開啟);Android 20 以上版本 Opera (預設為開啟)
  • Firefox 22 以上版本 (預設為開啟)
  • Microsoft Edge 16 以上版本
  • Safari 11.2 (iOS) 和 11.1 或更新版本 (MacOS)
  • Samsung Internet 4 以上版本

RTCDataChannel API

  • Chrome 25 中的實驗性版本,但在 Chrome 26 以上版本中則更為穩定 (且與 Firefox 互通性也更穩定);Android 29 以上版本的 Google Chrome
  • Opera 18 以上版本的穩定版 (與 Firefox 互通性);Opera (適用於 Android 20 以上版本)
  • Firefox 22 以上版本 (預設為開啟)

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

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