如果可以实现记得点赞分享,谢谢老铁~
首先在页面中给两个按钮,分别是"开始录音","结束录音"。以及录音成功后生成一个下载语音的链接。
1. 先看页面展示
html
<template>
<div>
<button @click="startRecording" :disabled="isRecording">Start Recording</button>
<button @click="stopRecording" :disabled="!isRecording">Stop Recording</button>
<a v-if="downloadLink" :href="downloadLink" download="recording.pcm">Download Recording</a>
</div>
</template>
2. 看vue3.0的代码实现
js
<script setup>
import { ref, onBeforeUnmount } from 'vue';
const isRecording = ref(false);
const downloadLink = ref('');
let audioContext = null;
let processor = null;
let socket = null;
let mediaStream = null;
let audioChunks = [];
let silenceTimeout = null;
const silenceDelay = 2000; // 停止录音的延迟时间(毫秒)
const desiredSampleRate = 16000; // 期望的采样率为16kHz
const startRecording = async () => {
try {
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: {
sampleRate: desiredSampleRate,
sampleSize: 16,
channelCount: 1,
} });
audioContext = new (window.AudioContext || window.webkitAudioContext)({
sampleRate: desiredSampleRate
});
const source = audioContext.createMediaStreamSource(mediaStream);
processor = audioContext.createScriptProcessor(4096, 1, 1);
source.connect(processor);
processor.connect(audioContext.destination);
socket = new WebSocket('ws://yourserver.com');
socket.binaryType = 'arraybuffer';
// 接收 WebSocket 消息
socket.onmessage = (event) => {
const receivedData = event.data;
console.log('Received data from server:', receivedData);
// 这里可以处理接收到的数据,例如显示在 UI 上
};
processor.onaudioprocess = processAudio;
isRecording.value = true;
audioChunks = []; // 清空之前的音频数据
} catch (error) {
console.error('Error accessing media devices.', error);
}
};
const stopRecording = async () => {
if (processor) {
processor.disconnect();
}
if (mediaStream) {
mediaStream.getTracks().forEach(track => track.stop());
}
if (audioContext && audioContext.state !== 'closed') {
await audioContext.close();
audioContext = null
}
if (socket) {
socket.close();
}
isRecording.value = false;
createDownloadLink();
};
const processAudio = (event) => {
const inputBuffer = event.inputBuffer;
const outputBuffer = new Float32Array(inputBuffer.length);
inputBuffer.copyFromChannel(outputBuffer, 0);
const pcmData = convertFloat32ToPCM(outputBuffer);
// 检查音量是否为静音
const isSilent = outputBuffer.every(sample => Math.abs(sample) < 0.01);
if (!isSilent) {
clearTimeout(silenceTimeout);
silenceTimeout = setTimeout(() => stopRecording(), silenceDelay);
}
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(pcmData);
}
audioChunks.push(pcmData);
};
const convertFloat32ToPCM = (input) => {
const buffer = new ArrayBuffer(input.length * 2);
const output = new DataView(buffer);
for (let i = 0; i < input.length; i++) {
const s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
return buffer;
};
const createDownloadLink = () => {
const blob = new Blob(audioChunks, { type: 'application/octet-stream' });
downloadLink.value = URL.createObjectURL(blob);
};
onBeforeUnmount(() => {
stopRecording();
});
</script>
解释
audioChunks 数组:
存储录音过程中的 PCM 数据块。
processAudio 方法:
将 PCM 数据块添加到 audioChunks 数组中。
stopRecording 方法:
停止录音,并调用 createDownloadLink 方法生成下载链接。
createDownloadLink 方法:
将存储的音频数据块创建为一个 Blob 对象,并生成一个下载链接。
downloadLink 变量:
存储生成的下载链接,供用户下载录音文件。
注意事项
确保WebSocket服务器可以处理PCM数据。
处理音频数据时,注意性能问题,避免阻塞主线程。
Web Audio API和WebSocket在不同浏览器上的实现可能会有所不同,确保在目标浏览器上测试。
OK,收工!如果可以实现记得点赞分享,谢谢老铁~