修复了一些bug
This commit is contained in:
+67
-30
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user