summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/video-player.js43
1 files changed, 43 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js
index 78760d8..0c0c6c7 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/video-player.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/video-player.js
@@ -164,6 +164,10 @@ function VideoPlayer({ entry, transportRef, gekRef, onClose, onDownload }) {
const castDeviceRef = useRef(null);
const castRestartGenRef = useRef(0);
const landingPlayheadRef = useRef(false);
+ // The current Screen Wake Lock sentinel, if the browser granted one — see
+ // the effect below. Null on any platform/context that does not support it,
+ // which playback has never depended on.
+ const wakeLockRef = useRef(null);
/**
* The buffered range the playhead is actually in, or null.
@@ -780,11 +784,49 @@ function VideoPlayer({ entry, transportRef, gekRef, onClose, onDownload }) {
if (t && t.connected) t.stopStream();
};
const onPageHide = () => leave('pagehide');
+
+ // Screen Wake Lock: keeps the display on while this page is open and
+ // visible, purely so the phone stops auto-locking mid-film on its own
+ // idle timer — the commonest real-world trigger for the WebRTC-drop
+ // recovery above, and the one case it can sidestep entirely rather than
+ // recover from. Unrelated to streaming/transport in every direction:
+ // requesting, holding, or losing this lock touches no DataChannel, no
+ // SourceBuffer, no playback state, so it cannot itself cause a stall or
+ // a regression in the existing pipeline. It also does nothing at all on
+ // a phone the user locks with the power button, or once the tab is
+ // backgrounded (the spec releases it automatically) — the reconnect path
+ // above is still the one that has to handle those.
+ const releaseWakeLock = () => {
+ const wl = wakeLockRef.current;
+ wakeLockRef.current = null;
+ if (wl) { try { wl.release(); } catch { /* already released */ } }
+ };
+ const acquireWakeLock = async () => {
+ if (!('wakeLock' in navigator)) return;
+ try {
+ const wl = await navigator.wakeLock.request('screen');
+ // The effect may have torn down while this was in flight.
+ if (cancelled) { try { wl.release(); } catch { /* ignore */ } return; }
+ wakeLockRef.current = wl;
+ wl.addEventListener('release', () => { wakeLockRef.current = null; });
+ } catch (e) {
+ // Battery saver, no permission, an insecure context — playback has
+ // never depended on this, so there is nothing to fall back to.
+ console.warn('[MeshBay] Wake lock request failed:', e.message);
+ }
+ };
+ acquireWakeLock();
+
// NOT wired to stopStream. Android fires visibilitychange when a video goes
// fullscreen, so cutting the stream here killed the film the moment it was
// watched properly. Logged only, until that is confirmed or ruled out.
const onVisibility = () => {
console.log('[MeshBay] visibilitychange:', document.visibilityState);
+ // The lock is released automatically the moment the page goes hidden
+ // (spec behaviour, not something to undo) — re-requesting it here is
+ // what makes it hold again once the film is actually back on screen,
+ // including the fullscreen transition this handler already exists for.
+ if (document.visibilityState === 'visible') acquireWakeLock();
};
window.addEventListener('pagehide', onPageHide);
document.addEventListener('visibilitychange', onVisibility);
@@ -838,6 +880,7 @@ function VideoPlayer({ entry, transportRef, gekRef, onClose, onDownload }) {
clearInterval(pumpTimer);
clearInterval(diagTimer);
clearTimeout(seekTimerRef.current);
+ releaseWakeLock();
// Closing the player is the commonest way to stop watching, so this is
// the write that matters most.
if (videoRef.current) {