163 lines
5.2 KiB
JavaScript
163 lines
5.2 KiB
JavaScript
|
// 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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|