BunnyLiveStreamPlayerViewModel
Backing view model for BunnyLiveStreamPlayer. Owns the polling loop, the play-data fetches, and the trailer fetch — exposes a single StateFlow of LiveStreamPlayerState for the UI to consume. Mirrors the behaviour of Bunny's web player.
Responsibilities, in order of execution:
start kicks off an initial fetchPlayData (carries stream snapshot + playable URL) and, if the snapshot warrants it, an async fetchTrailerUrl. Starts the 5s poll loop.
The poll loop calls LiveStreamRepository.pollLiveStream every 5 s — lightweight, returns only the stream snapshot, no play-data. In-flight guard prevents overlapping requests.
Whenever the snapshot status transitions to a state that needs a URL we don't have yet (Running with no live URL; Ended/VodProcessing+recordVod with no VOD URL), the view model re-fetches play-data to pick up the new URL. We avoid re-fetching on every poll because play-data is the heavier endpoint.
Lifecycle: onForeground fires one immediate poll then resumes the 5s cadence; onBackground cancels the loop. Terminal failure (
401/403/404/410) stops polling permanently per the spec.
The class deliberately does not own any Android Context, ExoPlayer, or View — those live in the composable. This keeps it unit-testable on the JVM with a fake LiveStreamRepository.
Properties
Functions
Called by the UI on lifecycle pause. Cancels the poll loop. The current state is preserved so the UI keeps rendering what it had.
Called by the UI on lifecycle resume. Per spec: fire one immediate poll, then resume the 5 s cadence. If polling has already been permanently stopped (terminal failure), this is a no-op.
Called by the playback surface when the live player errors mid-play (network drop, falling behind the live window, stale segment URLs). Mirrors the iOS player's recovery: re-poll the status and refresh play-data immediately; if the stream is still live afterwards, bump playerRebuildToken so the surface rebuilds the player from the live edge even when the URL didn't change. If the status flipped (offline/ended), state re-routes the UI instead.
Initialise the view model. Idempotent; subsequent calls with the same streamId are ignored. Must be called before onForeground / onBackground.
Forces a state recomputation. Used by the countdown UI on each tick so an expiring scheduledStartTime flips to "Starting soon…" without waiting for a poll.