廖列法,張幸平
(江西理工大學(xué) 信息工程學(xué)院,江西 贛州 341000)
隨著人工智能時代的來臨以及Android智能設(shè)備的普及,針對移動端的應(yīng)用越來越廣泛,移動設(shè)備上的應(yīng)用技術(shù)已成為當前科技領(lǐng)域熱門的研究方向。傳統(tǒng)的指揮系統(tǒng)中要求使用專用設(shè)備,比如對講機、照相機、GPS等,對設(shè)備要求性較高、負擔較大。與此同時,支持的功能和使用界面較為簡單,沒有良好的用戶體驗感,無法滿足日益增長的用戶需求。近些年智能指揮類系統(tǒng)在各行各業(yè)都有不斷的被提出及應(yīng)用,比如基于Android的應(yīng)急指揮系統(tǒng)[1]、調(diào)度指揮系統(tǒng)[2]、扁平化的圖形類指揮系統(tǒng)[3]等,但這些系統(tǒng)主要還是采用傳統(tǒng)的Client/Server技術(shù),系統(tǒng)架構(gòu)部署較為復(fù)雜,對服務(wù)器要求較高。因此基于當前主流的Spring Cloud[4]微服務(wù)架構(gòu)體系實現(xiàn)一套滿足云服務(wù)器下分布式集群化的輕量型實時可視化指揮系統(tǒng)具有非常重要的應(yīng)用與研究價值。
本文設(shè)計并實現(xiàn)了一種基于Android的智能可視化指揮系統(tǒng)。為了滿足大用戶、高并發(fā)、可擴展的部署需求,該系統(tǒng)采用了采用Spring Cloud微服務(wù)架構(gòu)和Ngnix[5]、Redis[6]、Nodejs[7]、Mysql[8]等技術(shù)。采用3種定位技術(shù)(網(wǎng)絡(luò)[9]、GPS[10]和離線[11])來保證用戶位置的實時獲取,設(shè)計用戶上下消息、語音控制類消息,通過自主的實時傳輸協(xié)議實現(xiàn)信息的實時傳輸,同時以地圖為基本元素,展示可視化指揮的所有功能。既增強了傳統(tǒng)指揮系統(tǒng)的功能,實現(xiàn)了直觀、可視化的展現(xiàn)方式,又提供了一套輕量型的實時可視化指揮系統(tǒng)方案。
方案設(shè)計的基本要求是支持在多臺云服務(wù)器上進行分布式和集群化的部署,以保證所開發(fā)系統(tǒng)的穩(wěn)定性、可靠性和可擴展性。接下來,我們將從系統(tǒng)的組織框架、整體架構(gòu)和功能架構(gòu)進行具體介紹。
在Spring Cloud微服務(wù)的框架下,根據(jù)不同的功能,設(shè)計的功能服務(wù)模塊包括音頻服務(wù)(Audi)、上下線服務(wù)(Online)、轉(zhuǎn)發(fā)服務(wù)(Forward)、消息通知服務(wù)(Notification),以及線程池同步服務(wù)。其中音頻服務(wù)模塊提供了視頻和音頻消息的相關(guān)接口,上線下服務(wù)模塊提供了用戶狀態(tài)的相關(guān)接口,轉(zhuǎn)發(fā)服務(wù)模塊提供了消息的轉(zhuǎn)發(fā)接口,消息通知服務(wù)模塊提供了通知的相關(guān)接口,線程池同步服務(wù)模塊提供了不同線程之間數(shù)據(jù)的同步。根據(jù)消息的類型,該系統(tǒng)設(shè)計的消息類型分為聊天文本、消息類文本(同步消息、下線消息、推送消息和通知消息)、圖像、視頻流、語音流等。圖1展示了如上所述的系統(tǒng)組織架構(gòu)。
圖1 系統(tǒng)組織框架
該系統(tǒng)涉及的主要模塊包括2個消息通知服務(wù)(notify server1和server2)、緩存服務(wù)(Redis)、消息服務(wù)進程(接收和轉(zhuǎn)發(fā))、通知推送服務(wù)平臺(包含自主和第三方的消息推送服務(wù))、Android移動端等。其中,所有加入的移動客戶端都會與消息通知服務(wù)器建立連接,而負載均衡模塊負責分配新加入設(shè)備需要連接的服務(wù)器。具體來說,消息的發(fā)生到接收會涉及以下過程。首先,消息發(fā)送到消息通知服務(wù)器;其次,消息通知服務(wù)將消息以異步的方式存入數(shù)據(jù)庫和緩存(Redis)中;第三,查詢目標用戶連接的服務(wù)器;第四,將消息轉(zhuǎn)發(fā)到上一步查詢到的服務(wù)器中;最后,接收到消息的服務(wù)器將數(shù)據(jù)推送到相應(yīng)的客戶端。圖2顯示了整個系統(tǒng)的架構(gòu)和消息流轉(zhuǎn)。
圖2 系統(tǒng)架構(gòu)
系統(tǒng)采用C/S架構(gòu),客戶端與服務(wù)器之間通過TCP協(xié)議通信。服務(wù)器提供的功能包括數(shù)據(jù)的持久化存儲(數(shù)據(jù)庫)、語音流和視頻流數(shù)據(jù)的實時傳輸、文本類消息的實時中轉(zhuǎn)(即時文本、位置類、控制類和狀態(tài)類消息)。同時以Nginx為負載均衡反向代理服務(wù),Redis為主從的集群方案,Nodejs為應(yīng)用服務(wù)器,Mysql為數(shù)據(jù)存儲服務(wù)來提供一套高可用、高并發(fā)的集群化解決方案。
客戶端提供的功能包括良好的使用界面、流數(shù)據(jù)的處理(如,發(fā)送、接收、解析和播放)、文本數(shù)據(jù)的處理(如,即時文本、位置類、控制類和狀態(tài)類等消息的解析和轉(zhuǎn)發(fā)),以及用戶位置的實時獲獲取、轉(zhuǎn)發(fā)和解析。圖3展示了該系統(tǒng)的功能架構(gòu)。
圖3 系統(tǒng)功能架構(gòu)
如圖3所示,客戶端支持的設(shè)備為Android的移動端和PAD端(系統(tǒng)版本號為4.0以上)。根據(jù)功能劃分,客戶端首先會連接Nginx服務(wù)器。該服務(wù)器作為負載均衡模塊,它將根據(jù)權(quán)重配比將所有請求進行隨機分發(fā),以確保動靜分離。其次,所有的交互數(shù)據(jù)將會由相應(yīng)的Nodjs服務(wù)器進行處理。該服務(wù)器作為數(shù)據(jù)處理的核心模塊,它將根據(jù)事件類型,通過異步的方式進行高效的數(shù)據(jù)傳送,以實現(xiàn)不同終端之間的數(shù)據(jù)交互。最后,為了保證數(shù)據(jù)的高速存取,臨時存儲的Session數(shù)據(jù)(如,會話狀態(tài)數(shù)據(jù))存入緩存服務(wù)模塊(Redis),以實現(xiàn)Nodejs服務(wù)器之間的數(shù)據(jù)共享。永久性存儲的數(shù)據(jù)則存入數(shù)據(jù)庫模塊(Mysql),非永久性存儲且常訪問的數(shù)據(jù)則存入內(nèi)存模塊中。
服務(wù)器是整個系統(tǒng)的數(shù)據(jù)中轉(zhuǎn)和處理中心。圖4展示了整個數(shù)據(jù)的處理流程。當服務(wù)器收到支持的所有消息(用戶上線和下線、語音流數(shù)據(jù)、實時位置、麥空閑狀態(tài)、鎖麥狀態(tài)等)等數(shù)據(jù)時直接透傳到系統(tǒng)中所有在線的用戶。收到搶麥消息時查詢用戶的信息,如果用戶具有管理員權(quán)限,則進入強制搶麥模式,若當前有人正在說話,則將用戶踢下保證搶麥的成功,同時將搶麥成功消息回調(diào)給用戶,如果用戶是普通權(quán)限,則進入正常搶麥模式,若當前有人正在說話,則搶麥失敗,相反則搶麥成功,同時將搶麥結(jié)果消息回調(diào)給用戶。
圖4 服務(wù)器數(shù)據(jù)流程
客戶端主要包括登錄和可視化對講兩個模塊,其功能流程如圖5所示,圖5中,用戶在登錄界面填寫用戶名、密碼、房間名、服務(wù)器地址等信息與服務(wù)器建立連接,完成登錄操作。登錄成功后則進入對講主界面,此模塊主要包含用戶位置信息、對講功能、搶麥功能的展示。其中位置信息的展示主要包含用戶上下線時動態(tài)的增加或刪除用戶、更新用戶列表,用戶位置發(fā)生變化時,在地圖上動態(tài)改變用戶的位置坐標。對講功能主要包含語音流數(shù)據(jù)的采集、編碼、轉(zhuǎn)發(fā)和語音流數(shù)據(jù)的接收、轉(zhuǎn)碼和播放。搶麥功能首先是發(fā)送搶麥指令到服務(wù)器。如果服務(wù)器返回成功的狀態(tài),則開始實時語音對講流程,對語音流數(shù)據(jù)進行實時的采集和編碼轉(zhuǎn)發(fā)、接收和解碼播放。相反,如果搶麥失敗,則在界面上顯示相關(guān)提示信息。
圖5 客戶端功能流程
數(shù)據(jù)傳送的實時性和可靠性是整個系統(tǒng)的關(guān)鍵,而涉及的主要數(shù)據(jù)是實時獲取的用戶定位信息和實時采集的語音流消息。因此,如何確保傳輸這些數(shù)據(jù)的效率和穩(wěn)定性該系統(tǒng)面臨的主要挑戰(zhàn)。簡單來說,需要滿足的基本要求是:終端用戶將大量的位置消息和語音流數(shù)據(jù)進行封裝,經(jīng)服務(wù)器處理和中轉(zhuǎn),到達指定的目標用戶后,實時的在終端設(shè)備上進行實時的解碼、界面展示和語音播放。
(1)音頻流的采集
通過調(diào)用原生API(AudioRecord)采集音頻流數(shù)據(jù),采集參數(shù)分別為音頻源(MediaRecorder.AudioSource.MIC)、采樣率(16 000 Hz)、音頻通道(單通道:CHANNEL_IN_MONO)、音頻格式(16位:ENCODING_PCM_16Bit)。整個音頻流的采集過程主要包括以下步驟:第一步,通過上面的初始化參數(shù)建立AudioRecord對象。第二步,開啟一個AudioCollectionThread線程,在該線程中采集音頻流數(shù)據(jù),并調(diào)用回調(diào)函數(shù)接口(sendAudioFrame)。第三步,在回調(diào)函數(shù)sendAudioFrame中,利用Speex[12]對語音流數(shù)據(jù)進行編碼后,再將封裝的數(shù)據(jù)傳輸?shù)椒?wù)器。這一過程涉及的主要代碼如下:
collectionRecord = new AudioRecord(collectionSource, collectionRateInHz, collectionChannel, collectionFormat, readBufferSize);
@Override
public void run() {
while (!isNeedExit) {
byte[] readBuffer = new byte[readBufferSize];
int count = collectionRecord.read(readBuffer, 0, readBufferSize);
onAudioFrameListener.sendAudioFrame(readBuffer, readBufferSize);
}
(2)音頻流的解碼和播放
首先是音頻流數(shù)據(jù)的解碼。解碼方式與采集方式相似,使用的是系統(tǒng)的另一個API(AudioTrack)。解碼接口的傳入?yún)?shù)與采集時的參數(shù)一致,分別為16 000 Hz、單通道、16位。整個音頻流的解碼和播放過程主要包括以下步驟:第一步,通過上面的初始化參數(shù)建立AudioTrack對象。第二步,開啟一個AudioDecodeThread線程,在該線程中接收音頻流數(shù)據(jù)。第三步,利用Speex對語音流數(shù)據(jù)進行解碼后,再將獲得的原始音頻流數(shù)據(jù)寫入AudioPlayTrack進行播放。這一過程涉及的主要代碼如下:
audioPlayTrack = new AudioPlayTrack(dataType, da-taRateInHz, dataChannel, dataFormat,
dataBufferSize, PLAY_AUDIO_MODE);
@Override
public void run() {
while (needPlaying) {
int readSize = ReceiveAudioStreamLib.receive_play_pcm(AudioStreamUtils.receive_steam, readBuffer, dataBufferSize);
if (readSize > 0) {
audioPlayTrack.write(readBuffer, 0, readSize);
}
}
}
通過百度地圖Android SDK[13]進行位置展示和定位,使用的參數(shù)分別為高精度模式(ParamHightAccuracy)、gcj02坐標系、1 s的間隔頻率,并開啟GPS、室內(nèi)定位。整個過程通過注冊監(jiān)聽回調(diào)接口的方式完成。首先,通過上述的初始化參數(shù)進行接口的注冊。其次,注冊成功后,終端設(shè)備上用戶的位置變化會實時反饋到receiveDecive-Location函數(shù)。最后,對每次收到的位置信息進行解析,若用戶位置發(fā)生了變化,則通過AudioStreamUtils.send-CustomDataToServer函數(shù)發(fā)送到目標用戶,并在終端設(shè)備的地圖上實施更新位置。這一過程涉及的主要代碼如下:
LocationClientOption locParam = currentLocClient.getLocOption();
locParam.setLocationMode(ParamHightAccuracy);
locParam.setCoorType("gcj02");
locParam.setLocationNotify(true);
currentLocClient.startIndoorMode();
currentLocClient.regDeviceLocationRecall(mRegDeviceLocationRecall);
@Override
public void receiveDeviceLocation(BDLocation currentLoc) {
AudioStreamUtils.sendCustomDataToServer(currentLoc);
}
當位置消息到達服務(wù)器時,首先該服務(wù)器會檢索當前在線的終端用戶,然后根據(jù)用戶列表將該消息透傳給每一個用戶。然后,終端用戶收到該消息時,則在終端設(shè)備的地圖上實施對應(yīng)用戶的位置。這一過程涉及的主要代碼如下:
其三,19世紀40年代的英國剛剛面臨第一次工業(yè)大蕭條,社會開始騷亂,工人運動興起,社會思想家托馬斯·卡萊爾通過比較現(xiàn)在與過去,無情地揭露出新時代產(chǎn)生的種種弊端,并呼吁社會改造,這幫作為社會意識形態(tài)建構(gòu)組成部分的藝術(shù)創(chuàng)作群體樹立了明確的斗爭對象,即專橫的藝術(shù)體制。
@Override
public void receiveData(String data) {
dataUtils.updateDeviceFromCustomData(data);
}
為了進一步提高系統(tǒng)在多用戶使用場景下的并發(fā)能力和可用性,除了滿足分布式、集群化部署的架構(gòu)要求外,還設(shè)計了一套定制化的、輕巧的、高效的消息傳輸協(xié)議[14,15]。該協(xié)議庫底層采用C語言實現(xiàn)和封裝,然后再通過JNA(Java Native Access)調(diào)用的方式進行訪問。該協(xié)議庫的主要代碼如下:
(1)建立連接
AudioStreamUtils.connectServer(String deviceParam, String teamParam, String serverIP,int serverPort, int advancedFlag)
實現(xiàn)說明:調(diào)用系統(tǒng)函數(shù)Socket建立與服務(wù)器的TCP連接,同時將deviceParam、teamParam、advancedFlag參數(shù)傳遞到服務(wù)器,參數(shù)說明見表1。
表1 參數(shù)說明
(2)斷開連接
AudioStreamUtils.disconnectServer()
實現(xiàn)說明:將Socket連接斷開。
(3)請求麥
AudioStreamUtils.requestMic()
實現(xiàn)說明:發(fā)送請求麥的消息到服務(wù)器。
(4)釋放麥
AudioStreamUtils.freeMic()
實現(xiàn)說明:發(fā)送釋放麥的消息到服務(wù)器。
(5)發(fā)送音頻流數(shù)據(jù)
AudioStreamUtils.sendCollectionAudioData (byte[] audioData, int audioSize)
實現(xiàn)說明:將音頻消息通過Socket發(fā)送到服務(wù)器,參數(shù)說明見表2。
表2 參數(shù)說明
(6)接收音頻流數(shù)據(jù)
AudioStreamUtils.getCollectionAudioData(int audioSize)
實現(xiàn)說明:通過線程實時獲取Socket收到的音頻數(shù)據(jù),再將音頻數(shù)據(jù)放入到音頻流處理模塊,參數(shù)說明見表3。
表3 參數(shù)說明
(7)發(fā)送定制化消息
AudioStreamUtils.sendCustomMessage(String customMessage)
實現(xiàn)說明:將自定義消息通過Socket發(fā)送到服務(wù)器,參數(shù)說明見表4。
表4 參數(shù)說明
(8)注冊回調(diào)函數(shù)
AudioStreamUtils.registerAudioRecallEvent
實現(xiàn)說明:定義回調(diào)接口并注冊回調(diào)函數(shù),回調(diào)接口見表5。
表5 回調(diào)函數(shù)
回調(diào)參數(shù)見表6。
表6 回調(diào)函數(shù)的參數(shù)
消息格式見表7。
表7 消息格式說明
支持的消息類型如下:
1)新用戶加入
cmdStatus=newEnter,表8列出了返回值。
表8 回調(diào)-新用戶加入
2)用戶申請麥
cmdStatus=grapMike,表9列出了返回值。
表9 回調(diào)-用戶申請麥
3)用戶結(jié)束麥
cmdStatus=releaseMike,表10列出了返回值。
表10 回調(diào)-用戶結(jié)束麥
4)轉(zhuǎn)發(fā)到指定用戶
cmdStatus=fwdUser,表11列出了返回值。
表11 回調(diào)-轉(zhuǎn)發(fā)到指定用戶
5)轉(zhuǎn)發(fā)到所有在線用戶
cmdStatus=fwdAllUser,表12列出了返回值。
表12 回調(diào)-轉(zhuǎn)發(fā)到所有在線用戶
為了評估系統(tǒng)的性能和穩(wěn)定性,首先在騰訊云上部署了該系統(tǒng),采用的服務(wù)器配置如下:實例配置(CPU:2核,內(nèi)存:4 G)、操作系統(tǒng)(CentOS 7.8 64位)、公網(wǎng)帶寬(5 Mbps)、高性能云硬盤(1 T)。其次,客戶端類型采用了Android的移動設(shè)備和PAD終端設(shè)備,涉及多個廠商不同系統(tǒng)版本的Android設(shè)備,比如華為的P40 Pro、小米的MIX4、三星的Note8、OPPO的R9、vivo的X80。
在當前主流的品牌和系統(tǒng)上的測試結(jié)果如下。首先,客戶端中包含的人機交互界面能適配所測試的全部機型,具有良好的UI適配性。其次,在4G和Wifi網(wǎng)絡(luò)下,測試過程中未出現(xiàn)連接斷開、數(shù)據(jù)延時、數(shù)據(jù)終端等異常情況,因此,在網(wǎng)絡(luò)較佳的情況下使用過程流暢。在網(wǎng)絡(luò)較弱或信號不穩(wěn)定的情況下(比如,電梯里),客戶端能即時給出相應(yīng)提示,并能夠在網(wǎng)絡(luò)恢復(fù)后重新連接上服務(wù)器,恢復(fù)終端設(shè)備狀態(tài)和同步當前在線設(shè)備和位置信息。由此說明,客戶端的異常機制進一步確保了客戶端的可用性。最后,由于可用于測試的Android移動設(shè)備和PAD終端的數(shù)量有限,我們利用額外的自動化測試工具對服務(wù)器的穩(wěn)定性和并發(fā)能力進行了測試。表13從并發(fā)設(shè)備(數(shù)量)、文本消息(條)、CPU利用率、響應(yīng)時間(秒)等指標進行了總結(jié)。
表13 服務(wù)器的并發(fā)測試結(jié)果
如表13所示,并發(fā)設(shè)備數(shù)量從200增加到400,400增加到800,800增加到1600時,CPU利用率的變化分別為0.4%、0.6%、0.9%,說明該服務(wù)器所需的系統(tǒng)資源較低,可認為是一種輕量型服務(wù)器。與此同時,消息數(shù)量在200~1600之間時,服務(wù)器的響應(yīng)時間在0.59 s至0.72 s之間,進一步表明了該服務(wù)器的消息處理能力。
最后,圖6~圖8展示了客戶端的用戶登錄界面和可視化對講界面(其它設(shè)備正在講話、當前設(shè)備正在講話)的使用效果。
圖6 用戶登錄界面
圖7 可視化對講界面-有人正在說話
圖8 可視化對講界面-正在說話
圖7、圖8中,頂部會動態(tài)顯示當前在線的用戶,地圖上會標注每個在線用戶的位置,點擊底部圓型按鈕可以發(fā)起對講,同時在所有終端設(shè)備的頂部欄實時提示當前說明的終端用戶。同樣,如果某一終端設(shè)備離線,所有終端設(shè)備上的頂部欄和地圖界面都會進行實時更新。
隨著人工智能與移動互聯(lián)網(wǎng)技術(shù)的快速發(fā)展,針對Android智能設(shè)備的應(yīng)用越來越廣泛,在Android智能設(shè)備上實現(xiàn)一套可視化指揮系統(tǒng),既能增強指揮系統(tǒng)的功能,又能提供多元化的界面展示,更好適應(yīng)互聯(lián)網(wǎng)時代用戶的需求。下一步的研究將在另一主流的iOS系統(tǒng)上實現(xiàn)相應(yīng)的指揮系統(tǒng)。