// audio-transmitter.js export default { data() { return { ws: null, // WebSocket 连接 mediaRecorder: null, // MediaRecorder 实例 audioChunks: [], // 音频数据 status: '点击按钮开始传输音频', isRecording: false, // 用于判断是否在录音 audioConfig: { sampleRate: 44100, // 固定为 44100Hz bitsPerSample: 16, // 固定为 16 位深度 channels: 2 // 固定为双声道 }, stream: null, audioContext: null, worklet: null, lastSendTime: 0, sendInterval: 200, // 数据传输间隔(毫秒) audioWs: null, // 音频 WebSocket 连接 }; }, beforeDestroy() { // 组件销毁前清理资源 this.cleanup(); // 关闭主 WebSocket 连接 if (this.ws) { console.log('关闭主 WebSocket 连接'); this.ws.close(); this.ws = null; } }, methods: { toggleRecording() { if (this.isRecording) { this.stopRecording(); } else { this.startRecording(); } }, async startRecording() { if (this.isRecording) return; console.log('音频传输器: 开始录音'); this.status = '开始录音并传输音频...'; this.isRecording = true; const constraints = { audio: { sampleRate: this.audioConfig.sampleRate, channelCount: this.audioConfig.channels, sampleSize: this.audioConfig.bitsPerSample } }; console.log('使用的音频配置:', constraints); try { // 直接获取麦克风权限,不再重新建立 WebSocket 连接 const stream = await navigator.mediaDevices.getUserMedia(constraints); console.log('成功获取麦克风权限'); const audioContext = new AudioContext({ sampleRate: this.audioConfig.sampleRate }); await audioContext.audioWorklet.addModule('audio-processor.js'); const source = audioContext.createMediaStreamSource(stream); const worklet = new AudioWorkletNode(audioContext, 'audio-processor'); worklet.port.onmessage = (event) => { if (this.audioWs && this.audioWs.readyState === WebSocket.OPEN) { const currentTime = Date.now(); if (!this.lastSendTime || currentTime - this.lastSendTime > this.sendInterval) { const pcmData = new Int16Array(event.data); console.log('发送的音频数据:', Array.from(pcmData.slice(0, 20))); this.audioWs.send(event.data); this.lastSendTime = currentTime; } } }; source.connect(worklet); worklet.connect(audioContext.destination); this.stream = stream; this.audioContext = audioContext; this.worklet = worklet; } catch (error) { console.error('音频初始化失败:', error); this.cleanup(); return; } }, // stopRecording() { // console.log('音频传输器: 停止录音'); // this.status = '停止录音'; // this.isRecording = false; // // 关闭音频资源 // if (this.stream) { // console.log('关闭音频流'); // this.stream.getTracks().forEach(track => track.stop()); // } // if (this.worklet) { // console.log('断开 AudioWorklet'); // this.worklet.disconnect(); // } // if (this.audioContext) { // console.log('关闭音频上下文'); // this.audioContext.close(); // } // // 关闭音频 WebSocket 连接 // if (this.audioWs) { // console.log('关闭音频 WebSocket 连接'); // this.audioWs.close(); // this.audioWs = null; // } // } // 修改停止录音方法 stopRecording() { console.log('音频传输器: 停止录音'); this.status = '停止录音'; this.isRecording = false; // 异步关闭防止状态冲突 const cleanup = async () => { // 优先关闭音频流 if (this.stream) { console.log('关闭音频流'); this.stream.getTracks().forEach(track => track.stop()); this.stream = null; } // 断开音频处理节点 if (this.worklet) { console.log('断开 AudioWorklet'); this.worklet.disconnect(); this.worklet = null; } // 安全关闭音频上下文 if (this.audioContext && this.audioContext.state !== 'closed') { console.log('关闭音频上下文'); await this.audioContext.close(); this.audioContext = null; } // 移除关闭 WebSocket 的代码 // if (this.audioWs) { // console.log('关闭音频 WebSocket 连接'); // this.audioWs.close(); // this.audioWs = null; // } }; cleanup().catch(error => { console.error('清理过程中发生错误:', error); }); }, async cleanup() { console.log('开始清理音频资源...'); // 停止录音 if (this.isRecording) { this.isRecording = false; } // 优先关闭音频流 if (this.stream) { console.log('关闭音频流'); this.stream.getTracks().forEach(track => track.stop()); this.stream = null; } // 断开音频处理节点 if (this.worklet) { console.log('断开 AudioWorklet'); this.worklet.disconnect(); this.worklet = null; } // 安全关闭音频上下文 if (this.audioContext && this.audioContext.state !== 'closed') { console.log('关闭音频上下文'); await this.audioContext.close(); this.audioContext = null; } // 关闭音频 WebSocket 连接 // if (this.audioWs) { // console.log('关闭音频 WebSocket 连接'); // this.audioWs.close(); // this.audioWs = null; // } } } };