Skip to content

3.4.0 — Live direct play: demuxed + packed audio, rejoin-at-edge reloads

Choose a tag to compare

@superuser404notfound superuser404notfound released this 12 Jun 10:43
· 133 commits to main since this release

Live TV release: live HLS upstreams with separate or packed audio renditions now direct-play, and live sessions survive reloads and flaky playlist origins. Built against real broadcast streams (ARD Das Erste 1080p50, device-verified on tvOS 26).

Added

Demuxed-audio HLS direct play

Many broadcasters publish video-only variants with the audio in a separate EXT-X-MEDIA rendition playlist. 3.3.0 detected this shape and failed fast; 3.4.0 plays it:

  • HLSLiveIngestReader resolves the variant's audio group and spawns a companion rendition reader for the audio playlist.
  • A side demuxer opens the audio stream, and HLSSegmentProducer pull-merges both sources by DTS onto one output timeline (audio gated on video so the first cut segment is A/V aligned).
  • The fail-fast from 3.3.0 remains for shapes the ingest cannot handle (encrypted, fMP4), so hosts keep their typed fallback.

Packed-audio renditions

Audio playlists that carry raw ADTS segments (no TS wrapper) framed by ID3 PRIV timestamps (com.apple.streaming.transportStreamTimestamp, 90 kHz) are classified per segment and wrapped on the fly (PackedAudioSegments), with a synthesized clock aligning them to the video timeline.

Live playlist-refresh retry

Transient playlist-refresh failures (CDN hiccup, origin restart) retry inside a bounded ~12 s budget before the ingest goes terminal. A single dropped poll no longer ends the session.

Fixed

Live reloads rejoin at the live edge

An audio-track switch (or any engine reload) on a live session used to re-apply a stale resume position against an origin that re-serves its full transcode backlog on reconnect (Jellyfin does), which could park AVPlayer in waitingToPlay indefinitely. Device-verified failure case on tvOS 26.

  • Reload positioning is now policy-driven (LiveReloadPolicy, pure and unit-tested): live rejoins take the playlist's own live-edge join, never a stale clock, and skip the pre-readiness zero seek.
  • A readiness watchdog (10 s budget from first serving evidence, 60 s lifetime) fails a wedged rejoin cleanly into the host's retune surface instead of hanging the session.

Swallowed play intent on the reused AVPlayer host

A play() issued while replaceCurrentItem was mid-swap could be silently dropped: the item reached readyToPlay but stayed paused forever. The host now latches the play intent and re-asserts it at readyToPlay (cleared on pause/unload), preserving the existing reuse gate.

Published audio index after a live reload

The engine reconciles the published audio-track selection with what the rebuilt pipeline actually plays, so hosts no longer observe a phantom track switch after a reload.

Tooling

  • aetherctl live --reload-test exercises the live rejoin end to end against the built-in fixture, including the full-backlog replay shape that reproduced the device failure.

Compatibility

No breaking API changes. New public surface: demuxed/packed-audio ingest is automatic inside HLSLiveIngestReader; LoadOptions gains the live-rejoin discriminator used by reloads. Pin from: "3.4.0".