JTT1078协议双向语音对讲和广播开发指南
部标JTT1078标准支持双向语音对讲和广播的功能,终端设备可以通过麦克风接收语音信息,并通过扬声器播放语音信息。这一功能使得驾驶员和监控平台之间可以实时进行语音沟通。
语音对讲是平台和设备终端之间的一对一的语音对讲。
广播是平向多个设备终端之间的单向语音传输;
无论是语音对讲或者是广播,都只能是平台用户发起请求,驾驶员司机不能通过设备终端主动发起请求。但是驾驶员可以通过终端发起紧急报警,监控人员收到紧急报警后可以调取视频画面,并发起语音对讲。
语音对讲在苏标主动安全平台中的应用场景。
苏标主动安全平台,虽然是基于短视频报警触发的主动安全管控机制,但它也需要实时监控和语音对讲功能的辅助,常规的功能是当前端收到主动安全报警辅助的时候,可以立即打开视频监控和语音对讲,对违规司机进行口头劝诫。如下图所示。
这也就是我们常说的报警联动功能的应用之一。
语音对讲面临的一些问题:
1) 语音对讲的通道是虚拟通道,不像摄像头所占用的通道是物理通道,原则上这个对讲的通道号是个什么数字都是无所谓的,但是很奇怪的是,很多厂家开发的时候,强制设定对讲的通道号只能是1,不是1,对讲就不可能成功。正常由于对讲是平台发起的,平台下发请求的对讲通道号是什么数字,那么终端按照这个数字来回复和打包RTP数据包就可以了;
2) 对讲和实时视频理论上不应该互相影响,但有些设备不支持一边看视频,一边对讲。这就造成了无法满足视频通话的需求;
3) JT078的RTP包头并没有标记区分是实时视频,历史回放视频,和语音对讲数据包,这就造成了在同一个端口,同一个通道是无法同时传输这三个数据包,服务器必须要采用不同的端口来接收并区分这三个数据包;
广播这一块漏洞比较大,可能设计者觉得没有什么应用场景,就设计一个指令草草了事,实际上广播这块目前存在的问题如下:
1) 平台主动发起广播,很多厂家设备设计的时候,收到广播请求后,只是向服务器建立了一个空的数据连接,但是不发一个数据包,这样平台就不可能知道这个连接来自那个车辆设备的,就像开远程会议的时候,都不说话,也不知道谁连上了谁没有连接上,主讲者只顾自己开大会讲话;
2) 接入广播的设备如果来自不同的厂家,如果他们的设备只能接受不同音频的编码,如锐明只支持Adpcma, 有为支持G711, 海康支持G726, 那么下发给三家设备的广播语音,必须要三次编解码,这就是语音对讲不统一音频编码带来的麻烦;
综上,广播功能就是个摆设,没啥意义。
开发语音对讲和广播功能是开发部标1078视频监控平台非常繁琐的一个技术环节。开发者需要掌握一定的网络通信技术和音视频编码的技术。
主要的交互分为
1)指令交互,主要是在808网关构建的指令通道中完成交互;
2)双向音频流交互传输;
开发者主要解决的技术问题:
1)如何调用桌面麦克风获取用户录音的音频流;
2)获取设备段上传的音频流并推流到网页端播放;
3)如何编解码和传输;
由于音频数据需要经历获取原始音频数据->编码压缩->传输->接收后解码还原的过程,所以开发者不仅仅需要了解基本的音视频编码基础知识和原理,还需要会进行音频编码和解码。
基本的音频编码知识
由于1078协议并没有对语音对讲的编码进行统一,实际上完全可以统一为AAC(Advanced Audio Coding),但是很遗憾就是没有,所以设备终端的语音压缩编码就是百花齐放,各自根据自己的设备芯片方案来决定编码,主要采用的编码如下:
1)G711A
2)G711U
3)G726, 最复杂,G.726 支持不同的比特率(如 16k、24k、32k、40k),需要判断终端采用什么比特率的编码;
4)Adpcma
5)AAC,最方便,对网站最有好的编码;
主要的参与脚色是平台1078视频服务器(中转分发), 网页前端(发起请求),终端(响应请求)
1)平台当中最核心的当然是JT1078视频服务器,视频服务器主要的职责是中转分发,音视频编码解码,连接管理,数据统计。 如需购买视频监控平台和主动安全平台源码,请联系2379423771@qq.com, 无意购买者勿扰。
2) 在网页前端需要开发者从抓取麦克风录音数据获得原生的音频数据开始,然后就是压缩,再通过websocket传输。需要开发一个复杂的播放器来完成此项工作,如下图所示:
基于spring4+springMVC4+mybatis3+Hibernate4+junit4框架构建高性能企业级的部标1078视频监控平台
前端简单DEMO代码示例如下(主要是为了说明技术流程,实际代码要远比这个复杂):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>麦克风录音并压缩传输</title> <script src="https://cdn.jsdelivr.net/npm/@ffmpeg-installer/ffmpeg"></script> </head> <body> <script> let audioContext; let mediaStream; let sourceNode; let scriptNode; const socket = new WebSocket('ws://your-server-url'); async function startRecording() { audioContext = new AudioContext(); mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true }); sourceNode = audioContext.createMediaStreamSource(mediaStream); scriptNode = audioContext.createScriptProcessor(4096, 1, 1); sourceNode.connect(scriptNode); scriptNode.connect(audioContext.destination); scriptNode.onaudioprocess = async (event) => { const pcmData = event.inputBuffer.getChannelData(0); const aacData = await compressPcmToAac(pcmData); socket.send(aacData); }; } async function compressPcmToAac(pcmData) { const ffmpeg = FFmpeg.createFFmpeg({ log: true }); await ffmpeg.load(); ffmpeg.FS('writeFile', 'input.pcm', new Uint8Array(pcmData)); await ffmpeg.run('-i', 'input.pcm', '-c:a', 'aac', 'output.aac'); const aacData = ffmpeg.FS('readFile', 'output.aac'); return aacData; } socket.addEventListener('open', (event) => { console.log('WebSocket连接已打开:', event); startRecording(); }); socket.addEventListener('message', (event) => { console.log('收到服务器消息:', event.data); }); </script> </body> </html>
(278)