fix(obs): port the source to moq_origin_request#2347
Open
kixelated wants to merge 1 commit into
Open
Conversation
#1772 removed `moq_origin_consume` from libmoq's C ABI but left cpp/obs/src/moq-source.cpp calling it, so the OBS plugin has not compiled against the in-tree libmoq on dev since that PR landed. The generated target/include/moq.h confirms the symbol is gone; MOQ_LOCAL defaults to the repo root, so `just obs build` resolves libmoq from the working tree and fails at link/compile. Nothing caught this because cpp/obs is absent from check.yml and every PR/push workflow. The only job that compiles it is `obs-build` in libmoq.yml, which triggers solely on a `libmoq-v*` tag and builds against the already-published release archive rather than the in-tree crate, so it would go red only after a libmoq release cut from dev was already live. `moq_origin_request` is the faithful replacement: it resolves against what is announced now plus any dynamic fallback and fails when neither can serve the path, matching the removed call's announced-only, fail-fast contract. Behavior is unchanged, including the existing blank-video/teardown/reconnect response to an unresolvable broadcast. The replacement delivers the broadcast via `on_broadcast` instead of returning it, so the post-consume setup moves out of moq_source_start_consume into that callback. The request is another libmoq subscription handed user_data, so it follows the established contract: a reference pre-added before the request exists and released by the terminal (<= 0) callback via subscription_ref, a stored handle that disconnect closes to make the terminal fire promptly, and user_data freed in the terminal. The generation travels with the request rather than living on ctx. A reconnect can issue a new request while an older one still has a delivery in flight, and a single slot on ctx would let that stale delivery read the new generation, pass the staleness check, and clobber ctx->consume. The synchronous call this replaces took the generation as a parameter, so it was immune. Also fold the two duplicated failure paths into moq_source_abort_consume_locked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @kixelated, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
kixelated
marked this pull request as ready for review
July 18, 2026 12:20
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.
Root cause
#1772 removed
moq_origin_consumefrom libmoq's C ABI but leftcpp/obs/src/moq-source.cppcalling it. The OBS plugin has not compiled against the in-tree libmoq ondevsince that PR landed.Verified from the generated artifact rather than inferred:
cargo check -p libmoqruns cbindgen, and the resultingtarget/include/moq.hcontainsmoq_origin_request/moq_origin_consume_announcedbut nomoq_origin_consume.MOQ_LOCALdefaults to the repo root, sojust obs buildresolves libmoq from the working tree and hits the missing symbol.This is a
dev-only regression, not pre-existing rot:moq_origin_consumeis still present onmain, so the plugin builds there. That is why this targetsdev.Why CI never caught it
cpp/obsis absent fromcheck.ymland every PR/push workflow. The only job that compiles it isobs-buildinlibmoq.yml, and it is doubly insulated:libmoq-v*tag push, never on a PR or branch push; andbuild.sh --libmoq-release "$VERSION"), not the in-tree crate.So the break cannot surface until a
libmoq-v*tag is cut from a branch containing #1772, and it would then go red inobs-build(which runsneeds: release) only after that libmoq release is already live. Worth deciding separately whethercpp/obsshould get a compile job on PRs; this PR does not add one.The change
moq_origin_requestis the faithful replacement. It resolves against what is announced now plus any dynamic fallback and fails when neither can serve the path, matching the removed call's announced-only, fail-fast contract. Behavior is unchanged, including the existing blank-video/teardown/reconnect response to an unresolvable broadcast.It is not a mechanical rename: the broadcast arrives via
on_broadcastinstead of being returned, so the post-consume setup moves out ofmoq_source_start_consumeinto that callback. The request is just another libmoq subscription handeduser_data, so it follows the contract the plugin already established for session/catalog/video:<= 0) callback viasubscription_ref;moq_source_disconnect_lockedcloses it, making the terminal fire promptly;user_datafreed in the terminal callback.The generation travels with the request rather than living on
ctx. A reconnect can issue a new request while an older one still has a delivery in flight; a singlerequest_genslot onctxwould let that stale delivery read the new generation, pass the staleness check, and clobberctx->consume. The synchronous call this replaces tookexpected_genas a parameter and was immune, so keying it offctxwould have introduced a race that did not previously exist. Hence the smallbroadcast_request { ctx, gen }user_data.Also folds the two duplicated failure paths into
moq_source_abort_consume_locked.Verification
just obs check(clang-format) passes.on_broadcastfunction-pointer type and both call signatures were type-checked against the real generatedmoq.hwithclang++ -fsyntax-only -Wall -Wextra -Werror.cmake/macos/compilerconfig.cmake), andxcodebuildon this machine fails to loadIDESimulatorFoundationand asks forxcodebuild -runFirstLaunch. That is a local toolchain problem unrelated to this change, but it means the full translation unit is unverified here and should be built by a reviewer (or by alibmoq-v*tag) before merge. Draft for that reason.Cross-Package Sync
rs/libmoqC ABI row:cpp/obs/srcis this change.doc/bin/obs.mdneeds no update; it is a build guide and references no C API symbols (grepformoq_origin/moq_consumethere is empty).