当前位置:   article > 正文

LiveMedia视频平台是如何实现基于网页的语音对讲

livemedia

        目前主流的安防厂家的摄像头或者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

浏览器兼容性

语法

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

示例:HTML 5调用音频

HTML

  1. <html>
  2. <head>
  3. <meta charset="utf-8">
  4. <title>test</title>
  5. </head>
  6. <body>
  7. <div>
  8. <button id="intercomBegin">开始对讲</button>
  9. <button id="intercomEnd">关闭对讲</button>
  10. </div>
  11. </body>
  12. </html>

javascript

开启本地音频采集、定时20毫秒通过Websocket发送音频PCM数据至LiveMedia中间件

  1. var begin = document.getElementById('intercomBegin');
  2. var end = document.getElementById('intercomEnd');
  3. navigator.mediaDevices.getUserMedia = navigator.mediaDevices.getUserMedia || navigator.mediaDevices.webkitGetUserMedia;
  4. var ws = null;//实现WebSocket
  5. var record=null;//多媒体对象,用来处理音频
  6. var timeInte = null;//定义一个定时器
  7. begin.onclick = function() {
  8. console.log('开始对讲')
  9. }
  10. end.onclick = function() {
  11. console.log('关闭对讲')
  12. if(ws) {
  13. ws.close();
  14. record.stop();
  15. clearInterval(timeInte);
  16. }
  17. }
  18. function init(rec){
  19. record = rec;
  20. }
  21. if (!navigator.mediaDevices.getUserMedia) {
  22. alert('浏览器不支持音频输入');
  23. }else{
  24. navigator.mediaDevices.getUserMedia( { audio: true })
  25. .then(function (mediaStream){
  26. init(new Recorder(mediaStream));
  27. }
  28. )
  29. .catch(function(err){ console.log(err.name + ": " + err.message); });
  30. }
  31. //录音对象
  32. var Recorder = function(stream) {
  33. var sampleBits = 16;//输出采样数位 8, 16
  34. var sampleRate = 44100;//输出采样率
  35. var bufSize = 8192;
  36. var context = new AudioContext();
  37. var audioInput = context.createMediaStreamSource(stream);
  38. var recorder = context.createScriptProcessor(0, 1, 1);
  39. var resample = new Resampler(context.sampleRate, 44100, 1, bufSize);
  40. var audioData = {
  41. size: 0 //录音文件长度
  42. , buffer: [] //录音缓存
  43. , inputSampleRate: context.sampleRate //输入采样率
  44. , inputSampleBits: 16 //输入采样数位 8, 16
  45. , outputSampleRate: sampleRate
  46. , oututSampleBits: sampleBits
  47. , clear: function() {
  48. this.buffer = [];
  49. this.size = 0;
  50. }
  51. , input: function (data) {
  52. this.buffer.push(new Float32Array(data));
  53. this.size += data.length;
  54. }
  55. , compress: function () { //合并压缩
  56. //合并
  57. var data = new Float32Array(this.size);
  58. var offset = 0;
  59. for (var i = 0; i < this.buffer.length; i++) {
  60. data.set(this.buffer[i], offset);
  61. offset += this.buffer[i].length;
  62. }
  63. //压缩
  64. var compression = parseInt(this.inputSampleRate / this.outputSampleRate);
  65. var length = data.length / compression;
  66. var result = new Float32Array(length);
  67. var index = 0, j = 0;
  68. while (index < length) {
  69. result[index] = data[j];
  70. j += compression;
  71. index++;
  72. }
  73. return result;
  74. }, encodePCM: function(){//这里不对采集到的数据进行其他格式处理,如有需要均交给服务器端处理。
  75. var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
  76. var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);
  77. var bytes = this.compress();
  78. var dataLength = bytes.length * (sampleBits / 8);
  79. var buffer = new ArrayBuffer(dataLength);
  80. var data = new DataView(buffer);
  81. var offset = 0;
  82. for (var i = 0; i < bytes.length; i++, offset += 2) {
  83. var s = Math.max(-1, Math.min(1, bytes[i]));
  84. data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
  85. }
  86. return new Blob([data]);
  87. }
  88. };
  89. this.start = function () {
  90. audioInput.connect(recorder);
  91. recorder.connect(context.destination);
  92. }
  93. this.stop = function () {
  94. recorder.disconnect();
  95. }
  96. this.getBlob = function () {
  97. return audioData.encodePCM();
  98. }
  99. this.clear = function() {
  100. audioData.clear();
  101. }
  102. recorder.onaudioprocess = function (e) {
  103. audioData.input(e.inputBuffer.getChannelData(0));
  104. }
  105. };
  106. function getDate(extra){
  107. var dat = new Date;//生成日期
  108. var year = dat.getFullYear();//取得年
  109. var month = dat.getMonth()+1; //取得月,js从0开始取,所以+1
  110. var date1 = dat.getDate(); //取得天
  111. var hour = dat.getHours();//取得小时
  112. var minutes = dat.getMinutes();//取得分钟
  113. var second = dat.getSeconds();//取得秒
  114. var haomiao = dat.getMilliseconds();
  115. dat = undefined;
  116. return year+"-"+month+"-"+date1+" "+hour+":"+minutes +":"+second+" "+haomiao + extra ;
  117. }
  118. begin.onclick = function() {
  119. ws = new WebSocket("ws://192.168.3.23:9030/ws_talk/57?token=607b9f0b-293f-4412-ac6f-278804be5982");
  120. ws.binaryType = 'arraybuffer'; //传输的是 ArrayBuffer 类型的数据
  121. ws.onopen = function(event) {
  122. console.log('握手成功');
  123. record.start();
  124. };
  125. timeInte=setInterval(function(){
  126. if(ws.readyState==1){//ws进入连接状态,则每隔500毫秒发送一包数据
  127. console.log(getDate('>>'));
  128. console.log(record.getBlob());
  129. if(record.getBlob().length != 0){
  130. console.log("###########send Blob start ########");
  131. ws.send(record.getBlob()); //发送音频数据
  132. console.log("##############send Blob end ###########");
  133. }
  134. record.clear(); //每次发送完成则清理掉旧数据
  135. }
  136. },20); //每隔20ms发送一次,定时器
  137. }

 LiveMedia可支持一对一,一对多的集群指挥对讲

qq交流群:698793654

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/685701
推荐阅读
相关标签
  

闽ICP备14008679号