From d3f6af831bb264c2ee153a93fa5bf26e7cd31922 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 30 Jul 2026 21:11:59 -0500 Subject: [PATCH] Recover a zone whose video fails, instead of leaving that region black MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL --- .../com/remotedisplay/player/player/ZoneManager.kt | 8 ++++++++ server/player/index.html | 11 ++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/remotedisplay/player/player/ZoneManager.kt b/android/app/src/main/java/com/remotedisplay/player/player/ZoneManager.kt index a1c5e05..7b9c1e1 100644 --- a/android/app/src/main/java/com/remotedisplay/player/player/ZoneManager.kt +++ b/android/app/src/main/java/com/remotedisplay/player/player/ZoneManager.kt @@ -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 diff --git a/server/player/index.html b/server/player/index.html index 896f888..54ef27a 100644 --- a/server/player/index.html +++ b/server/player/index.html @@ -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');