This commit is contained in:
JayJiaJun 2025-03-26 17:10:39 +08:00
parent e8da4a76a8
commit de18827af6
8 changed files with 472 additions and 234 deletions

View File

@ -1500,13 +1500,14 @@
screen_start = new Object()
screen_start.get_screen = 1;
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "获取屏幕参数中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -1527,13 +1528,14 @@
screen_start = new Object()
screen_start.get_sensor = 1;
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "获取传感器中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -1554,13 +1556,14 @@
screen_start = new Object()
screen_start.get_program = parseInt(pro_num);
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "获取屏幕参数中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -1589,11 +1592,12 @@
manage.pro_manage.type = type;
manage.pro_manage.data = data;
let string = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -1705,13 +1709,14 @@
}
}
let string = JSON.stringify(json_cfg);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
console.log(string);
result_prompt_display(1, "设置中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {

View File

@ -212,6 +212,8 @@
screen_start.get_cmd = new Object()
screen_start.get_cmd.type = _type
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
// 设置超时逻辑
var timeoutId = setTimeout(function () {
result_prompt_display(2, "数据获取失败");
@ -222,7 +224,7 @@
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -292,13 +294,14 @@
screen_start.cmd.data2 = parseInt($('#power_on2').find('option:selected').val());
screen_start.cmd.data3 = 0;
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -332,13 +335,14 @@
screen_start.cmd.data2 = 0;
screen_start.cmd.data3 = 0;
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -395,13 +399,14 @@
screen_start.cmd.data2 = 0;
screen_start.cmd.data3 = 0;
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -429,13 +434,14 @@
screen_close.cmd.data2 = 0;
screen_close.cmd.data3 = 0;
var str = JSON.stringify(screen_close);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -467,13 +473,14 @@
screen_clear.cmd.data2 = 0;
screen_clear.cmd.data3 = 0;
var str = JSON.stringify(screen_clear);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {

View File

@ -150,13 +150,14 @@
screen_start = new Object()
screen_start.get_screen = 1;
var str = JSON.stringify(screen_start);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "获取中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('POST', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -224,11 +225,12 @@
manage.pro_manage.type = 2;
manage.pro_manage.data = -1;
var str = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@ -271,13 +273,14 @@
screen.screen_p.data = parseInt($('#data_polarity').val())
screen.screen_p.screen_angle = screen_angle;
let str = JSON.stringify(screen);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + str + "}";
console.log(str);
result_prompt_display(1, "设置中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(str);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {

View File

@ -257,11 +257,12 @@
manage.pro_manage.remarks = new Array();
manage.pro_manage.remarks[0] = cont;
let string = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 || xhr.status == 200) {
program_list_reply_parse(xhr.responseText);
@ -295,11 +296,12 @@
manage = new Object();
manage.get_pro_manage = 1;
let string = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
program_list_reply_parse(xhr.responseText);
@ -329,11 +331,12 @@
manage.pro_manage.data = data;
result_prompt_display(1, "删除中...");
let string = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest()
xhr.open('post', baseHost + '/communication', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(string);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if ((xhr.readyState == 4) && (xhr.status == 200)) {
program_list_reply_parse(xhr.responseText);
@ -375,12 +378,13 @@
manage.pro_manage.type = type;
manage.pro_manage.data = data;
let string = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
result_prompt_display(1, "发送中...");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest()
xhr.open('post', baseHost + '/communication', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(string)
xhr.send(send_string)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {

View File

@ -96,11 +96,12 @@
manage = new Object();
manage.get_pro_manage = 1;
let string = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest();
xhr.open('post', baseHost + '/communication', true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(string);
xhr.send(send_string);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
screen_virtual_reply_parse(xhr.responseText);
@ -126,12 +127,13 @@
manage.pro_manage.type = 6;
manage.pro_manage.data = parseInt(data);
let string = JSON.stringify(manage);
let send_string = "{\"JSON_id\":" + json_id + ",\"board_id\":102"+",\"led_protocol\":" + string + "}";
result_prompt_display(1, "打开中");
if (MQTT_MODE == 0) {
var xhr = new XMLHttpRequest()
xhr.open('post', baseHost + '/communication', true)
xhr.setRequestHeader('content-type', 'application/json')
xhr.send(string)
xhr.send(send_string)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {

View File

@ -12,17 +12,26 @@ class GamepadController {
this.gamepadIndex = null;
this.gamepad = null;
this.interval = null;
this.angle = 0; // 这里将存储 0-360 的角度值
this.angle = 0;
this.speed = 0;
this.directionAxis9 = 0;
this.rightJoystickPressed = false;
this.isActive = false;
this.updateLoop = setInterval(() => this.update(), this.options.updateInterval);
// 立即开始更新循环,不等待连接事件
this.startUpdateLoop();
}
update() {
const gamepad = navigator.getGamepads()[0];
// 获取所有手柄
const gamepads = navigator.getGamepads();
if (!gamepads) {
this.isActive = false;
return;
}
// 找到第一个连接的手柄
const gamepad = Array.from(gamepads).find(pad => pad && pad.connected);
if (!gamepad) {
this.isActive = false;
return;
@ -45,25 +54,26 @@ class GamepadController {
this.updateDirection(gamepad.axes);
}
// 获取右摇杆的值(用于云台控制)
const rightY = gamepad.axes[3];
if (Math.abs(rightY) > this.options.deadZone) {
this.directionAxis9 = rightY > 0 ? 1 : 2;
} else {
this.directionAxis9 = 0;
}
// 更新 platform 值
this.updateDirectionAxis9(gamepad.axes);
// 更新右摇杆按钮状态
this.rightJoystickPressed = gamepad.buttons[10].pressed;
// 更新右摇杆按钮状态 - 尝试多个可能的按钮索引
this.rightJoystickPressed =
(gamepad.buttons[10] && gamepad.buttons[10].pressed) ||
(gamepad.buttons[9] && gamepad.buttons[9].pressed) ||
(gamepad.buttons[11] && gamepad.buttons[11].pressed);
if (this.options.debug) {
console.log('GamepadController 状态:', {
id: gamepad.id,
index: gamepad.index,
x: x.toFixed(2),
y: y.toFixed(2),
angle: this.angle,
speed: this.speed.toFixed(2),
directionAxis9: this.directionAxis9,
rightJoystickPressed: this.rightJoystickPressed
rightJoystickPressed: this.rightJoystickPressed,
buttons: Array.from(gamepad.buttons).map((btn, idx) => btn.pressed ? idx : null).filter(idx => idx !== null)
});
}
}
@ -90,22 +100,52 @@ class GamepadController {
// 计算速度0-100
const distance = Math.sqrt(axis0 * axis0 + axis1 * axis1);
this.speed = Math.min(Math.round(distance * 100), 100);
}
updateDirectionAxis9(axes) {
// 添加调试输出,查看所有轴的值
if (this.options.debug) {
// console.log('所有轴的值:', axes.map((value, index) => `轴${index}: ${value}`));
}
// 检查第9轴是否存在
if (axes[9] === undefined) {
// 可能是第3轴或第4轴
const axis3 = axes[3];
const axis4 = axes[4];
if (axis3 !== undefined && Math.abs(axis3) > this.options.deadZone) {
this.directionAxis9 = axis3 > 0 ? 2 : 1;
} else if (axis4 !== undefined && Math.abs(axis4) > this.options.deadZone) {
this.directionAxis9 = axis4 > 0 ? 2 : 1;
} else {
this.directionAxis9 = 0;
}
} else {
const axis9 = axes[9];
const roundedAxis9 = Math.round(axis9 * 100) / 100;
if (roundedAxis9 <= -0.9) {
this.directionAxis9 = 1; // 向上
} else if (roundedAxis9 >= 0.0 && roundedAxis9 <= 0.2) {
this.directionAxis9 = 2; // 向下
} else {
this.directionAxis9 = 0; // 中间位置
}
}
if (this.options.debug) {
console.log('方向计算:', {
x: axis0,
y: axis1,
angle: this.angle,
speed: this.speed
});
// console.log('当前 directionAxis9 值:', this.directionAxis9);
}
}
startUpdateLoop() {
this.updateLoop = setInterval(() => this.update(), this.options.updateInterval);
}
destroy() {
if (this.updateLoop) {
clearInterval(this.updateLoop);
}
}
}
}export default GamepadController;
export default GamepadController;

View File

@ -1,163 +1,204 @@
// 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();
}
data() {
return {
ws: null, // WebSocket 连接
mediaRecorder: null, // MediaRecorder 实例
audioChunks: [], // 音频数据
status: '点击按钮开始传输音频',
isRecording: false, // 用于判断是否在录音
audioConfig: {
sampleRate: 44100, // 固定为 44100Hz
bitsPerSample: 16, // 固定为 16 位深度
channels: 2 // 固定为双声道
},
async startRecording() {
console.log('音频传输器: 开始录音');
this.status = '开始录音并传输音频...';
this.isRecording = true;
const constraints = {
audio: {
sampleRate: this.audioConfig.sampleRate,
channelCount: this.audioConfig.channels,
sampleSize: this.audioConfig.bitsPerSample
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;
}
}
};
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;
// 关闭音频资源
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) {
// 安全关闭音频上下文
if (this.audioContext && this.audioContext.state !== 'closed') {
console.log('关闭音频上下文');
this.audioContext.close();
}
// 关闭音频 WebSocket 连接
if (this.audioWs) {
console.log('关闭音频 WebSocket 连接');
this.audioWs.close();
this.audioWs = null;
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;
// }
}
};
}
};

View File

@ -2,6 +2,9 @@
<div class="control-panel">
<!-- 顶部状态栏 -->
<div class="status-bar">
<div class="back-button" @click="handleBack">
</div>
<div class="placeholder-div"></div>
<div class="title-container">
<div class="title-box">
@ -13,6 +16,7 @@
</div>
<div class="top-right-icons">
<img :src="connectionImage" alt="link" class="top-icon">
<img src="../assets/img/bat_full.png" class="top-icon" alt="">
<!-- 注释掉电池图标 -->
<!-- <img :src="batteryImage" alt="battery" class="top-icon"> -->
</div>
@ -42,7 +46,7 @@
<!-- 中间车辆状态显示区域 -->
<div class="center-display">
<div class="status-text">云台状态</div>
<div class="status-text">{{ getptz }}</div>
<div class="car-display">
<div class="boom-container">
<img src="../assets/img/boom.png" alt="boom" class="boom-image top-boom" v-show="obstacleStatus.top">
@ -68,10 +72,11 @@
</div>
<div class="control-button">
<div class="circle-border" :class="{ 'pressed': isControlPressed }" @mousedown="handleControlPress"
@mouseup="handleControlRelease" @mouseleave="handleControlRelease" @touchstart="handleControlPress"
@touchend="handleControlRelease" @touchcancel="handleControlRelease">
@mouseup="handleControlRelease" @mouseleave="handleControlRelease" @touchstart.prevent="handleControlPress"
@touchend.prevent="handleControlRelease" @touchcancel.prevent="handleControlRelease" @contextmenu.prevent
@copy.prevent @selectstart.prevent style="user-select: none;">
<img src="../assets/img/stop.png" alt="control" class="control-button-img"
style="width: 80px; height: 80px;">
style="width: 80px; height: 80px; pointer-events: none;" draggable="false">
</div>
</div>
</div>
@ -117,12 +122,15 @@ export default {
reconnectTimer: null, //
isComponentUnmounted: false, //
isInitialized: false, //
contenttext: "",
_mousePressed: false, // /
contentptz: "",
}
},
created() {
// GamepadController
// GamepadController
this.gamepadController = new GamepadController({
debug: false, // debug false
debug: false, //
deadZone: 0.1,
updateInterval: 50
});
@ -131,24 +139,39 @@ export default {
window.addEventListener("gamepadconnected", this.handleGamepadConnected);
window.addEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
this.isComponentUnmounted = false; //
this.isComponentUnmounted = false;
this.initWebSocket();
//
this.connectionCheckInterval = setInterval(() => {
this.checkConnectionStatus();
}, 3000); // 3
}, 3000);
//
this.sendInterval = setInterval(() => {
this.sendControlData();
}, 400); // 100ms
}, 400);
//
this.audioHandler = {
...audioTransmitter.data(),
...audioTransmitter.methods
};
// WebSocket
this.audioHandler.audioWs = new WebSocket('ws://192.168.4.103/ws');
this.audioHandler.audioWs.onopen = () => {
console.log('音频 WebSocket 已连接');
};
this.audioHandler.audioWs.onerror = (error) => {
console.error('音频 WebSocket 错误:', error);
};
this.audioHandler.audioWs.onclose = () => {
console.log('音频 WebSocket 已关闭');
};
},
beforeDestroy() {
this.isComponentUnmounted = true; //
@ -159,19 +182,7 @@ export default {
this.reconnectTimer = null;
}
//
if (this.gamepadController) {
this.gamepadController.destroy();
}
//
window.removeEventListener("gamepadconnected", this.handleGamepadConnected);
window.removeEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
if (this.ws) {
this.ws.close();
this.ws = null;
}
//
if (this.connectionCheckInterval) {
clearInterval(this.connectionCheckInterval);
}
@ -180,10 +191,34 @@ export default {
clearInterval(this.sendInterval);
}
//
window.removeEventListener("gamepadconnected", this.handleGamepadConnected);
window.removeEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
//
if (this.gamepadController) {
this.gamepadController.destroy();
}
//
if (this.audioHandler && this.audioHandler.isRecording) {
this.audioHandler.stopRecording();
}
// WebSocket
if (this.audioHandler && this.audioHandler.audioWs) {
console.log('关闭音频 WebSocket 连接');
this.audioHandler.audioWs.close();
this.audioHandler.audioWs = null;
}
// WebSocket
if (this.ws) {
console.log('关闭控制 WebSocket 连接');
this.ws.close();
this.ws = null;
this.wsConnected = false;
}
},
methods: {
goto(path) {
@ -207,17 +242,19 @@ export default {
}
},
handleControlPress() {
console.log('按钮被按下,设置 isControlPressed = true');
this._mousePressed = true;
this.isControlPressed = true;
//
console.log('开始音频传输...');
if (this.audioHandler) {
this.audioHandler.startRecording();
}
},
handleControlRelease() {
console.log('按钮被释放,设置 isControlPressed = false');
this._mousePressed = false;
this.isControlPressed = false;
//
console.log('停止音频传输...');
if (this.audioHandler) {
this.audioHandler.stopRecording();
}
@ -289,7 +326,7 @@ export default {
// 0-4
let direction = 0; //
if (speed > 10) { //
if (speed > 10) {
if (angle >= 315 || angle < 45) {
direction = 4; //
} else if (angle >= 45 && angle < 135) {
@ -301,27 +338,29 @@ export default {
}
}
//
const wasPressed = this.isControlPressed;
this.isControlPressed = this.gamepadController.rightJoystickPressed;
// /
const gamepadButtonPressed = this.gamepadController.rightJoystickPressed;
//
if (!wasPressed && this.isControlPressed) {
//
console.log('手柄按钮按下,开始音频传输...');
//
if (gamepadButtonPressed && !this.isControlPressed) {
console.log('手柄按钮被按下,开始录音');
this.isControlPressed = true;
if (this.audioHandler) {
this.audioHandler.startRecording();
}
} else if (wasPressed && !this.isControlPressed) {
//
console.log('手柄按钮释放,停止音频传输...');
}
//
else if (!gamepadButtonPressed && this.isControlPressed && !this._mousePressed) {
console.log('手柄按钮被释放,停止录音');
this.isControlPressed = false;
if (this.audioHandler) {
this.audioHandler.stopRecording();
}
}
//
this.lastDirection = direction;
//
this.contenttext = direction;
this.lastDirection = angle;
if (directionAxis9 !== undefined) this.platform_fun = directionAxis9;
if (speed !== undefined) this.lastSpeed = speed;
}
@ -357,15 +396,16 @@ export default {
top: data.attribute.obstacle_sta === 1,
bottom: data.attribute.obstacle_sta === 2
};
//
if (!this.isInitialized) {
this.screenStatus = data.attribute.screen_en === 1;
this.warningLightStatus = data.attribute.warn_light_en === 1;
this.followStatus = data.attribute.follow_en === 1;
this.obstacleAvoidEnabled = data.attribute.obstacle_avoid_en === 1;
this.isInitialized = true;
}
// if (!this.isInitialized) {
this.screenStatus = data.attribute.screen_en === 1;
this.warningLightStatus = data.attribute.warn_light_en === 1;
this.followStatus = data.attribute.follow_en === 1;
this.obstacleAvoidEnabled = data.attribute.obstacle_avoid_en === 1;
this.contentptz = data.attribute.platform;
// this.isInitialized = true;
// }
}
//
@ -431,6 +471,64 @@ export default {
}
},
handleBack() {
//
this.isComponentUnmounted = true;
//
if (this.connectionCheckInterval) {
clearInterval(this.connectionCheckInterval);
this.connectionCheckInterval = null;
}
if (this.sendInterval) {
clearInterval(this.sendInterval);
this.sendInterval = null;
}
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
//
if (this.audioHandler && this.audioHandler.isRecording) {
this.audioHandler.stopRecording();
}
//
window.removeEventListener("gamepadconnected", this.handleGamepadConnected);
window.removeEventListener("gamepaddisconnected", this.handleGamepadDisconnected);
//
if (this.gamepadController) {
this.gamepadController.destroy();
this.gamepadController = null;
}
// WebSocket
const closePromises = [];
if (this.ws) {
console.log('断开控制 WebSocket 连接');
this.ws.onclose = null; //
this.ws.close();
this.ws = null;
this.wsConnected = false;
}
if (this.audioHandler && this.audioHandler.audioWs) {
console.log('断开音频 WebSocket 连接');
this.audioHandler.audioWs.onclose = null; //
this.audioHandler.audioWs.close();
this.audioHandler.audioWs = null;
}
//
setTimeout(() => {
//
this.$router.push('/');
}, 100);
},
},
computed: {
//
@ -450,7 +548,7 @@ export default {
},
getDirectionText() {
// direction
switch (this.lastDirection) {
switch (this.contenttext) {
case 0:
return '遥控车已停止';
case 1:
@ -464,6 +562,18 @@ export default {
default:
return '遥控车当前状态';
}
},
getptz() {
switch (this.contentptz) {
case 0:
return '云台静止';
case 1:
return '云台上升';
case 2:
return '云台下降';
default:
return '云台静止';
}
}
},
setup() {
@ -526,7 +636,8 @@ export default {
display: flex;
align-items: center;
justify-content: center;
min-width: 180px; /* 确保文本变化时盒子大小稳定 */
min-width: 180px;
/* 确保文本变化时盒子大小稳定 */
}
.main-content {
@ -675,6 +786,12 @@ export default {
align-items: center;
transition: border-color 0.3s ease;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.circle-border.pressed {
@ -701,4 +818,23 @@ export default {
:deep(.van-nav-bar) {
z-index: 999;
}
.back-button {
cursor: pointer;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: background-color 0.3s;
font-size: 24px;
/* 调整箭头大小 */
color: #00ffff;
/* 使用青色,与其他元素保持一致 */
}
.back-button:hover {
background-color: rgba(255, 255, 255, 0.1);
}
</style>