debug(player): log pause reason and flatten the debug tick

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.
This commit is contained in:
2026-07-30 13:55:06 +02:00
parent 75cd07a5c0
commit a2dbde5492
+28 -9
View File
@@ -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);