Skip to content

4.2.2 — loopback-HLS VOD scrub-burst livelock fix (#65)

Choose a tag to compare

@superuser404notfound superuser404notfound released this 26 Jun 06:02

Fixed

Loopback-HLS VOD scrub-burst livelock (#65)

A sustained bidirectional scrub burst on the native (loopback-HLS) direct-play path could deadlock playback. The on-screen picture froze 30 to 40 seconds behind the reported clock and never recovered.

Root cause (two coupled halves, no recovery floor):

  • Engine clock latch. A native VOD seek published an optimistic clock target up front, then awaited AVPlayer's landing with no timeout. The only path that pulls the clock back to AVPlayer's real position is gated off while a seek is in flight, and that gate only clears on the winning seek's completion. If AVPlayer could never land (because the producer was starved, below), the clock stayed pinned at the unreachable target and isSeeking never cleared.
  • Producer backpressure park. The segment producer parks once it is a fixed number of segments ahead of AVPlayer's fetch high-water, which only advances when AVPlayer requests a forward segment. While AVPlayer was wedged it issued no forward request, so the park never released, and unlike the live paths the VOD pump had no watchdog to break it.

Each half waited on the other.

Fix (defense in depth):

  • The native VOD seek await is now bounded by a cadence budget. When a seek does not land within it and AVPlayer is genuinely starved (no forward buffer at its rendered position), the engine reconciles its clock to AVPlayer's real rendered position instead of the unreachable target, hands playback state back to AVPlayer's actual transport status, and re-anchors the producer there. A slow-but-buffering seek still awaits its real landing exactly as before, preserving the established seek-landing behavior (#37 / #38 / #49).
  • The VOD backpressure park gains the watchdog the live paths always had. A consumer fetch target frozen past a break threshold exits the pump and re-anchors the producer on AVPlayer's real (lagging) position through the existing burst-restart coalescer. A slow-but-advancing consumer never trips the detector, and a storm guard bounds re-anchors if AVPlayer never resumes.

Both halves deliberately anchor on AVPlayer's real position, not the engine's forward optimistic target.

Testing: new unit tests cover the wedge detector and the starvation predicate; aetherctl seektest now reports the wedge-break / re-anchor / reconcile recovery signals. 164 tests pass, strict-concurrency clean.

Thanks to rrgomes for the frame-exact trace that pinned the root cause.

Full diff: 4.2.1...4.2.2