新闻动态

新闻动态

联系我们

联系人:吴先生

手机:180 6796 8693

电话:180 6796 8693

邮箱:373898224@qq.com

地址:浙江省杭州市余杭区奥克斯缔逸城5-1202

公司新闻

基于LiveMedia视频平台实现语音指挥和广播

  • 作者:wjf
  • 发布时间:2022-07-05
  • 点击:439次

        目前主流的安防厂家的摄像头或者NVR都可以支持语音通道,只要配备拾音器和Mic即可实现和平台的语音交互,甚至渠道机已经内置Mic和扬声器,实现即插即用的的语音交互体验,但是目前主流的安防平台,需要安装CS客户端,或者使用厂家提供的浏览器插件来实现语音对讲,应用厂家如果想实现语音互动、大屏指挥等语音场景业务,需要切换到厂家提供的平台或者页面,无法与自己的业务平台实现完美的兼容。

        LiveMedia视频中间件提供了完美的语音互动API,在自身的业务平台上全过程使用HTTP API接口通过视频中间件对前端设备进行语音交互,语音界面可由第三方应用厂家自由定制。实现拓扑如下图示:

编辑

平台对讲组实现时序图

 上图中网页端中获取麦克风声音数据需要服务端开启https

getUserMedia API简介

      HTML5的getUserMedia API为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备。 
      getUserMedia API最初是navigator.getUserMedia,目前已被最新Web标准废除,变更为navigator.mediaDevices.getUserMedia(),但浏览器支持情况不如旧版API普及。 
MediaDevices.getUserMedia()方法提示用户允许使用一个视频和/或一个音频输入设备,例如相机或屏幕共享和/或麦克风。如果用户给予许可,就返回一个Promise对象,MediaStream对象作为此Promise对象的Resolved[成功]状态的回调函数参数,相应的,如果用户拒绝了许可,或者没有媒体可用的情况下PermissionDeniedError或者NotFoundError作为此PromiseRejected失败]状态的回调函数参数。注意,由于用户不会被要求必须作出允许或者拒绝的选择,所以返回的Promise对象可能既不会触发resolve也不会触发 reject

浏览器兼容性


语法

navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) { ... })
.catch(function(error) { ... })


示例:HTML 5调用音频

HTML

<html>
<head>
    <meta charset="utf-8">
    <title>test</title>
</head>
<body>
<div>
    <button id="intercomBegin">开始对讲</button>
    <button id="intercomEnd">关闭对讲</button>
</div>
</body>
</html>

javascript

开启本地音频采集、定时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


在线客服
联系方式

热线电话

180 6796 8693

上班时间

周一到周五

公司电话

180 6796 8693

二维码
线