Skip to content

AetherEngine 5.18.5

Choose a tag to compare

@superuser404notfound superuser404notfound released this 22 Jul 06:27

Fixed

Long-GOP live restarts inside AVPlayer's stall-danger zone at startup (#189)

A 4K50 HEVC-in-MPEG-TS stream routed onto the live-ingest loopback (the #168 reroute) cuts keyframe-aligned segments of ~4.8-5.76 s, so the served EXT-X-TARGETDURATION is 6. The media playlist advertised no explicit EXT-X-SERVER-CONTROL:HOLD-BACK, so AVPlayer fell back to its implicit live-edge holdback of 3 x TARGETDURATION (~18 s) and tried to begin playback that far behind the live edge, while the fixed two-segment startup cushion built only ~9.6 s of content:

-16832 restarting 9.600000s from end of live playlist; target duration 6s - stall danger

Root cause. The startup cushion was a fixed segment count (2), decoupled from the holdback AVPlayer computes from TARGETDURATION. For long-GOP segments the two-segment window (~9.6 s) is thinner than the 3 x TARGETDURATION (~18 s) holdback, so AVPlayer's initial seek to edge-minus-holdback lands inside the window's stall-danger region and it restarts in a loop, rebuffering on every channel open until the real-time window naturally deepens past the holdback. The served TARGETDURATION was correct all along (TD=6); the driver is the holdback, not TARGETDURATION.

Fix. The loopback now advertises HOLD-BACK explicitly at the RFC 8216bis floor (3 x TARGETDURATION, which is also AVPlayer's implicit default made explicit), merged onto a single EXT-X-SERVER-CONTROL line alongside CAN-BLOCK-RELOAD. The startup gate holds the first manifest until the window carries at least that holdback depth (bounded above by the sliding-window size and the existing startup deadline), so AVPlayer's live-edge seek always lands inside real content. Both the served playlist and the startup cushion derive TARGETDURATION through one shared LiveEdgePolicy, so the depth built can never drift from the holdback advertised.

HOLD-BACK must be at least 3 x TARGETDURATION per RFC 8216bis 4.4.3.8, so advertising a smaller value to match a thin cushion is not an option; the cushion is deepened to the holdback instead. Sources that arrive with a backlog (a Jellyfin transcode, or an upstream live window pulled at I/O speed) satisfy the gate almost immediately; only a strict-real-time origin pays the deepen-the-buffer latency, which is inherent to joining long-GOP live without stalling.

Covered by the new Issue189LiveEdgeHoldbackTests suite: TARGETDURATION / holdback / cushion decisions plus the served-playlist HOLD-BACK emission on a single combined SERVER-CONTROL line.

Acknowledgements

Root-caused with field-verified diagnostics (confirmed the holdback mechanism on 5.18.3, retracting the earlier TARGETDURATION framing) by kskchaitanya1993 (#189).

Full test suite: 942/942. macOS, iOS Simulator, and tvOS Simulator builds green.