2017年3月25日 星期六

如何用webrtc建立一個視訊聊天室網頁應用程式

簡介

WebRTC(Web即時通信)是目前由Google,Mozilla和Opera支持的一種新的Web標準。它允許瀏覽器之間的點對點通信。其目的是為瀏覽器,移動平台和網路物件Web of Things(WoT)提供更豐富的高質量RTC應用程序,並允許他們通過一組通用的協議進行通信。

Web的最後一個主要挑戰是通過語音和視頻實現人與人通信,而無需使用特殊的插件並且無需支付任何費用使用這些服務。

第一個WebRTC實施是由愛立信於2011年5月建立的。 WebRTC定義了用於實時,無插件視頻,音頻和數據通信的開放標準。

目前已經有許多Web服務已經使用RTC,但還是需要下載應用程序或相關插件。

其中包括Skype,Facebook(使用Skype)和Google Hangouts(使用Google Talk插件)。下載、安裝和更新插件的程序可能會很複雜,容易出錯和惱人,並且通常很難說服人們首先安裝插件!

準備工作

一般來說,使用webRTC相關應用程式需要:

  1. 取得音頻(audio)、視頻(video)、其他資料流(data stream)。
  2. 收集網路訊息(例如:Ip address 和port),並與其他WebRTC client交換此訊息。
  3. “訊息”通信用於回報錯誤,以及發起或關閉session。
  4. client必須交換關於media的訊息,例如解析度和編解碼器。
  5. 音頻、視頻、資料的串流。

WebRTC主要實現三個API:

  • MediaStream:允許client(例如:網頁瀏覽器)進入點的串流,例如:來自WebCam或麥克風的串流。
  • RTCPeerConnection:啟用音頻或視頻資料的傳輸,並且支持加密和頻寬管理。
  • RTCDataChannel:啟用點對點的通訊資料。
理論上,有可能創建一個簡單的WebRTC應用程式,沒有任何服務器元件用於訊息。 在實作中,這樣的應用沒有多大意義,但因為它可以在單個頁面上使用,所以它可以在點與點之間分享資料。

MediaStream

MediaStream表示同步的媒體串流,每個MediaStream都有一個輸入和一個輸出。

getUserMedia方法有三個參數:
  • a constraints object
  • a success callback method
  • a failure callback method
例如:本機端WebCam串流可以在HTML5視頻元素中顯示。

<!DOCTYPE html>
<html>
  <head>
    <script src="webrtc.js"></script>
    <title>WebRTC Test</title>
  </head>
  
  <body>
    <video id="localVideo" autoplay/>
    <script>
      window.addEventListener("load", function (evt) {
        navigator.getUserMedia({ audio: true, video: true},
          function(stream) {
            var video = document.getElementById('localVideo');
            video.src = window.URL.createObjectURL(stream);
          },
          function(err) {
            console.log("The following error occurred: " + err.name);
          }
        );
      });
    </script>
  </body></html>

RTCPeerConnection


RTCPeerConnection interface 表示本機端電腦和遠程點之間的WebRTC連接,它用於處理點與點之間的資料有效串流。 雙方(the caller and the called party)需要設定一個屬於自己的RTCPeerConnection實例來表示點與點連接的結束。 一般來說,我們使用RTCPeerConnection串流事件callback來處理音頻/視頻的串流。

例如:將它分配給HTML5視頻。
var peerConn= new RTCPeerConnection();
peerConn.onaddstream = function (evt) {
  var videoElem = document.createElement("video");
  document.appendChild(videoElem);
  videoElem.src = URL.createObjectURL(evt.stream);
};


呼叫的發起者(呼叫者/撥電話的人)需要創建提議並使用信令服務(例如,使用WebSockets的NodeJS服務器應用)將其發送到被叫者(接收者/接電話的人):
navigator.getUserMedia({video: true}, function(stream) {
  videoElem.src = URL.createObjectURL(stream);
  peerConn.addStream(stream);

  peerConn.createOffer(function(offer) {
    peerConn.setLocalDescription(new RTCSessionDescription(offer), function() {
      // send the offer to a server to be forwarded to the other peer
    }, error);
  }, error);
});


呼叫者接收到提供並需要的回答的答覆並且建立有效回答,並將其傳送給呼叫者:
navigator.getUserMedia({video: true}, function(stream) {
  videoElem.src = URL.createObjectURL(stream);
  peerConn.addStream(stream);

  peerConn.setRemoteDescription(new RTCSessionDescription(offer), function() {
    peerConn.createAnswer(function(answer) {
      peerConn.setLocalDescription(new RTCSessionDescription(answer), function() {
        // send the answer to a server to be forwarded back to the caller
      }, error);
    }, error);
  }, error);
});

setLocalDescription方法有三個參數:
  1. a session description
  2. a success callback system 
  3. an error callback method

RTCPeerConnection and Servers

在實際的應用中,WebRTC需要伺服器,用於以下目的:
  1. 用戶管理。
  2. 點與點之間的訊息交流。
  3. 關於媒體的資料交換,例如格式和視頻分辨率。
  4. 連接需要穿透NAT gateways 和防火牆。
ICE 框架使用STUN協定和擴展的TURN,使RTCPeerConnection能夠穿越NATgateways和其他網絡特定的細節。ICE是一種連結點與點的框架,例如:兩個視訊視訊聊天室的clients端,ICE嘗試直接通過UDP連結點,並且盡可能降低的延遲。
在這個過程中,STUN伺服器有一個單獨的工作,使NAT後面的點,能夠找到public address和port,Google和Mozilla能夠提供了幾個免費使用的STUN伺服器。 例如,Google STUN伺服器用於得到ICE candidates,然後轉發給其他的點。

var peerConnCfg =  {'iceServers': [{'url': 'stun:stun.l.google.com:19302'}]},
    peerConn= new RTCPeerConnection(peerConnCfg),
    signalingChannel = new WebSocket('ws://my-websocket-server:port/');

peerConn.onicecandidate = function (evt) {
  // send any ice candidates to the other peer, i.e., evt.candidate
  signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
};

signalingChannel.onmessage = function (evt) {
  var signal = JSON.parse(evt.data);
  if (signal.sdp)
    peerConn.setRemoteDescription(new RTCSessionDescription(signal.sdp));
  else if (signal.candidate)
    peerConn.addIceCandidate(new RTCIceCandidate(signal.candidate));
};

訊號頻道表示基於WebSockets,XHR或其他內容的通信頻道,目的是幫助交換點與點間連接初始化中所需的信息。

setRemoteDescription的方法有三個參數:

  1. a session description
  2. a success callback method
  3. an error callback method 

RTCDataChannel

RTCDataChannel interface 表示連接點與點之間的雙向資料頻道,並且可以使用RTCPeerConnection.createDataChannel()建立頻道,或者在現有RTCPeerConnection上的類型為RTCDataChannelEvent的data channel事件中接收到該對象,並且一定要使用資料頻道的功能,因為他利用消息傳遞的事件機制進行通訊的。

var peerConn= new RTCPeerConnection(),
    dc = peerConn.createDataChannel("my channel");

dc.onmessage = function (event) {
  console.log("received: " + event.data);
};

dc.onopen = function () {
  console.log("datachannel open");
};

dc.onclose = function () {
  console.log("datachannel close");
};


原文