1、背景
要求在机器人项目的页面中展示,实时由websocket发来的音频流(波形图)
2、技术调研
Express
Websocket
音频波形图(recorder-core、pcm-p)
解码(js-64、g7112pcm)
3、Express
使用express建立后端服务做demo
const express = require('express');
const io = require('nodejs-websocket');
const app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
const server = app.listen(3000, function () {
let host = server.address().address;
let port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
4、Websocket
var url = "ws://127.0.0.7:3001";
this.ws = new WebSocket(url);
this.ws.binaryType = "arraybuffer";
var that = this;
this.ws.addEventListener("open", function() {
let jsonData = { state: "start", channel: "1" };
that.ws.send(JSON.stringify(jsonData));
});
const fs = require("fs");
const source = "./audio.pcm"; // 读取目标
io.createServer(connection => {
console.log('new connection...');
connection.on("text", function(data) {
console.log("接收到的客户端消息:"+data);
let rs = fs.createReadStream(source);
rs.on("data", data => {
connection.sendBinary(data);
});
});
connection.on("close", function (code, reason) {
console.log("Connection closed");
});
connection.on("error",() => {
console.log('服务异常关闭...');
});
}).listen(3001);
5、音频波形图(recorder-core、pcm-p)
import Recorder from "recorder-core";
import PCMP from "pcm-p"
//需要使用到的音频格式编码引擎的js文件统统加载进来
import "recorder-core/src/engine/mp3";
import "recorder-core/src/engine/mp3-engine";
//比如 import Recorder from 'recorder-core/recorder.mp3.min' //已包含recorder-core和mp3格式支持
//可选的扩展支持项
import "recorder-core/src/extensions/wavesurfer.view";
this.p = new PCMP({
encoding: "16bitInt",
channels: 1,
sampleRate: 32000,
flushTime: 2000
})
var wave;
var set = {
elem: ".recwave",
scale: 2, //缩放系数,应为正整数,使用2(3? no!)倍宽高进行绘制,避免移动端绘制模糊
fps: 50, //绘制帧率,不可过高,50-60fps运动性质动画明显会流畅舒适,实际显示帧率达不到这个值也并无太大影响
duration: 2500, //当前视图窗口内最大绘制的波形的持续时间,此处决定了移动速率
direction: -1, //波形前进方向,取值:1由左往右,-1由右往左
position: 0, //绘制位置,取值-1到1,-1为最底下,0为中间,1为最顶上,小数为百分比
centerHeight: 1, //中线基础粗细,如果为0不绘制中线,position=±1时应当设为0
//波形颜色配置:[位置,css颜色,...] 位置: 取值0.0-1.0之间
linear: [
0,
"rgba(0,187,17,1)",
0.7,
"rgba(255,215,0,1)",
1,
"rgba(255,102,0,1)"
],
centerColor: "" //中线css颜色,留空取波形第一个渐变颜色
};
wave = Recorder.WaveSurferView(set);
6、解码(js-64、g7112pcm)
import { 64 } from 'js-64';
import { decodeUlaw } from 'g7112pcm';
this.ws.addEventListener("message", function(event) {
let dataAudio = decodeUlaw(64.toUint8Array(response.VoiceData)); // 后端为节约流量直接发送G711压缩μ-law算法形式的64
this.pAudio.feed(dataAudio);
this.pAudio.volume(this.volumeAudio);
let buf = Buffer.from(dataAudio);
let data = new Uint16Array(buf.buffer, buf.byteOffset, buf.byteLength / Uint16Array.BYTES_PER_ELEMENT);
this.waverAudio.input(data, 70, this.Config.sampleRate);
});
7、备注
Express是前端调研可行性时,临时后端服务的方案,正式的环境,使用后端同学的服务,音频流也是从硬件采集,实时经后端处理,传输到前端展示
Html
<div class="lb_audio_waver" v-if="Config.controlPanelHasAudio">
<div class="pandect_cont_top">
<div class="pandect_cont_top_left">
<div class="_icon"></div>
<div class="pandect_cont_">音频波形图</div>
</div>
</div>
<div class="audio_recwave"></div>
<div class="audio_btn" @click="volumePlay" v-show="audioIsQuiet">
<i class="el-icon-phone-outline"></i> 播放
</div>
<div class="audio_btn" @click="volumeQuiet" v-show="!audioIsQuiet">
<i class="el-icon-phone"></i> 静音
</div>
</div>