6.20.0 - A segment grid the source's keyframes can actually open
Drop-in from 6.19.4. No API changes; the segment plan for one class of source is cut differently, which is why this is a minor.
A grid the source's keyframes can actually open
Since 4.8.0 the VOD cutter has been keyframe-gated (#92): a segment opens at the IRAP that reaches its plan boundary, so every segment starts on a clean random-access point. What that change did not carry is its own consequence. EXTINF still comes from the plan, so when a boundary has no IRAP to open it, the cutter steps over that index while the playlist keeps offering it. The consumer fetches it, the serve rides out the slow threshold, sends the early chunked header, has nothing for the body and closes for a retry that meets the same nothing. Forever.
The uniform fallback grid walked into this by construction: a fixed 4 s stride over a 10 s GOP has two boundaries in three with no IRAP anywhere near them. The comment above buildSegmentedSourcePlan has said so since #268 ("the uniform grid advertises boundaries no keyframe sits on ... until AVPlayer starves"); #268 fixed it only for sources that declare their own boundaries, which a local MPEG-TS does not.
The stride is now measured, not assumed. The scan reads the distance between the first two IRAPs from the bitstream, bounded to 30 s of content, only on the fallback path, and never for live. The index cannot answer this question: it is untrustworthy by the time this path runs, and the 10 s-GOP TS used to reproduce it indexed 1.400, 59.960, 60.000, 60.280, 121.360, whose smallest gap (0.04 s) and largest (58.6 s) miss the real spacing by an order of magnitude in opposite directions.
before: uniform stride fallback (index unusable ...)
ledger seg-0, seg-2, seg-5, seg-7, seg-10 ... GET /seg1 never completes
after: uniform stride fallback (..., measured IRAP spacing 10.000s -> stride=10.000s, 12 segments)
ledger seg-0 .. seg-11 contiguous, every drift 0.000
A gap is repaired or fails, never waited out
The rest of the class stays reachable: a keyframe index that passes the trust check and still misdescribes the bitstream, or a GOP longer than the scan budget. For those, a hole must not be a session that freezes in silence.
The cut now records the plan indices it jumped, in the segment cache rather than on the producer, because a restart rebuilds the producer and the repeat across restarts is the entire signal.
- First fold: re-anchor the producer at that index. Boundaries move with the base, so the index can open, and on a 40 s-GOP source against the 30 s grid it does: the run goes from a clock frozen at 90.00 s to playing through the whole title.
- Second fold: the repair reproduced its own trigger, so
onVODSourceFailedfires instead of another attempt. - A retry arriving while the repair is in flight waits;
adoptclears the record when the index lands.
This also fixes where the decision lives. The backpressure wedge handler never saw these sessions at all: with the pump finished, nothing is parked, so the detector does not fire. The provider sees every request before the wait.
Live is untouched throughout. Its playlist is built from what was finalized, so it never offers an index the pump skipped.
Reported by @DrHurt through AetherPlayer#2, tracked in #358, which stays open for the trusted-index-that-lies half.