Skip to content

fix(media player): hold typefind back when a stinger clip loads paused - #1076

Merged
srperens merged 1 commit into
mainfrom
fix/stinger-cue-retry
Oct 15, 2026
Merged

srperens merged 1 commit into
mainfrom
fix/stinger-cue-retry

Conversation

@srperens

Copy link
Copy Markdown
Collaborator

Closes #1069

Problem

On the Windows CI runner a stinger clip source now and then never parked its clip, so the stinger stayed unready. Nine stinger tests were skipped on Windows for it (#1067, #1071).

The cause: load_current_file_inner loads a clip that should stay paused (every stinger cue does) with a plain pipeline.set_state(Paused) from READY. That bypasses up_from_ready, so the typefind hold from #963 did not apply on that path. Typefind then raced the state change. The clip's stream reached decodebin3 while it was still changing state, the push returned FLUSHING, and urisourcebin's multiqueue stopped pushing for good. No pad was added, no frame reached the park clocksync, and the cue timed out after CUE_TIMEOUT (5 s). With heavier timing (more logging) the same race showed as typefind never completing.

Change

  • Root fix: the paused load goes through up_from_ready, as start already does.
  • Safety net: when no frame has parked within CUE_TIMEOUT, the cue loads the clip again once (reload_unparked). Before this, a clip whose stream never reached the bridge left the stinger unready until an operator reloaded it by hand. The reload is skipped when the frame arrives meanwhile, when another clip was cued, or when the pipeline stopped.
  • Test hook: stall_next_clip_for_tests(flow, block_id) drops the next clip's video before the park clocksync. It is keyed on (flow_id, block_id), and the bridge checks it with one relaxed atomic load per new chain.
  • Skips: the Stinger clip source sometimes never parks its first clip on Windows #1069 Windows skips are removed. a_take_that_fails_to_program_leaves_the_old_source_on_air keeps a Windows skip for a different flake (the old source's first frames miss, seen on the runner while tracing this).

Rejected:

  • Raising CUE_TIMEOUT: the stream never recovers on its own.
  • Retry only: it would hide the race instead of fixing it.

Evidence

  • Root cause: traced on the Windows runner on a temporary diag branch that is never merged. It runs stinger_test repeatedly with dot dumps, pad dumps and cdb stacks; the findings are in Stinger clip source sometimes never parks its first clip on Windows #1069. The dumps show decodebin3's input identity blocked and unlinked, last_flow_result Flushing from urisourcebin's src pad up through the demuxer, and no unblock_streams for that decodebin3. Every GStreamer thread was idle; there was no deadlock.
  • Root fix: same loop, same runner, 30 runs each. Without the fix 8 of 30 runs stalled (run 38595584527); with only the one-line fix and no retry, 0 of 30 (run 38657745982). There is no deterministic guard test for the race, so the diag runs are the evidence.
  • Reload: a_clip_that_delivers_no_frame_is_loaded_again fails with the reload disabled (stinger never ready: ... parked false) and passes with it (7.6 s: one 5 s timeout, then parked and a full take).

Tests

Ran, on macOS:

  • cargo clippy --all-targets -- -D warnings: clean.
  • cargo test --test stinger_test a_clip_that_delivers_no_frame_is_loaded_again: passes with the change, fails with the reload disabled (both runs above).
  • cargo test --test stinger_test: 12 passed, 2 failed in one run.
    • gpu_stingers_land_frame_accurately fails the same way on main's code locally (2 of 2 runs), the known macOS failure.
    • cpu_stingers_play_classic failed once and then passed 3 of 3 reruns. On main's code it passed 2 of 2.
  • cargo test --test stinger_api_test: 9 passed.

Skipped: nothing locally; the skip switch is only set in CI.

Not run: the full suite locally. Windows runs through this PR's ci:windows job.

For the reviewer

  • The reload adds up to CUE_TIMEOUT more before a cue gives up, and it runs only when the first attempt produced nothing.
  • up_from_ready holds typefind back on one more path. That path is load_current_file_inner with play = false: stinger cues, and any other caller that loads a clip paused.

🤖 Generated with Claude Code

A clip loaded paused (every stinger cue) went up from READY with a plain
set_state, outside up_from_ready, so the typefind hold from #963 did not
apply. On the Windows runner typefind then raced the state change: the
clip's stream reached decodebin3 while it was still changing state, got
FLUSHING and stayed stuck, and the clip never parked (#1069).

The cue also loads a clip again once when no frame has parked within
CUE_TIMEOUT, so a stinger no longer stays unready for good. Drops the
Windows skips for #1069.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@srperens srperens added the ci:windows Run Build (Windows) on this pull request label Oct 15, 2026
@srperens
srperens merged commit 8defeac into main Oct 15, 2026
9 of 18 checks passed
@srperens
srperens deleted the fix/stinger-cue-retry branch October 15, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:windows Run Build (Windows) on this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stinger clip source sometimes never parks its first clip on Windows

1 participant