呂海東+鄧永康+鐘越星+肖瑞+李文博
摘要:針對(duì)使用傳統(tǒng)的軟件架構(gòu)無法使用超大并發(fā)實(shí)時(shí)應(yīng)用的性能需求,采用了全新的異步非阻塞工作模式的Node.js平臺(tái)和在其基礎(chǔ)上的支持集群功能的實(shí)時(shí)傳輸框架SocketCluster實(shí)現(xiàn)了工作在移動(dòng)平臺(tái)上的Web視頻會(huì)議系統(tǒng)。該系統(tǒng)能支持CPU多核以及多服務(wù)器的集群下的可伸縮性,以適應(yīng)實(shí)時(shí)應(yīng)用系統(tǒng)對(duì)性能的需求。測(cè)試證明采用以上平臺(tái)開發(fā)的實(shí)時(shí)系統(tǒng)性能優(yōu)越,為未來實(shí)時(shí)應(yīng)用開發(fā)提供的經(jīng)驗(yàn)和基礎(chǔ)。
關(guān)鍵詞: 視頻會(huì)議; 實(shí)時(shí)應(yīng)用; Node.js; SocketCluster; 視頻音頻采集
中圖分類號(hào):TP311 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2017)01-0208-03
Abstract:Due to the traditional software architecture can not meet the performance requirements of large concurrent real-time applications, using the SocketCluster real-time transmission frame of the new non blocking asynchronous mode of Node.js platform and on the basis of the realization of the function of the cluster support Web video conferencing system work on mobile platform. The system can support the scalability of CPU multi core and multi server cluster, so as to meet the requirement of real-time application system.The test proves that the real time system developed by the above platform is superior to the experience and foundation for the future development of real time application.
Key words: video conferencing; real-time application; Node.js; SocketCluster; video and audio collection
1 概述
目前市場上各個(gè)主流的視頻會(huì)議系統(tǒng)[1]都基于企業(yè)內(nèi)部的平臺(tái)或私有云基礎(chǔ)上,才能保證視頻和音頻的流暢傳輸,尤其是移動(dòng)視頻會(huì)議移動(dòng)端基本上都運(yùn)行在移動(dòng)平臺(tái)的原生App模式,需要會(huì)議參加者在自己的手機(jī)或平板上下載安裝,使得系統(tǒng)的更新難以實(shí)時(shí)完成。同時(shí)在視頻會(huì)議的設(shè)計(jì)與實(shí)現(xiàn)上,傳統(tǒng)視頻會(huì)議都采用基于多線程阻塞模式[2]的服務(wù)器框架如JavaEE或MS.NET,難以滿足在大數(shù)據(jù)量、高并發(fā)情況下對(duì)視頻會(huì)議實(shí)時(shí)性能要求。
針對(duì)以上問題,本文采用專門支持高并發(fā)和實(shí)時(shí)性的Node.js[3]作為服務(wù)器平臺(tái),使用基于Noded的Express[4] Web框架和SocketCluster[5]實(shí)時(shí)通訊集群框架,結(jié)合客戶端HTML5 Video[6]和Audio API[7]開發(fā)了純Web模式的移動(dòng)視頻會(huì)議系統(tǒng)。
該系統(tǒng)具有Web應(yīng)用的優(yōu)點(diǎn),同時(shí)服務(wù)器端利用其多核和多CPU的特性,使用Socket集群模式來實(shí)現(xiàn)移動(dòng)視頻會(huì)議的多用戶高并發(fā)和高性能的視頻和音頻傳輸。
2 系統(tǒng)總體架構(gòu)設(shè)計(jì)
本移動(dòng)視頻會(huì)議系統(tǒng)采用Web工作模式,服務(wù)器采用Linux Ubuntu Server上運(yùn)行Node.js,在Node平臺(tái)上采用Express為Web服務(wù)器,為移動(dòng)客戶端提供視頻會(huì)議Web頁面的請(qǐng)求和呈現(xiàn)。
系統(tǒng)的核心功能是參與會(huì)議的每個(gè)成員的視頻和音頻的傳輸,為支持多用戶的實(shí)時(shí)數(shù)據(jù)傳輸,采用能支持Socket傳輸集群的SocketCluster框架在服務(wù)器端和客戶端之間實(shí)現(xiàn)視頻和音頻數(shù)據(jù)的雙向?qū)崟r(shí)傳輸。
客戶端智能手機(jī)或平臺(tái)利用內(nèi)置的支持HTML5的瀏覽器,結(jié)合Google的Web框架AngularJS[8]和Twitter的Bootstrap[9]框架實(shí)現(xiàn)Web頁面元素的渲染和數(shù)據(jù)綁定,并引入SocketCluster的客戶端負(fù)責(zé)發(fā)送本地用戶的視頻和音頻,以及接收其他用戶發(fā)送的視頻和音頻,并使用HTML5 Audio API實(shí)現(xiàn)音頻的合成和播放。系統(tǒng)的總體架構(gòu)如圖1所示。
Node.js是基于JavaScript的輕量級(jí)的,高性能的用于開發(fā)現(xiàn)代移動(dòng)和企業(yè)級(jí)應(yīng)用的服務(wù)器平臺(tái)。其核心特點(diǎn)是非阻塞,單線程,異步工作模式,特別適用于開發(fā)大量用戶連接的高并發(fā)應(yīng)用,目的是為解決傳統(tǒng)的應(yīng)用服務(wù)器,如JavaEE,MS.NET, PHP無法適用當(dāng)連接超過10萬的高并發(fā)場合。
Express是基于Node.js平臺(tái)的web應(yīng)用開發(fā)框架,它基于Node.js的非阻塞和異步模式,可提供超高速的Web請(qǐng)求和響應(yīng)處理,適合開發(fā)各種高并發(fā)的移動(dòng)設(shè)備應(yīng)用。
SocketCluster是建立在Node.js平臺(tái)的基于WebSocket協(xié)議的支持集群的實(shí)時(shí)通訊開源框架。它既支持豎向伸縮(多核CPU),也支持橫向伸縮性(多個(gè)主機(jī)組建的集群)以適應(yīng)超并發(fā)的密集的數(shù)據(jù)實(shí)時(shí)數(shù)據(jù)傳輸。
在傳輸對(duì)象上,它既支持客戶-服務(wù)器間傳輸,也支持客戶之間的數(shù)據(jù)傳輸。在傳輸方式上同時(shí)支持請(qǐng)求/響應(yīng)模式的點(diǎn)對(duì)點(diǎn)數(shù)據(jù)傳輸,也支持發(fā)布/訂閱模式的群發(fā)群收功能,本系統(tǒng)正是利用此發(fā)布和訂閱模式,在所有會(huì)議的參加者之間群發(fā)和群收視頻和音頻數(shù)據(jù),實(shí)現(xiàn)雙向的實(shí)時(shí)視頻會(huì)議。
3 服務(wù)器端設(shè)計(jì)與實(shí)現(xiàn)
服務(wù)器端主要實(shí)現(xiàn)Web服務(wù)器和Socket數(shù)據(jù)傳輸服務(wù)器兩個(gè)核心功能。
Web服務(wù)器采用Express框架,用于實(shí)現(xiàn)系統(tǒng)Web頁面的響應(yīng)服務(wù),系統(tǒng)采用純靜態(tài)HTML5頁面,通過AngularJS框架實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)顯示。
數(shù)據(jù)傳輸采用SocketCluster5.0.19最新版,其支持Socket集群功能,可使用CPU的多核或多服務(wù)器集群運(yùn)行在Node.js多線程模式,可更好地支持更多參與會(huì)議的用戶的數(shù)據(jù)傳輸。
Node.js自身工作在單線程工作模式,無法支持多CPU或多內(nèi)核CPU,為能實(shí)現(xiàn)多CPU時(shí)的多線程N(yùn)ode,需要使用Node集群框架,SocketCluster是能支持此類特性的優(yōu)秀集群框架。
SocketCluster自身工作在如下3種線程下。
1) 主線程:此線程執(zhí)行SocketCluster的服務(wù)器啟動(dòng)和管理功能。
2) 工作線程(Workers):啟動(dòng)多個(gè)Node.js實(shí)例對(duì)象,每個(gè)對(duì)象內(nèi)有Event Lopp機(jī)制實(shí)現(xiàn)對(duì)事件的檢測(cè)和處理。每個(gè)CPU內(nèi)核運(yùn)行一個(gè)Node線程,這個(gè)具有2個(gè)CPU且每個(gè)具有8核的服務(wù)器可運(yùn)行16個(gè)Node實(shí)例,如此可處理超大量并發(fā)用戶的請(qǐng)求處理。
3) 代理線程(Brokers):該線程內(nèi)執(zhí)行一個(gè)代理服務(wù)對(duì)象,用于在各個(gè)工作線程間實(shí)現(xiàn)事件的共享。
如下代碼簡要演示SocketClutser主線程了啟動(dòng)16個(gè)工作線程和1個(gè)代理線程。
var SocketCluster = require('socketcluster').Socket Cluster;
var socketCluster = new SocketCluster({
workers: 16, brokers: 1, port:8000,
appName: "mobilemeeting",
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',});
在每個(gè)工作線程worker.js中用于啟動(dòng)一個(gè)Node及Express和SocketServer實(shí)例,用于Web服務(wù)和Socket傳輸服務(wù),如下代碼展示了工作線程的實(shí)現(xiàn)。
var express = require('express');
var serveStatic = require('serve-static');
var path = require('path');
var meetingvideo=require("./business/meetingvideo");
var meetingaudio=require("./business/meetingaudio");
module.exports.run = function (worker) {
var app = express ();
var httpServer = worker.httpServer; //啟動(dòng)Express Web服務(wù)器
var scServer = worker.scServer; //啟動(dòng)Socket Server傳輸服務(wù)器
app.use(serveStatic(path.resolve(__dirname, 'web')));
httpServer.on('request', app);
//啟動(dòng)會(huì)議視頻和音頻傳輸模塊
meetingvideo.start(scServer);
meetingaudio.start(scServer); };
工作線程中通過worker對(duì)象創(chuàng)建HTTP服務(wù)器并集成Express,并啟動(dòng)視頻和音頻傳輸服務(wù)器。
4 視頻采集和傳輸實(shí)現(xiàn)
SocketCluster內(nèi)部實(shí)現(xiàn)了與Socket.io框架相同的Socket數(shù)據(jù)傳輸機(jī)制,它基于HTTP5的WebSocket協(xié)議實(shí)現(xiàn)雙向?qū)崟r(shí)的數(shù)據(jù)傳輸,用于高性能實(shí)時(shí)應(yīng)用的開發(fā)。
SocketCluster即支持客戶端-服務(wù)器端的請(qǐng)求-響應(yīng)的點(diǎn)對(duì)點(diǎn)傳輸模式,也支持基于發(fā)布/訂閱模式的群發(fā)群收傳輸模式。本系統(tǒng)因?yàn)橐С侄鄠€(gè)會(huì)議參與者的雙向?qū)崟r(shí)通訊,采用的是發(fā)布/訂閱模式的Socket傳輸,在Socket服務(wù)器上各個(gè)客戶端端都訂閱視頻主題meeting.video和音頻主題meeting.audio,當(dāng)某個(gè)客戶端發(fā)送視頻或音頻數(shù)據(jù)到此主題后,所有參與會(huì)議的客戶端自動(dòng)接收到該主題上的數(shù)據(jù),實(shí)現(xiàn)視頻和音頻的顯示和播放。如下代碼簡要演示了視頻主題的編程,音頻主題編程與之基本類似,不再贅述。
module.exports.start=function(scServer){
scServer.on('connection', function (socket) {
socket.on("meeting.video",function(data){
scServer.exchange.publish("meetimg.video.data",data);
}); }); };
Socket服務(wù)器通過監(jiān)聽數(shù)據(jù)到達(dá)事件,使用exchange.publish方法實(shí)現(xiàn)群發(fā)。由于該服務(wù)器工作在16線程下,可以處理大量的并發(fā)數(shù)據(jù)傳輸,得以實(shí)現(xiàn)高性能的移動(dòng)Web視頻會(huì)議系統(tǒng)。
5 客戶端視頻采集傳輸接收和顯示實(shí)現(xiàn)
客戶端視頻的采集使用HTML5的瀏覽器支持的getUserMedia方法取得攝像頭的圖像,并把實(shí)時(shí)采集的數(shù)據(jù)發(fā)送到本地頁面中的
程序4:視頻采集實(shí)現(xiàn)代碼
navigator.getUserMedia({video:true },function(stream){
video.src =window.URL.createObjectURL(stream);
video.play();
$scope.$apply();
視頻數(shù)據(jù)采集到
$scope.videotimer=$interval(function(){
canvasContext.drawImage(video, 0, 0, 100, 90);
meetingVideoData=canvas.toDataURL();
socket.sendVideoData({meetingNo:$scope.meetingNo,userid:$rootScope.loginuserid,videodata:meetingVideoData}); },1000/60);
SocketCluster提供了Web客戶端插件,在Web頁面載入后,會(huì)通過此插件實(shí)現(xiàn)與服務(wù)器的SocketCluster的連接,并通過發(fā)送數(shù)據(jù)到主題或監(jiān)聽主題的數(shù)據(jù)到達(dá)事件,將接收數(shù)據(jù)中包含的用戶ID取出,定位該用戶的視頻顯示元素,將視頻數(shù)據(jù)發(fā)送到該元素上,實(shí)現(xiàn)此用戶的視頻顯示,簡要實(shí)現(xiàn)代碼如下所示。
//監(jiān)聽視頻數(shù)據(jù)到達(dá)事件
socket.watchVideoData(function(data){
var senduserid=data.userid;
var videoimage=document.querySelector("img#img_"+ senduserid);
videoimage.src=data.videodata;});
6 客戶端音頻采集傳輸接收和播放實(shí)現(xiàn)
系統(tǒng)采用視頻和音頻分開采集的方式,將采集的音頻按照最小失真原理,盡可能減少傳輸?shù)臄?shù)據(jù),提高系統(tǒng)的性能。
客戶端音頻處理過程首先使用HTML5提供的getUserMedia方法采集麥克音頻,并使用Audio API對(duì)其進(jìn)行過濾處理,將解析的音頻數(shù)據(jù)按采樣率打包為二進(jìn)制數(shù)據(jù),通過SocketCluster的群發(fā)模式發(fā)送給所有參加會(huì)議的客戶端,客戶端接收到音頻采樣數(shù)據(jù)后,通過Audio API實(shí)現(xiàn)與揚(yáng)聲器連接進(jìn)行播放。
音頻采集使用navigator.getUserMedia({ audio: true },function (stream) {}方法取得stream對(duì)象,此對(duì)象包含音頻的所有信息,包括左右聲道數(shù)據(jù)。
取得音頻數(shù)據(jù)后,創(chuàng)建Audio API的處理對(duì)象audioctx=new window.AudioContext();,將采集的音頻對(duì)導(dǎo)入到此處理對(duì)象var auidoinput = audioctx.createMediaStreamSource(stream);,再使用Audio對(duì)象創(chuàng)建音頻處理緩存對(duì)象var scriptNode = audiocontext.createScriptProcessor(1024, 1, 1); 通過此處理對(duì)象的采樣處理回調(diào)函數(shù),取得采集的音頻數(shù)據(jù),并通過SocketCluster客戶端發(fā)送給指定的主題,這樣所有訂閱此主題的Socket客戶均可接收到傳輸?shù)囊纛l數(shù)據(jù),其示意代碼如下。
scriptNode.onaudioprocess = function(event) {
var left = event.inputBuffer.getChannelData(0);
var leftdata=left;
socket.publish("meeting.audio",leftdata);};
為減少傳輸?shù)臄?shù)據(jù)量代碼中只取得左聲道數(shù)據(jù)發(fā)送到Socket主題。
所有SocketClutser的客戶端會(huì)監(jiān)聽音頻主題的數(shù)據(jù)到達(dá)事件,接收到音頻數(shù)據(jù)后,依然使用Audio API的對(duì)象解析音頻數(shù)據(jù),并與目標(biāo)設(shè)備揚(yáng)聲器連接,將處理的音頻發(fā)送到目標(biāo)對(duì)象實(shí)現(xiàn)音頻的播放,其簡要示意實(shí)現(xiàn)代碼如下。
msocket.on("meeting.audio",function(data){
var auidosource = audiocontext.createBufferSource();
auidosource.buffer = buffer;
auidosource.connect(audiocontext.destination);
auidosource.start(0); // 0是當(dāng)前audio context中的同步時(shí)間 });
系統(tǒng)經(jīng)過測(cè)試證明,基于Node.js的SocketClutser是高性能的數(shù)據(jù)傳輸服務(wù)器,其內(nèi)置的集群支持使得處理能力極大提高。移動(dòng)視頻會(huì)議的運(yùn)行如圖2所示。
7 結(jié)論
基于Node.js及其Socket集群框架未來可以開發(fā)出性能出眾的各種實(shí)時(shí)應(yīng)用,這是傳統(tǒng)架構(gòu)的軟件系統(tǒng)無法達(dá)到的,必將成為實(shí)時(shí)應(yīng)用開發(fā)的主流技術(shù)。
未來將深入探索在Node.js架構(gòu)下以響應(yīng)式微服務(wù)集群模式開發(fā)各種實(shí)時(shí)應(yīng)用的模式和實(shí)現(xiàn)。
參考文獻(xiàn):
[1] 聶曉飛. 基于WebRTC的跨平臺(tái)視頻會(huì)議系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[D].北京交通大學(xué),2014.
[2] 劉應(yīng)天. 時(shí)鐘共享多線程處理單元的設(shè)計(jì)與實(shí)現(xiàn)[D]. 西安郵電大學(xué),2015.
[3] 王金龍, 宋斌,丁銳. Node.js:一種新的Web應(yīng)用構(gòu)建技術(shù)[J]. 現(xiàn)代電子技術(shù), 2015(06):70-73.
[4] 楊小嬌. 輕量級(jí)高并發(fā)Web服務(wù)器的研究與實(shí)現(xiàn)[D].南京郵電大學(xué) 2014.
[5] SocketCluster.io.SocketCluster[EB/OL]. http://socketcluster.io/#!/.
[6] 張文. 基于HTML5的視頻播控和客戶服務(wù)系統(tǒng)[D]. 西安電子科技大學(xué), 2014.
[7] 陳迪. 基于HTML5的Web視頻會(huì)議系統(tǒng)的研究與實(shí)現(xiàn)[D]. 華南理工大學(xué), 2015.
[8] 董英茹. 簡談AngularJS在下一代Web開發(fā)中的應(yīng)用[J].軟件工程師,2015(5):30-31.
[9] 陳思濛.基于Bootstrap的響應(yīng)式拼車網(wǎng)站設(shè)計(jì)與實(shí)現(xiàn)[D]. 大連理工大學(xué),2015.