修复了一些bug

This commit is contained in:
2026-08-11 08:32:25 +08:00
parent feb7c72e94
commit b1fca95250
6 changed files with 394 additions and 150 deletions
+67 -30
View File
@@ -35,13 +35,13 @@ const state = {
socket: null,
reconnectTimer: 0,
frameTimer: 0,
frameTimeout: 0,
framePending: false,
requestStarted: 0,
lastFrameAt: 0,
smoothedFps: 0,
frameCount: 0,
paused: false,
manuallyReconnecting: false,
requestedWidth: 960,
requestedHeight: 600
};
@@ -120,20 +120,68 @@ function syncViewport() {
sendEvent("resize", {width, height});
}
function scheduleFrame(delay = 42) {
function streamActive() {
return !state.paused && !document.hidden;
}
function stopFramePump() {
window.clearTimeout(state.frameTimer);
if (!state.paused)
state.frameTimer = window.setTimeout(requestFrame, delay);
state.frameTimer = 0;
}
function clearFrameRequest() {
window.clearTimeout(state.frameTimeout);
state.frameTimeout = 0;
state.framePending = false;
}
function scheduleFrame(delay = 42) {
stopFramePump();
if (!streamActive())
return;
state.frameTimer = window.setTimeout(() => {
state.frameTimer = 0;
requestFrame();
}, delay);
}
function requestFrame() {
if (state.paused || state.framePending)
if (!streamActive() || state.framePending)
return;
if (!sendEvent("frame"))
return;
state.requestStarted = performance.now();
state.framePending = sendEvent("frame");
state.framePending = true;
window.clearTimeout(state.frameTimeout);
state.frameTimeout = window.setTimeout(() => {
state.frameTimeout = 0;
if (!state.framePending)
return;
state.framePending = false;
if (!streamActive() || state.socket?.readyState !== WebSocket.OPEN)
return;
sendEvent("show");
scheduleFrame(42);
}, 2000);
}
function syncStreamActivity() {
stopFramePump();
const active = streamActive();
if (!active) {
state.lastFrameAt = 0;
state.smoothedFps = 0;
elements.fps.textContent = "0.0";
}
if (!state.socket || state.socket.readyState !== WebSocket.OPEN)
return;
sendEvent(active ? "show" : "hide");
if (active)
requestFrame();
}
function drawPixelFrame(buffer) {
clearFrameRequest();
if (!(buffer instanceof ArrayBuffer) || buffer.byteLength < 16)
throw new Error("像素帧长度无效");
const bytes = new Uint8Array(buffer);
@@ -163,7 +211,6 @@ function drawPixelFrame(buffer) {
const megabitsPerSecond = roundTrip > 0 ? buffer.byteLength * 8 / roundTrip / 1000 : 0;
state.lastFrameAt = now;
state.frameCount += 1;
state.framePending = false;
elements.fps.textContent = state.smoothedFps.toFixed(1);
elements.latency.textContent = roundTrip.toFixed(1);
@@ -176,12 +223,10 @@ function drawPixelFrame(buffer) {
function connect() {
window.clearTimeout(state.reconnectTimer);
window.clearTimeout(state.frameTimer);
state.framePending = false;
if (state.socket && state.socket.readyState < WebSocket.CLOSING) {
state.manuallyReconnecting = true;
stopFramePump();
clearFrameRequest();
if (state.socket && state.socket.readyState < WebSocket.CLOSING)
state.socket.close(1000, "reconnect");
}
setConnectionState("", "正在连接", "建立纯 WebSocket 像素通道");
const socket = new WebSocket(endpoint);
@@ -191,14 +236,12 @@ function connect() {
socket.addEventListener("open", () => {
if (socket !== state.socket)
return;
state.manuallyReconnecting = false;
setConnectionState("online", "通道在线", "等待首个 RGBA 像素帧");
elements.connectionLabel.textContent = "通道在线";
sendEvent("show");
syncViewport();
sendEvent("resize", {width: state.requestedWidth, height: state.requestedHeight});
sendControlSnapshot();
requestFrame();
syncStreamActivity();
});
socket.addEventListener("message", event => {
@@ -207,7 +250,7 @@ function connect() {
try {
drawPixelFrame(event.data);
} catch (error) {
state.framePending = false;
clearFrameRequest();
setConnectionState("offline", "帧协议错误", error.message);
socket.close(1003, "invalid pixel frame");
}
@@ -216,10 +259,10 @@ function connect() {
socket.addEventListener("close", event => {
if (socket !== state.socket)
return;
state.framePending = false;
stopFramePump();
clearFrameRequest();
setConnectionState("offline", "通道离线", event.reason || `WebSocket 已关闭 (${event.code})`);
if (!state.manuallyReconnecting)
state.reconnectTimer = window.setTimeout(connect, 1200);
state.reconnectTimer = window.setTimeout(connect, 1200);
});
socket.addEventListener("error", () => {
@@ -309,9 +352,7 @@ elements.pause.addEventListener("click", () => {
elements.pause.setAttribute("aria-pressed", String(state.paused));
elements.pause.classList.toggle("paused", state.paused);
elements.pauseLabel.textContent = state.paused ? "PAUSED" : "LIVE";
sendEvent(state.paused ? "hide" : "show");
if (!state.paused)
requestFrame();
syncStreamActivity();
});
elements.reconnect.addEventListener("click", connect);
@@ -321,15 +362,11 @@ new ResizeObserver(() => {
resizeFrame = requestAnimationFrame(syncViewport);
}).observe(elements.stage);
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
sendEvent("hide");
} else if (!state.paused) {
sendEvent("show");
requestFrame();
}
document.addEventListener("visibilitychange", syncStreamActivity);
window.addEventListener("beforeunload", () => {
stopFramePump();
sendEvent("hide");
});
window.addEventListener("beforeunload", () => sendEvent("hide"));
syncViewport();
connect();