建構 WebRTC 應用程式所需的後端服務

什麼是信號?

信號是協調通訊的過程。為了讓 WebRTC 應用程式設定通話,其用戶端需要交換下列資訊:

  • 用於開啟或關閉通訊的會話控制訊息
  • 錯誤訊息
  • 媒體中繼資料,例如編解碼器、編解碼器設定、頻寬和媒體類型
  • 用於建立安全連線的重要資料
  • 網路資料,例如外部世界看到的主機 IP 位址和連接埠

這個訊號傳送程序需要用戶端來來回傳遞訊息。WebRTC API 並未實作這項機制。您必須自行建構。本文稍後會說明如何建構信號傳遞服務。不過,首先需要一點背景資訊。

為什麼 WebRTC 未定義訊號?

為避免重複,並盡可能與既有技術相容,WebRTC 標準並未指定訊號傳送方法和通訊協定。JavaScript 工作階段建立協定 (JSEP) 概述了這種做法:

JSEP 的架構也能避免瀏覽器必須儲存狀態,也就是當作信號狀態機制運作。舉例來說,如果每次重新載入網頁時都會遺失信號資料,就會發生問題。而是將信號狀態儲存在伺服器上。

JSEP 架構圖
JSEP 架構

JSEP 要求offeranswer 之間的對等端交換,也就是上述所述的媒體中繼資料。系統會以會話描述協定 (SDP) 格式傳送提案和答案,格式如下:

v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…

想知道這些 SDP 的內容實際上代表什麼嗎?參閱 網際網路工程任務組 (IETF) 範例

請注意,WebRTC 的設計可讓您在將提案或答案設為本機或遠端說明之前,先透過編輯 SDP 文字中的值來調整提案或答案。舉例來說,您可以使用 appr.tc 中的 preferAudioCodec() 函式設定預設編解碼器和位元率。使用 JavaScript 操作 SDP 會比較麻煩,因此有人討論是否應在日後的 WebRTC 版本中改用 JSON,但堅持使用 SDP 也有一些優點

RTCPeerConnection API 和訊號:商品、答案和候選項目

RTCPeerConnection 是 WebRTC 應用程式用來在對等端之間建立連線,以及傳輸音訊和視訊的 API。

為了初始化這項程序,RTCPeerConnection 有兩項工作:

  • 確認本機媒體條件,例如解析度和編解碼器功能。這是用於報價和回應機制的中繼資料。
  • 取得應用程式主機的潛在網路位址,稱為候選值

確認本機資料後,必須透過訊號機制與遠端對等端交換資料。

假設Alice 嘗試撥打電話給 Eve,以下是完整的提供/回應機制:

  1. Alice 建立 RTCPeerConnection 物件。
  2. Alice 使用 RTCPeerConnection createOffer() 方法建立優惠 (SDP 工作階段說明)。
  3. Alice 撥打電話給 setLocalDescription(),並提供優惠。
  4. Alice 將優惠轉為字串,並使用信號機制將其傳送給 Eve。
  5. Eve 會呼叫 setRemoteDescription() 並傳送 Alice 的商品,讓 RTCPeerConnection 瞭解 Alice 的設定。
  6. Eve 呼叫 createAnswer(),成功回呼會傳遞本機工作階段說明 - Eve 的答案。
  7. Eve 呼叫 setLocalDescription(),將自己的答案設為本機說明。
  8. 接著,Eve 會使用信號機制,將字串化答案傳送給 Alice。
  9. Alice 使用 setRemoteDescription() 將 Eve 的答案設為遠端工作階段說明。

Alice 和 Eve 也需要交換網路資訊。「尋找候選項目」這個詞彙指的是使用 ICE 架構尋找網路介面和通訊埠的程序。

  1. Alice 使用 onicecandidate 處理常式建立 RTCPeerConnection 物件。
  2. 網路候選項目可用時,系統會呼叫這個處理常式。
  3. 在處理程序中,Alice 會透過信號通道,將字串化候選資料傳送給 Eve。
  4. 當 Eve 從 Alice 取得候選訊息時,她會呼叫 addIceCandidate(),將候選訊息新增至遠端對等端描述。

JSEP 支援 ICE 候選端點涓滴傳送,可讓呼叫端在初始提供後,逐步將候選端點提供給被叫端,讓被叫端開始處理通話並建立連線,而無須等待所有候選端點到達。

為信號編寫 WebRTC 程式碼

以下程式碼片段是W3C 程式碼範例,可概略說明完整的信號傳送程序。程式碼假設存在某些信號機制 SignalingChannel。稍後會詳細說明信號。

// 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);
  }
};

// After 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);
  }
};

如要查看報價/答覆和候選交換程序的實際運作情形,請參閱 simpl.info RTCPeerConnection,並查看主控台記錄中的單頁面視訊通話範例。如需更多資訊,請從 Google Chrome 的 about://webrtc-internals 頁面或 Opera 的 opera://webrtc-internals 頁面,下載完整的 WebRTC 訊號和統計資料傾印。

同類應用程式探索

這是詢問「如何找到可以交談的人」的另一種說法。

電話號碼和電話簿。如要提供線上視訊通訊和訊息服務,您需要建立身分和狀態管理系統,並提供使用者啟動工作階段的方式。WebRTC 應用程式需要一種方式,讓用戶端彼此傳送訊號,表示要開始或加入通話。

WebRTC 並未定義同端偵測機制,因此您無法在此選項中進行設定。這個程序可以簡單到只要透過電子郵件或訊息傳送網址即可。對於 Talkytawk.toBrowser Meeting 等視訊聊天應用程式,您可以透過分享自訂連結邀請他人加入通話。開發人員 Chris Ball 建立了一個有趣的 無伺服器 webrtc 實驗,讓 WebRTC 通話參與者可以透過任何喜歡的訊息服務 (例如即時通訊、電子郵件或信鴿) 交換中繼資料。

如何建構信號傳遞服務?

再次強調,WebRTC 標準並未定義信號傳遞通訊協定和機制。無論您選擇哪種方式,都需要中介伺服器,才能在用戶端之間交換信號訊息和應用程式資料。很遺憾,網頁應用程式無法直接向網路大喊「請幫我連線給朋友!」

所幸,信號訊息的大小不大,而且大多是在通話開始時交換。在使用 appr.tc 進行視訊通話工作階段的測試中,信號傳遞服務處理的訊息總數約為 30 到 45 則,所有訊息的總大小約為 10 KB。

除了頻寬需求相對較低之外,WebRTC 信號服務也不會耗用太多處理或記憶體資源,因為它們只需要轉送訊息,並保留少量的工作階段狀態資料,例如哪些用戶端已連線。

將訊息從伺服器推送至用戶端

用於信號傳遞的訊息服務必須是雙向的:用戶端傳送至伺服器,伺服器傳送至用戶端。雙向通訊違反 HTTP 用戶端/伺服器的請求/回應模型,但多年以來,我們已開發出各種駭客攻擊,例如長時間輪詢,用於將資料從在網路伺服器上執行的服務推送至在瀏覽器中執行的網路應用程式。

近期,EventSource API廣泛導入。這可啟用伺服器傳送事件,也就是透過 HTTP 從網路伺服器傳送至瀏覽器用戶端的資料。EventSource 是專為單向訊息設計,但可與 XHR 搭配使用,建立用於交換信號訊息的服務。信號服務會透過 EventSource 將 XHR 要求傳送的訊息,從呼叫端傳遞至被叫端。

WebSocket 是更自然的解決方案,專為全雙工用戶端-伺服器通訊而設計,可同時傳送雙向訊息。使用純 WebSocket 或伺服器傳送事件 (EventSource) 建構的信號傳遞服務,其中一個優點是這些 API 的後端可在多種網路架構上實作,這些架構適用於 PHP、Python 和 Ruby 等語言的大多數網路代管套件。

除了 Opera Mini 以外,所有新型瀏覽器都支援 WebSocket,更重要的是,所有支援 WebRTC 的瀏覽器 (包括電腦和行動版) 也支援 WebSocket。應針對所有連線使用 TLS,確保無法攔截未加密的郵件,並減少 Proxy 轉送問題。(如要進一步瞭解 WebSocket 和 Proxy Traversal,請參閱 Ilya Grigorik 的 高效能瀏覽器網路連線一書中的 WebRTC 章節)。

您也可以透過讓 WebRTC 用戶端透過 Ajax 重複輪詢訊息伺服器的方式處理訊號,但這會導致大量不必要的網路要求,對行動裝置來說尤其成問題。即使建立工作階段後,同儕仍需輪詢訊號訊息,以防其他同儕變更或終止工作階段。WebRTC Book 應用程式範例採用了這個選項,並針對輪詢頻率進行了一些最佳化。

規模信號

雖然每個用戶端的信號傳遞服務所消耗的頻寬和 CPU 相對較少,但熱門應用程式的信號傳遞伺服器可能必須處理來自不同位置的大量訊息,並且同時處理大量訊息。流量龐大的 WebRTC 應用程式需要信號傳送伺服器,才能處理大量負載。您未在此處詳述,但有許多選項可用於傳送大量高效能訊息,包括:

  • eXtensible Messaging and Presence Protocol (XMPP),原本稱為 Jabber,這是一種專為即時通訊而開發的通訊協定,可用於信號傳送 (伺服器實作包括 ejabberdOpenfire)。JavaScript 用戶端 (例如 Strophe.js) 會使用 BOSH 模擬雙向串流,但由於各種原因,BOSH 可能不如 WebSocket 有效率,且基於相同原因,可能無法順利擴充。(順帶一提,Jingle 是 XMPP 擴充功能,可啟用語音和視訊功能。WebRTC 專案使用 libjingle 程式庫中的網路和傳輸元件,這是 Jingle 的 C++ 實作。

  • 開放原始碼程式庫,例如 ZeroMQ (TokBox 用於其 Rumour 服務) 和 OpenMQ (NullMQ 將 ZeroMQ 概念套用至使用 WebSocket 的 STOMP 通訊協定的網站平台)。

  • 使用 WebSocket (但可能會改用長時間輪詢) 的商業雲端訊息平台,例如 PusherKaazingPubNub (PubNub 也提供 WebRTC API)。

  • 商業 WebRTC 平台,例如 vLine

(開發人員 Phil Leggetter 的即時網路技術指南提供完整的訊息傳遞服務和程式庫清單)。

在 Node 上使用 Socket.io 建構信號服務

以下是簡易網頁應用程式的程式碼,該應用程式使用在 Node 上以 Socket.io 建構的信號傳遞服務。由於 Socket.io 的設計,您可以輕鬆建構用於交換訊息的服務,而且 Socket.io 內建的房間概念特別適合 WebRTC 訊號。這個範例並非用於擴充為正式版的信號傳遞服務,但對於相對少數的使用者來說,這項服務很容易理解。

Socket.io 會使用 WebSocket 搭配備用方案:AJAX 長時間輪詢、AJAX 多部分串流、Forever Iframe 和 JSONP 輪詢。它已移植至各種後端,但最知名的版本可能是本範例中使用的 Node 版本。

這個範例中沒有 WebRTC。這項功能僅用於說明如何在網路應用程式中建構信號。您可以查看控制台記錄,瞭解用戶端加入聊天室並交換訊息時發生的情況。這個 WebRTC 程式碼研究室提供逐步操作說明,說明如何將此功能整合至完整的 WebRTC 視訊聊天應用程式。

以下是用戶端 index.html

<!DOCTYPE html>
<html>
  <head>
    <title>WebRTC client</title>
  </head>
  <body>
    <script src='/socket.io/socket.io.js'></script>
    <script src='js/main.js'></script>
  </body>
</html>

以下是用戶端參照的 JavaScript 檔案 main.js

const isInitiator;

room = prompt('Enter room name:');

const socket = io.connect();

if (room !== '') {
  console.log('Joining room ' + room);
  socket.emit('create or join', room);
}

socket.on('full', (room) => {
  console.log('Room ' + room + ' is full');
});

socket.on('empty', (room) => {
  isInitiator = true;
  console.log('Room ' + room + ' is empty');
});

socket.on('join', (room) => {
  console.log('Making request to join room ' + room);
  console.log('You are the initiator!');
});

socket.on('log', (array) => {
  console.log.apply(console, array);
});

以下是完整的伺服器應用程式:

const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
  file.serve(req, res);
}).listen(2013);

const io = require('socket.io').listen(app);

io.sockets.on('connection', (socket) => {

  // Convenience function to log server messages to the client
  function log(){
    const array = ['>>> Message from server: '];
    for (const i = 0; i < arguments.length; i++) {
      array.push(arguments[i]);
    }
      socket.emit('log', array);
  }

  socket.on('message', (message) => {
    log('Got message:', message);
    // For a real app, would be room only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', (room) => {
    const numClients = io.sockets.clients(room).length;

    log('Room ' + room + ' has ' + numClients + ' client(s)');
    log('Request to create or join room ' + room);

    if (numClients === 0){
      socket.join(room);
      socket.emit('created', room);
    } else if (numClients === 1) {
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room);
    } else { // max two clients
      socket.emit('full', room);
    }
    socket.emit('emit(): client ' + socket.id +
      ' joined room ' + room);
    socket.broadcast.emit('broadcast(): client ' + socket.id +
      ' joined room ' + room);

  });

});

(您不需要瞭解 node-static 就能完成這項操作。只是剛好在本範例中使用。)

如要在本機主機上執行這個應用程式,您必須安裝 Node、Socket.IO 和 node-static。您可以從 Node.js 下載 Node (安裝程序簡單又快速)。如要安裝 Socket.IO 和 node-static,請在應用程式目錄中的終端機中執行 Node Package Manager:

npm install socket.io
npm install node-static

如要啟動伺服器,請在應用程式目錄的終端機中執行下列指令:

node server.js

在瀏覽器中開啟 localhost:2013。在任何瀏覽器中開啟新的分頁或視窗,然後再次開啟 localhost:2013。如要查看發生什麼事,請查看控制台。在 Chrome 和 Opera 中,您可以透過 Google Chrome 開發人員工具使用 Ctrl+Shift+J (或在 Mac 上使用 Command+Option+J) 存取主控台。

無論您選擇何種方式傳送信號,後端和用戶端應用程式至少都需要提供類似於此範例的服務。

信號相關注意事項

  • RTCPeerConnection 會在 setLocalDescription() 呼叫後才開始收集候選項目。這項規定已在 JSEP IETF 草案中明文規定。
  • 善用 Trickle ICE。應徵者抵達後,請立即呼叫 addIceCandidate()

現成訊號伺服器

如果您不想自行建構,可以使用幾個 WebRTC 信號傳送伺服器,這些伺服器會像前述範例一樣使用 Socket.IO,並與 WebRTC 用戶端 JavaScript 程式庫整合:

如果您不想編寫任何程式碼,可以使用 vLineOpenTokAsterisk 等公司提供的完整商業 WebRTC 平台。

據我們所知,Ericsson 在 WebRTC 初期,使用 Apache 上的 PHP 建立了訊號傳送伺服器。這項功能現已淘汰,但如果您考慮類似的功能,不妨參考這段程式碼。

信號安全性

「安全性是一種讓事情不發生的藝術。」

Salman Rushdie

所有 WebRTC 元件都必須進行加密。

不過,WebRTC 標準並未定義信號機制,因此您必須自行確保信號安全。如果攻擊者成功劫持訊號,就能停止工作階段、重新導向連線,以及記錄、變更或插入內容。

在安全信號中,最重要的因素就是使用安全通訊協定 (HTTPS 和 WSS,例如 TLS),確保訊息不會在未加密的情況下遭到攔截。此外,請注意不要以可讓其他使用相同訊號伺服器的呼叫端存取的方式,廣播訊號訊息。

訊號傳送後:使用 ICE 處理 NAT 和防火牆

針對中繼資料訊號,WebRTC 應用程式會使用中介伺服器,但在建立工作階段後,如果要進行實際的媒體和資料串流,RTCPeerConnection 會嘗試直接連線至用戶端或點對點。

在較為簡單的情況下,每個 WebRTC 端點都會有專屬的地址,可與其他端點交換資料,以便直接通訊。

簡單的對等點連線
沒有 NAT 和防火牆的世界

實際上,大多數裝置都位於一或多層 NAT 後方,有些裝置的防毒軟體會封鎖特定連接埠和通訊協定,許多裝置則位於 Proxy 和公司防火牆後方。防火牆和 NAT 其實可以由同一個裝置 (例如家用 Wi-Fi 路由器) 實作。

NAT 和防火牆後方的對等端
真實世界

WebRTC 應用程式可以使用 ICE 架構,克服現實網路環境的複雜性。如要實現這項功能,應用程式必須將 ICE 伺服器網址傳遞至 RTCPeerConnection,如本文所述。

ICE 會嘗試找出連線至對等端的最佳路徑。並且會並行嘗試所有可能的做法,然後選擇最有效的選項。ICE 會先嘗試使用從裝置作業系統和網路卡取得的主機位址建立連線。如果失敗 (NAT 後端裝置會發生這種情況),ICE 會使用 STUN 伺服器取得外部位址,如果失敗,流量會透過 TURN 中繼伺服器轉送。

換句話說,STUN 伺服器用於取得外部網路位址,而 TURN 伺服器則用於在直接 (端對端) 連線失敗時轉送流量。

每個 TURN 伺服器都支援 STUN。TURN 伺服器是 STUN 伺服器,內建額外的中繼功能。ICE 也能處理 NAT 設定的複雜問題。實際上,NAT 洞轉可能需要的資訊不只限於公開 IP 位址:連接埠位址。

WebRTC 應用程式會在 iceServers 設定物件中 (可選) 指定 STUN 和/或 TURN 伺服器的網址,該物件是 RTCPeerConnection 建構函式的第一個引數。對於 appr.tc,這個值會如下所示:

{
  'iceServers': [
    {
      'urls': 'stun:stun.l.google.com:19302'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=udp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=tcp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    }
  ]
}

RTCPeerConnection 取得這些資訊後,ICE 就會自動發揮作用。RTCPeerConnection 會使用 ICE 架構找出對等端之間的最佳路徑,並視需要與 STUN 和 TURN 伺服器搭配使用。

STUN

NAT 會為裝置提供 IP 位址,供裝置在私人區域網路中使用,但這個位址無法用於外部。沒有公開位址的情況下,WebRTC 同儕無法通訊。為解決這個問題,WebRTC 會使用 STUN

STUN 伺服器位於公開網際網路上,且有一個簡單的任務:檢查傳入要求的 IP 位址:通訊埠 (來自在 NAT 後方執行的應用程式),並將該位址傳回做為回應。換句話說,應用程式會使用 STUN 伺服器,從公開角度探索其 IP 位址和連接埠。這個程序可讓 WebRTC 對等端取得可公開存取的位址,然後透過訊號機制將該位址傳遞給另一個對等端,以便設定直接連結。(實際上,不同 NAT 的運作方式不同,且可能有多個 NAT 層,但原則仍相同)。

STUN 伺服器不需要執行或記住太多內容,因此規格較低的 STUN 伺服器也能處理大量要求。

根據 Webrtcstats.com 的資料,大多數 WebRTC 通話都能成功使用 STUN 建立連線 (86%),但如果是防火牆後方的對等端通訊,或是複雜的 NAT 設定,則可能會降低成功率。

使用 STUN 伺服器進行對等連線
使用 STUN 伺服器取得公開 IP 位址:連接埠

轉動

RTCPeerConnection 會嘗試透過 UDP 在對等端之間建立直接通訊。如果失敗,RTCPeerConnection 會改用 TCP。如果失敗,則可使用 TURN 伺服器做為備用方案,在端點之間轉送資料。

在此重申,TURN 用於在對等端之間轉送音訊、視訊和資料串流,而不是信號資料!

TURN 伺服器有公開位址,因此即使對等端位於防火牆或 Proxy 後方,也能與其聯絡。從概念上來說,TURN 伺服器的工作很簡單,就是轉送串流。不過,與 STUN 伺服器不同,這些伺服器本身會消耗大量頻寬。換句話說,TURN 伺服器需要更強大的功能。

使用 STUN 伺服器進行對等連線
完整的 Monty:STUN、TURN 和訊號

下圖顯示 TURN 的運作情形。純粹的 STUN 無法成功,因此每個對等端都會改用 TURN 伺服器。

部署 STUN 和 TURN 伺服器

為了測試,Google 會執行公開的 STUN 伺服器 stun.l.google.com:19302,這正是 appr.tc 所使用的伺服器。如要使用正式版的 STUN/TURN 服務,請使用 rfc5766-turn-server。您可以在 GitHub 上取得 STUN 和 TURN 伺服器的原始碼,並查看幾個安裝伺服器的資訊來源連結。您也可以使用 Amazon Web Services 的 VM 映像檔

我們也提供替代性 TURN 伺服器,可做為原始碼使用,也適用於 AWS。以下說明如何在 Compute Engine 上設定退款。

  1. 視需要為 tcp=443、udp/tcp=3478 開啟防火牆。
  2. 建立四個執行個體,每個公開 IP 一個,使用標準 Ubuntu 12.06 映像檔。
  3. 設定本機防火牆設定 (允許來自任何來源的任何流量)。
  4. 安裝工具: shell sudo apt-get install make sudo apt-get install gcc
  5. creytiv.com/re.html 安裝 libre。
  6. creytiv.com/restund.html 擷取退款資料並解壓縮。
  7. wget hancke.name/restund-auth.patch,並套用 patch -p1 < restund-auth.patch
  8. 執行 makesudo make install 以取得 Libre 和退款。
  9. 根據您的需求調整 restund.conf (替換 IP 位址,並確保包含相同的共用密鑰),然後複製到 /etc
  10. restund/etc/restund 複製到 /etc/init.d/
  11. 設定退款:
    1. 設定 LD_LIBRARY_PATH
    2. restund.conf 複製到 /etc/restund.conf
    3. 設定 restund.conf 以使用正確的 10。IP 位址。
  12. 執行 restund
  13. 從遠端機器使用 stund 用戶端進行測試:./client IP:port

不只一對一:多方 WebRTC

您也可以參考 Justin Uberti 提出的 IETF 標準,瞭解如何使用 REST API 存取 TURN 服務

媒體串流的用途不只限於簡單的一對一通話,例如,一群同事之間的視訊會議,或是有一位講者和數百萬或數百萬名觀眾的公開活動。

WebRTC 應用程式可使用多個 RTCPeerConnections,讓每個端點都能連線至網格設定中的所有其他端點。talky.io 等應用程式採用的就是這種方法,而且在少數情況下效果非常出色。除此之外,處理和頻寬消耗量也會過高,尤其是行動用戶端。

網格:小型 N 方通話
完整網格拓撲:每個節點都與其他節點相連

或者,WebRTC 應用程式可以選擇一個端點,將串流發送至星號設定中的所有其他端點。您也可以在伺服器上執行 WebRTC 端點,並自行建構重新分配機制 (webrtc.org 提供範例用戶端應用程式)。

自 Chrome 31 和 Opera 18 起,一個 RTCPeerConnectionMediaStream 可用於另一個 RTCPeerConnection 的輸入內容。這可讓網路應用程式選擇要連線的其他對等端,進而處理呼叫轉送作業,因此可實現更彈性的架構。如要查看實際運作情形,請參閱 WebRTC 範例 Peer connection relayWebRTC 範例 Multiple peer connections

多點控制單元

如要管理大量端點,建議使用多點控制單元 (MCU)。這項伺服器可做為橋樑,在大量參與者之間分發媒體內容。MCU 可處理視訊會議中的不同解析度、編解碼器和影格速率;處理轉碼作業;選擇性轉送串流;以及混合或錄製音訊和影像。對於多方通話,您需要考慮許多問題,尤其是如何顯示多個視訊輸入內容,以及混合來自多個來源的音訊。雲端平台 (例如 vLine) 也會嘗試最佳化流量路由。

您可以購買完整的 MCU 硬體套件,也可以自行建構。

Cisco MCU5300 的背面
Cisco MCU
背面

您可以選擇使用多種開放原始碼 MCU 軟體。舉例來說,Licode (舊稱 Lynckia) 會為 WebRTC 製作開放原始碼 MCU。OpenTok 有 Mantis

除了瀏覽器之外:VoIP、電話和訊息

由於 WebRTC 具有標準化特性,因此在瀏覽器中執行的 WebRTC 應用程式,可以與在其他通訊平台 (例如電話或視訊會議系統) 上執行的裝置或平台建立通訊。

SIP 是 VoIP 和視訊會議系統使用的信號協定。如要讓 WebRTC 網頁應用程式與 SIP 用戶端 (例如視訊會議系統) 之間進行通訊,WebRTC 需要 Proxy 伺服器來仲介信號。信號必須透過閘道傳送,但一旦建立通訊連線,SRTP 流量 (視訊和音訊) 就能直接在對等端之間傳送。

公用交換電話網路 (PSTN) 是所有「傳統」類比電話的電路交換網路。如果是 WebRTC 網路應用程式和電話之間的通話,則流量必須經過 PSTN 閘道。同樣地,WebRTC 網路應用程式需要中介 XMPP 伺服器,才能與 Jingle 端點 (例如即時通訊用戶端) 通訊。Jingle 是 Google 開發的 XMPP 擴充功能,可為訊息服務提供語音和視訊功能。目前的 WebRTC 實作是以 C++ libjingle 程式庫為基礎,這是最初為 Talk 開發的 Jingle 實作。

許多應用程式、程式庫和平台都會利用 WebRTC 與外界通訊的功能:

  • sipML5:開放原始碼 JavaScript SIP 用戶端
  • jsSIP:JavaScript SIP 程式庫
  • Phono:開放原始碼 JavaScript 電話 API,可做為外掛程式建構
  • Zingaya:可嵌入的手機小工具
  • Twilio:語音和訊息
  • Uberconference:會議通訊

sipML5 開發人員也已建構 webrtc2sip 閘道。Tethr 和 Tropo 已展示災難通訊架構的「公事包」,使用OpenBTS 小型基地台,透過 WebRTC 讓功能型手機和電腦之間進行通訊。也就是不透過電信業者進行的電話通訊!

瞭解詳情

WebRTC 程式碼研究室提供逐步操作說明,說明如何使用在 Node 上執行的 Socket.io 信號服務,建構視訊和文字聊天應用程式。

2013 年 Google I/O 大會 WebRTC 簡報,由 WebRTC 技術負責人 Justin Uberti 主講

Chris Wilson 的 SFHTML5 簡報 - WebRTC 應用程式簡介

這本 350 頁的書籍「WebRTC:HTML5 即時網頁的 API 和 RTCWEB 通訊協定」提供許多關於資料和訊號傳送路徑的詳細資訊,並附上許多詳細的網路拓撲圖。

WebRTC 和訊號:兩年來的經驗教訓 - 說明為何將訊號從規格中移除是個好主意的 TokBox 網誌文章

Ben Strong建構 WebRTC 應用程式的實用指南提供許多有關 WebRTC 拓樸和基礎架構的資訊。

Ilya Grigorik高效瀏覽器網路一書的 WebRTC 章節深入探討 WebRTC 架構、用途和效能。