LiveStreamPlayerState

sealed interface LiveStreamPlayerState(source)

Pure description of what the live player should display right now. Computed from the latest LiveStream + LiveStreamPlayData snapshot plus the wall clock — no Android types, no coroutines, no mutable state. Lives here so we can unit-test the entire web-player decision tree without spinning up a player.

The branches mirror Bunny's web player:

  • Loading — first poll hasn't returned yet.

  • Offline — one of "Live stream not active", "Live stream ended", "Live stream error", with a reason tag so the UI can render the right copy.

  • Countdown — Scheduled stream with enableCountdown == true and a future scheduledStartTime. UI ticks the timer locally; transition to playback is driven by the poll, not by the timer hitting zero.

  • Trailer — Pre-stream trailer loop. Only when preStreamTrailerVideoId is set, the stream hasn't started (startedAt == null, status in {Created, Scheduled, Error}), and we've already resolved the trailer's HLS URL.

  • LivePlay — Stream is Running. Play hlsUrl.

  • VodPlay — Stream is Ended or VodProcessing AND recordVod == true AND a playable URL is available.

Note that the state resolver does not read LiveStreamPlayData.videoPlaylistUrl directly — the caller is responsible for picking the right URL (videoPlaylistUrl > fallbackUrl > playbackUrlHls) and passing it in. This keeps the resolver decoupled from URL-priority bugs.

Inheritors

Types

Link copied to clipboard
data class Countdown(val targetEpochMs: Long, val title: String = "", val posterUrl: String? = null, val trailerUrl: String? = null) : LiveStreamPlayerState

Scheduled stream with a live countdown. Carries the title and the background to render behind the timer, mirroring the web player: when a pre-stream trailer is configured and resolved, trailerUrl is set and the overlay loops that video (muted) behind the countdown; otherwise it falls back to the blurred posterUrl thumbnail. The overlay shows "{title} will start in" above a large day/hour/minute/second timer in both cases.

Link copied to clipboard
data class LivePlay(val hlsUrl: String, val dvrEnabled: Boolean = false) : LiveStreamPlayerState

Stream is Running. Play hlsUrl. dvrEnabled mirrors the stream's DVR setting: a DVR live stream shows a seekable timeline (+ jump-to-live); a non-DVR one hides the VOD-style timeline and time counter (its window-relative position is meaningless), leaving just the LIVE badge.

Link copied to clipboard
Link copied to clipboard
data class Offline(val reason: LiveStreamPlayerState.OfflineReason, val posterUrl: String? = null) : LiveStreamPlayerState

Stream isn't playing. posterUrl is the stream's thumbnail (when available), rendered behind the status message so the thumbnail stays visible before a live stream starts — mirroring the web player's poster.

Link copied to clipboard
data class Trailer(val hlsUrl: String) : LiveStreamPlayerState
Link copied to clipboard
data class VodPlay(val hlsUrl: String) : LiveStreamPlayerState