From a2dbde549222d1f91296ebfbe634394ca9283885 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Thu, 30 Jul 2026 13:55:06 +0200 Subject: [PATCH] debug(player): log pause reason and flatten the debug tick MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An unexplained pause/resume loop was invisible over adb: handlePause logged nothing at all, so only the "playing" half of each cycle showed up, and the 1s debug tick logged an object — which the Android WebView console bridge renders as "[object Object]", discarding every field. Log the element state on pause (readyState, networkState, seeking, ended, plus the component's own isSeeking/isBuffering/handoff flags) and emit the debug tick as a flat string. This is what identified DR-097: the element was fully buffered and healthy at every pause, ruling out a stall and pointing at a competing controller instead. --- src/lib/components/player/VideoPlayer.svelte | 37 +++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/lib/components/player/VideoPlayer.svelte b/src/lib/components/player/VideoPlayer.svelte index 6ac710ea..143e7ed0 100644 --- a/src/lib/components/player/VideoPlayer.svelte +++ b/src/lib/components/player/VideoPlayer.svelte @@ -686,15 +686,19 @@ bufferedRanges.push(`[${buffered.start(i).toFixed(1)} - ${buffered.end(i).toFixed(1)}]`); } - console.log("[VideoPlayer Debug]", { - currentTime: videoElement.currentTime.toFixed(2), - displayTime: currentTime.toFixed(2), - buffered: bufferedRanges.join(", "), - readyState: videoElement.readyState, - paused: videoElement.paused, - seeking: videoElement.seeking, - playbackRate: videoElement.playbackRate, - }); + // Flattened to a single string on purpose: the Android WebView console + // bridge stringifies objects as "[object Object]" in logcat, which made + // this whole payload useless when diagnosing over adb. + console.log( + `[VideoPlayer Debug] t=${videoElement.currentTime.toFixed(2)}` + + ` display=${currentTime.toFixed(2)}` + + ` readyState=${videoElement.readyState}` + + ` networkState=${videoElement.networkState}` + + ` paused=${videoElement.paused}` + + ` seeking=${videoElement.seeking}` + + ` rate=${videoElement.playbackRate}` + + ` buffered=${bufferedRanges.join(", ")}` + ); } }, 1000); }); @@ -1101,6 +1105,21 @@ } function handlePause() { + // The element pausing is normally user intent, but a stall, a source change, + // or a competing controller can also do it — and the pause itself carries no + // reason. Log the element state so an unexplained pause/resume loop can be + // attributed from an adb capture instead of guessed at. + const el = videoElement; + console.log( + `[VideoPlayer] pause event — t=${el ? el.currentTime.toFixed(2) : "?"}` + + ` readyState=${el?.readyState}` + + ` networkState=${el?.networkState}` + + ` seeking=${el?.seeking}` + + ` ended=${el?.ended}` + + ` isSeeking=${isSeeking}` + + ` isBuffering=${isBuffering}` + + ` handoff=${handoffState.active}` + ); isPlaying = false; stopTimeUpdates(); // Stop RAF loop when paused html5Adapter.reportState("paused", reportMediaId ?? null);