Recover a zone whose video fails, instead of leaving that region black

In a multi-zone layout a zone's video advanced only on `ended`. On the web there was no error
handler and — alone among the zone branches, which all arm a timer — no timer either. On Android the
zone player listened for STATE_ENDED with no error listener and no fallback.

A playback error lands in STATE_IDLE, never STATE_ENDED, so nothing advanced. A 404, an unreachable
remote_url, a clip the device cannot decode, or content not yet cached while the device is offline
(the zone then falls back to the server URL, which fails with no network) all had the same result:
that region of the screen went black and stayed black for days, while every other zone kept rotating
normally. It reads as a rendering bug rather than a bad file, and nothing self-heals — the layout has
to change or the app has to restart.

Both fixes already existed elsewhere and were simply not carried across. MediaPlayerManager treats a
playback error as a completion for exactly this reason ("Root-2: a corrupt/undecodable video used to
freeze the playlist forever"), the fullscreen web path has both an onerror and a timer, and Tizen's
ZoneRenderer has an onerror plus a duration+5s safety net. The multi-zone paths were the gap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
This commit is contained in:
Claude 2026-07-30 21:11:59 -05:00
parent f66c941c1d
commit d3f6af831b
2 changed files with 18 additions and 1 deletions

View file

@ -252,6 +252,14 @@ class ZoneManager(
override fun onPlaybackStateChanged(state: Int) {
if (state == Player.STATE_ENDED) handler.post { advance() }
}
// Same reason MediaPlayerManager treats a playback error as a completion
// ("Root-2: a corrupt/undecodable video used to freeze the playlist
// forever"): an error lands in STATE_IDLE, never STATE_ENDED, so without
// this the zone stops rotating and goes black until the layout changes or
// the app restarts — while every other zone keeps going.
override fun onPlayerError(error: androidx.media3.common.PlaybackException) {
handler.post { advance() }
}
})
prepare()
playWhenReady = true

View file

@ -3091,7 +3091,16 @@
video.loop = !multi; // single-item zone loops; multi advances on end
video.playsInline = true;
video.style.cssText = `width:100%;height:100%;object-fit:${zone.fit_mode || 'cover'}`;
if (multi) video.onended = advance;
if (multi) {
video.onended = advance;
// A zone video advanced ONLY on `ended`, with no error handler and — alone among the zone
// branches — no timer either. A 404, an unreachable remote_url, an undecodable clip, or an
// `ended` that simply never fires left that region black for days while the other zones
// kept rotating: the screen looks half broken and nothing self-heals. The fullscreen web
// path and Tizen's ZoneRenderer both already carry these two guards.
video.onerror = advance;
zoneTimers[zone.id] = setTimeout(advance, dur + 5000);
}
div.appendChild(video);
} else {
const img = document.createElement('img');