一、WebRTC架構
當兩個電腦都在各自私有網路,透過NAT連接到公有網路,此時無法得知遠端電腦的私有IP,所以透過Stun Server 伺服器,當兩端的電腦連線到Stun Server 就可以得知各自的網路IP,再透過NAT伺服器內部路由表對照,就會對應到內部的私有IP,此時就能建立P2P連線。
當兩個不同電腦PeerA和PeerB 通訊時,彼此之間一定要知道對方的IP和PORT號,但如果兩台電腦並沒有對外IP時,就需要TURN和NAT穿過防火牆,
PeerA 會先產生Offer 訊號,WebRTC經由signal channel把PeerA電腦端的Offer訊息傳給PeerB,當PeerB 從signal channel接收到PeerA的Offer 的訊息,會立即回覆Answer 給PeerA,此時這兩台電腦就會以ICE candidat 開始互傳訊息給對方。
二、範例練習
Index.html
<html>
<head>
<meta name="viewport" content="width=device-width,
initial-scale=1" charset="utf-8">
<title></title>
</head>
<body>
<div>Content goes here.</div>
<video id="localVideo" autoplay muted controls></video>
<video id="remoteVideo" autoplay controls></video>
<div>
<button id="startButton">Start</button>
<button id="callButton">Call</button>
<button id="hangupButton">Hang Up</button>
</div>
</body>
</html>
|
l navigator.getUserMedia :瀏覽器可呼叫視訊串流的語法
navigator.getUserMedia = navigator.getUserMedia
||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
navigator.getUserMedia({
video: true
}, gotStream,
function (error) {
console.log('navigator.getUserMedia error: ',
error);
});
|
l webkitRTCPeerConnection: 建立遠端連線
var servers = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] };
//Stun Server
var localPeerConnection = new webkitRTCPeerConnection(servers);
|
l addIceCandidate : 透過Turn/Stun 機制, 取得相關的IP和Port
localPeerConnection.onicecandidate
= gotLocalIceCandidate;
//建立本機的 ICE Candidate
function gotLocalIceCandidate(event) {
if (event.candidate) {
//將自己的ICE Candidate 附加在遠端電腦上 (為了與遠端互換串流)
remotePeerConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
}
}
|
l RTCSessionDescription 交換多媒體的傳輸通道
localPeerConnection.createOffer(gotLocalDescription); //產生offer
function gotLocalDescription(description) {
localPeerConnection.setLocalDescription(description);
remotePeerConnection.setRemoteDescription(description);
remotePeerConnection.createAnswer(gotRemoteDescription); //回應 Answer
}
function gotRemoteDescription(description) {
remotePeerConnection.setLocalDescription(description);
localPeerConnection.setRemoteDescription(description);
}
|
完整範例
Javascript
<script>
var localStream; //取得本地端的視訊串流
var localPeerConnection; //本地端的連線
var remotePeerConnection; //遠端的連線
var localVideo = document.getElementById('localVideo');
var remoteVideo = document.getElementById('remoteVideo');
var startButton = document.getElementById('startButton');
var callButton = document.getElementById('callButton');
var hangupButton = document.getElementById('hangupButton');
startButton.disabled = false;
callButton.disabled = true;
hangupButton.disabled = true;
startButton.onclick =
start; //按下startButton 觸發start function
callButton.onclick = call; //按下callButton 觸發call function
hangupButton.onclick =
hangup;
//取得本地端的串流的函式
function gotStream(stream) {
localVideo.src =
URL.createObjectURL(stream);
localStream = stream; //將此全域變數loalStream 儲存本地端視訊串流
callButton.disabled = false;
}
//取得遠端串流的函式
function gotRemoteStream(event) {
remoteVideo.src =
URL.createObjectURL(event.stream);
}
//建立本機的 ICE Candidate
function gotLocalIceCandidate(event) {
if (event.candidate) {
//將自己的ICE Candidate 附加在遠端電腦上 (為了與遠端互換串流)
remotePeerConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
}
}
//建立遠機的 ICE Candidate
function gotRemoteIceCandidate(event) {
if (event.candidate) {
//將遠端的ICE Candidate 附加在本機電腦上(為了與本機互換串流)
localPeerConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
}
}
function start() {
startButton.disabled =
true;
navigator.getUserMedia
= navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
navigator.getUserMedia({
video: true
}, gotStream,
function (error) {
console.log('navigator.getUserMedia error: ',
error);
});
}
function call() {
callButton.disabled = true;
hangupButton.disabled
= false;
//用來當作STUN Server 的公用伺服器,Google 免費提供
var servers = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] };
localPeerConnection = new webkitRTCPeerConnection(servers); //本地端和STUN Server建立連線
localPeerConnection.onicecandidate
= gotLocalIceCandidate; //建立本地端的ICE
remotePeerConnection =
new
webkitRTCPeerConnection(remotServer); //遠端建立連線
remotePeerConnection.onicecandidate = gotRemoteIceCandidate; //建立遠端的ICE
remotePeerConnection.onaddstream = gotRemoteStream; //取得遠端的視訊串流
//取得本機電腦的視訊串流,並將串流加在localPeerConnection
localPeerConnection.addStream(localStream);
//由本機產生offer 給遠端電腦,並開始將本地端的電腦和遠端的電腦進行傳輸設定
localPeerConnection.createOffer(gotLocalDescription);
}
//透過 setLocalDescription() 將該物件設定為 local description,再將其傳送給對方。
function gotLocalDescription(description)
{
localPeerConnection.setLocalDescription(description);
remotePeerConnection.setRemoteDescription(description);
//當對方接收到 offer 的資料,必須回傳一個
answer 作為回應
remotePeerConnection.createAnswer(gotRemoteDescription);
}
//透過 setLocalDescription() 將該物件設定為remotePeerConnection,再傳送給本地端
function gotRemoteDescription(description)
{
remotePeerConnection.setLocalDescription(description);
localPeerConnection.setRemoteDescription(description);
}
//結束雙方的通訊
function hangup() {
localPeerConnection.close();
remotePeerConnection.close();
localPeerConnection = null;
remotePeerConnection =
null;
hangupButton.disabled
= true;
callButton.disabled = false;
}
</script>
|
測試結果:
作者目前受限於環境,只在區域網內測試結果,無法嘗試兩台不同PC互相通訊,如果以上有觀念錯誤地方,請高手們幫忙導正觀念。
參考文獻
沒有留言:
張貼留言