DUNGEONS-34: keep host screen awake while streaming
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
62
frontend/utils/screenWakeLock.ts
Normal file
62
frontend/utils/screenWakeLock.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
export type WakeStatus = "off" | "waiting" | "requesting" | "active" | "unavailable" | "unsupported";
|
||||
type Sentinel = Pick<WakeLockSentinel, "released" | "release" | "addEventListener">;
|
||||
|
||||
// Browser access is injected so asynchronous acquisition and release can be tested.
|
||||
export function createScreenWakeLock(options: {
|
||||
request?: () => Promise<Sentinel>;
|
||||
visible: () => boolean;
|
||||
status: (value: WakeStatus) => void;
|
||||
}) {
|
||||
let desired = false;
|
||||
let disposed = false;
|
||||
let pending = false;
|
||||
let generation = 0;
|
||||
let lock: Sentinel | null = null;
|
||||
const report = (value: WakeStatus) => { if (!disposed) options.status(value); };
|
||||
const wanted = () => desired && !disposed && options.visible();
|
||||
function release() {
|
||||
generation++;
|
||||
const old = lock;
|
||||
lock = null;
|
||||
if (old) void old.release().catch(() => {});
|
||||
}
|
||||
async function sync() {
|
||||
if (!wanted()) {
|
||||
release();
|
||||
report(desired ? "waiting" : "off");
|
||||
return;
|
||||
}
|
||||
if (!options.request) { report("unsupported"); return; }
|
||||
if (lock && !lock.released) { report("active"); return; }
|
||||
if (pending) return;
|
||||
pending = true;
|
||||
const version = generation;
|
||||
report("requesting");
|
||||
try {
|
||||
const acquired = await options.request();
|
||||
if (version !== generation || !wanted()) {
|
||||
await acquired.release();
|
||||
return;
|
||||
}
|
||||
lock = acquired;
|
||||
acquired.addEventListener("release", () => {
|
||||
if (lock !== acquired) return;
|
||||
lock = null;
|
||||
// Do not repeatedly fight a system/battery decision to revoke the lock.
|
||||
report(wanted() ? "unavailable" : desired ? "waiting" : "off");
|
||||
}, { once: true });
|
||||
report(acquired.released ? "unavailable" : "active");
|
||||
} catch {
|
||||
if (version === generation && wanted()) report("unavailable");
|
||||
} finally {
|
||||
pending = false;
|
||||
// An off/on or hidden/visible transition may have invalidated a pending request.
|
||||
if (version !== generation && wanted()) void sync();
|
||||
}
|
||||
}
|
||||
return {
|
||||
update(enabled: boolean) { desired = enabled; void sync(); },
|
||||
refresh() { void sync(); },
|
||||
dispose() { disposed = true; desired = false; release(); },
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user