WebRTC - RTCPeerConnection API



RTCPeerConnection API 是瀏覽器之間點對點連線的核心。要建立 RTCPeerConnection 物件,只需編寫以下程式碼:

var pc = RTCPeerConnection(config);

其中 config 引數至少包含一個鍵 iceServers。它是一個 URL 物件陣列,包含有關 STUN 和 TURN 伺服器的資訊,在查詢 ICE 候選者期間使用。您可以在 code.google.com 找到可用公共 STUN 伺服器的列表。

根據您是呼叫方還是被呼叫方,RTCPeerConnection 物件在連線的每一側的使用方式略有不同。

以下是使用者流程示例:

  • 註冊 onicecandidate 處理程式。它在收到任何 ICE 候選者時將其傳送到另一個對等方。

  • 註冊 onaddstream 處理程式。它在從遠端對等方收到影片流後處理影片流的顯示。

  • 註冊 message 處理程式。您的信令伺服器也應該有一個處理程式來處理從另一個對等方接收到的訊息。如果訊息包含 RTCSessionDescription 物件,則應使用 setRemoteDescription() 方法將其新增到 RTCPeerConnection 物件。如果訊息包含 RTCIceCandidate 物件,則應使用 addIceCandidate() 方法將其新增到 RTCPeerConnection 物件。

  • 利用 getUserMedia() 設定您的本地媒體流,並使用 addStream() 方法將其新增到 RTCPeerConnection 物件。

  • 啟動 offer/answer 協商過程。這是呼叫方的流程與被呼叫方的流程唯一不同的步驟。呼叫方使用 createOffer() 方法啟動協商,並註冊一個接收 RTCSessionDescription 物件的回撥函式。然後,此回撥函式應使用 setLocalDescription() 將此 RTCSessionDescription 物件新增到您的 RTCPeerConnection 物件。最後,呼叫方應透過信令伺服器將此 RTCSessionDescription 傳送到遠端對等方。另一方面,被呼叫方註冊相同的回撥函式,但在 createAnswer() 方法中。請注意,只有在從呼叫方收到 offer 後,被呼叫方的流程才會啟動。

RTCPeerConnection API

屬性

  • RTCPeerConnection.iceConnectionState (只讀) - 返回一個 RTCIceConnectionState 列舉,描述連線的狀態。當此值更改時,會觸發 iceconnectionstatechange 事件。可能的值 -

    • new - ICE 代理正在等待遠端候選者或收集地址

    • checking - ICE 代理有遠端候選者,但尚未找到連線

    • connected - ICE 代理已找到可用的連線,但仍在檢查更多遠端候選者以獲得更好的連線。

    • completed - ICE 代理已找到可用的連線並停止測試遠端候選者。

    • failed - ICE 代理已檢查所有遠端候選者,但至少一個元件沒有找到匹配項。

    • disconnected - 至少一個元件不再處於活動狀態。

    • closed - ICE 代理已關閉。

  • RTCPeerConnection.iceGatheringState (只讀) - 返回一個 RTCIceGatheringState 列舉,描述連線的 ICE 收集狀態 -

    • new - 物件剛剛建立。

    • gathering - ICE 代理正在收集候選者

    • complete ICE 代理已完成收集。

  • RTCPeerConnection.localDescription (只讀) - 返回一個 RTCSessionDescription,描述本地會話。如果尚未設定,它可以為 null。

  • RTCPeerConnection.peerIdentity (只讀) - 返回一個 RTCIdentityAssertion。它由一個 idp(域名)和一個表示遠端對等方身份的名稱組成。

  • RTCPeerConnection.remoteDescription (只讀) - 返回一個 RTCSessionDescription,描述遠端會話。如果尚未設定,它可以為 null。

  • RTCPeerConnection.signalingState (只讀) - 返回一個 RTCSignalingState 列舉,描述本地連線的信令狀態。此狀態描述 SDP offer。當此值更改時,會觸發 signalingstatechange 事件。可能的值 -

    • stable - 初始狀態。沒有 SDP offer/answer 交換正在進行。

    • have-local-offer - 連線的本地端已在本地應用 SDP offer。

    • have-remote-offer - 連線的遠端端已在本地應用 SDP offer。

    • have-local-pranswer - 已應用遠端 SDP offer,並在本地應用 SDP pranswer。

    • have-remote-pranswer - 已應用本地 SDP,並在遠端應用 SDP pranswer。

    • closed - 連線已關閉。

事件處理程式

序號 事件處理程式 & 描述
1

RTCPeerConnection.onaddstream

當觸發 addstream 事件時,將呼叫此處理程式。當遠端對等方將 MediaStream 新增到此連線時,會發送此事件。

2

RTCPeerConnection.ondatachannel

當觸發 datachannel 事件時,將呼叫此處理程式。當 RTCDataChannel 新增到此連線時,會發送此事件。

3

RTCPeerConnection.onicecandidate

當觸發 icecandidate 事件時,將呼叫此處理程式。當 RTCIceCandidate 物件新增到指令碼時,會發送此事件。

4

RTCPeerConnection.oniceconnectionstatechange

當觸發 iceconnectionstatechange 事件時,將呼叫此處理程式。當 iceConnectionState 的值更改時,會發送此事件。

5

RTCPeerConnection.onidentityresult

當觸發 identityresult 事件時,將呼叫此處理程式。在建立 offer 或 answer 期間透過 getIdentityAssertion() 生成身份斷言時,會發送此事件。

6

RTCPeerConnection.onidpassertionerror

當觸發 idpassertionerror 事件時,將呼叫此處理程式。當 IdP(身份提供者)在生成身份斷言時發現錯誤時,會發送此事件。

7

RTCPeerConnection.onidpvalidation

當觸發 idpvalidationerror 事件時,將呼叫此處理程式。當 IdP(身份提供者)在驗證身份斷言時發現錯誤時,會發送此事件。

8

RTCPeerConnection.onnegotiationneeded

當觸發 negotiationneeded 事件時,將呼叫此處理程式。瀏覽器傳送此事件以通知將來某個時間點需要協商。

9

RTCPeerConnection.onpeeridentity

當觸發 peeridentity 事件時,將呼叫此處理程式。在此連線上設定並驗證對等方身份時,會發送此事件。

10

RTCPeerConnection.onremovestream

當觸發 signalingstatechange 事件時,將呼叫此處理程式。當 signalingState 的值更改時,會發送此事件。

11

RTCPeerConnection.onsignalingstatechange

當觸發 removestream 事件時,將呼叫此處理程式。當 MediaStream 從此連線中移除時,會發送此事件。

方法

序號 方法 & 描述
1

RTCPeerConnection()

返回一個新的 RTCPeerConnection 物件。

2

RTCPeerConnection.createOffer()

建立 offer(請求)以查詢遠端對等方。此方法的前兩個引數是成功和錯誤回撥函式。可選的第三個引數是選項,例如啟用音訊或影片流。

3

RTCPeerConnection.createAnswer()

在 offer/answer 協商過程中建立對遠端對等方收到的 offer 的答覆。此方法的前兩個引數是成功和錯誤回撥函式。可選的第三個引數是建立答覆的選項。

4

RTCPeerConnection.setLocalDescription()

更改本地連線描述。描述定義連線的屬性。連線必須能夠支援舊描述和新描述。該方法採用三個引數:RTCSessionDescription 物件、如果描述更改成功則呼叫的回撥函式、如果描述更改失敗則呼叫的回撥函式。

5

RTCPeerConnection.setRemoteDescription()

更改遠端連線描述。描述定義連線的屬性。連線必須能夠支援舊描述和新描述。該方法採用三個引數:RTCSessionDescription 物件、如果描述更改成功則呼叫的回撥函式、如果描述更改失敗則呼叫的回撥函式。

6

RTCPeerConnection.updateIce()

更新 ICE 代理 ping 遠端候選者和收集本地候選者的過程。

7

RTCPeerConnection.addIceCandidate()

向 ICE 代理提供遠端候選者。

8

RTCPeerConnection.getConfiguration()

返回一個 RTCConfiguration 物件。它表示 RTCPeerConnection 物件的配置。

9

RTCPeerConnection.getLocalStreams()

返回本地 MediaStream 連線的陣列。

10

RTCPeerConnection.getRemoteStreams()

返回遠端 MediaStream 連線的陣列。

11

RTCPeerConnection.getStreamById()

根據給定的 ID 返回本地或遠端 MediaStream。

12

RTCPeerConnection.addStream()

新增 MediaStream 作為影片或音訊的本地源。

13

RTCPeerConnection.removeStream()

移除 MediaStream 作為影片或音訊的本地源。

14

RTCPeerConnection.close()

關閉連線。

15

RTCPeerConnection.createDataChannel()

建立一個新的 RTCDataChannel。

16

RTCPeerConnection.createDTMFSender()

建立一個新的 RTCDTMFSender,與特定的 MediaStreamTrack 關聯。允許透過連線傳送 DTMF(雙音多頻)電話訊號。

17

RTCPeerConnection.getStats()

建立一個新的 RTCStatsReport,其中包含有關連線的統計資訊。

18

RTCPeerConnection.setIdentityProvider()

設定 IdP。採用三個引數:名稱、用於通訊的協議和可選的使用者名稱。

19

RTCPeerConnection.getIdentityAssertion()

收集身份斷言。應用程式中不需要處理此方法。因此,您可能只在預期需要時顯式呼叫它。

建立連線

現在讓我們建立一個示例應用程式。首先,透過“node server”執行我們在“信令伺服器”教程中建立的信令伺服器。

頁面上將有兩個文字輸入框,一個用於登入,另一個用於我們想要連線到的使用者名稱。建立一個index.html檔案並新增以下程式碼 -

<html lang = "en"> 
   <head> 
      <meta charset = "utf-8" /> 
   </head>
	
   <body> 
	
      <div> 
         <input type = "text" id = "loginInput" /> 
         <button id = "loginBtn">Login</button> 
      </div> 
	
      <div> 
         <input type = "text" id = "otherUsernameInput" />
         <button id = "connectToOtherUsernameBtn">Establish connection</button> 
      </div> 
		
      <script src = "client2.js"></script>
		
   </body>
	
</html>

您可以看到我們添加了登入的文字輸入框、登入按鈕、另一個對等方使用者名稱的文字輸入框以及連線到他的按鈕。現在建立一個client.js檔案並新增以下程式碼 -

var connection = new WebSocket('ws://:9090'); 
var name = ""; 
 
var loginInput = document.querySelector('#loginInput'); 
var loginBtn = document.querySelector('#loginBtn'); 
var otherUsernameInput = document.querySelector('#otherUsernameInput'); 
var connectToOtherUsernameBtn = document.querySelector('#connectToOtherUsernameBtn'); 
var connectedUser, myConnection;
  
//when a user clicks the login button 
loginBtn.addEventListener("click", function(event){ 
   name = loginInput.value; 
	
   if(name.length > 0){ 
      send({ 
         type: "login", 
         name: name 
      }); 
   } 
	
});
  
//handle messages from the server 
connection.onmessage = function (message) { 
   console.log("Got message", message.data);
   var data = JSON.parse(message.data); 
	
   switch(data.type) { 
      case "login": 
         onLogin(data.success); 
         break; 
      case "offer": 
         onOffer(data.offer, data.name); 
         break; 
      case "answer": 
         onAnswer(data.answer); 
         break; 
      case "candidate": 
         onCandidate(data.candidate); 
         break; 
      default: 
         break; 
   } 
};
  
//when a user logs in 
function onLogin(success) { 

   if (success === false) { 
      alert("oops...try a different username"); 
   } else { 
      //creating our RTCPeerConnection object 
		
      var configuration = { 
         "iceServers": [{ "url": "stun:stun.1.google.com:19302" }] 
      }; 
		
      myConnection = new webkitRTCPeerConnection(configuration); 
      console.log("RTCPeerConnection object was created"); 
      console.log(myConnection); 
  
      //setup ice handling
      //when the browser finds an ice candidate we send it to another peer 
      myConnection.onicecandidate = function (event) { 
		
         if (event.candidate) { 
            send({ 
               type: "candidate", 
               candidate: event.candidate 
            }); 
         } 
      }; 
   } 
};
  
connection.onopen = function () { 
   console.log("Connected"); 
};
  
connection.onerror = function (err) { 
   console.log("Got error", err); 
};
  
// Alias for sending messages in JSON format 
function send(message) { 

   if (connectedUser) { 
      message.name = connectedUser; 
   } 
	
   connection.send(JSON.stringify(message)); 
};

您可以看到我們建立了與信令伺服器的套接字連線。當用戶點選登入按鈕時,應用程式會將其使用者名稱傳送到伺服器。如果登入成功,應用程式將建立RTCPeerConnection物件並設定onicecandidate處理程式,該處理程式將所有找到的icecandidate傳送到另一個對等方。現在開啟頁面並嘗試登入。您應該會看到以下控制檯輸出 -

Establishing a Connection

下一步是向另一個對等方建立offer。將以下程式碼新增到您的client.js檔案中 -

//setup a peer connection with another user 
connectToOtherUsernameBtn.addEventListener("click", function () { 
 
   var otherUsername = otherUsernameInput.value; 
   connectedUser = otherUsername;
	
   if (otherUsername.length > 0) { 
      //make an offer 
      myConnection.createOffer(function (offer) { 
         console.log(); 
         send({ 
            type: "offer", 
            offer: offer 
         });
			
         myConnection.setLocalDescription(offer); 
      }, function (error) { 
         alert("An error has occurred."); 
      }); 
   } 
}); 
 
//when somebody wants to call us 
function onOffer(offer, name) { 
   connectedUser = name; 
   myConnection.setRemoteDescription(new RTCSessionDescription(offer)); 
	
   myConnection.createAnswer(function (answer) { 
      myConnection.setLocalDescription(answer); 
		
      send({ 
         type: "answer", 
         answer: answer 
      }); 
		
   }, function (error) { 
      alert("oops...error"); 
   }); 
}
  
//when another user answers to our offer 
function onAnswer(answer) { 
   myConnection.setRemoteDescription(new RTCSessionDescription(answer)); 
} 
 
//when we got ice candidate from another user 
function onCandidate(candidate) { 
   myConnection.addIceCandidate(new RTCIceCandidate(candidate)); 
}	

您可以看到,當用戶點選“建立連線”按鈕時,應用程式會向另一個對等方發出SDP offer。我們還設定了onAnsweronCandidate處理程式。重新載入頁面,在兩個選項卡中開啟它,使用兩個使用者登入並嘗試在它們之間建立連線。您應該會看到以下控制檯輸出 -

Console Output

現在對等方連線已建立。在接下來的教程中,我們將新增影片和音訊流以及文字聊天支援。

廣告