Symptom
On a slow or stalling origin, a sequential-origin session (AetherEngine 6.25.1, tvOS 26.6, Xtream timeshift .ts) never starts: AVPlayer's first /media.m3u8 GET is held for the full 30 s startup wait and the asset load times out (NSURLError -1008 / CoreMedia -12884) even though two segments were already produced and ~12 s of media sat on disk:
[HLSSegmentProducer] seg-0.m4s captured (2336504 B)
[HLSSegmentProducer] #65 ledger seg-1 base=0 itemAxis=6.000s sourceStart=32076.800s planSource=32074.800s drift=2.000s shift=32070.800s
[HLSSegmentProducer] seg-1.m4s captured (2308798 B)
... 30 s later ...
[NativeAVPlayerHost] #8 asset.load(duration) failed: NSURLErrorDomain/-1008 ... underlying=CoreMediaErrorDomain/-12884
[HLSLocalServer] media.m3u8 tail: ... #EXTINF:6.000, / seg0.mp4
[HLSLocalServer] -> 200 /media.m3u8 bytes=176
Cause — two compounding startup costs
- The gate demands 2 published durations, which takes 3 ledger opens.
waitForSequentialStartupSegments reuses LiveEdgePolicy.minStartupSegments = 2, a live sliding-window constant (its doc comment guards against -12888 on a window whose holdback can't fit). On the append-only EVENT playlist a segment's EXTINF only becomes final when the next segment's ledger opens (real duration = nextStart − start), so N published durations require N+1 segment opens: the gate effectively waits for ~3 segments ≈ 12-18 s of media through a possibly-throttled origin. A one-segment EVENT playlist is legal HLS, and this playlist already carries the refresh counter tag that defeats AVPlayer's unchanged-playlist patience — the live rationale does not apply.
- The keyframe-spacing scan spends the origin's prefix before the pump even starts. For the uniform-stride fallback plan,
measureKeyframeSpacing first seeks — a silent no-op on a non-seekable sequential pb — then consumes up to 20 000 packets / 30 s of content from the single byte-0-only connection. Those bytes never reach the pump, so the session starts late and silently drops the archive's first GOP(s). Both field cases ended in max(4.0, measured) = the 4 s floor anyway (measured 0.480 s and 2.000 s), so the scan bought nothing.
Proposed fix (PR follows)
Not proposed: publishing a segment before its successor opens. The append playlist exists because plan-EXTINF lies, published EVENT entries must not mutate, and capture/duration-known already coincide at the earliest knowable moment — the lag is inherent; the fix is to stop demanding two of them before serving.
Symptom
On a slow or stalling origin, a sequential-origin session (AetherEngine 6.25.1, tvOS 26.6, Xtream timeshift
.ts) never starts: AVPlayer's first/media.m3u8GET is held for the full 30 s startup wait and the asset load times out (NSURLError -1008/ CoreMedia-12884) even though two segments were already produced and ~12 s of media sat on disk:Cause — two compounding startup costs
waitForSequentialStartupSegmentsreusesLiveEdgePolicy.minStartupSegments = 2, a live sliding-window constant (its doc comment guards against-12888on a window whose holdback can't fit). On the append-only EVENT playlist a segment's EXTINF only becomes final when the next segment's ledger opens (real duration = nextStart − start), so N published durations require N+1 segment opens: the gate effectively waits for ~3 segments ≈ 12-18 s of media through a possibly-throttled origin. A one-segment EVENT playlist is legal HLS, and this playlist already carries the refresh counter tag that defeats AVPlayer's unchanged-playlist patience — the live rationale does not apply.measureKeyframeSpacingfirst seeks — a silent no-op on a non-seekable sequentialpb— then consumes up to 20 000 packets / 30 s of content from the single byte-0-only connection. Those bytes never reach the pump, so the session starts late and silently drops the archive's first GOP(s). Both field cases ended inmax(4.0, measured)= the 4 s floor anyway (measured 0.480 s and 2.000 s), so the scan bought nothing.Proposed fix (PR follows)
sequentialStartupSegments = 1, leavingLiveEdgePolicyuntouched), and release the held startup GET immediately when the pump dies before publishing anything.Not proposed: publishing a segment before its successor opens. The append playlist exists because plan-EXTINF lies, published EVENT entries must not mutate, and capture/duration-known already coincide at the earliest knowable moment — the lag is inherent; the fix is to stop demanding two of them before serving.