WebSocket发送音频流

  • 原始每包数据过于大,后台不能接收,需要分包处理,每包最大1024
  • 原始采样率为48000;通过合并压缩为自己所需采样率,本例中最终采样率为8000
    1. <!DOCTYPE html>
    2. <html>
    3.     <head>
    4.         <meta charset=“utf-8”>
    5.         <meta name=“viewport” content=“width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0”>
    6.         <meta name=“apple-mobile-web-capable” content=“yes”>
    7.         <title>WebSocket发送音频流</title>
    8.     </head>
    9.     <body>
    10.         <button id=“intercomBegin”>开始对讲</button>
    11.         <button id=“intercomEnd”>关闭对讲</button>
    12.     </body>
    13.     <script type=“text/javascript”>
    14.         var begin = document.getElementById(‘intercomBegin’);
    15.         var end = document.getElementById(‘intercomEnd’);
    16.         var ws = null; //实现WebSocket
    17.         var record = null; //多媒体对象,用来处理音频
    18.         function init(rec) {
    19.             recrecord = rec;
    20.         }
    21.         //录音对象
    22.         var Recorder = function(stream) {
    23.             var sampleBits = 16; //输出采样数位 8, 16
    24.             var sampleRate = 8000; //输出采样率
    25.             var context = new AudioContext();
    26.             var audioInput = context.createMediaStreamSource(stream);
    27.             var recorder = context.createScriptProcessor(4096, 1, 1);
    28.             var audioData = {
    29.                 size: 0, //录音文件长度
    30.                 buffer: [], //录音缓存
    31.                 inputSampleRate: 48000, //输入采样率
    32.                 inputSampleBits: 16, //输入采样数位 8, 16
    33.                 outputSampleRate: sampleRate, //输出采样数位
    34.                 oututSampleBits: sampleBits, //输出采样率
    35.                 clear: function() {
    36.                     this.buffer = [];
    37.                     this.size = 0;
    38.                 },
    39.                 input: function(data) {
    40.                     this.buffer.push(new Float32Array(data));
    41.                     this.size += data.length;
    42.                 },
    43.                 compress: function() { //合并压缩
    44.                     //合并
    45.                     var data = new Float32Array(this.size);
    46.                     var offset = 0;
    47.                     for (var i = 0; i < this.buffer.length; i++) {
    48.                         data.set(this.buffer[i], offset);
    49.                         offset += this.buffer[i].length;
    50.                     }
    51.                     //压缩
    52.                     var compression = parseInt(this.inputSampleRate / this.outputSampleRate);
    53.                     var length = data.length / compression;
    54.                     var result = new Float32Array(length);
    55.                     var index = 0,
    56.                     j = 0;
    57.                     while (index < length) {
    58.                         result[index] = data[j];
    59.                         j += compression;
    60.                         index++;
    61.                     }
    62.                     return result;
    63.                 },
    64.                 encodePCM: function() { //这里不对采集到的数据进行其他格式处理,如有需要均交给服务器端处理。
    65.                     var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
    66.                     var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);
    67.                     var bytes = this.compress();
    68.                     var dataLength = bytes.length * (sampleBits / 8);
    69.                     var buffer = new ArrayBuffer(dataLength);
    70.                     var data = new DataView(buffer);
    71.                     var offset = 0;
    72.                     for (var i = 0; i < bytes.length; i++, offset += 2) {
    73.                     var s = Math.max(-1, Math.min(1, bytes[i]));
    74.                         data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
    75.                     }
    76.                     return new Blob([data]);
    77.                 }
    78.             };
    79.             var sendData = function() { //对以获取的数据进行处理(分包)
    80.                 var reader = new FileReader();
    81.                 reader.onload = e => {
    82.                     var outbuffer = e.target.result;
    83.                     var arr = new Int8Array(outbuffer);
    84.                     if (arr.length > 0) {
    85.                         var tmparr = new Int8Array(1024);
    86.                         var j = 0;
    87.                         for (var i = 0; i < arr.byteLength; i++) {
    88.                             tmparr[j++] = arr[i];
    89.                             if (((i + 1) % 1024) == 0) {
    90.                                 ws.send(tmparr);
    91.                                 if (arr.byteLength – i – 1 >= 1024) {
    92.                                     tmparr = new Int8Array(1024);
    93.                                 } else {
    94.                                     tmparr = new Int8Array(arr.byteLength – i – 1);
    95.                                 }
    96.                                 j = 0;
    97.                             }
    98.                             if ((i + 1 == arr.byteLength) && ((i + 1) % 1024) != 0) {
    99.                                 ws.send(tmparr);
    100.                             }
    101.                         }
    102.                     }
    103.                 };
    104.                 reader.readAsArrayBuffer(audioData.encodePCM());
    105.                 audioData.clear();//每次发送完成则清理掉旧数据
    106.             };
    107.             this.start = function() {
    108.                 audioInput.connect(recorder);
    109.                 recorder.connect(context.destination);
    110.             }
    111.             this.stop = function() {
    112.                 recorder.disconnect();
    113.             }
    114.             this.getBlob = function() {
    115.                 return audioData.encodePCM();
    116.             }
    117.             this.clear = function() {
    118.                 audioData.clear();
    119.             }
    120.             recorder.onaudioprocess = function(e) {
    121.                 var inputBuffer = e.inputBuffer.getChannelData(0);
    122.                 audioData.input(inputBuffer);
    123.                 sendData();
    124.             }
    125.         }
    126.         /*
    127.         * WebSocket
    128.         */
    129.         function useWebSocket() {
    130.             ws = new WebSocket(“ws://172.18.5.61/ws”);
    131.             ws.binaryType = ‘arraybuffer’; //传输的是 ArrayBuffer 类型的数据
    132.             ws.onopen = function() {
    133.                 console.log(‘握手成功’);
    134.                 if (ws.readyState == 1) { //ws进入连接状态,则每隔500毫秒发送一包数据
    135.                     record.start();
    136.                 }
    137.             };
    138.             ws.onmessage = function(msg) {
    139.                 console.info(msg)
    140.             }
    141.             ws.onerror = function(err) {
    142.                 console.info(err)
    143.             }
    144.         }
    145.         /*
    146.         * 开始对讲
    147.         */
    148.         begin.onclick = function() {
    149.             navigatornavigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
    150.             if (!navigator.getUserMedia) {
    151.                 alert(‘浏览器不支持音频输入’);
    152.             } else {
    153.                 navigator.getUserMedia({
    154.                 audio: true
    155.             },
    156.             function(mediaStream) {
    157.                 init(new Recorder(mediaStream));
    158.                 console.log(‘开始对讲’);
    159.                 useWebSocket();
    160.             },
    161.             function(error) {
    162.                 console.log(error);
    163.                 switch (error.message || error.name) {
    164.                     case ‘PERMISSION_DENIED’:
    165.                     case ‘PermissionDeniedError’:
    166.                         console.info(‘用户拒绝提供信息。’);
    167.                         break;
    168.                     case ‘NOT_SUPPORTED_ERROR’:
    169.                     case ‘NotSupportedError’:
    170.                         console.info(‘浏览器不支持硬件设备。’);
    171.                         break;
    172.                     case ‘MANDATORY_UNSATISFIED_ERROR’:
    173.                     case ‘MandatoryUnsatisfiedError’:
    174.                         console.info(‘无法发现指定的硬件设备。’);
    175.                         break;
    176.                         default:
    177.                         console.info(‘无法打开麦克风。异常信息:’ + (error.code || error.name));
    178.                         break;
    179.                         }
    180.                     }
    181.                 )
    182.             }
    183.         }
    184.         /*
    185.         * 关闭对讲
    186.         */
    187.         end.onclick = function() {
    188.             if (ws) {
    189.                 ws.close();
    190.                 record.stop();
    191.                 console.log(‘关闭对讲以及WebSocket’);
    192.             }
    193.         }
    194.     </script>
    195. </html>

    本文链接地址: WebSocket发送音频流

    发表回复

    您的电子邮箱地址不会被公开。 必填项已用*标注