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>