Repository navigation
feat(software): a live join starts near the newest media once the connect burst has landed - #797
Merged
superuser404notfound merged 2 commits intoOct 16, 2026
Conversation
…nect burst has landed A continuous live stream over HTTP opens with a burst of what the origin holds of the channel (8 to 18 s on one IPTV panel, at link speed), and the software host armed its clock on that burst's first packet. Nothing on the software path catches up, so the picture ran the whole burst behind the broadcast for as long as the channel played: measured 17 s behind on a channel whose native-path session ran 6 s behind. The live feeder now waits for the burst to land (the ring growing no faster than real time over a quarter second, from 0.3 s on, or 1.5 s at most) and starts 4 s behind the newest media, on a keyframe. A source that delivers in real time, or a ring too shallow to be worth a later keyframe, still starts from its first packet. The media behind the start stays in the rewind ring. Measured on the same channel: first picture 1.1 s after the open, 4 to 6 s behind the newest media. SoftwareLiveJoinPolicy, SoftwareLiveJoinPlacementTests.
…join-placement # Conflicts: # CHANGELOG.md
superuser404notfound
merged commit Oct 16, 2026
54f1443
into
superuser404notfound:main
3 of 4 checks passed
Owner
|
Merged as Two things went in after the merge:
One observation for later, not a request: every software live join with a DVR ring now waits at least |
Owner
|
Released in 7.38.0. Thanks again for this. |
jpsts
pushed a commit
to jpsts/AetherEngine
that referenced
this pull request
Oct 16, 2026
… first The feeder decided the placement and then wrote the cursor unconditionally, so a seek between the two had its target overwritten by the join. The write is now compare-and-set on the seek generation the feeder iteration read, and the placement is logged only when it took. Follow-up to superuser404notfound#797. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJcXkGQrMiBPixVEFTSBJS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A continuous live stream over HTTP (an IPTV panel's MPEG-TS form of a channel) opens with a burst of what the origin holds of the channel, at link speed, and real time after that.
SoftwarePlaybackHost's live feeder arms its clock on the first packet of that burst, and nothing on the software path ever catches up, so the picture runs the whole burst behind the broadcast for as long as the channel plays. Measured on one panel: 17 s behind, on a channel whose native-path session (AVPlayer placed a holdback behind the newest segment) ran 6 s behind. This places a software-path live join near the newest media once the burst has landed.What changed
SoftwareLiveJoinPolicy(new, pure): fed the ring's first and newest PTS from the feeder thread, it says when the burst has landed and where to start. The burst is landed when the ring has grown no faster than 1.5× real time over a 0.25 s window, judged from 0.3 s after the first packet, or after 1.5 s at most on a link still catching up. Then: a ring holding at leastleadSeconds + minimumSkipSeconds(4 + 2 s) ahead of its first packet startsleadSeconds(4 s) behind the newest media; anything shallower, and a source that delivers in real time, starts from the first packet as before. 4 s isAudioLookaheadPolicy.targetLeadSeconds, and a panel that hands over about a second of media at a time leaves the lead swinging within it.runLiveFeederLoopasks the policy before it feeds anything (two new closures,liveJoinPlacementandplaceCursor, defaulting to the old behaviour), waits 50 ms between asks, and on.placemoves the feed cursor to the keyframe at or before the target (PacketRingBuffer.seq(forKeyframeAtOrBefore:)), so the clock arms there on the first decoded audio as it always did. A seek that lands before the decision retires it; a source that ends first plays what there is. The media behind the start stays in the rewind ring, andsessionStartPtsis unchanged, so the session's axis andbehindLiveSecondsread as before.docs/formats.md's paragraph on raw live MPEG-TS described it as always routed software, which has not been so since live sources were exempted from the forward-only rule; it now says how it is routed and describes the placement.DocumentedConstantsTestspins the numbers the paragraph quotes.Evidence
The origin: an IPTV panel's live MPEG-TS channel, H.264 (2 s GOPs) + AAC, 6 to 12 Mbit/s, read over a wired connection. Probed with a plain socket read, the first half second brought 8.5 MB and the stream then ran at the media rate in chunks about a second apart; the video PTS span over the first 14 s of wall clock was 24 s, so about 10 s of media arrived ahead of real time on that connect (a later connect brought 17 s, the burst varies with the content's bitrate).
aetherctl play --live --fast-zap --dvr-window 600 --max-concurrent-requests 1 --sw, before, 40 s (behindis the engine'sbehindLiveSeconds, the distance from the newest demuxed media):First picture 0.45 s after the open, and 17 s behind for the whole run.
The same command with this change, 100 s:
First picture 1.06 s after the open (the settle: the burst had calmed by then), 4.6 to 6 s behind for the whole run, no underrun or rebuffer (
aLeadheld at 4.0 s in the[SWDiag]line throughout). The same channel's native-path session in the same session of measurements ran 5.3 to 7.3 s behind (TARGETDURATION sealed at 3 s, holdback 9 s), so the two routes now agree to within a GOP.Test plan
swift test, andaetherctl playon the same Mac.SoftwareLiveJoinPlacementTests, new: a 12 s burst over the first half second is landed and placed 4 s behind the newest media between 0.3 and 1 s in; a real-time source starts from its first packet by 0.7 s; a burst still landing at 1.5 s is placed on what arrived; a 5 s burst and backwards timestamps start from the first packet.DocumentedConstantsTests(new pin),PublicAPIDocumentationTests, the software-host suites, and the full suite (4,432 Swift Testing tests and the XCTests) pass.Scripts/check-doc-links.pypasses.Note: the
CHANGELOG.mdbullet sits under[Unreleased] › Changed; #796 adds one underFixedat the same spot, so whichever merges second may need a trivial rebase there.Checklist
CHANGELOG.mdupdatedfeat(...),fix(...),chore(...))SoftwareLiveJoinPolicyis internal)