提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、js-audio-recorder是什么?
- 二、使用步骤
- 1.引入库
- 2.读入数据
- 3,完整代码
- 总结
前言
最近实现一个录音上传功能,并且识别语音转为汉字。
一、js-audio-recorder是什么?
js-audio-recorder是基于第三方的vue插件,实现录音,播放等功能。
二、使用步骤
1.引入库
代码如下(示例):
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import axios from 'axios'
Vue.use(ElementUI)
Vue.config.productionTip = false
Vue.prototype.$axios = axios
new Vue({
el:'#app',
router,
store,
render: h => h(App)
}).$mount('#app')
2.读入数据
代码如下(示例):
data = pd.read_csv(
'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())
该处使用的url网络请求的数据。
3,完整代码
<template>
<div class="hea1" style="padding: 20px;">
<h3>录音上传</h3>
<div style="font-size: 14px">
<h3>录音时长:{{ recorder && recorder.duration.toFixed(4) }}</h3>
<el-button type="primary" @click="handleStart">开始录音</el-button>
<el-button type="info" @click="handlePause">暂停录音</el-button>
<el-button type="success" @click="handleResume">继续录音</el-button>
<el-button type="warning" @click="handleStop">停止录音</el-button>
<br><br>
<h3>
播放时长:{{
recorder &&
(playTime > recorder.duration
? recorder.duration.toFixed(4)
: playTime.toFixed(4))
}}
</h3>
<audio ref="audios" :src="this.audio" controls ></audio>
<br />
<div class="bo">
<!-- <el-button type="primary" @click="handlePlay">播放录音</el-button>
<el-button type="info" @click="handlePausePlay">暂停播放</el-button>
<el-button type="success" @click="handleResumePlay">继续播放</el-button>
<el-button type="warning" @click="handleStopPlay">停止播放</el-button> -->
<el-button type="error" @click="handleDestroy">销毁录音</el-button>
<el-button type="info" @click="downWAV">下载WAV</el-button>
<el-button type="info" @click="downPCM">下载pcm</el-button>
<el-button type="primary" @click="uploadRecord">上传</el-button>
<el-button type="success" @click="getResults">识别结果</el-button>
</div>
<br />
<br />
<textarea
name=""
id="textarea"
style="width: 100%; height: 100px"
cols="30"
rows="10"
v-model="result"
/>
</div>
</div>
</template>
<script>
import Recorder from "js-audio-recorder";
//import MyRecorder from '../js/MyRecorder'
import { v4 as uuidv4 } from "uuid";
import axios from 'axios';
uuidv4();
//const baseURL = "http://10.34.23.133:8899/asr/non_real";
export default {
data() {
return {
recorder: null,
playTime: 0,
timer: null,
src: null,
sessionId: "",
audio: "",
data: "",
result: "",
};
},
created() {},
mounted() {
this.dataRecorder = this.data;
},
methods: {
// 开始录音
handleStart() {
const uuid = require("uuid");
this.sessionId = uuid.v4();
console.log(this.sessionId);
this.recorder = new Recorder({
sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
numChannels: 1, // 声道,支持 1 或 2, 默认是1
// compiling: false,(0.x版本中生效,1.x增加中) // 是否边录边转换,默认是false
});
console.log(this.recorder)
Recorder.getPermission().then(
() => {
console.log("开始录音");
this.recorder.start(); // 开始录音
},
(error) => {
this.$message({
message: "请先允许该网页使用麦克风",
type: "info",
});
console.log(`${error.name} : ${error.message}`);
}
);
},
handlePause() {
console.log("暂停录音");
this.recorder.pause(); // 暂停录音
},
handleResume() {
console.log("恢复录音");
this.recorder.resume(); // 恢复录音
},
handleStop() {
console.log("停止录音");
this.recorder.stop(); // 停止录音
this.handlePlay(); //
},
handlePlay() {
console.log("播放录音");
console.log(this.recorder);
const bl=this.recorder.getWAVBlob()
const r = new FileReader();
r.readAsArrayBuffer(bl);
r.onload = (e) => {
const bufer = e.srcElement.result;
const b = this.addWavHeader(bufer, 16000, 16, 1);
this.audio = window.URL.createObjectURL(b);
};
console.log(this.$refs.audios);
// this.recorder.play(); // 播放录音
// 播放时长
this.timer = setInterval(() => {
try {
this.playTime = this.recorder.getPlayTime();
} catch (error) {
this.timer = null;
}
}, 100);
},
addWavHeader(samples, sampleRateTmp, sampleBits, channelCount) {
const dataLength = samples.byteLength;
/* 新的buffer类,预留44bytes的heaer空间 */
const buffer = new ArrayBuffer(44 + dataLength);
/* 转为 Dataview, 利用API来填充字节 */
const view = new DataView(buffer);
let offset = 0;
/* ChunkID, 4 bytes, 资源交换文件标识符 */
this.writeString(view, offset, 'RIFF'); offset += 4;
/* ChunkSize, 4 bytes, 下个地址开始到文件尾总字节数,即文件大小-8 */
view.setUint32(offset, /* 32 */ 36 + dataLength, true); offset += 4;
/* Format, 4 bytes, WAV文件标志 */
this.writeString(view, offset, 'WAVE'); offset += 4;
/* Subchunk1 ID, 4 bytes, 波形格式标志 */
this.writeString(view, offset, 'fmt '); offset += 4;
/* Subchunk1 Size, 4 bytes, 过滤字节,一般为 0x10 = 16 */
view.setUint32(offset, 16, true); offset += 4;
/* Audio Format, 2 bytes, 格式类别 (PCM形式采样数据) */
view.setUint16(offset, 1, true); offset += 2;
/* Num Channels, 2 bytes, 通道数 */
view.setUint16(offset, channelCount, true); offset += 2;
/* SampleRate, 4 bytes, 采样率,每秒样本数,表示每个通道的播放速度 */
view.setUint32(offset, sampleRateTmp, true); offset += 4;
/* ByteRate, 4 bytes, 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */
view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4;
/* BlockAlign, 2 bytes, 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */
view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
/* BitsPerSample, 2 bytes, 每样本数据位数 */
view.setUint16(offset, sampleBits, true); offset += 2;
/* Subchunk2 ID, 4 bytes, 数据标识符 */
this.writeString(view, offset, 'data'); offset += 4;
/* Subchunk2 Size, 4 bytes, 采样数据总数,即数据总大小-44 */
view.setUint32(offset, dataLength, true); offset += 4;
if (sampleBits === 16) {
this.floatTo16BitPCM(view, samples);
} else if (sampleBits === 8) {
this.floatTo8BitPCM(view, samples);
} else {
this.floatTo32BitPCM(view, samples);
}
return new Blob([view], { type: 'audio/wav' });
},
writeString(view, offset, string) {
for (let i = 0; i < string.length; i += 1) {
view.setUint8(offset + i, string.charCodeAt(i));
}
},
floatTo32BitPCM(output, input) {
const oinput = new Int32Array(input);
let newoffset = 44;
for (let i = 0; i < oinput.length; i += 1, newoffset += 4) {
output.setInt32(newoffset, oinput[i], true);
}
},
floatTo16BitPCM(output, input) {
const oinput = new Int16Array(input);
let newoffset = 44;
for (let i = 0; i < oinput.length; i += 1, newoffset += 2) {
output.setInt16(newoffset, oinput[i], true);
}
},
floatTo8BitPCM(output, input) {
const oinput = new Int8Array(input);
let newoffset = 44;
for (let i = 0; i < oinput.length; i += 1, newoffset += 1) {
output.setInt8(newoffset, oinput[i], true);
}
},
handlePausePlay() {
console.log("暂停播放");
this.recorder.pausePlay(); // 暂停播放
// 播放时长
this.playTime = this.recorder.getPlayTime();
this.time = null;
},
handleResumePlay() {
console.log("恢复播放");
this.recorder.resumePlay(); // 恢复播放
// 播放时长
this.timer = setInterval(() => {
try {
this.playTime = this.recorder.getPlayTime();
} catch (error) {
this.timer = null;
}
}, 100);
},
handleStopPlay() {
console.log("停止播放");
this.recorder.stopPlay(); // 停止播放
// 播放时长
this.playTime = this.recorder.getPlayTime();
this.timer = null;
},
handleDestroy() {
console.log("销毁实例");
this.recorder.destroy(); // 毁实例
this.timer = null;
},
downWAV() {
this.recorder.downloadWAV("下载wav");
},
downPCM() {
this.recorder.downloadPCM("下载pcm");
},
uploadRecord() {
if (this.recorder == null || this.recorder.duration === 0) {
this.$message({
message: "请先录音",
type: "error",
});
return false;
}
this.recorder.pause(); // 暂停录音
this.timer = null;
console.log("上传录音"); // 上传录音
const formData = new FormData();
const blob = this.recorder.getWAVBlob(); // 获取wav格式音频数据
console.log(blob);
// 此处获取到blob对象后需要设置fileName满足当前项目上传需求,可直接传把blob作为file塞入formData
const newbolb = new Blob([blob], { type: "audio/wav" });
const fileOfBlob = new File([newbolb], new Date().getTime() + ".wav");
console.log(fileOfBlob);
formData.append("file", blob);
console.log(formData);
const url = window.URL.createObjectURL(fileOfBlob);
this.src = url;
console.log(url);
this.$axios({
url:'https://10.45.192.42:8899/asr/non_real/putAudio?asrType=non_real&sessionId=' + this.sessionId ,
//url: this.baseURL + '/putAudio?asrType=non_real&sessionId=' + this.sessionID,
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
}).then(function (res) {
if (res.data == 200) {
alert("上传完成可以识别");
} else {
alert("上传失败请重试");
}
});
},
//识别结果
getResults() {
console.log("识别结果");
this.$axios({
url:"https://10.85.134.230:8899/asr/non_real/getResult",
method: "get",
params: {
sessionId: this.sessionId,
}
}).then((response) => (this.result = response.data));
},
},
};
</script>
<style scoped>
.hea1 {
line-height: 20px;
}
.bo {
display: flex;
justify-content: space-between;
flex:1
}
</style>
总结
前端调用js-audio-recorder使用封装好的功能比较方便,但是在与后端对接过程,要把语音音频传给后端,再返回识别结果也会遇到很多困难,重要的是要多查资料,积极沟通。