6.1.1 - Off-main demuxer reposition
A main-thread fix on the software playback path. Anyone shipping the software path against remote sources wants this one.
Fixed
-
A seek on the software path no longer blocks the main thread for the length of a network read.
SoftwarePlaybackHostis@MainActorand ran the demuxer reposition inline, with no suspension point between the generation bump and the FFmpeg call.Demuxer.readPacketholds the demuxer's access lock across the whole ofav_read_frame, so a seek issued while the demux loop sat in a slow remote read waited that read out on the main thread, up to the 20 s connection-stall timeout. The field saw two App Hangs, "Fully Blocked", 4.4 s and 5.2 s, on a WAN source over a scrub burst. Reported by rrgomes from two production crash-reporter events (#254).Worth stating because it inverts the obvious fix: the existing
seekBoundeddeadline could not have prevented either hang, since it is armed after the lock, on the far side of the wait that actually blocked. Off-main is the fix; the deadline is a second, latent hazard that now also closes.The reposition runs on a caller-owned serial queue under an 8 s read deadline, and its supersede check is evaluated on that queue immediately before the FFmpeg call, so a burst of scrubs collapses onto its last target instead of paying one lock wait per seek. The same inline call sat in both hosts'
startPositionresume, so this covers every resume into a remote source, not only scrubbing.AudioPlaybackHostcarried the identical shape and is fixed with it.HLSVideoEngineand the #232 interlace probe share the unbounded-seek property but not the main thread (@unchecked Sendableand an already-detached task respectively) and are unchanged.
Changed
-
A software-path seek that spends its budget now reports
.stalledinstead of a landing. TheseekEventsstream added in 6.1.0 closed these tickets as.landedunconditionally. A reposition that exhausted its read deadline left the read position undefined, and nothing on that path re-issues it, unlike the native recovery loop whose ticket deliberately stays open because AVPlayer keeps aiming at the target. So this one is terminal. -
The software and audio hosts hold their published position across a reposition. Now that the seek suspends, the 0.25 s time tick would otherwise republish the pre-seek synchronizer anchor for the duration and then snap, trading a frozen scrubber for a drifting one.
Upgrading
.package(url: "https://github.com/superuser404notfound/AetherEngine", from: "6.1.1")No API change and no source change for consumers. AetherEngine.seek(to:) is unchanged in signature and behaviour; the only observable difference is that a software-path seek can now end its seekEvents ticket as .stalled, which a consumer already has to handle for the native path.