(譯)WebRTC實戰: STUN, TURN, Signaling

http://xiaol.me/2014/08/24/webrtc-stun-turn-signaling/javascript

 

原文:WebRTC in the real world: STUN, TURN and signaling By Sam Duttonphp

WebRTC 實現了網頁點對點交流。
可是…
WebRTC 仍然須要服務器來:css

  • 交換客戶端元數據協調通信,即信令(Signaling)。
  • 應對NATs(Network Address Translators) 和防火牆。

本文將向你展現如何創建一個信令服務器,並使用STUN和TURN服務器來處理實際應用中出現的一些怪異的鏈接問題。也將解釋WebRTC應用是如何處理多方通信並與相似VoIP、PSTN的服務互動的。html

若是你沒有了解過WebRTC,我強烈建議你在看這篇文章以前先看看這篇文章 Getting Started With WebRTC
html5

什麼是信令?

信令即協調通信的過程。WebRTC應用要發起一個對話,客戶端就須要交換以下信息:java

  • 用於打開和關閉通信的會話信息;
  • 錯誤信息;
  • 媒體元數據如編解碼器及其設置,帶寬和媒體類型;
  • 祕鑰數據,用於建立安全鏈接;
  • 網絡數據,如外部能訪問的主機IP和端口。

這個信令過程須要客戶端之間能來回傳遞消息,可是WebRTC APIs並無提供這種機制的實現,你須要本身建立。下面將描述創建信令服務器的幾種方式。無論怎麼樣,先來點上下文吧…node

爲何WebRTC不提供信令實現?

爲了不冗餘,以及作到與現有技術的最大兼容,信令方法和協議都不禁WebRTC標準來指定。這些都由JSEP(JavaScript Session Establishment Protocol)來概述.python

WebRTC呼叫創建背後的想法已是徹底指定和控制媒體連接,可是儘可能託管和應用間的信令鏈接。
由是不一樣的應用可能會喜歡用不一樣的協議,好比已存在的SIP、Jungle信令協議,或者也許爲了一些新奇的用例而作的特殊應用而自定義的協議。
這一節文字要傳達的關鍵信息點是多媒體會話的描述,這個描述指定了必要的傳輸和創建媒體連接所必要的媒體配置信息。git

JSEP的架構也避免了讓瀏覽器去保存狀態,那就是,像一個信令狀態機同樣工做。這裏也許會有一個問題,好比,當頁面被刷新時,信令數據會丟失。不過,也能夠把這些信令狀態存在服務器。github

alt

JSEP architecture

JSEP須要offer和answer之間作出以前提到的媒體元數據的信息交換。offer和answer經過Session Description Protocol(SDP)格式來溝通,以下

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
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 examples.
請記住WebRTC被設計使得offer或answer能夠在被擰在一塊兒以前經過編輯SDP文原本設置好本地或遠程描述。好比apprtc.appspot.com中的preferAudioCodec()方法就被用於設置默認的編解碼器和比特率。SDP用JavaScript來操做是有點痛苦,因此如今有個討論是關於WebRTC的將來版本是否能夠用JSON格式來替代,不過這裏提到了一些堅持使用SDP的好處

RTCPeerConnection + 信令: offer, answer and candidate

RTCPeerConnection接口被WebRTC應用用於建立各點之間的鏈接並交流視音頻信息。
要開始這個過程RTCPeerConnection須要先作兩個工做:

  • 肯定本地媒體狀況,好比分辨率和編解碼器的能力。這些元數據會用在offeranswer機制中。
  • 獲取可能的應用主機網絡地址,就死所謂的candidate。

當本地信息被確認後,就會經過信令系統與遠程終端進行交換。
聯想下alice is trying to call Eve這幅漫畫,發起/響應機制在其中完整的展示出來:

  • Alice建立一個RTCPeerConnection對象。
  • Alice經過RTCPeerConnection的createOffer()方法建立一個offer(SDP會話描述)。
  • Alice經過這個offer調用setLocalDescription()。
  • Alice將offer字符串化並經過信令服務器發給Eve。
  • Eve經過調用setRemoteDescription()設置Alice的offer,來讓本身的RTCPeerConnection知道Alice的設置。
  • Eve調用createAnswer()和成功回調函數來傳遞Eve的本地會話描述—answer。
  • Eve經過setLocalDescription()來將她的本地描述設置到她的answer中。
  • 而後Eve將她字符串化後的answer經過信令服務器發回給Alice。
  • Alice經過setRemoteDescription()將Eve的anwser設置爲遠程會話描述。

Alice和Eve還須要交換網絡信息。’finding candidates’就是經過ICE框架找到網絡連接和端口的過程。

  • Alice 經過onicecandidate事件處理器來建立RTCPeerConnection對象。
  • 這個事件處理器將在candidates可用時被調用。
  • 在這個處理器中,Alice經過信令服務器將candidate數據字符串化後發送給Eve。
  • 當Eve獲得Alice的candidate信息,她將調用addIceCandidate()方法將這個candidate加入本身的遠程終端描述中。
    JSEP支持ICE Candidate Trickling, 這個可使呼叫者在初始化offer以後增量的提供candidates給被呼叫者,被呼叫者在這個呼叫中直接開始設置連接而不用等待收到其餘candidates。
編寫WebRTC信令服務

下面是一個簡略的信令過程W3C代碼示例。這片代碼假設已經存在一些信令機制,如SignalingChannel. 下面討論信令的一些詳細細節。

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 
var signalingChannel = new SignalingChannel(); var configuration = {  'iceServers': [{  'url': 'stun:stun.example.org'  }] }; var pc;  // call start() to initiate  function start() {  pc = new RTCPeerConnection(configuration);   // send any ice candidates to the other peer  pc.onicecandidate = function (evt) {  if (evt.candidate)  signalingChannel.send(JSON.stringify({  'candidate': evt.candidate  }));  };   // let the 'negotiationneeded' event trigger offer generation  pc.onnegotiationneeded = function () {  pc.createOffer(localDescCreated, logError);  }   // once remote stream arrives, show it in the remote video element  pc.onaddstream = function (evt) {  remoteView.src = URL.createObjectURL(evt.stream);  };   // get a local stream, show it in a self-view and add it to be sent  navigator.getUserMedia({  'audio': true,  'video': true  }, function (stream) {  selfView.src = URL.createObjectURL(stream);  pc.addStream(stream);  }, logError); }  function localDescCreated(desc) {  pc.setLocalDescription(desc, function () {  signalingChannel.send(JSON.stringify({  'sdp': pc.localDescription  }));  }, logError); }  signalingChannel.onmessage = function (evt) {  if (!pc)  start();   var message = JSON.parse(evt.data);  if (message.sdp)  pc.setRemoteDescription(new RTCSessionDescription(message.sdp), function () {  // if we received an offer, we need to answer  if (pc.remoteDescription.type == 'offer')  pc.createAnswer(localDescCreated, logError);  }, logError);  else  pc.addIceCandidate(new RTCIceCandidate(message.candidate)); };  function logError(error) {  log(error.name + ': ' + error.message); } 

要知道這片代碼中offer/answer和candidate交換過程是如何運做的,能夠看看simpl.info/pc 中視頻聊天示例的控制檯記錄。若是你須要跟多細節,能夠下載完整的WebRTC信令轉儲,並經過Chrome的 chrome://webrtc-internals 或Opera的 opera://webrtc-internals 頁面來統計。

終端的發現

要說清楚’我怎麼才能找到某人來聊天’挺複雜的。
對於電話來講,咱們有電話號碼目錄。對於在線視頻聊天,咱們須要身份認證以及在線狀態管理系統,即用戶初始化會話。WebRTC應用須要一種方式來讓客戶端來互相標識他們是像建立一個聊天室仍是加入一個聊天。

WebRTC沒有提供終端目錄機制,因此咱們不會進入這一項。這個過程能夠簡單的經過郵件或信息分享一個URL,好比 talky.iotawk.com 和 browsermeeting.com這些視頻聊天應用中,你邀請別人加入是經過跟他們分享你的自有連接。開發者Chris Ball建立了一個有趣的實驗serverless-webrtc讓WebRTC的參與者經過IM,email或者信鴿來交換元數據。

要如何創建一個信令服務器?

 

重申一下,信令協議及機制並不禁WebRTC標準定義。無論你選擇什麼,你都須要一箇中介服務器來交換客戶端之間的信令信息和應用數據。很惋惜,網頁應用並不能簡單的直接衝着英特網說’把我和個人朋友連起來!’.

還好信令信息很小,而且大多數只在一個呼叫的開始才須要交換.在對apprtc.appspot.comsamdutton-nodertc.jit.su測試中咱們發現,一個視頻聊天會話中,信令服務器總共處理了30-45條消息,全部消息的總大小才10kb左右。

而且對帶寬的要求也較低,WebRTC信令服務器並不消耗太多cpu或內存,由於它們只須要作消息中轉,並保存少許的會話狀態數據(例如,有哪些客戶已經鏈接了)。

Tip!
信令機制能夠用來交換會話元數據,也能夠用來作應用數據通信。它就是一個消息服務器。

從服務器推送消息到客戶端

信令的消息服務須要是雙向的:客戶端發到服務器且服務器發到客戶端。雙向通信違反了HTTP協議的客戶/服務,請求/響應模型。不過一些hack,好比爲了將數據從服務器推送到網頁的長輪詢)已經出現不少年了。

最近,EventSource API已被普遍的應用了,他使得服務器經過HTTP發送數據到瀏覽器成爲可能。這裏有個簡單的demo。EventSource被設計成單向傳遞消息,可是它能夠和XHR結合構建成交換信令消息的服務器:一個從呼叫者開始傳遞消息,用XHR請求傳輸,經過EventSource推送到被呼叫者那去。

WebSocket是一個更天然的解決方案,被設計成全雙工的客戶端/服務器通信(消息能夠同時雙向傳輸)。一個將信令服務器用純WebSocket或服務器發送事件(EventSource)的型式構建的好處是後臺接口能夠由各類語言的通用框架公共託管包來實現,好比PHP,Python和Ruby。

大概四分之三的瀏覽器都支持WebSocket了,更重要的是,全部支持WebRTC的瀏覽器都支持WebSocket,無論是桌面端仍是移動端。全部鏈接都須要使用TLS,去保證不被截獲到未加密的信息,而且減小proxy traveral引發的問題。(須要更多WebSocket和proxy traversal相關的信息,能夠看看Ilya Grigorik的High Performance Browser Networking一書的WebRTC章節。Peter Lubber的WebSocket Cheat Sheet有更多關於WebSocket客戶端和服務器端的信息)。

apprtc.appspot.comWebRTC視頻聊天應用的信令是經過Google App Engine Channel API完成的,這個API用到了Comet)技術(長輪詢)去實現信令推送信息(這裏有一個App Engine爲支持WebSocket存在好久的bug,快去關注這個bug,給它投票別讓它沉了!)。這裏有一份這個應用的詳細代碼。

WebRTC客戶端經過ajax輪詢獲取服務器信息處理信令也是可行的,可是這致使太多冗餘的網絡請求,尤爲對於移動端客戶來講更是一個問題。甚至在一個會話創建以後,終端仍須要輪詢信令信息去查詢是否會話有變化或者會話是否被對方終止了。這個示例使用了該方法,但作了一些輪詢頻率的優化。

擴展信令服務器規模

雖然信令服務器對於每一個客戶來講消耗的帶寬和CPU都較少,可是應用流行起來的話依然要處理不一樣地域的大量的數據,應對高併發。通訊量較高的WebRTC應用須要可以應對高負載。

這裏咱們不會討論細節,但仍有以下一些爲高容量,高性能信息能夠注意的點。

(開發者Phil Leggetter的Real-Time Web Technologies Guide提供了一個關於消息服務和代碼庫的總結性清單。)

在Node上用Socket.io創建信令服務器

如下的簡單網頁應用代碼使用到了基於Node上的Socket.io而創建的信令服務器。Socket.io的設計使創建信息交換服務器變得簡單,並且它尤爲適用於WebRTC信令服務器,由於它內置了’房間’的概念。這個例子不是爲產品級別的信令服務器設計的,可是它面向相對較小的用戶羣工做得很好。

Socket.io除了用WebSocket,還適配如下備用技術:Adobe Flash Socket, AJAX long polling, AJAX multipart streaming, Forever Iframe and JSONP polling. 它有多種後臺實現,可是它的Node版本應該是最著名的,咱們下面的例子就用的這個版本。

例子中沒有WebRTC,這裏只是展現網頁應用信令該如何設計。查看控制檯能夠看到客戶是如何加入一個房間且交換信息的。咱們的WebRTC codelab有如何將這個例子集成進完整的WebRTC視頻聊天應用的步驟。你能夠在codelab repo第五步下載這些代碼,也能夠在samdutton-nodertc.jit.su在線試試效果。

index.html的代碼以下:

1
2 3 4 5 6 7 8 9 10 
<!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> 

html中引用的的javascript文件main.js代碼以下:

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 
var isInitiator;  room = prompt('Enter room name:');  var socket = io.connect();  if (room !== '') {  console.log('Joining room ' + room);  socket.emit('create or join', room); }  socket.on('full', function (room){  console.log('Room ' + room + ' is full'); });  socket.on('empty', function (room){  isInitiator = true;  console.log('Room ' + room + ' is empty'); });  socket.on('join', function (room){  console.log('Making request to join room ' + room);  console.log('You are the initiator!'); });  socket.on('log', function (array){  console.log.apply(console, array); }); 

完整的服務端應用代碼:

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 
var static = require('node-static'); var http = require('http'); var file = new(static.Server)(); var app = http.createServer(function (req, res) {  file.serve(req, res); }).listen(2013);  var io = require('socket.io').listen(app);  io.sockets.on('connection', function (socket){   // convenience function to log server messages to the client  function log(){  var array = ['>>> Message from server: '];  for (var i = 0; i < arguments.length; i++) {  array.push(arguments[i]);  }  socket.emit('log', array);  }   socket.on('message', function (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', function (room) {  var 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能夠直接在官網下載(安裝過程很簡單)。要安裝socket.io和node-static,在你的應用目錄終端運行Node包管理器(NPM)就好了.

1
2 
npm install socket.io npm install node-static 

要運行應用,只須要在你應用目錄裏終端運行以下命令:

1
node server.js 

在你的瀏覽器中打開localhost:2013。在新的標籤頁或窗口將localhost:2013再打開一次。看看發生了什麼,檢查下Chrome或Opera的控制檯,你能夠用經過快捷鍵Command-Option-JCtrl-Shift-J來打開開發者工具DevTool。

無論你選擇什麼來實現你的信令,你的後臺和客戶端都至少至少須要提供一個和這個例子相似的服務。

在信令服務器中使用RTCDataChannel

信令服務器須要初始化一個WebRTC會話。

然而,當兩個終端間的鏈接創建後,RTCDataChannel理論上能夠看成信令通道。這個能夠減小信令的延遲而且減小信令服務器帶寬和cpu的消耗,由於這樣的信息是直接交流的。這裏咱們沒有demo,不過你們仍需留意。

信令陷阱?
  • setLocalDescription()方法被調用前RTCPeerConnection都不會開始收集candidates,這是JSEP IRTF draft中要求的。
  • 利用Trickle ICE(見前文):收到candidates信息馬上調用addIceCandidate()方法。
現成的信令服務器

若是你不想你本身來作信令服務器,這裏有提供一些WebRTC信令服務器,用的也是以前提到的Socket.io,並都集成了WebRTC客戶端JavaScript代碼庫。

…若是你壓根任何代碼都不想寫,這裏也有一些徹底商業化的WebRTC平臺如vLine,OpenTok,Asterisk.

須要指出來,Ericsson在WebRTC早期就已經用PHP在Apache上搭了個信令服務器。可是這個如今多少已經廢棄了,不過若是你在考慮作相似的事的話,這代碼仍是值得一看的。

信令安全

Security is the art of makeing nothing happen.
Salman Rushdie

加密在WebRTC組件中是強制的。

然而,信令機制並不禁WebRTC標準所定義,因此讓信令更安全就是你本身的事了。若是攻擊者試圖劫持信令, HTTPS和WSS(i.e TLS),能夠保證他們不會攔截到未加密的信息。你也要注意不要在其餘用同一個服務器的用戶能訪問到的地方廣播信令信息。

要保護WebRTC應用,在信令中使用TLS是絕對必要的。

信令以外:使用ICE應付NAT和防火牆

對於信令元數據,WebRTC應用使用了中介服務器,可是對於會話創建後的真正媒體數據流,RTCPeerConnection試圖讓客戶終端直連:點對點鏈接。
簡單的狀況下,每一個WebRTC終端都有一個惟一的地址,可使得各終端都能互相直接通信。
{}p2p

沒有NAT和防火牆的狀況

可是大多數設備都處於一層或多層NAT(網絡地址轉換器)以後,還有殺毒軟件的阻擋了一些端口或協議,又或者使用了代理或者防火牆。防火牆和NAT事實上可能在同一設備上,好比家庭無線路由器。
nat

實際狀況

WebRTC應用可使用ICE框架來克服實際應用中複雜的網絡問題。要使用ICE的話,你的應用必須以下所述的在RTCPeerConnection中傳遞ICE服務器的URL。

ICE試圖找到鏈接端點的最佳路徑。它並行的查找全部可能性,而後選擇最有效率的一項。ICE首先用從設備操做系統和網卡上獲取的主機地址來嘗試鏈接,若是失敗了(好比設備處於NAT以後),ICE會使用從STUN 服務器獲取到的外部地址,若是仍然失敗,則交由TURN中繼服務器來鏈接。

換句話說:

  • STUN服務器用於獲取設備的外部網絡地址
  • TURN服務器是在點對點失敗後用於通訊中繼。

每個TURN服務器都支持STUN,由於TURN就是在STUN服務器中內建了一箇中繼功能。ICE也能夠應付NAT複雜的設定:實際上,NAR’打洞’會有不止一個公共 IP : port 地址。STUN或TURN服務器的URL由WebRTC中RTCPeerConnection的第一個參數iceServers配置對象可選指定。apprtc.appspot.com中的值是這樣的:

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
{
 'iceServers': [  {  'url': 'stun:stun.l.google.com:19302'  },  {  'url': 'turn:192.158.29.39:3478?transport=udp',  'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',  'username': '28224511:1379330808'  },  {  'url': '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服務器處於公網中並有個簡單任務:檢查請求(來自運行於NAT以後的應用)的IP:port 地址,而且將這個地址響應回去。換句話說,NAT後的應用使用STUN服務器來找到他的IP:port 公網地址。這個過程使得WebRTC終端能夠找到本身公共訪問方法,並經過信令機制將之發送給其餘終端,就能夠建立一個直連連接。(在實踐中,不一樣的NAT工做方式不一樣,並有可能有多層NAT,可是原理是同樣的。)

STUN服務器並無作太多東西,也不用記住不少東西,因此一個相對低規格的的STUN服務器能夠處理大量的請求。

根據webrtcstats.com的調查,大部分(86%)WebRTC請求均可以經過STUN成功的建立鏈接,雖然對處於防火牆或者配置複雜的NAT以後的終端要低一些。
stun

用STUN服務器獲取公共IP:port 地址
TURN

RTCPeerConnection嘗試用UDP協議創建終端間的直連。若是失敗了,就嘗試TCP協議,仍是失敗的話,TURN 服務器就會用於作終端間的數據中繼。

重申一下:TURN用於中繼視頻音頻數據流,而不是信令數據!

TURN服務器有公共地址,因此他能夠被終端聯繫到,哪怕終端處於防火牆或者代理以後。TURN服務器有一個概念上簡單的工做—作數據流中繼—可是,不像STUN服務器,它天生須要消耗大量帶寬,也就是說,TURN服務器須要很強大。
turn

STUN,TURN和信令

這幅圖展示了TURN的運做,純STUN不能成功的話,各終端將使用TURN服務器。

部署STUN和TURN服務器

Google運行了一個公用的STUN服務器用做測試,stun.l.google.com:19302,apprtc.appspot.com用到了它。咱們建議使用rfc5766-turn-server看成產品用途的STUN/TURN服務,STUN/TURN服務器的源代碼能夠在code.google.com/p/rfc5766-turn-server 找到,這裏也提供了一些服務器安裝的相關信息連接。Amazon Web Services(AWS)也提供了WebRTC的虛擬機鏡像

另外一個備選TURN服務器是restund,有源代碼,也能夠裝到在AWS上。下面是介紹如何將restund裝到Google Compute Engine上。

  1. 防火牆開放tcp=443,udp/tcp=3478
  2. 建立4個實例(?),各自的公用IP,使用標準Ubuntu 12.06鏡像
  3. 配置本地防火牆(容許全部訪問源)
  4. 安裝工具:
    sudo apt-get install make
    sudo apt-get install gcc
  5. creytiv.com/re.html安裝libre
  6. creytiv.com/restund.html獲取restund並解包
  7. wget hancke.name/restund-auth.patch 並應用patch -p1 < restund-auth.patch
  8. 對libre和restund運行 make, sudo make install
  9. 按你本身的需求配置restund.conf(替換IP地址,確保正確的共享密鑰)並複製到/etc目錄
  10. 複製restund/etc/restund/etc/init.d/
  11. 配置restund:
    設置LD_LIBRARY_PATH
    複製restund.conf/etc/restund.conf
    設置restund.conf使用以前配的IP地址
  12. 運行restund
  13. 在遠程機器運行stund client命令作測試: ./client IP:port

點對點以外:多方WebRTC通信

你也許會對Justin Uberti爲REST API for access to TURN Services提出的IETF標準感興趣。

很容易想到一個超越簡單的點對點媒體流用例:好比,同事間的視頻會議,或者一個有數百(萬)用戶的公共演講。

WebRTC應用可使用多RTCPeerConnection,讓各終端之間以網狀配置鏈接。這就是如talky.io這類應用所使用的方法,而且在少許終端的狀況下運行的很是良好。不過,CPU和帶寬都消耗很是多,尤爲是在移動終端上。
mesh

網狀拓撲結構:全部終端都互相鏈接

此外,WebRTC應用能夠按星狀拓撲結構來選擇一個終端分發數據流。在服務器運行一個WebRTC終端來做爲從新分配機制也是可行的(webrtc.org提供了一個簡單例子)。

從Chrome 31和Opera 18開始,RTCPeerConnection的MediaStream能夠看成另外一個RTCPeerConnection的輸入:這裏有個簡單演示simpl.info/rtcpeerconnection/multi, 這使得應用結構更靈活,由於它使網絡應用經過選擇其餘終端的鏈接來處理路由成爲可能。

Multipoint Control Unit

對於大量終端的更好選擇是使用Multipoint Control Unit(MCU).這是一個服務器,像大量參與者之間的橋樑同樣用於分發媒體信息。MCU能夠在一個視頻會議中使用多種分辨率,編解碼器和幀率,處理轉換編碼,選擇數據流徑,調製或錄製視頻音頻。對於多方通話,有一堆問題須要注意: 特別是,如何顯示多視頻輸入和混調多源音頻。雲平臺如vLine有嘗試優化流量路徑。

能夠考慮買一個MCU的硬件,或者本身作一個。

mcu
Cisco MCU的背面

有很多能用的開源MCU軟件供選擇。好比,Licode(以前叫Lynckia)就爲WebRTC作了一個開源MCU,OpenTok也有一個開源產品Mantis

瀏覽器以外: VoIP, 電話和短信

WebRTC的標準性質使得瀏覽器中運行的WebRTC應用能夠和運行其餘通訊平臺的設備或者平臺創建通信,好比電話或者視頻會議系統。

SIP是VoIP和視頻會議系統的信令協議。要使WebRTC網頁應用能和其餘如視頻會議系統的SIP客戶端通信,WebRTC須要一個代理服務器作中介信令。信令須要流過網關,可是一旦通訊已經創建起來,SRTP(視頻和音頻)就能夠點對點傳輸。

PSTN(Public Switched Telephone Network),公用電話交換網絡,是全部普通模擬電話的閉路交換網絡。要用WebRTC網頁應用打電話,流量必須通過PSTN網關。此外,WebRTC網頁應用須要用中介XMPP服務器來與Jingle)終端如即時通訊客戶端通信。
Jingle由Google開發來做爲XMPP擴展用於支持視頻和音頻信息:如今WebRTC的實現基於libjingleC++庫,這個Jingle的實現剛開始是爲Google Talk開發的。

一些應用,代碼庫和平臺利用WebRTC的能力來於外界通信,如:

  • sipML5:開源JavaScript SIP客戶端
  • jsSIP:JavaScript SIP代碼庫
  • Phono:開源JavaScript電話接口,做爲插件開發
  • Zingaya:嵌入式電話組件
  • Twilio:音頻消息應用
  • Uberconference:會議系統

sipML5的開發們也開發了webrtc2sip網關。Tethr and Tropo在筆記本上演示過一個救災通信框架, 使用OpenBTS cell讓電腦能經過WebRTC與一個特別的電話通信。無需電信就能打電話啦!

更多

WebRTC codelab:一步一步介紹如何創建一個視頻文字聊天應用,使用了在Node中運行的Socket.io信令服務器。

2013 Google I/O 大會上由WebRTC技術組長Justin Uberti作的WebRTC報告

Chris Wilson在SFHTML5上的報告:Introduction to WebRTC Apps

WebRTC Book提供了不少數據和信令路徑的詳細信息,包括了許多詳細的網絡拓撲圖。

WebRTC and Signaling: What Two Years Has Taught Us:TokBox的一篇博文告訴咱們爲何要把信令從WebRTC細則中單獨拎出來。

Ben Strong的報告A Practical Guide to Building WebRTC Apps提供了不少WebRTC拓撲和基礎。

Ilya GrigorikHigh Performance Browser Networking一書中的WebRTC章節深刻描述了WebRTC結構,用例和性能。

相關文章
相關標籤/搜索