项目中需要语音录入,以及转为wav格式进行后端提取语音文字,强制转wav格式不能满足需求,所以记录一下解决方法
if (window.navigator.mediaDevices.getUserMedia) {
const constraints = { audio: true };
window.navigator.mediaDevices.getUserMedia(constraints).then(
stream => {
console.log("授权成功!");
//绑定点击按钮
const recordBtn = document.querySelector(".record-btn");
const mediaRecorder = new MediaRecorder(stream);
recordBtn.onclick = () => {
mediaRecorder.start();
console.log("录音中...");
};
recordBtn.onclick = () => {
if (mediaRecorder.state === "recording") {
mediaRecorder.stop();
recordBtn.textContent = "开始录音";
console.log("录音结束");
} else {
mediaRecorder.start();
console.log("录音中...");
recordBtn.textContent = "停止录音";
}
console.log("录音器状态:", mediaRecorder.state);
};
this.chunks = [];
mediaRecorder.ondataavailable = (e) => {
console.log(e.data, 'e')
this.chunks.push(e.data);
};
mediaRecorder.onstop = e => {
const reader = new FileReader();
reader.onload = async (event) => {
//设置采样率为16000,不设置会根据浏览器自己来判断设置
const audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 });
const arrayBuffer = event.target.result;
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
//设置wav的头
const wavData = encodeWAV(audioBuffer);
const wavBlob = new Blob([wavData], { type: 'audio/wav' });
const formData = new FormData();
formData.append('file', wavBlob, 'recording.wav');
//生成本地的访问地址
var audioURL = window.URL.createObjectURL(wavBlob);
console.log(audioURL, 'audioURL')
this.chunks = [];
//调用接口存储
uploadFileSystem(formData).then(res => {
if (res.data.code == 0) {
this.chunks = [];
this.message.videoUrl = res.data.data;
ElMessage({
type: 'success',
message: '语音录入成功',
})
} else {
ElMessage({
type: 'error',
message: '语音上传失败,请重试',
})
this.chunks = [];
}
})
};
reader.readAsArrayBuffer(this.chunks[0]);
function encodeWAV(audioBuffer) {
const numOfChan = audioBuffer.numberOfChannels,
length = audioBuffer.length * numOfChan * 2 + 44,
buffer = new ArrayBuffer(length),
view = new DataView(buffer),
sampleRate = audioBuffer.sampleRate,
samples = audioBuffer.getChannelData(0);
let offset = 0;
const writeString = (str) => {
for (let i = 0; i < str.length; i++) {
view.setUint8(offset++, str.charCodeAt(i));
}
};
writeString('RIFF');
view.setUint32(offset, length - 8, true);
offset += 4;
writeString('WAVE');
writeString('fmt ');
view.setUint32(offset, 16, true);
offset += 4;
view.setUint16(offset, 1, true);
offset += 2;
view.setUint16(offset, numOfChan, true);
offset += 2;
view.setUint32(offset, sampleRate, true);
offset += 4;
view.setUint32(offset, sampleRate * 2 * numOfChan, true);
offset += 4;
view.setUint16(offset, numOfChan * 2, true);
offset += 2;
view.setUint16(offset, 16, true);
offset += 2;
writeString('data');
view.setUint32(offset, length - offset - 8, true);
offset += 4;
for (let i = 0; i < samples.length; i++) {
view.setInt16(offset, samples[i] * 0x7FFF, true);
offset += 2;
}
return view;
}
};
}
() => {
console.error("授权失败!");
}
);
} else {
console.error("浏览器不支持 getUserMedia");
}