Skip to content

fix(ts): hold audio behind a stale start group's next keyframe - #5810

Merged
kixelated merged 2 commits into
mainfrom
quest/m1/ts-reliability/audio-lead
Oct 17, 2026
Merged

kixelated merged 2 commits into
mainfrom
quest/m1/ts-reliability/audio-lead

Conversation

@kixelated

@kixelated kixelated commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Found reading #5713 (quest quest/m1/ts-reliability/audio-lead.md). When a joiner's video start group is older than the delay, the jitter buffer's acquisition marks its keyframe stale and drops the group whole, so the video queue stays empty until the next keyframe lands. Export::leads_video then fell back to video_start, the dropped keyframe's timestamp, and released audio and data ahead of the first video frame, by up to the rest of the GOP less the delay.

Approach

  • leads_video: until video goes out, a non-video frame is dropped (counted as trimmed) unless a video frame is queued and the frame presents at or after it. With no video queued, nothing goes out ahead of the keyframe that has yet to arrive. This is the fix settled in fix(ts): start an export on a whole group and count every drop #5713.
  • Regression a_stale_start_group_holds_the_audio_behind_the_next_keyframe: the exporter joins 160 ms into a GOP with a 100 ms delay, and the audio is one frame per group so its live edge is fresher than the video's start group. It fails without the fix (audio at 192, 256, 320 ms leads the 600 ms keyframe) and passes with it, across repeated runs.
  • Two existing tests only passed because of the leak. Both had a stale video start group and no next keyframe, and they asserted output that was audio or data with no video:
    • tune_in_does_not_wait_on_dropped_audio now writes less than a delay of the group, which keeps its original intent (tune-in does not wait on the dropped lead audio).
    • moq-srt publisher_preserves_scte35_cues joins the clip's 2 s last group all at once. Its egress now uses a 3 s latency so that group's keyframe is not stale.

Impact

  • No public API or wire change.
  • Behavior: until a joiner's first video frame goes out, its audio and data no longer go out.
  • Behavior change: a joiner whose start group is stale and whose next keyframe never arrives (for example, a feed that stalls) now exports nothing, where it used to export audio-only TS.

Alternatives

  • Fall back to video_start once every video track has finished, so a program whose video ends before its first frame still carries its audio. Not done: no test needs it, and the program's PMT still declares the video.

Decisions

  • A program whose video tracks all end before any video frame went out does not release its remaining audio. This is the recommended choice, applied while the maintainer was away: it keeps the fix minimal, and the program's PMT still declares the video.

Follow-ups

  • The jitter acquisition depends on HashMap iteration order in Export::fill. It can end partway through one fill pass, before reading another track's frames that are already available, so the same input anchors differently from run to run. While building the fixture, the same broadcast started on either the 0 ms or the 600 ms keyframe depending on which track was filled first. Recommend a quest to make acquisition see every track's available frames before it decides.

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

kixelated and others added 2 commits October 16, 2026 17:04
A joiner's video start group older than the delay goes stale at
acquisition, leaving the video queue empty until its next keyframe.
leads_video fell back to the dropped keyframe's timestamp, so audio and
data went out ahead of the first video frame. Drop them as trimmed until
a video frame is queued.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Outcome: the quest is implemented, and its regression fails without the fix and passes with it on repeated runs. just check origin/main passed (3242 + 467 + 182 + 98 + 10 tests, plus lints). The fixture works because the exporter joins mid-GOP with audio at the live edge, which leaves the video start group stale whatever the track fill order. Earlier attempts used a running exporter, and its start group never went stale.

One open decision is listed in the body: should audio be released once every video track ends before going out? I recommend no. One follow-up: the acquisition depends on HashMap fill order.

(Written by Claude Opus 5.5)

@kixelated
kixelated marked this pull request as ready for review October 17, 2026 00:26
@coderabbitai

coderabbitai Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 19 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 98504e2c-0c26-4f69-84cb-9d0475d946a4
📥 Commits

Reviewing files that changed from the base of the PR and between b7d7e99 and 145abe4.

📒 Files selected for processing: 5
  • quest/m1/ts-reliability/README.md
  • quest/m1/ts-reliability/audio-lead.md
  • rs/moq-mux/src/container/ts/export.rs
  • rs/moq-mux/src/container/ts/export_test.rs
  • rs/moq-srt/src/ts.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T00:28:47.516772Z 145abe4 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merging. Summary:

  • Export::leads_video drops non-video frames as trimmed until a video frame is queued and the frame presents at or after it, so audio and data never lead a stale start group's next keyframe.
  • Regression a_stale_start_group_holds_the_audio_behind_the_next_keyframe covers it; two tests that relied on the leak were adjusted.
  • Decision, applied as recommended while the maintainer was away: a program whose video tracks all end before any video frame went out does not release its remaining audio (the PMT still declares video).
  • Behavior change: a joiner whose start group is stale and whose next keyframe never arrives now exports nothing instead of audio-only TS.
  • Review: Codex completed on 145abe4 with no findings. CI green (io_uring rerun after a cachix download failure). CodeRabbit was rate limited.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 17, 2026
Merged via the queue into main with commit 3cf978c Oct 17, 2026
13 of 14 checks passed
@kixelated
kixelated deleted the quest/m1/ts-reliability/audio-lead branch October 17, 2026 01:34
kixelated added a commit that referenced this pull request Oct 17, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant