Repository navigation
refactor(gst): moqsrc playback helpers share one session context - #7558
Conversation
Quest-Claim: c656d8c713eff025
The session's element, pads, and shutdown travel together as a Session, and run, follow_path, play, and follow_catalog are its methods, instead of each helper taking them as separate arguments. A run's Playback holds the Session plus its own broadcast, timeline, and stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: a902362
No actionable bugs found. A private Session is a sensible simplification of the repeated plumbing: pad ownership remains session-wide while timelines and cancellation remain run-specific. Keeping Play's fields separate preserves the pad actor's weak ownership rather than introducing a reference cycle. The inspected shutdown, restart, and pad-release paths retain their behavior; no public API or wire change.
Verification: static inspection of the refactor, callers, ownership/cancellation paths, and updated test setup only. I did not run builds, GStreamer tests, or independently reproduce the reported gate results.
(Written by OpenAI)
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- New
Sessioncontext: a private, cloneableSession { element, pads, shutdown }(rs/moq-gst/src/source/imp.rs:748) built once bySession::new, which creates a freshPads::default()and holds the state every run, follower, and reader shares. run_sessionbecomesSession::run: takes&selfplus only the connection, origin, and path (:769), preserving the dial-vs-shutdown race and thelostfuture.follow_path,play,follow_catalogbecome methods: each drops the repeatedpads/element/shutdownarguments (:795,:856,:871);follow_pathnow releasesself.pads, andplayclones the whole session for the spawned run.PlaybacknestsSession: replaces its three shared fields with onesession(:1183) and migrates every access site (reconcile,Follower,Reader::run).- Tests and quest cleanup: tests use
Session::newwhere pads are per-run and directSession { .. }literals where pads are shared; the finished quest doc and its README entry are removed.
I verified the behavior-preserving claims: each Session clone of the shutdown receiver starts from the same seen version the moved receiver carried before (the Session field is never polled), Pads lifetime and refcounts are unchanged by creating it one frame earlier in Session::new, Play still holds element/shutdown directly rather than a Session, and no stale free-function call sites remain. The unrelated run_session/follow_catalog symbols in the hang/tokio examples and moq-rtc are different functions.
Technical details
# Behavior equivalence check
## Notes
- `run` and `follow_path` clone `self.shutdown` before polling; the `Session.shutdown`
field itself is never polled, so every downstream clone sees the same version the
original moved receiver carried (the poll that resolves only happens when shutdown
fires, which breaks the loop).
- `Play.shutdown` is consumed only as `*play.shutdown.borrow()` in
`PadActor::play` (`rs/moq-gst/src/source/imp.rs:703`); `watch` version state is
irrelevant there.
- Original `follow_path` created `Pads::default()` locally; `Session::new` now creates
it. The session is constructed immediately before `run`, so no other holder observes
a different `Pads`. Early `run` returns drop an empty `Pads` (no `Drop` on `Pads`,
only `PadTable`), so no release is skipped.
- No remaining callers of `follow_path`/`follow_catalog`/`run_session` free functions
inside `rs/moq-gst`.
## Required outcome
- None; no change requested.deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Merged base
maininto the branch: the merge brought in themax-delayfeaturemainnow carries, and the branch folded that argument into the new session context instead of re-threading it as a parameter. max_delaymoved ontoSession: added the field and aSession::newparameter, then populated it fromsettings.max_delayand read it inReader::runthroughplayback.sessionforSubscription::default().with_max_delay(max_delay).- Test coverage for the new plumbing: added
a_rendition_subscribes_with_the_session_max_delay, and updated the refactor's test setup to passDEFAULT_MAX_DELAYand buildSessiondirectly where pads are shared.
Behavior is unchanged from main: git diff --merge-base main shows only the refactor plus the max_delay field move, with main's property/Settings/DEFAULT_MAX_DELAY machinery untouched, so the merge dropped nothing. run_session has no remaining references in rs/moq-gst, and the Play.shutdown/Pads-lifetime equivalence points from the prior review still hold. I verified statically; pkg-config for GStreamer is unavailable in this environment, so I did not compile moq-gst locally.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
Main's rational timestamps (#6946) replace the Dart durations export beside the retired epoch export. Main's moq-c epoch validation (#7246) has nothing to validate on an instance, which is any non-empty text: its malformed-epoch cases are dropped, and the instance parse keeps its MOQ_ERROR_INVALID_CONFIG mapping in one helper. Main's new relay-hops C test and resume-history bench are ported onto instances, and moqsrc's refactored session (#7558) logs the instance escaped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Finishes
quest/m2/gst-session-context.mdand removes its milestone link.Problem
moqsrc's playback helpers passed session plumbing to each other as separate arguments:
run_session,follow_path,play, andfollow_catalogeach took the element, the pads, and the shutdown receiver (five arguments apiece), andPlaybackcopied the same three fields again. Any new session-wide setting, such as themax-delayin moq-dev/moq#7084, has to be threaded through every one of them.Approach
Session { element, pads, shutdown }context, built once per session bySession::new.run(wasrun_session),follow_path,play, andfollow_catalogare nowSessionmethods. Each takes only what varies per call: the connection, origin, and path, the run's source, and its cancel handle.Playbackholds theSessionplus the run's own broadcast, timeline, and stop, so followers and readers reach session state throughplayback.session.Sessiondirectly where they share pads across runs, and useSession::newotherwise.A whitespace-insensitive diff is about half the size of the plain diff: most of the plain diff is the helper bodies indenting into
impl Session.Choices made without asking
Sessionholds only the state every level shared (element, pads, shutdown). The origin and the connection stay arguments: onlyrunandfollow_pathuse them, and thefollow_catalogtests build their sources from origins of their own.&Session. The methods read better, but the move costs indentation churn.Playstill copieselementandshutdowninstead of holding aSession. Holding one would give each queued play a strong reference to the pad table, whichPadActordeliberately reaches only weakly.source_lostandcatalog_lostmoved belowimpl Session, so all ofSession's methods sit in one block.Impact
Coordination
moq-dev/moq#7084 (m1,
moqsrc max-delay) already conflicts with main after moq-dev/moq#7368. Whichever PR lands second resolves the conflict. On top of this PR,max_delaybecomes aSessionfield read inReader::run, with no new arguments.Validation
quest gate nix develop -c just ci origin/mainpassed, including 225/225 moq-gst tests and clippy.quest check --base origin/mainpassed.Follow-ups
None.
Review
mechanical fix by codex / Codex:
Merged base and mechanically preserved configurable max-delay through the PR session context; passed cargo fmt -p moq-gst -- --check, cargo build -p moq-gst --locked, and cargo test -p moq-gst --locked with local GStreamer pkg-config/library paths configured.(head f8a7021)quest review --base origin/main, Codex, gpt-6.1-sol, medium effort, heada90236242c7a4ac686045d43dec11a9a2f6b11b1. 0 findings.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code