fix(video): sequential EVENT startup - serve from the first finalized segment, skip the spacing scan (#370) - #373
Conversation
…d segment (superuser404notfound#370) The startup gate reused LiveEdgePolicy.minStartupSegments = 2, a sliding-window constant whose -12888 rationale does not apply to an append-only EVENT playlist (media sequence 0, refresh counter already defeats the unchanged-playlist patience). Because a sequential duration is only final when the NEXT segment's ledger opens, demanding 2 durations really demanded 3 segment opens (~12-18 s of media) before AVPlayer's held playlist GET was answered; on a stalling origin the GET sat out the full 30 s and the asset load died on -12884 with ~12 s of media already on disk. A one-segment EVENT playlist is legal HLS. The publish lag itself stays: a segment's real EXTINF is nextStart - start, published EVENT entries must not mutate, and capture and duration-known already coincide at the earliest knowable moment - the fix is to stop demanding two of them, not to publish provisional durations. A pump that dies before publishing anything now also releases a held startup GET immediately (abortSequentialStartupWait) instead of letting the server thread sit out the rest of its timeout while the session is already surfacing failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…he spacing scan (superuser404notfound#370) measureKeyframeSpacing starts with a seek - a silent no-op on the non-seekable sequential pb - and then consumes up to 20000 packets / 30 s of content from the single byte-0-only connection. Those packets never reach the pump, so the session both started late and silently dropped the archive's first GOP(s); in both field traces the measured spacing (0.48 s, 2.0 s) fell below the 4 s floor anyway, so the scan bought nothing. Sequential plans now go straight to the target stride. The superuser404notfound#358 holes the scan exists to soften don't bite this path: the append playlist gives zero-duration holes no URI and its EXTINF is real by construction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
d619d6b
into
superuser404notfound:main
|
Merged as d619d6b. Thanks for this one, and in particular for the trace that makes both costs legible: the #65 ledger lines are what turn "2 published durations" into a measurable 3 segment opens, and the served tail (one EXTINF after the full 30 s hold) is the direct witness that the constant was the gate. Two things pulled in afterwards, in 244de44: The release now belongs to the failure surface. The gate counts advertisable entries. Two things that held up on re-reading, worth recording here: the plan-side skip costs nothing in cut geometry, because cuts are keyframe-gated either way, so a stride below the GOP yields the same segments and only leaves index holes the append playlist already renders away. And since Full suite green on the merged tree (1845 Swift Testing tests, 268 suites). Unreleased so far; the issue stays open for the device retest against the next tagged build. |
Fixes #370. Two startup costs that together kept a sequential-origin session from ever starting on a slow or stalling origin — AVPlayer's first playlist GET was held the full 30 s and the asset load died on
-1008/CoreMedia-12884while ~12 s of media already sat on disk.Commit 1: serve the EVENT playlist from its first finalized segment
waitForSequentialStartupSegmentsreusedLiveEdgePolicy.minStartupSegments = 2, a sliding-window constant whose-12888rationale (a 1-segment live window with holdback that can't fit) does not apply to an append-only EVENT playlist: it starts at media sequence 0, grows monotonically, and#EXT-X-SODALITE-REFRESHalready defeats the unchanged-playlist patience. The demand was also steeper than it looks: a sequential duration is only final when the NEXT segment's ledger opens (real EXTINF = nextStart − start), so "2 published durations" meant 3 segment opens ≈ 12-18 s of media through the origin. The gate is nowsequentialStartupSegments = 1on the provider (LiveEdgePolicyuntouched — its constant stays correct for live).The publish lag itself stays, deliberately: published EVENT entries must not mutate, and capture / duration-known already coincide at the earliest knowable moment — the fix is to stop demanding two of them, not to publish provisional durations that would need correcting.
Also: a pump that dies before publishing anything now releases a held startup GET immediately (
abortSequentialStartupWait, called from both fatal VOD surfaces) instead of letting the server thread sit out the rest of its timeout while the session is already surfacing failure.Commit 2: plan without spending the origin's prefix on the spacing scan
For the uniform-stride fallback plan,
measureKeyframeSpacingstarts with a seek — a silent no-op on the non-seekable sequential pb — and then consumes up to 20000 packets / 30 s of content from the single byte-0-only connection. Those packets never reach the pump, so the session both started late and silently dropped the archive's first GOP(s). In both field traces the measurement (0.48 s and 2.0 s) fell below the 4 s floor anyway, so the scan bought nothing. Sequential plans now go straight to the target stride; the #358 holes the scan exists to soften don't bite this path, because the append playlist gives zero-duration holes no URI and its EXTINF is real by construction. Live and seekable VOD keep the scan.Tests
SequentialAppendPlaylistTests: one finalized segment releases the gate; an empty session still times out; EOF with zero segments still releases (the ENDLIST arm); an aborted wait returns immediately instead of sitting out its timeout.Test plan
swift test(full suite, counts above).Fully independent of the #368/#369 PRs; the three-way combination is integration-tested locally (full suite green on the merged tree).