janus介紹
janus是Meetecho開發的一個WebRTC網關,janus的主要作用就是它可以和你的內網設備和瀏覽器同時建立連接,并將瀏覽器發來的音視頻數據包如rtp/rtcp包,通過自定義插件轉發給你的內網設備,也可以將你發給janus的音視頻數據包,加密后轉發給瀏覽器。
這樣就完成了內網音視頻服務器和外網瀏覽器的互通。
janus為我們完成了與瀏覽器建立會話的復雜邏輯,并且提供給我們簡單的插件機制來處理音視頻數據。
對于PeerConnection連接的建立過程,涉及到復雜的NAT穿透的ICE協議的實現,SDP的交換,DTLS-SRTP的握手和數據包加密發送,數據包接收后解密的復雜邏輯。
janus將我們從與瀏覽器交互的PeerConnection建立的過程中解脫出來,更專注于音視頻業務邏輯。
janus的設計思想
janus基于插件思想,通過實現基礎架構,完成了與瀏覽器鏈接的建立過程。
janus的插件主要完成一些必須的函數實現,如RTP/RTCP數據的接收。
我們通過實現自己的插件,來完成在將瀏覽器RTP數據轉發到內網服務器的業務邏輯。
janus的用途
janus一般用于拓展已有視頻會議系統,提供對瀏覽器客戶端的支持。
janus的安裝
官網安裝步驟
按照官網的安裝步驟可以順利的完成安裝。
本文在ubuntu16.04系統下測試。
首先安裝全新虛擬機ubuntu16.04
下載源碼,需要先安裝git
git clone git@github.com:meetecho/janus-gateway.git
然后安裝janus依賴庫
sudo apt-get install aptitute
sudo aptitude install libmicrohttpd-dev libjansson-dev libnice-dev \
libssl-dev libsrtp-dev libsofia-sip-ua-dev libglib2.0-dev \
libopus-dev libogg-dev libcurl4-openssl-dev liblua5.3-dev \
pkg-config gengetopt libtool automake
安裝libsrtp 2.0
wget https://github.com/cisco/libsrtp/archive/v2.0.0.tar.gz
tar xfv v2.0.0.tar.gz
cd libsrtp-2.0.0
./configure --prefix=/usr --enable-openssl
make shared_library && sudo make install
編譯安裝janus
git clone https://github.com/meetecho/janus-gateway.git
cd janus-gateway
sh autogen.sh
./configure --prefix=/opt/janus
make
sudo make install
到此為止,janus安裝到了/opt/janus目錄
janus的配置文件
janus的運行需要進行一些配置
使用命令生成一些默認配置文件
cd janus-gateway
make configs
對于最基本的演示用途,配置到此就結束了。
詳細的配置可以打開文件/opt/janus/etc/janus/janus.cfg
按照注釋進行配置。
運行janus服務器
直接啟動janus的可執行程序即可前臺運行janus
cd /opt/janus/bin
./janus
運行janus http server
我們需要研究janus提供的demo,比如EchoTest。我們需要在瀏覽器中打開測試網頁才可以進行測試。所以,我們需要一個http server
cd /opt/janus/share/janus/demos
python -m SimpleHTTPServer
命令行輸出:Serving HTTP on 0.0.0.0 port 8000 ...
這樣就搭建了簡單的http server,監聽端口為8000
使用瀏覽器打開地址,假設ubuntu 16.04的ip為10.1.32.146
http://10.1.32.146:8000/
即可看到janus的官網運行起來了。
運行echotest
首先確保你有攝像頭和麥克風
選擇Demos->Echo Test
點擊start就能夠正常運行演示程序。
Echo Test完成了將瀏覽器發來的音視頻數據,發回給瀏覽器。
演示了會話建立,插件編寫等基本功能。
Echo Test對應的插件源碼為
janus-gateway/plugins/janus_echotest.c
通過閱讀janus-gateway/plugins/plugin.h
中的注釋,可以基本了解插件編寫的規則。
janus.js的作用
在echo test的例子中,前端部分使用了janus.js。janus.js是和janus服務器進行通信的javascript庫,通過使用janus.js簡化了webrtc api的使用,以及前端與janus服務器建立連接,交換sdp等功能。如果你不依賴于janus.js你可以自行實現這些邏輯,不過會比較復雜。
janus服務器和瀏覽器建立會話的過程
整個會話建立的過程符合標準的webrtc peerconnection連接建立的過程。這里的janus服務器就像另一個瀏覽器端一樣。兩端分別通過stun server拿到自己的外網地址,以及內網地址。推薦看一下ICE協議文檔,深入了解下NAT穿透的過程。
然后交換sdp方面。在生成sdp的過程中,我們可以通過設置需要使用的音視頻編解碼參數,來要求瀏覽器使用我們希望使用的音視頻編碼。
sdp交換后,雙方進行連通性測試,即UDP打洞過程。由于echo test中我們并沒有配置stun server,所以無法獲取到外網IP。所以最終打洞成功的只有本地局域網地址。
janus的插件機制介紹
janus的關鍵概念是它的插件機制。janus底層完成了連接建立的通用部分,而把具體業務部分作為插件來提供。對于會話的整個生命周期,都會有對應的插件回調產生。插件在自己的實現中,完成了需要的業務邏輯。如echo test就在它的業務邏輯中給瀏覽器原樣返回了RTP數據。而我們公司的業務就是將數據轉發到媒體服務器的某個會議中。
janus如何編寫插件
janus plugin需要實現的接口
在plugins.h頭文件中,定義了插件結構體struct janus_plugin
。我們只需要按照struct janus_plugin
中定義的函數,逐個實現,就可以完成插件的編寫。
需要實現的接口有:
struct janus_plugin {
int (* const init)(janus_callbacks *callback, const char *config_path);
void (* const destroy)(void);
int (* const get_version)(void);
const char *(* const get_package)(void);
void (* const create_session)(janus_plugin_session *handle, int *error);
struct janus_plugin_result * (* const handle_message)(janus_plugin_session *handle, char *transaction, json_t *message, json_t *jsep);
void (* const setup_media)(janus_plugin_session *handle);
void (* const incoming_rtp)(janus_plugin_session *handle, int video, char *buf, int len);
void (* const incoming_rtcp)(janus_plugin_session *handle, int video, char *buf, int len);
void (* const incoming_data)(janus_plugin_session *handle, char *buf, int len);
void (* const destroy_session)(janus_plugin_session *handle, int *error);
...
};
這些接口體現了整個會話的生命周期。對于incoming_rtp,incoming_rtcp,incoming_data來說,分別代表收到的瀏覽器發來的rtp,rtcp,自定義數據。這是我們媒體處理的重點。你可以根據業務需求去實現自己的邏輯。
使用janus_callbacks轉發數據給瀏覽器
當我們希望janus幫助我們把數據發給對方時,我們需要使用janus暴露給我們的callback:
struct janus_callbacks {
void (* const relay_rtp)(janus_plugin_session *handle, int video, char *buf, int len);
void (* const relay_rtcp)(janus_plugin_session *handle, int video, char *buf, int len);
void (* const relay_data)(janus_plugin_session *handle, char *buf, int len);
void (* const close_pc)(janus_plugin_session *handle);
void (* const end_session)(janus_plugin_session *handle);
...
};
其中relay_rtp,relay_rtcp,relay_data分別是用來發送rtp,rtcp,自定義數據的。
janus的插件都有唯一的標識符,如echo test插件的標識符為:
#define JANUS_ECHOTEST_PACKAGE "janus.plugin.echotest"
在前端js中需要指定需要與哪個插件建立會話,在調用janus.js的janus.attach接口時指定:
janus.attach({
plugin: "janus.plugin.echotest",
...
})
總結
本文介紹了janus的環境搭建,janus的設計思想,和插件的編寫方法。閱讀本文后,你能夠對janus的使用有基本的認識。具體的細節可以通過閱讀源碼的方式繼續深入了解。