Playback errors drop the viewer back to the list without ever showing the error #7

Closed
opened 2026-08-26 01:53:38 +02:00 by benjamin · 1 comment
Owner

Problem

When playback fails permanently, PlayerController.onPlayerError() gives up after two silent retries and sets errorMessage = "unreachable". Media3 also moves the player to STATE_IDLE on a fatal error.

hasMedia is mediaItemCount > 0 && playbackState != STATE_IDLE, so it becomes false. AppState.syncFromPlayer() then hides the player:

if (!player.hasMedia && playerVisible) {
    playerVisible = false
    currentChannel = null
}

The overlay would have rendered "Wiedergabefehler" — but the whole player screen is gone by then, so that text never appears on the TV. The error only reaches the phone remote via currentStatus().

Failure scenario

A family member picks a channel whose stream is dead. The screen goes black for a moment, then silently returns to the channel list with no explanation. Nothing says what happened or what to do — precisely the "self-healing, plain language" behaviour the app is supposed to have (issue #13 of the original set).

Suggested fix

  • Keep the player visible while errorMessage != null and show a plain-language message with one action ("Erneut versuchen")
  • Or route the failure into the existing AppError fullscreen state, which already has the right tone and a retry path
  • Clear the error and re-prepare() when the user retries, since the player does not recover on its own

Found by multi-agent code review; verified against current PlayerController.kt and AppState.kt.

## Problem When playback fails permanently, `PlayerController.onPlayerError()` gives up after two silent retries and sets `errorMessage = "unreachable"`. Media3 also moves the player to `STATE_IDLE` on a fatal error. `hasMedia` is `mediaItemCount > 0 && playbackState != STATE_IDLE`, so it becomes `false`. `AppState.syncFromPlayer()` then hides the player: ```kotlin if (!player.hasMedia && playerVisible) { playerVisible = false currentChannel = null } ``` The overlay would have rendered "Wiedergabefehler" — but the whole player screen is gone by then, so that text never appears on the TV. The error only reaches the phone remote via `currentStatus()`. ## Failure scenario A family member picks a channel whose stream is dead. The screen goes black for a moment, then silently returns to the channel list with no explanation. Nothing says what happened or what to do — precisely the "self-healing, plain language" behaviour the app is supposed to have (issue #13 of the original set). ## Suggested fix - Keep the player visible while `errorMessage != null` and show a plain-language message with one action ("Erneut versuchen") - Or route the failure into the existing `AppError` fullscreen state, which already has the right tone and a retry path - Clear the error and re-`prepare()` when the user retries, since the player does not recover on its own Found by multi-agent code review; verified against current `PlayerController.kt` and `AppState.kt`.
Author
Owner

Fixed in dd612fc, shipped in v0.9.0.

  • AppState.syncFromPlayer() only hides the player when there is neither an error nor a pending reconnect, so a failure no longer drops the viewer back to the list.
  • The overlay is forced visible in that state and says "Sender gerade nicht erreichbar" (or "Verbindung wird wiederhergestellt…" while retries are running).
  • The transport row swaps its buttons for a focused Erneut versuchen next to Beenden. retryNow() clears the error, resets the backoff and re-prepare()s — the player does not recover on its own, so this is the path back.

Together with the spaced retries from #12 the sequence is now: drop → three quiet attempts with a visible hint → a plain-language message with one action.

Fixed in dd612fc, shipped in v0.9.0. - `AppState.syncFromPlayer()` only hides the player when there is neither an error nor a pending reconnect, so a failure no longer drops the viewer back to the list. - The overlay is forced visible in that state and says "Sender gerade nicht erreichbar" (or "Verbindung wird wiederhergestellt…" while retries are running). - The transport row swaps its buttons for a focused **Erneut versuchen** next to Beenden. `retryNow()` clears the error, resets the backoff and re-`prepare()`s — the player does not recover on its own, so this is the path back. Together with the spaced retries from #12 the sequence is now: drop → three quiet attempts with a visible hint → a plain-language message with one action.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: be-nj/castarr#7