廖列法,張幸平
(江西理工大學 信息工程學院,江西 贛州 341000)
隨著人工智能時代的來臨以及Android智能設備的普及,針對移動端的應用越來越廣泛,移動設備上的應用技術已成為當前科技領域熱門的研究方向。傳統的指揮系統中要求使用專用設備,比如對講機、照相機、GPS等,對設備要求性較高、負擔較大。與此同時,支持的功能和使用界面較為簡單,沒有良好的用戶體驗感,無法滿足日益增長的用戶需求。近些年智能指揮類系統在各行各業都有不斷的被提出及應用,比如基于Android的應急指揮系統[1]、調度指揮系統[2]、扁平化的圖形類指揮系統[3]等,但這些系統主要還是采用傳統的Client/Server技術,系統架構部署較為復雜,對服務器要求較高。因此基于當前主流的Spring Cloud[4]微服務架構體系實現一套滿足云服務器下分布式集群化的輕量型實時可視化指揮系統具有非常重要的應用與研究價值。
本文設計并實現了一種基于Android的智能可視化指揮系統。為了滿足大用戶、高并發、可擴展的部署需求,該系統采用了采用Spring Cloud微服務架構和Ngnix[5]、Redis[6]、Nodejs[7]、Mysql[8]等技術。采用3種定位技術(網絡[9]、GPS[10]和離線[11])來保證用戶位置的實時獲取,設計用戶上下消息、語音控制類消息,通過自主的實時傳輸協議實現信息的實時傳輸,同時以地圖為基本元素,展示可視化指揮的所有功能。既增強了傳統指揮系統的功能,實現了直觀、可視化的展現方式,又提供了一套輕量型的實時可視化指揮系統方案。
方案設計的基本要求是支持在多臺云服務器上進行分布式和集群化的部署,以保證所開發系統的穩定性、可靠性和可擴展性。接下來,我們將從系統的組織框架、整體架構和功能架構進行具體介紹。
在Spring Cloud微服務的框架下,根據不同的功能,設計的功能服務模塊包括音頻服務(Audi)、上下線服務(Online)、轉發服務(Forward)、消息通知服務(Notification),以及線程池同步服務。其中音頻服務模塊提供了視頻和音頻消息的相關接口,上線下服務模塊提供了用戶狀態的相關接口,轉發服務模塊提供了消息的轉發接口,消息通知服務模塊提供了通知的相關接口,線程池同步服務模塊提供了不同線程之間數據的同步。根據消息的類型,該系統設計的消息類型分為聊天文本、消息類文本(同步消息、下線消息、推送消息和通知消息)、圖像、視頻流、語音流等。圖1展示了如上所述的系統組織架構。

圖1 系統組織框架
該系統涉及的主要模塊包括2個消息通知服務(notify server1和server2)、緩存服務(Redis)、消息服務進程(接收和轉發)、通知推送服務平臺(包含自主和第三方的消息推送服務)、Android移動端等。其中,所有加入的移動客戶端都會與消息通知服務器建立連接,而負載均衡模塊負責分配新加入設備需要連接的服務器。具體來說,消息的發生到接收會涉及以下過程。首先,消息發送到消息通知服務器;其次,消息通知服務將消息以異步的方式存入數據庫和緩存(Redis)中;第三,查詢目標用戶連接的服務器;第四,將消息轉發到上一步查詢到的服務器中;最后,接收到消息的服務器將數據推送到相應的客戶端。圖2顯示了整個系統的架構和消息流轉。

圖2 系統架構
系統采用C/S架構,客戶端與服務器之間通過TCP協議通信。服務器提供的功能包括數據的持久化存儲(數據庫)、語音流和視頻流數據的實時傳輸、文本類消息的實時中轉(即時文本、位置類、控制類和狀態類消息)。同時以Nginx為負載均衡反向代理服務,Redis為主從的集群方案,Nodejs為應用服務器,Mysql為數據存儲服務來提供一套高可用、高并發的集群化解決方案。
客戶端提供的功能包括良好的使用界面、流數據的處理(如,發送、接收、解析和播放)、文本數據的處理(如,即時文本、位置類、控制類和狀態類等消息的解析和轉發),以及用戶位置的實時獲獲取、轉發和解析。圖3展示了該系統的功能架構。

圖3 系統功能架構
如圖3所示,客戶端支持的設備為Android的移動端和PAD端(系統版本號為4.0以上)。根據功能劃分,客戶端首先會連接Nginx服務器。該服務器作為負載均衡模塊,它將根據權重配比將所有請求進行隨機分發,以確保動靜分離。其次,所有的交互數據將會由相應的Nodjs服務器進行處理。該服務器作為數據處理的核心模塊,它將根據事件類型,通過異步的方式進行高效的數據傳送,以實現不同終端之間的數據交互。最后,為了保證數據的高速存取,臨時存儲的Session數據(如,會話狀態數據)存入緩存服務模塊(Redis),以實現Nodejs服務器之間的數據共享。永久性存儲的數據則存入數據庫模塊(Mysql),非永久性存儲且常訪問的數據則存入內存模塊中。
服務器是整個系統的數據中轉和處理中心。圖4展示了整個數據的處理流程。當服務器收到支持的所有消息(用戶上線和下線、語音流數據、實時位置、麥空閑狀態、鎖麥狀態等)等數據時直接透傳到系統中所有在線的用戶。收到搶麥消息時查詢用戶的信息,如果用戶具有管理員權限,則進入強制搶麥模式,若當前有人正在說話,則將用戶踢下保證搶麥的成功,同時將搶麥成功消息回調給用戶,如果用戶是普通權限,則進入正常搶麥模式,若當前有人正在說話,則搶麥失敗,相反則搶麥成功,同時將搶麥結果消息回調給用戶。

圖4 服務器數據流程
客戶端主要包括登錄和可視化對講兩個模塊,其功能流程如圖5所示,圖5中,用戶在登錄界面填寫用戶名、密碼、房間名、服務器地址等信息與服務器建立連接,完成登錄操作。登錄成功后則進入對講主界面,此模塊主要包含用戶位置信息、對講功能、搶麥功能的展示。其中位置信息的展示主要包含用戶上下線時動態的增加或刪除用戶、更新用戶列表,用戶位置發生變化時,在地圖上動態改變用戶的位置坐標。對講功能主要包含語音流數據的采集、編碼、轉發和語音流數據的接收、轉碼和播放。搶麥功能首先是發送搶麥指令到服務器。如果服務器返回成功的狀態,則開始實時語音對講流程,對語音流數據進行實時的采集和編碼轉發、接收和解碼播放。相反,如果搶麥失敗,則在界面上顯示相關提示信息。

圖5 客戶端功能流程
數據傳送的實時性和可靠性是整個系統的關鍵,而涉及的主要數據是實時獲取的用戶定位信息和實時采集的語音流消息。因此,如何確保傳輸這些數據的效率和穩定性該系統面臨的主要挑戰。簡單來說,需要滿足的基本要求是:終端用戶將大量的位置消息和語音流數據進行封裝,經服務器處理和中轉,到達指定的目標用戶后,實時的在終端設備上進行實時的解碼、界面展示和語音播放。
(1)音頻流的采集
通過調用原生API(AudioRecord)采集音頻流數據,采集參數分別為音頻源(MediaRecorder.AudioSource.MIC)、采樣率(16 000 Hz)、音頻通道(單通道:CHANNEL_IN_MONO)、音頻格式(16位:ENCODING_PCM_16Bit)。整個音頻流的采集過程主要包括以下步驟:第一步,通過上面的初始化參數建立AudioRecord對象。第二步,開啟一個AudioCollectionThread線程,在該線程中采集音頻流數據,并調用回調函數接口(sendAudioFrame)。第三步,在回調函數sendAudioFrame中,利用Speex[12]對語音流數據進行編碼后,再將封裝的數據傳輸到服務器。這一過程涉及的主要代碼如下:
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)音頻流的解碼和播放
首先是音頻流數據的解碼。解碼方式與采集方式相似,使用的是系統的另一個API(AudioTrack)。解碼接口的傳入參數與采集時的參數一致,分別為16 000 Hz、單通道、16位。整個音頻流的解碼和播放過程主要包括以下步驟:第一步,通過上面的初始化參數建立AudioTrack對象。第二步,開啟一個AudioDecodeThread線程,在該線程中接收音頻流數據。第三步,利用Speex對語音流數據進行解碼后,再將獲得的原始音頻流數據寫入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]進行位置展示和定位,使用的參數分別為高精度模式(ParamHightAccuracy)、gcj02坐標系、1 s的間隔頻率,并開啟GPS、室內定位。整個過程通過注冊監聽回調接口的方式完成。首先,通過上述的初始化參數進行接口的注冊。其次,注冊成功后,終端設備上用戶的位置變化會實時反饋到receiveDecive-Location函數。最后,對每次收到的位置信息進行解析,若用戶位置發生了變化,則通過AudioStreamUtils.send-CustomDataToServer函數發送到目標用戶,并在終端設備的地圖上實施更新位置。這一過程涉及的主要代碼如下:
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);
}
當位置消息到達服務器時,首先該服務器會檢索當前在線的終端用戶,然后根據用戶列表將該消息透傳給每一個用戶。然后,終端用戶收到該消息時,則在終端設備的地圖上實施對應用戶的位置。這一過程涉及的主要代碼如下:
其三,19世紀40年代的英國剛剛面臨第一次工業大蕭條,社會開始騷亂,工人運動興起,社會思想家托馬斯·卡萊爾通過比較現在與過去,無情地揭露出新時代產生的種種弊端,并呼吁社會改造,這幫作為社會意識形態建構組成部分的藝術創作群體樹立了明確的斗爭對象,即專橫的藝術體制。
@Override
public void receiveData(String data) {
dataUtils.updateDeviceFromCustomData(data);
}
為了進一步提高系統在多用戶使用場景下的并發能力和可用性,除了滿足分布式、集群化部署的架構要求外,還設計了一套定制化的、輕巧的、高效的消息傳輸協議[14,15]。該協議庫底層采用C語言實現和封裝,然后再通過JNA(Java Native Access)調用的方式進行訪問。該協議庫的主要代碼如下:
(1)建立連接
AudioStreamUtils.connectServer(String deviceParam, String teamParam, String serverIP,int serverPort, int advancedFlag)
實現說明:調用系統函數Socket建立與服務器的TCP連接,同時將deviceParam、teamParam、advancedFlag參數傳遞到服務器,參數說明見表1。

表1 參數說明
(2)斷開連接
AudioStreamUtils.disconnectServer()
實現說明:將Socket連接斷開。
(3)請求麥
AudioStreamUtils.requestMic()
實現說明:發送請求麥的消息到服務器。
(4)釋放麥
AudioStreamUtils.freeMic()
實現說明:發送釋放麥的消息到服務器。
(5)發送音頻流數據
AudioStreamUtils.sendCollectionAudioData (byte[] audioData, int audioSize)
實現說明:將音頻消息通過Socket發送到服務器,參數說明見表2。

表2 參數說明
(6)接收音頻流數據
AudioStreamUtils.getCollectionAudioData(int audioSize)
實現說明:通過線程實時獲取Socket收到的音頻數據,再將音頻數據放入到音頻流處理模塊,參數說明見表3。

表3 參數說明
(7)發送定制化消息
AudioStreamUtils.sendCustomMessage(String customMessage)
實現說明:將自定義消息通過Socket發送到服務器,參數說明見表4。

表4 參數說明
(8)注冊回調函數
AudioStreamUtils.registerAudioRecallEvent
實現說明:定義回調接口并注冊回調函數,回調接口見表5。

表5 回調函數
回調參數見表6。

表6 回調函數的參數
消息格式見表7。

表7 消息格式說明
支持的消息類型如下:
1)新用戶加入
cmdStatus=newEnter,表8列出了返回值。

表8 回調-新用戶加入
2)用戶申請麥
cmdStatus=grapMike,表9列出了返回值。

表9 回調-用戶申請麥
3)用戶結束麥
cmdStatus=releaseMike,表10列出了返回值。

表10 回調-用戶結束麥
4)轉發到指定用戶
cmdStatus=fwdUser,表11列出了返回值。

表11 回調-轉發到指定用戶
5)轉發到所有在線用戶
cmdStatus=fwdAllUser,表12列出了返回值。

表12 回調-轉發到所有在線用戶
為了評估系統的性能和穩定性,首先在騰訊云上部署了該系統,采用的服務器配置如下:實例配置(CPU:2核,內存:4 G)、操作系統(CentOS 7.8 64位)、公網帶寬(5 Mbps)、高性能云硬盤(1 T)。其次,客戶端類型采用了Android的移動設備和PAD終端設備,涉及多個廠商不同系統版本的Android設備,比如華為的P40 Pro、小米的MIX4、三星的Note8、OPPO的R9、vivo的X80。
在當前主流的品牌和系統上的測試結果如下。首先,客戶端中包含的人機交互界面能適配所測試的全部機型,具有良好的UI適配性。其次,在4G和Wifi網絡下,測試過程中未出現連接斷開、數據延時、數據終端等異常情況,因此,在網絡較佳的情況下使用過程流暢。在網絡較弱或信號不穩定的情況下(比如,電梯里),客戶端能即時給出相應提示,并能夠在網絡恢復后重新連接上服務器,恢復終端設備狀態和同步當前在線設備和位置信息。由此說明,客戶端的異常機制進一步確保了客戶端的可用性。最后,由于可用于測試的Android移動設備和PAD終端的數量有限,我們利用額外的自動化測試工具對服務器的穩定性和并發能力進行了測試。表13從并發設備(數量)、文本消息(條)、CPU利用率、響應時間(秒)等指標進行了總結。

表13 服務器的并發測試結果
如表13所示,并發設備數量從200增加到400,400增加到800,800增加到1600時,CPU利用率的變化分別為0.4%、0.6%、0.9%,說明該服務器所需的系統資源較低,可認為是一種輕量型服務器。與此同時,消息數量在200~1600之間時,服務器的響應時間在0.59 s至0.72 s之間,進一步表明了該服務器的消息處理能力。
最后,圖6~圖8展示了客戶端的用戶登錄界面和可視化對講界面(其它設備正在講話、當前設備正在講話)的使用效果。

圖6 用戶登錄界面

圖7 可視化對講界面-有人正在說話

圖8 可視化對講界面-正在說話
圖7、圖8中,頂部會動態顯示當前在線的用戶,地圖上會標注每個在線用戶的位置,點擊底部圓型按鈕可以發起對講,同時在所有終端設備的頂部欄實時提示當前說明的終端用戶。同樣,如果某一終端設備離線,所有終端設備上的頂部欄和地圖界面都會進行實時更新。
隨著人工智能與移動互聯網技術的快速發展,針對Android智能設備的應用越來越廣泛,在Android智能設備上實現一套可視化指揮系統,既能增強指揮系統的功能,又能提供多元化的界面展示,更好適應互聯網時代用戶的需求。下一步的研究將在另一主流的iOS系統上實現相應的指揮系統。