赞
踩
目前主流的安防厂家的摄像头或者NVR都可以支持语音通道,只要配备拾音器和Mic即可实现和平台的语音交互,甚至渠道机已经内置Mic和扬声器,实现即插即用的的语音交互体验,但是目前主流的安防平台,需要安装CS客户端,或者使用厂家提供的浏览器插件来实现语音对讲,应用厂家如果想实现语音互动、大屏指挥等语音场景业务,需要切换到厂家提供的平台或者页面,无法与自己的业务平台实现完美的兼容。
LiveMedia视频中间件提供了完美的语音互动API,在自身的业务平台上全过程使用HTTP API接口通过视频中间件对前端设备进行语音交互,语音界面可由第三方应用厂家自由定制。实现拓扑如下图示:
平台对讲组实现时序图
上图中网页端中获取麦克风声音数据需要服务端开启https
HTML5的getUserMedia API为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备。
getUserMedia API最初是navigator.getUserMedia
,目前已被最新Web标准废除,变更为navigator.mediaDevices.getUserMedia()
,但浏览器支持情况不如旧版API普及。 MediaDevices.getUserMedia()
方法提示用户允许使用一个视频和/或一个音频输入设备,例如相机或屏幕共享和/或麦克风。如果用户给予许可,就返回一个Promise
对象,MediaStream
对象作为此Promise
对象的Resolved
[成功]状态的回调函数参数,相应的,如果用户拒绝了许可,或者没有媒体可用的情况下PermissionDeniedError
或者NotFoundError
作为此Promise
的Rejected
[失败]状态的回调函数参数。注意,由于用户不会被要求必须作出允许或者拒绝的选择,所以返回的Promise
对象可能既不会触发resolve
也不会触发 reject
。
- navigator.mediaDevices.getUserMedia(constraints)
- .then(function(mediaStream) { ... })
- .catch(function(error) { ... })
- <html>
- <head>
- <meta charset="utf-8">
- <title>test</title>
- </head>
- <body>
- <div>
- <button id="intercomBegin">开始对讲</button>
- <button id="intercomEnd">关闭对讲</button>
- </div>
- </body>
- </html>
开启本地音频采集、定时20毫秒通过Websocket发送音频PCM数据至LiveMedia中间件
- var begin = document.getElementById('intercomBegin');
- var end = document.getElementById('intercomEnd');
- navigator.mediaDevices.getUserMedia = navigator.mediaDevices.getUserMedia || navigator.mediaDevices.webkitGetUserMedia;
- var ws = null;//实现WebSocket
- var record=null;//多媒体对象,用来处理音频
- var timeInte = null;//定义一个定时器
- begin.onclick = function() {
- console.log('开始对讲')
- }
- end.onclick = function() {
- console.log('关闭对讲')
- if(ws) {
- ws.close();
- record.stop();
- clearInterval(timeInte);
- }
- }
-
- function init(rec){
- record = rec;
- }
- if (!navigator.mediaDevices.getUserMedia) {
- alert('浏览器不支持音频输入');
- }else{
-
- navigator.mediaDevices.getUserMedia( { audio: true })
- .then(function (mediaStream){
- init(new Recorder(mediaStream));
- }
- )
- .catch(function(err){ console.log(err.name + ": " + err.message); });
- }
- //录音对象
- var Recorder = function(stream) {
- var sampleBits = 16;//输出采样数位 8, 16
- var sampleRate = 44100;//输出采样率
- var bufSize = 8192;
- var context = new AudioContext();
- var audioInput = context.createMediaStreamSource(stream);
- var recorder = context.createScriptProcessor(0, 1, 1);
- var resample = new Resampler(context.sampleRate, 44100, 1, bufSize);
- var audioData = {
- size: 0 //录音文件长度
- , buffer: [] //录音缓存
- , inputSampleRate: context.sampleRate //输入采样率
- , inputSampleBits: 16 //输入采样数位 8, 16
- , outputSampleRate: sampleRate
- , oututSampleBits: sampleBits
- , clear: function() {
- this.buffer = [];
- this.size = 0;
- }
- , input: function (data) {
- this.buffer.push(new Float32Array(data));
- this.size += data.length;
- }
- , compress: function () { //合并压缩
- //合并
- var data = new Float32Array(this.size);
- var offset = 0;
- for (var i = 0; i < this.buffer.length; i++) {
- data.set(this.buffer[i], offset);
- offset += this.buffer[i].length;
- }
- //压缩
- var compression = parseInt(this.inputSampleRate / this.outputSampleRate);
- var length = data.length / compression;
- var result = new Float32Array(length);
- var index = 0, j = 0;
- while (index < length) {
- result[index] = data[j];
- j += compression;
- index++;
- }
- return result;
- }, encodePCM: function(){//这里不对采集到的数据进行其他格式处理,如有需要均交给服务器端处理。
- var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
- var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);
- var bytes = this.compress();
- var dataLength = bytes.length * (sampleBits / 8);
- var buffer = new ArrayBuffer(dataLength);
- var data = new DataView(buffer);
- var offset = 0;
- for (var i = 0; i < bytes.length; i++, offset += 2) {
- var s = Math.max(-1, Math.min(1, bytes[i]));
- data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
- }
- return new Blob([data]);
- }
- };
- this.start = function () {
- audioInput.connect(recorder);
- recorder.connect(context.destination);
- }
-
- this.stop = function () {
- recorder.disconnect();
- }
-
- this.getBlob = function () {
- return audioData.encodePCM();
- }
-
- this.clear = function() {
- audioData.clear();
- }
-
- recorder.onaudioprocess = function (e) {
- audioData.input(e.inputBuffer.getChannelData(0));
- }
- };
-
- function getDate(extra){
- var dat = new Date;//生成日期
- var year = dat.getFullYear();//取得年
- var month = dat.getMonth()+1; //取得月,js从0开始取,所以+1
- var date1 = dat.getDate(); //取得天
- var hour = dat.getHours();//取得小时
- var minutes = dat.getMinutes();//取得分钟
- var second = dat.getSeconds();//取得秒
- var haomiao = dat.getMilliseconds();
- dat = undefined;
- return year+"-"+month+"-"+date1+" "+hour+":"+minutes +":"+second+" "+haomiao + extra ;
- }
-
- begin.onclick = function() {
-
- ws = new WebSocket("ws://192.168.3.23:9030/ws_talk/57?token=607b9f0b-293f-4412-ac6f-278804be5982");
- ws.binaryType = 'arraybuffer'; //传输的是 ArrayBuffer 类型的数据
- ws.onopen = function(event) {
- console.log('握手成功');
- record.start();
- };
- timeInte=setInterval(function(){
- if(ws.readyState==1){//ws进入连接状态,则每隔500毫秒发送一包数据
-
- console.log(getDate('>>'));
- console.log(record.getBlob());
- if(record.getBlob().length != 0){
- console.log("###########send Blob start ########");
- ws.send(record.getBlob()); //发送音频数据
- console.log("##############send Blob end ###########");
- }
-
- record.clear(); //每次发送完成则清理掉旧数据
-
- }
- },20); //每隔20ms发送一次,定时器
-
-
- }
LiveMedia可支持一对一,一对多的集群指挥对讲
qq交流群:698793654
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。