一、搭建 Web 伺服器
-
前面我們已經實現過,但是沒有詳細說HTTPS服務
-
首先需要引入了
express
庫,它的功能非常強大,用它來實現 Web 伺服器非常方便 -
同時還需要引入
HTTPS
服務,並讓 Web 服務執行於 HTTPS 之上即可
var https = require('https');
var express = require('express');
var serveIndex = require('serve-index');
// 使用 express 實現 WEB 服務
var app = express();
app.use(serveIndex('./public'));
app.use(express.static('./public'));
//HTTPS 證書和金鑰檔案
var options = {
key : fs.readFileSync('./cert/www.autofelix.cn.key'),
cert: fs.readFileSync('./cert/www.autofelix.cn.pem')
}
//https server
var https_server = https.createServer(options, app);
var io = socketIo.listen(https_server);
https_server.listen(443, '0.0.0.0');
二、實現信令系統
-
信令系統超級重要,直播系統中,由誰來發起呼叫、什麼時間發 SDP 等各種操作都是由信令控制的
-
客戶端命令︰
join
使用者加入房間、leave
使用者離開房間、message
端到端命令 -
服務端命令︰
joined
使用者已加入、leaved
使用者已離開、other_joined
其他使用者已加入、bye其他使用者已離開、full
房間已滿 -
在初始時,客戶端處於
init/leaved
狀態,在該狀態下使用者只能傳送 join 訊息 -
服務端收到 join 訊息後,會返回 joined 訊息,此時客戶端為 joined 狀態
-
如果使用者離開房間,那客戶端又回到了初始狀態
-
如果客戶端收到
second user join
訊息,則切換到joined_conn
狀態,該狀態下可以進行通話 -
如果客戶端收到
second user leave
訊息,則切換到joined_unbind
狀態,該狀態與 joined 狀態基本一致
三、搭建 TURN 伺服器
-
其中最重要的 TURN 服務。它有兩個作用,一是提供 STUN 服務,客戶端可以通過 STUN 服務獲取自己的外網地址;二是提供資料中繼服務
-
目前最著名的 TURN 伺服器是由 Google 發起的開源專案
coturn
︰https://github.com/coturn/coturn -
coturn 的編譯安裝與部署步驟如下︰
// 下載原始碼
git clone https://github.com/coturn/coturn.git
// 編譯, 生成 Makefile
./configure --prefix=/usr/local/coturn
// 安裝
make && make install
// 關於 coturn 服務配置
listening-port=3478 // 指定偵聽的埠
external-ip=147.104.34.27 // 指定雲主機的公網ip地址
user=username:password // 訪問stun/turn服務的使用者名稱和密碼
realm=stun.xxx.cn // 域名,這個必須設定
四、視訊直播之音視訊資料的採集
-
第一步通過 getUserMedia 就可以獲取到音視訊資料
-
以前是在瀏覽器顯示頁面時就開始採集,而現在則是在使用者點選
Connect Sig Server
按鈕時才開始採集音視訊資料 -
信令系統建立好後,後面的邏輯都是圍繞著信令系統建立起來的,
RTCPeerConnection
物件也不例外 -
在客戶端,使用者要想與遠端通話,首先要傳送 join 訊息,也就是要先進入房間,如果伺服器判定使用者是合法的,則會給客戶端回 joined 訊息
-
客戶端收到 joined 訊息後,就要建立 RTCPeerConnection 物件了,也就是要建立一條與遠端通話的音視訊資料傳輸通道
-
我們需要設定 TURN 伺服器地址、使用者名稱和密碼,這樣當 RTCPeerConnection 通過 P2P 建立連線失敗時,就會使用 TURN 伺服器進行資料中繼
-
RTCPeerConnection
物件建立好後,我們要將前面獲取的音視訊資料與它繫結到一起,這樣才能通過RTCPeerConnection
物件將音視訊資料傳輸出去
var pcConfig = {
'iceServers': [{ // 指定 ICE 伺服器信令
'urls': 'turn:stun.al.learningrtc.cn:3478', //turn 伺服器地址
'credential': "passwd", //turn 伺服器密碼,你要用自己的
'username': "username" //turn 伺服器使用者名稱,你要用自己的
}]
};
function createPeerConnection(){
if(!pc){
pc = new RTCPeerConnection(pcConfig); // 建立 peerconnection 物件
pc.ontrack = getRemoteStream; // 當遠端的 track 到來時會觸發該事件
}else {
console.log('the pc have be created!');
}
return;
}
// 將獲取的音視訊資料與 RTCPeerConnection 繫結到一起
function bindTracks(){
//add all track into peer connection
localStream.getTracks().forEach((track)=>{
pc.addTrack(track, localStream); // 將 track 與 peerconnection 繫結
});
}
五、視訊直播之音視訊的渲染與播放
-
按照上面的步驟,音視訊資料就可以被採集到了,
RTCPeerConnection
物件也建立好了,通過信令伺服器也可以將各端的Candidate
交換完成了 -
此時在 WebRTC 的底層就會進行連通性檢測,它首先判斷通訊的雙方是否在同一個區域網內
-
如果在同一個區域網內,則讓雙方直接進行連線
-
如果不在同一區域網內,則嘗試用P2P 連線
-
如果仍然不成功,則使用 TURN 服務進行資料中繼
-
一旦資料連通後,資料就從一端源源不斷地傳到了遠端,此時遠端只需要將資料與播放器對接,就可以看到對端的視訊、聽到對方的聲音了
-
當資料流過來的時候會觸發
RTCPeerConnection
物件的ontrack
事件 -
只要我們偵聽該事件,並在回撥函式中將收到的
track
與<video>
標籤繫結到一起即可
var remoteVideo = document.querySelector('video#remotevideo');
pc = new RTCPeerConnection(pcConfig);
pc.ontrack = getRemoteStrea // 當遠端的 track 過來時觸發該事件
function getRemoteStream(e){ // 事件處理函式
remoteStream = e.streams[0]; // 儲存遠端的流
remoteVideo.srcObject = e.streams[0]; // 與 HTML 中的視訊標籤繫結
}