GateWay/src/assets/js/audio-transmitter.js

163 lines
5.2 KiB
JavaScript
Raw Normal View History

2025-02-22 21:04:37 +08:00
// 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 连接
};
},
mounted() {
// 初始化 WebSocket 连接
this.ws = new WebSocket('ws://192.168.4.103/ws'); // 替换为 ESP32 IP 地址
this.ws.onopen = () => {
console.log('WebSocket 连接已打开');
};
this.ws.onmessage = (event) => {
console.log(' 接收到来自 ESP32 的消息:', event.data);
};
this.ws.onclose = () => {
console.log('WebSocket 连接已关闭');
};
},
methods: {
toggleRecording() {
if (this.isRecording) {
this.stopRecording();
} else {
this.startRecording();
}
},
async startRecording() {
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 连接
this.audioWs = new WebSocket('ws://192.168.1.60:81');
// 等待 WebSocket 连接成功
await new Promise((resolve, reject) => {
this.audioWs.onopen = () => {
console.log('音频 WebSocket 已连接');
resolve();
};
this.audioWs.onerror = (error) => {
console.error('音频 WebSocket 错误:', error);
reject(error);
};
});
// WebSocket 连接成功后,开始获取麦克风权限
const stream = await navigator.mediaDevices.getUserMedia(constraints);
console.log('成功获取麦克风权限');
// 创建 AudioContext
const audioContext = new AudioContext({
sampleRate: this.audioConfig.sampleRate
});
// 加载 AudioWorklet
await audioContext.audioWorklet.addModule('audio-processor.js');
const source = audioContext.createMediaStreamSource(stream);
const worklet = new AudioWorkletNode(audioContext, 'audio-processor');
// 监听来自 worklet 的消息
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);
// 清理音频相关资源
if (this.stream) {
this.stream.getTracks().forEach(track => track.stop());
}
if (this.worklet) {
this.worklet.disconnect();
}
if (this.audioContext) {
this.audioContext.close();
}
if (this.audioWs) {
this.audioWs.close();
this.audioWs = null;
}
this.isRecording = false;
// 不抛出错误,让程序继续执行
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;
}
}
}
};