Skip to content

fix(obs): port the source to moq_origin_request#2347

Open
kixelated wants to merge 1 commit into
devfrom
claude/obs-origin-request
Open

fix(obs): port the source to moq_origin_request#2347
kixelated wants to merge 1 commit into
devfrom
claude/obs-origin-request

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Root cause

#1772 removed moq_origin_consume from libmoq's C ABI but left cpp/obs/src/moq-source.cpp calling it. The OBS plugin has not compiled against the in-tree libmoq on dev since that PR landed.

Verified from the generated artifact rather than inferred: cargo check -p libmoq runs cbindgen, and the resulting target/include/moq.h contains moq_origin_request / moq_origin_consume_announced but no moq_origin_consume. MOQ_LOCAL defaults to the repo root, so just obs build resolves libmoq from the working tree and hits the missing symbol.

This is a dev-only regression, not pre-existing rot: moq_origin_consume is still present on main, so the plugin builds there. That is why this targets dev.

Why CI never caught it

cpp/obs is absent from check.yml and every PR/push workflow. The only job that compiles it is obs-build in libmoq.yml, and it is doubly insulated:

  • it triggers only on a libmoq-v* tag push, never on a PR or branch push; and
  • it builds against the published release archive (build.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 in obs-build (which runs needs: release) only after that libmoq release is already live. Worth deciding separately whether cpp/obs should get a compile job on PRs; this PR does not add one.

The change

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.

It is not a mechanical rename: the broadcast arrives via on_broadcast instead of being returned, so the post-consume setup moves out of moq_source_start_consume into that callback. The request is just another libmoq subscription handed user_data, so it follows the contract the plugin already established for session/catalog/video:

  • a lifetime reference pre-added before the request exists, released by the terminal (<= 0) callback via subscription_ref;
  • the request handle stored so moq_source_disconnect_locked closes it, making the terminal fire promptly;
  • user_data freed 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 single request_gen 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 expected_gen as a parameter and was immune, so keying it off ctx would have introduced a race that did not previously exist. Hence the small broadcast_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.
  • The on_broadcast function-pointer type and both call signatures were type-checked against the real generated moq.h with clang++ -fsyntax-only -Wall -Wextra -Werror.
  • The plugin was NOT compiled end-to-end. OBS's cmake hard-requires the Xcode generator on macOS (cmake/macos/compilerconfig.cmake), and xcodebuild on this machine fails to load IDESimulatorFoundation and asks for xcodebuild -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 a libmoq-v* tag) before merge. Draft for that reason.

Cross-Package Sync

rs/libmoq C ABI row: cpp/obs/src is this change. doc/bin/obs.md needs no update; it is a build guide and references no C API symbols (grep for moq_origin/moq_consume there is empty).

#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>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @kixelated, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@kixelated
kixelated marked this pull request as ready for review July 18, 2026 12:20
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