標籤:
自建 AppRTC字數3158 閱讀1718 評論2 喜歡2
AppRTC 是 webrtc 的一個 demo。
自建 AppRTC 可以苦其心志勞其筋骨餓其體膚,更重要的是能學會 webrtc 伺服器的搭建流程……
AppRTC 的組成部分是這樣的:
1、AppRTC - 房間伺服器。Github
2、Collider - 信令伺服器。上面 Github 工程裡內建,在 src/collider 下
3、coTurn - 打洞(內網穿透)伺服器。Google Code
4、還需要自己實現一個 coTurn 串連資訊(主要是使用者名稱、密碼的配置)擷取介面,通常叫做 TURN REST API。
零. 準備工作
0、為避免其他動作系統的各種尿性問題,這裡作業系統推薦使用 Ubuntu 14.04。
1、AppRTC 依賴 grunt 和 Google AppEngine SDK for Python 離線版本。
GAE SDK 安裝很簡單:下載、解壓、添加到PATH環境變數即可完成。
grunt,是 Node.js 下的一套任務執行系統,經過 Gruntfile.js 的配置,可以做很多事情。首先安裝 Node.js。使用 nvm 可以很方便的為自己的 Linux 賬戶安裝並設定好 Node.js。(而後,你可以選擇安裝 cnpm,這樣就可以使用國內的緩衝節點,npm install 命令會快許多,如果你只用這一次 grunt,那麼不裝這個也是可以的。)接下來只需要執行一個 npm install -g grunt-cli 即可安裝好 grunt。
2、Collider 依賴 golang。尿性的問題來了:牆……安裝 golang 和日後使用 golang 所需的包,幾乎都要FQ。所以這裡解決掉牆這個問題後,再使用 gvm 安裝 golang(目前的版本 go1.4.2) 即可完成我們的準備工作。
一. coTurn,打洞伺服器,安裝需 sudo
0、這貨是一個基本依賴,而且不需要改代碼,只要安裝,然後改設定檔,再啟動服務、開好連接埠就行了。
1、下載,去 這裡 ,下載最新版,turnserver-*-debian-wheezy-ubuntu-mint-x86-64bits.tar.gz
2、建立個目錄,然後,tar xzf <下載的檔案名稱> -c <目錄名>。
3、進入目錄,cat INSTALL,查看安裝須知,並根據指引安裝所需軟體,而後安裝該目錄下的deb包。
4、安裝完成後,修改設定檔 /etc/turnserver.conf 成如下內容:
# 不多講
listening-device=eth0
listening-port=3478
relay-device=eth0
# 記得開防火牆
min-port=59000
max-port=65000
# 更繁雜的輸出日誌
Verbose
# WebRTC 的訊息裡會用到
fingerprint
# WebRTC 認證需要
lt-cred-mech
# REST API 認證需要
use-auth-secret
# REST API 加密所需的 KEY
# 這裡我們使用“靜態”的 KEY,Google 自己也用的這個
static-auth-secret=4080218913
# 使用者登入網域
realm=<填寫你自己的網域名稱>
# 可為 TURN 服務提供更安全的訪問
stale-nonce
# SSL 需要用到的, 產生命令:
# sudo openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 -nodes
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
# 屏蔽 loopback, multicast IP地址的 relay
no-loopback-peers
no-multicast-peers
# 啟用 Mobility ICE 支援(具體幹啥的我也不曉得)
mobility
# 禁用本地 telnet cli 管理介面
no-cli
設定檔儲存成功後,使用命令 service coturn start ,啟動 coTurn 服務。
如果伺服器在內網,還需要做好連接埠映射:3478,3479:tcp&udp,外加設定檔裡的 59000~65000:tcp&udp。
二. coTurn 串連資訊介面(TURN REST API)
0、由於 coTurn 沒有內建該介面,所以需要我們碼農自行實現。關於該介面的實現方式,詳細的內容請參考 coTurn原始文檔。我這裡只做簡要說明:
* TURN 伺服器自身沒有必要實現該介面,所以需要服務提供者自行實現及部署。
* 此 TURN REST API 有標準的參考文檔,包括了請求參數以及返回內容,都有明確規定。碼農們需要按照該文檔內描述的內容來實現該介面。
* 文檔裡提到的內容有:
* ① 請求資訊,方式 GET:
* 需要包含:service(“turn”)、username、key
* 例如:/turn?username=392938130&key=4080218913
* ② 響應資訊,內容格式 JSON Dictionary:
* 需要包涵:username、password、ttl(可選, 單位秒. 推薦86400)、uris(數組)
* 例如:
{"username": "1433065916:392938130", "password": "***base64 encoded string***", "ttl":86400, "uris": ["turn:104.155.31.139:3478?transport=udp", "turn:104.155.31.139:3478?transport=tcp", "turn:104.155.31.139:3479?transport=udp", "turn:104.155.31.139:3479?transport=tcp"]}
基本形式就是這樣。需要提及的有:
1、響應的 username 欄位,需要以【timestamp + ":" + username】的形式輸出。注意:這裡 timestamp 為密碼失效的 UNIX 時間戳記,即【當前 timestamp + ttl 時間長度】;而 username 則是請求時提交的 username,原封不動;中間使用半形冒號做字串串連(預設設定下是這樣,你也可以自己改,不過多蛋疼……)。為便於後文敘述,此處響應內容裡的 username 欄位,我們稱之為 turn-username。
2、響應的 password 欄位,需要以 HMAC-SHA1 演算法計算得出,公式為:【base64_encode( hmac( key, turn-username ) )】。此處的 key,為 coTurn 伺服器配置中的 “static-auth-secret”值。以 key 作為 hmac 演算法的密鑰,turn-username 為被計算的內容,得出的 hmac 摘要後,經 base64 編碼得到最終密碼。
3、就是這些。uris 一般根據 coTurn 伺服器的假設規模來從後台配置好,而後再直接輸出到前台。我用 Node.js 簡單寫了個介面代碼,有需要可以參考:
var express = require(‘express‘);
var crypto = require(‘crypto‘);
var app = express();
var hmac = function(key, content){
var method = crypto.createHmac(‘sha1‘, key);
method.setEncoding(‘base64‘);
method.write(content);
method.end();
return method.read();
};
app.get(‘/turn‘, function(req, resp) {
var query = req.query;
var key = ‘4080218913‘; // 這裡的 key 是事先設定好的, 我們把他當成一個常亮來看, 所以就不從HTTP請求參數裡讀取了
if (!query[‘username‘]) {
return resp.send({‘error‘:‘AppError‘, ‘message‘:‘Must provide username.‘});
} else {
var time_to_live = 600;
var timestamp = Math.floor(Date.now() / 1000) + time_to_live;
var turn_username = timestamp + ‘:‘ + query[‘username‘];
var password = hmac(key, turn_username);
return resp.send({
username:turn_username,
password:password,
ttl:time_to_live,
"uris": [
"turn:turn.server.ip.address:3478?transport=udp",
"turn:turn.server.ip.address:3478?transport=tcp",
"turn:turn.server.ip.address:3479?transport=udp",
"turn:turn.server.ip.address:3479?transport=tcp"
]
});
}
});
app.listen(‘3033‘, function(){
console.log(‘server started‘);
});
代碼裡沒處理跨域的問題,所以雖說上面代碼監聽了 3033 連接埠,但我用 nginx 做了一個反代,以便能夠使用同一個網域名稱。這樣也就不會出現跨域的問題了。
三. Collider 信令伺服器
0、現在可以擺好FQ的pose了,如果不知道怎麼翻說明你還沒有準備好……
1、首先,可能是因為WALL的原因亦或是我FQ的姿勢不對,我在 get Collider 的依賴庫的時候遇到了點麻煩,不過改了原始碼就好了:
# $PWD = apprtc/src/collider/collider/
進入上面的這個目錄
# $FILES = [ ‘collider.go‘, ‘collider_test.go‘ ]
把上面倆檔案裡的這行:
"code.google.com/p/go.net/websocket"
替換成:
"golang.org/x/net/websocket"
記得儲存
2、然後就可以參照著 src/collider/README.md 裡面的步驟執行了:
......
# $PWD = apprtc/src/collider/
3. 將 以下3個目錄, 軟連結到 $GOPATH/src/
注意,應當先檢查自己的 golang 是否安裝好,並檢查 $GOPATH 是否不為空白且路徑 $GOPATH/src/ 已存在.
假設:當前現在就在 apprtc/src/collider/ 下
命令:ln -s $PWD/{collider,collidermain,collidertest} $GOPATH/src/
結果:會把 3 個目錄軟連結到 $GOPATH/src/ 下
4. 軟連結建立好後,執行:
命令:go get collidermain && go install collidermain
3、以上命令成功執行後,路徑 $GOPATH/bin/collidermain 將會是一個可執行檔。
可以追加 --help 參數查看所有可用的命令列參數。這裡我們使用這樣的配置:
# $GOPATH/bin/collidermain -port=8089 -room-server=‘http://apprtc.domain.com:8083‘ -tls=false
# 到這裡我們還沒有接觸過 AppRTC 的搭建,所以暫時我們並不知道 room-server 參數的值是什麼。
# 這條命令應該是等下搞好了 AppRTC 後,再回來執行的。
-port = 表示 collider 監聽的連接埠。我們這裡用 8089。如果有防火牆,記得開啟,如果在內網,記得在路由器上做映射。
-room-server = 表示 AppRTC 可訪問的 URL。如果使用了非標準連接埠(80、443),則務必寫好連接埠號碼。
-tls = false 表示關閉 TLS 加密。因為這個需要配置認證("/cert/cert.pem", "/cert/key.pem"),所以以自己研究為目的的,關了是最方便的……
4、這裡的 8089 是服務連接埠,如果你在內網裡並需要對外提供服務,需要將 8089:tcp 映射出外網。
四. AppRTC 房間伺服器
0、這是最後一步,只需要改幾處配置就可以開啟運行了。這裡假設你所在的路徑是 apprtc 項目的根目錄。
1、由於前面我們的 Collider 使用了 tls = false 參數,且為了訪問方便,這裡需要做以下修改:
# $FILE = apprtc/src/app_engine/apprtc.py
搜尋 "wss:" 和 "https:" (注意冒號)
可以在方法 get_wss_parameters 裡搜尋到,這裡需要把 wss: 替換成 ws:、把 https: 替換成 http:,儲存退出,就可以了。
2、編輯設定檔,檔案位於 apprtc/src/app_engine/constants.py。
① 搜尋 TURN_BASE_URL
將等號後面的字串替換為 apprtc 可以訪問到的地址,如:‘http://apprtc.domain.com:8083‘
② 搜尋 WSS_INSTANCES
可以看到,這裡被配置為了一個數組,不過我們只有單台伺服器。所以先刪掉數組的其他元素,只保留一個。
在保留下來的元素中,我們只修改 WSS_INSTANCE_HOST_KEY 對應的值即可。
將其改為上面 Collider 伺服器的可訪問地址。比如:apprtc.domain.com:8089。不需要協議,沒有 URI。
改完以上兩處,可以儲存退出了
3、如果你使用了非標準連接埠,或者使用路由器上的連接埠映射為廣域網路提供測試和服務,還需要修改WEB前端的一些代碼。否則會遇到瀏覽器的跨域訪問問題(主要是 pushState 會產生一個錯誤),這麼改:
# $FILE = apprtc/src/web_app/js/appcontroller.js
這個檔案裡有這樣的兩個函數:
AppController.prototype.pushCallNavigation_
AppController.prototype.displaySharingInfo_
分別在這兩行函數內部的開頭,加上如下代碼:
roomLink = roomLink.replace(/apprtc\.domain\.com\//, ‘apprtc.domain.com:8083/‘);
儲存退出
4、現在再次確認目前的目錄是 apprtc 項目的根目錄,而後執行:
$ grunt build; dev_appserver.py --host=0.0.0.0 ./out/app_engine
# 因為是為公網、或者區域網路其他人提供服務,所以這裡 host=0.0.0.0,以避免只監聽 127.0.0.1 的狀況。
5、需要注意的是,dev_appserver 預設監聽了 8080 連接埠。但配置裡到處都是 8083,因為還差了最後一步……
五. nginx,用來統一 HTTP 對外服務連接埠,以及最主要的反代 3033 TURN REST API 服務。
0、先裝好nginx:apt-get install nginx -y
1、預設設定檔在 /etc/nginx/sites-enabled/default 。開啟後,新增:
server {
listen 8083;
server_name apprtc.domain.com;
location / {
proxy_pass http://ip.address.of.apprtc:8080;
proxy_set_header Host $host;
}
location /turn {
proxy_pass http://ip.address.of.turn-rest-api:3033;
proxy_set_header Host $host;
}
}
# 儲存後退出
2、使用 service nginx reload 重載設定檔。
3、如果有需要,可以在路由器上做連接埠映射:8083:tcp。
4、此時,外部可以訪問到的 AppRTC 服務的 URL 已經確定了,你可以檢查並執行【三(3)】中的命令。注意如果前面運行過此命令,就不需要再次運行了。
六. 開啟瀏覽器訪問 http://apprtc.domain.com:8083/ 。輸入房間號,並把房間URL發給你的好基友,就可以面基了……
--------------------------------------------------------------
由於我搭建整套環境是在內網虛擬機器上操作的,所以文章裡到處都會出現”在路由器上設定好連接埠映射“這樣的句子。
在這裡,統一做一下整理吧:
8083:tcp - AppRTC 的連接埠,提供 HTTP 服務。預設使用的是 8080:tcp,我把它改了。
8089:tcp - Collider 服務的連接埠,提供 WebSocket 服務。
3478、3479:tcp&udp - coTurn 的監聽連接埠。
59000~65000:tcp&udp - coTurn 的服務連接埠。
TURN REST API 的連接埠(3033)由於被 nginx 反向 Proxy了,所以並不需要再單獨給它做連接埠映射。
就這樣吧,EOF
自建 AppRTC