Skip to content

3.3.0

Choose a tag to compare

@superuser404notfound superuser404notfound released this 11 Jun 14:23
· 161 commits to main since this release

Added

Live HLS ingest (HLSLiveIngestReader). A public forward-only IOReader that plays a live HLS upstream directly, no media server in the data path:

try await player.load(
    source: .custom(HLSLiveIngestReader(playlistURL: upstreamM3U8), formatHint: "mpegts"),
    options: LoadOptions(isLive: true, dvrWindowSeconds: 600)
)

It resolves master playlists (highest-BANDWIDTH variant), polls the media playlist, fetches the MPEG-TS segments sequentially, and feeds them to the demuxer as one continuous TS stream; DVR timeshift, scrub previews, and the session-relative timeline work exactly like any other live session. Phase 1 supports unencrypted TS segments: EXT-X-KEY and EXT-X-MAP playlists terminate with a typed HLSIngestError (encryptedNotSupported, unsupportedSegmentFormat, playlistUnreachable, playlistInvalid, ingestStalled) so a host can fall back to a server-mediated URL.

Two timing details that came out of on-device testing and are worth knowing about: the live-edge join is duration-capped (newest segments covering up to 1.5x the upstream target duration), and the local loopback playlist adapts to the upstream's real cadence. Sources whose segments are materially longer than the engine's cut target drop the LL-HLS blocking-reload advertisement and raise TARGETDURATION to the arrival cadence; without that, AVPlayer flags invalid blocking behavior (CoreMediaErrorDomain -15410) and punishes bursty upstreams with deferred starts and periodic stalls.

Live custom sources reach the native loopback. Demuxer.open(reader:) threads isLive into the demuxer options (suppressing the duration-estimate SEEK_END that latched EOF on forward-only readers), and the forward-only-means-software dispatch rule is exempted for live sessions. A live custom source whose pump exits fires the existing liveSourceReset retune surface instead of entering a URL-reopen backoff that cannot succeed for a synthetic custom URL.

Sidecar subtitles with auth headers. selectSidecarSubtitle(url:httpHeaders:) attaches custom HTTP headers to the subtitle fetch and forwards the session's LoadOptions.httpHeaders by default, so subtitles on authenticated hosts (WebDAV and friends) load like the media itself. Requested by @bitxeno in #32.

aetherctl hlsfixture. Local HLS live fixture server: slices a .ts into a sliding live playlist with fault knobs (--master indirection, --discontinuity-at, --slow-refresh, --drop-segment, --encrypted, --fmp4) and a --self-test mode that runs HLSLiveIngestReader against it end to end.

Credits

Thanks @bitxeno for the sidecar-header request with the WebDAV context (#32).