Repository navigation
feat(obs): disable simulcast rungs the grant cannot fund - #7029
Conversation
Quest-Claim: e0203655a73462a1
OBS follows each video encoder's grant through moq-ffi's new MoqRateControl, the same moq_mux::rate::Control the native publishers use, replacing the C++ MoQRate mirror. A rung above a lower encoder sits one track priority below it (MoqVideoInit.lower), drops its packets while disabled (catalog enabled=false via MoqMediaTrackProducer::set_enabled), and resumes at the next keyframe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Python, Swift, and Go wrap MoqRateControl, MediaTrackProducer.set_enabled, and the video init's lower rendition; Kotlin and Dart alias them. The docs describe the pre-encoded path and the OBS ladder, and the quest is rewritten to the remaining shaped-uplink proof, which requires BBR3 aging. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WalkthroughThe change adds reservation-based rate control with enabled or disabled sender targets and optional lower-rendition bitrate policies. Video producer APIs can link renditions to set relative priority and change a track’s advertised enabled state. Rust FFI and language bindings expose these APIs. OBS applies rate targets to encoders, initializes linked tracks in dependency order, and resumes disabled tracks on keyframes. Tests cover rendition priority, disablement, and resumption. Merge Risk:
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc15a13e01
ℹ️ 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".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: fc15a13e01877256923d6fa88be6d6d7d2c8887c.
No actionable bugs found in the OBS disable/resume path, lower-rendition priority propagation, mux enabled setters, or the FFI/wrapper changes. The discontinuity path preserves cached codec parameters while clearing partial frames, and OBS waits for a natural keyframe before advertising the rung enabled again.
Direction: replacing the duplicated C++ rate rule with the shared Rust control is a good simplification. Keeping the configured ceiling separate from the applied bitrate also makes stop-time restoration and ladder discovery clearer. The deferred shaped-uplink proof remains important: the targeted OBS test drives Retarget directly, so it does not establish the complete grant/probe/encoder feedback loop or BBR3 recovery behavior.
Verification: static GitHub review of the changes and relevant surrounding code, including an independent FFI/bindings pass. No tests, binding builds, real OBS runs or shaped-network experiments performed; reported validation was not independently reproduced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A higher rung's first packet started its lower rung's track, before an encoder that supplies parameter sets only after its first frame had them, so the lower track was cached without them. Wait for the lower's own first packet instead, and open every track on a keyframe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 20a56a3.
The direct two-rung startup case reported in #7029 (comment) is addressed, with focused header-readiness and initial-keyframe coverage. Deferring publication is the right direction, but one P2 remains inline: recursive deferral must propagate through a three-rung ladder rather than permanently publishing the top rung without its lower relation.
GitHub-only static delta and surrounding-code/test review. No OBS tests, builds, binding checks, or shaped-uplink experiments were run. The remaining end-to-end bandwidth proof is not established by the targeted fixture.
(Written by OpenAI)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: ba63bd1
Prior P2 fixed: the recursive startup-deferral finding is addressed. After recursive initialization, an absent lower track now defers its caller too, so the top rung cannot be cached without its lower relation. The expanded 8/4/2 Mbps fixture delays the bottom headers and verifies both priority steps once startup resumes. The earlier direct two-rung header fix remains intact.
No new actionable bugs found in this delta. The narrow propagation check is a sound, simpler fix than repairing already-published tracks. Compared against the previous reviewed commit 20a56a3; the only intervening commit changes this check and its regression fixture.
Verification: static GitHub delta and surrounding VideoInit/VideoData/test review. No OBS tests, builds, binding checks or shaped-uplink experiments were run; the fixture does not establish the deferred end-to-end grant/probe/encoder feedback proof.
|
Merge summary for
(Written by Claude Opus 5.5) |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merge summary for
(Written by Claude Opus 5.5) |
|
quest land removed this pull request from the queue: the batch check failed (exit 1). test_core 0.6.20 (0.6.21 available)
vm_service 15.3.0 (15.4.0 available)
web 1.1.1 (1.1.2 available)
Got dependencies!
14 packages have newer versions incompatible with dependency constraints.
Try `dart pub outdated` for more information.
Resolving dependencies...
Downloading packages...
_fe_analyzer_shared 105.0.0 (111.0.0 available)
analyzer 14.1.0 (14.7.0 available)
code_assets 2.0.0 (2.1.0 available)
coverage 1.15.1 (1.16.0 available)
crypto 3.0.7 (3.0.8 available)
frontend_server_client 4.0.0 (4.2.0 available)
http_multi_server 3.2.2 (3.2.3 available)
! moq_ffi 0.0.0-dev from path ../moq_ffi (overridden)
shelf 1.4.2 (1.4.3 available)
shelf_static 1.1.3 (1.2.0 available)
test 1.32.0 (1.33.0 available)
test_api 0.7.14 (0.7.15 available)
test_core 0.6.20 (0.6.21 available)
vm_service 15.3.0 (15.4.0 available)
web 1.1.1 (1.1.2 available)
Got dependencies!
14 packages have newer versions incompatible with dependency constraints.
Try `dart pub outdated` for more information.
Publishing moq 0.1.0 to https://pub.dev:
├── CHANGELOG.md (<1 KB)
├── LICENSE (1 KB)
├── MIGRATE.md (16 KB)
├── README.md (1 KB)
├── analysis_options.yaml (<1 KB)
├── bench
│ └── ffi.dart (5 KB)
├── lib
│ ├── audio.dart (2 KB)
│ ├── json.dart (2 KB)
│ ├── media.dart (4 KB)
│ ├── moq.dart (<1 KB)
│ ├── src
│ │ ├── aliases.dart (7 KB)
│ │ ├── client.dart (10 KB)
│ │ ├── durations.dart (<1 KB)
│ │ ├── epoch.dart (<1 KB)
│ │ ├── server.dart (5 KB)
│ │ ├── stream.dart (2 KB)
│ │ └── version.dart (<1 KB)
│ └── video.dart (3 KB)
├── pubspec.yaml (<1 KB)
└── test
├── cancellation_test.dart (7 KB)
├── docs
│ ├── prelude.dart (<1 KB)
│ └── samples.dart (4 KB)
└── moq_test.dart (24 KB)
Total compressed archive size: 29 KB.
Validating package...
Package validation found the following hint:
* Non-dev dependencies are overridden in pubspec.yaml.
This indicates you are not testing your package against the same versions of its
dependencies that users will have when they use it.
This might be necessary for packages with cyclic dependencies.
Please be extra careful when publishing.
The server may enforce additional checks.
Package has 0 warnings and 1 hint.
ci: check py failed
ci: check gh failed
ci: seconds per module
237 check py (failed)
831 check rs
337 test rs
1049 check rs_shapes
425 check c
192 check cpp
22 check obs_compile
260 check js
57 test js
17 check markdown
1 check gh (failed)
223 check kt
51 check flake
1 check swift
85 check go
0 check drill
2 check quest
3 check obs
1 check ts_paths
17 check shell
0 check large_files
1 check toml
0 check nix
0 check justfile
118 check dart
2336 wall time
error: recipe `ci` failed on line 104 with exit code 1
. |
|
quest land removed this pull request from the queue: the batch check failed (exit 101). …�[1mgenerate�[0m: �[2mcargo_cyclonedx::generator�[0m�[2m:�[0m Hash for package ID path+file:///work/rs/moq-pattern#0.1.2 not found in Cargo.lock
�[2m2026-11-01T16:55:01.504988Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mgenerate�[0m: �[2mcargo_cyclonedx::generator�[0m�[2m:�[0m Hash for package ID path+file:///work/rs/moq-net/fuzz#moq-net-fuzz@0.0.0 not found in Cargo.lock
�[2m2026-11-01T16:55:01.543130Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mgenerate�[0m: �[2mcargo_cyclonedx::generator�[0m�[2m:�[0m Hash for package ID path+file:///work/rs/kio#0.6.2 not found in Cargo.lock
�[2m2026-11-01T16:55:01.543181Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mgenerate�[0m: �[2mcargo_cyclonedx::generator�[0m�[2m:�[0m Hash for package ID path+file:///work/rs/kio/macros#kio-macros@0.1.0 not found in Cargo.lock
�[2m2026-11-01T16:55:01.543194Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mgenerate�[0m: �[2mcargo_cyclonedx::generator�[0m�[2m:�[0m Hash for package ID path+file:///work/rs/moq-congestion#0.1.0 not found in Cargo.lock
�[2m2026-11-01T16:55:01.543205Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mgenerate�[0m: �[2mcargo_cyclonedx::generator�[0m�[2m:�[0m Hash for package ID path+file:///work/rs/moq-quic#0.1.0 not found in Cargo.lock
�[2m2026-11-01T16:55:01.544838Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mgenerate�[0m: �[2mcargo_cyclonedx::generator�[0m�[2m:�[0m Hash for package ID path+file:///work/rs/moq-quic/fuzz#moq-quic-fuzz@0.0.0 not found in Cargo.lock
�[2m2026-11-01T16:55:01.630278Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mgenerate�[0m: �[2mmaturin::sbom�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m2.99s �[3mtime.idle�[0m�[2m=�[0m2.80µs
�[2m2026-11-01T16:55:01.674598Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m:�[1mcompile_cdylib�[0m: �[2mmaturin::compile�[0m�[2m:�[0m Setting crate_type to cdylib for Rust >= 1.64.0
�[2m2026-11-01T16:55:01.676724Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m:�[1mcompile_cdylib�[0m: �[2mmaturin::compile�[0m�[2m:�[0m Running env -u CARGO "cargo" "rustc" "--features" "testing,openh264" "--message-format" "json-render-diagnostics" "--locked" "--manifest-path" "/work/rs/moq-ffi/Cargo.toml" "--lib" "--crate-type" "cdylib"
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.14s
mbx[savings]: the running total stands at 11d 57m across 13447 builds. nobody is counting except the box.
�[2m2026-11-01T16:55:03.238680Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m:�[1mcompile_cdylib�[0m: �[2mmaturin::build_orchestrator�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m1.56s �[3mtime.idle�[0m�[2m=�[0m8.83µs
🚉 Overriding platform tag from _PYTHON_HOST_PLATFORM environment variable as linux_x86_64.
�[2m2026-11-01T16:55:03.444416Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mglobset�[0m�[2m:�[0m glob `Glob("**/moq_ffi/_uniffi/**/*")` converted to regex: `"(?-u)^(?:/?|.*/)moq_ffi/_uniffi(?:/|/.*/)[^/]*$"`
�[2m2026-11-01T16:55:03.444554Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mglobset�[0m�[2m:�[0m glob `Glob("**/__pycache__/**/*")` converted to regex: `"(?-u)^(?:/?|.*/)__pycache__(?:/|/.*/)[^/]*$"`
�[2m2026-11-01T16:55:03.444614Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mglobset�[0m�[2m:�[0m built glob set; 0 literals, 0 basenames, 0 extensions, 0 prefixes, 0 suffixes, 0 required extensions, 2 regexes
�[2m2026-11-01T16:55:03.448624Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::build_context::repair�[0m�[2m:�[0m copy_back_cargo_outputs: copied unpatched /home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/libmoq_ffi.so -> /work/target/py/debug/libmoq_ffi.so
�[2m2026-11-01T16:55:20.138962Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::binding_generator::uniffi_binding�[0m�[2m:�[0m Running cd "/work" && env -u CARGO_BUILD_TARGET "cargo" "run" "--bin" "uniffi-bindgen" "--features" "cli" "generate" "--no-format" "--language" "python" "--out-dir" "/home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/uniffi/moq_ffi._uniffi" "--config" "/work/rs/moq-ffi/uniffi.toml" "--library" "/home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/libmoq_ffi.so"
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.98s
Running `target/py/debug/uniffi-bindgen generate --no-format --language python --out-dir /home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/uniffi/moq_ffi._uniffi --config /work/rs/moq-ffi/uniffi.toml --library /home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/libmoq_ffi.so`
warning: /work/rs/moq-ffi/uniffi.toml looks like an old-style --config override file. The --config flag now expects a global config file with [defaults], [crates.<name>], and/or [crate-roots] sections. Old-style flat config files are no longer supported.
writing out /home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/uniffi/moq_ffi._uniffi
writing /home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/uniffi/moq_ffi._uniffi/moq.py
�[2m2026-11-01T16:55:25.127345Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::binding_generator�[0m�[2m:�[0m Removing previously built module /work/py/moq-ffi/moq_ffi/_uniffi/libmoq_ffi.so
�[2m2026-11-01T16:55:25.127465Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::binding_generator�[0m�[2m:�[0m Installing /work/py/moq-ffi/moq_ffi/_uniffi/libmoq_ffi.so from /home/check/mbx-targets/check/v1/7a4aae51b2e53b173e0e88b328d8b5d16a3ff418f0f523578c8ab24ae8dfd401/py/maturin/libmoq_ffi.so
�[2m2026-11-01T16:55:25.127640Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::binding_generator�[0m�[2m:�[0m Generating file /work/py/moq-ffi/moq_ffi/_uniffi/__init__.py
�[2m2026-11-01T16:55:25.127798Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::binding_generator�[0m�[2m:�[0m Generating file /work/py/moq-ffi/moq_ffi/_uniffi/moq.py
�[2m2026-11-01T16:55:25.129723Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer�[0m�[2m:�[0m Adding moq_ffi.pth from /work/py/moq-ffi
�[2m2026-11-01T16:55:25.129741Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer::virtual_writer�[0m�[2m:�[0m Tracked entry "moq_ffi.pth"
�[2m2026-11-01T16:55:25.130287Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer::virtual_writer�[0m�[2m:�[0m Tracked entry "moq_ffi-0.4.12.dist-info/sboms/moq-ffi.cyclonedx.json"
�[2m2026-11-01T16:55:25.130325Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer::virtual_writer�[0m�[2m:�[0m Tracked entry "moq_ffi-0.4.12.dist-info/METADATA"
�[2m2026-11-01T16:55:25.130334Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer::virtual_writer�[0m�[2m:�[0m Tracked entry "moq_ffi-0.4.12.dist-info/WHEEL"
�[2m2026-11-01T16:55:25.130341Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer::virtual_writer�[0m�[2m:�[0m Tracked entry "moq_ffi-0.4.12.dist-info/licenses/LICENSE-APACHE"
�[2m2026-11-01T16:55:25.130345Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer::virtual_writer�[0m�[2m:�[0m Tracked entry "moq_ffi-0.4.12.dist-info/licenses/LICENSE-MIT"
�[2m2026-11-01T16:55:25.245807Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::module_writer::wheel_writer�[0m�[2m:�[0m Adding moq_ffi-0.4.12.dist-info/RECORD
📦 Built wheel to /tmp/.tmpkkewoX/moq_ffi-0.4.12-py3-none-linux_x86_64.whl
�[2m2026-11-01T16:55:25.246124Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m:�[1mbuild_uniffi_wheel�[0m: �[2mmaturin::build_orchestrator�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m23.6s �[3mtime.idle�[0m�[2m=�[0m5.34µs
�[2m2026-11-01T16:55:25.246212Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m:�[1mbuild_wheels_inner�[0m: �[2mmaturin::build_orchestrator�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m26.6s �[3mtime.idle�[0m�[2m=�[0m851ns
�[2m2026-11-01T16:55:25.246219Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m:�[1mbuild_wheels�[0m: �[2mmaturin::build_orchestrator�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m26.6s �[3mtime.idle�[0m�[2m=�[0m892ns
✏️ Setting installed package as editable
�[2m2026-11-01T16:55:25.887472Z�[0m �[34mDEBUG�[0m �[1mdevelop_cmd�[0m:�[1minstall_wheel�[0m:�[1mconfigure_as_editable�[0m: �[2mmaturin::develop�[0m�[2m:�[0m running UV_PYTHON="/work/.venv/bin/python" "uv" "pip" "show" "--files" "moq-ffi" �[2m�[3mwheel_filename�[0m�[2m=�[0m/tmp/.tmpkkewoX/moq_ffi-0.4.12-py3-none-linux_x86_64.whl�[0m
�[2m2026-11-01T16:55:25.989103Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m:�[1minstall_wheel�[0m:�[1mconfigure_as_editable�[0m: �[2mmaturin::develop�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m109ms �[3mtime.idle�[0m�[2m=�[0m2.12µs �[2m�[3mwheel_filename�[0m�[2m=�[0m/tmp/.tmpkkewoX/moq_ffi-0.4.12-py3-none-linux_x86_64.whl�[0m
�[2m2026-11-01T16:55:25.989138Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m:�[1minstall_wheel�[0m: �[2mmaturin::develop�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m743ms �[3mtime.idle�[0m�[2m=�[0m582ns �[2m�[3mwheel_filename�[0m�[2m=�[0m/tmp/.tmpkkewoX/moq_ffi-0.4.12-py3-none-linux_x86_64.whl�[0m
🛠 Installed moq-ffi-0.4.12
�[2m2026-11-01T16:55:26.001915Z�[0m �[32m INFO�[0m �[1mdevelop_cmd�[0m: �[2mmaturin::commands::develop�[0m�[2m:�[0m close �[3mtime.busy�[0m�[2m=�[0m29.9s �[3mtime.idle�[0m�[2m=�[0m3.72µs
DEBUG Command exited with code: 0
uv pip install --no-deps -e moq-rs
Using Python 3.14.8 environment at: /work/.venv
Resolved 1 package in 1ms
Building moq-rs @ file:///work/py/moq-rs
Built moq-rs @ file:///work/py/moq-rs
Prepared 1 package in 6.42s
Installed 1 package in 7ms
+ moq-rs==0.6.0 (from file:///work/py/moq-rs)
bash ../sh/local.sh uv run --no-sync pytest moq-rs/tests/ moq-ffi/tests/
error: recipe `test` failed on line 65 with exit code 143
ci: test rs failed
ci: seconds per module
321 check py
38 test py (cancelled)
80 check rs
279 test rs (failed)
359 check c (cancelled)
360 wall time
error: recipe `ci` failed on line 107 with exit code 101
. |
|
codex / Codex land fixer: (written by codex / Codex) |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng-disable Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng-disable Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: b4dff1f
No new actionable defects found. OBS behavior, rate policy and regression tests remain unchanged. The regenerated Dart disposal allocates status before marking the object disposed and detaching its finalizer, preserving ownership if allocation fails; the remaining changes are largely base adaptations and formatting.
Verification: static GitHub comparison and wrapper inspection only; no builds or tests run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Quest: quest/m1/simulcast-rung-disable.md. This PR lands the OBS rung disable and rewrites the quest to the remaining shaped-uplink proof.
Summary
cpp/obs/src/moq-rate.h(a C++ copy ofmoq_mux::rate::Controlwithout the rung rule) and its test are deleted. Each retunable video encoder follows its reservation through moq-ffi's newMoqRateControl, which wrapsmoq_mux::rate::Controland reads both the grant and whether a session probes for it.Disabledtarget marks a discontinuity (once the track has written a frame), sets the catalogenabled: false, and drops the encoder's packets. OBS cannot stop one encoder of a live output or force it to keyframe. After anEnabledtarget, the rung resumes at the encoder's next natural keyframe withenabled: true. Stop restores the configured bitrate whenever the applied one moved.rs/moq-ffi):MoqRateControl/MoqRatePolicy { max_bps, lower_bps }/MoqRateTarget { Enabled { bitrate_bps }, Disabled }.update(&MoqReservation)feeds the current grant and probe state on the ambient clock, for a sender that is driven per frame.MoqVideoInit.lower: Option<MoqMediaTrackProducer>publishes a pre-encoded track one priority below the lower video track. A lower audio track is refused.MoqMediaTrackProducer::set_enabled(bool)flips the catalogenabledof a video track. An audio track refuses.import::VideoInit.priority(defaults toPRIORITY.video),import::Track::set_enabled(video only,Error::WrongKindfor audio), andset_enabledon the AV1, VP8, and VP9 importers, matching H.264/H.265.RateControl,RateTarget,TrackProducer.set_enabled,lower=on both video importers), Swift (same), Go (RateControl,RatePolicy,RateTarget*,TrackProducer.SetEnabled, andmedia.VideoInitas a struct withLower *TrackProducer), Kotlin and Dart aliases, and regenerated Dart bindings.doc/lib/*anddoc/bin/obs.mddescribe the pre-encoded path and the OBS ladder.Required; its Plan uses main's rate-steppingmoq-shaperprofiles (cellular-step). Summaries inquest/m1/README.mdandquest/m2/probe/README.mdare updated.Impact
enabledis already in the catalog).MoqRateControl,MoqRatePolicy,MoqRateTarget,MoqMediaTrackProducer::set_enabled, andMoqVideoInit.lower(UniFFI defaultNone;nullptrin C++).import::VideoInit::priority(the struct is#[non_exhaustive]with a constructor),import::Track::set_enabled, and{av1,vp8,vp9}::Import::set_enabled.media.VideoInitis a struct rather than an alias of the generated record. Composite literals withFormat,Data,Label, andHintcompile unchanged. A MIGRATE note is added.rs/moq-c,c/moq). OBS uses the generated moq-ffi package, so nothing consumes a C equivalent yet (see decision 4).Decisions settled
The maintainer accepted every recommendation in a /quest-complete session:
MoqRateControlin moq-ffi wrapsmoq_mux::rate::Control, replacing the C++MoQRatemirror (done here).MoqVideoInit.lowerhandle, matchingMoqVideoProducerOptions.lower, not an explicitpriority(done here).MoqMediaTrackStreamProducer::videoacceptslowertoo, but a stream producer cannot itself be passed as one.OBS_ENCODER_CAP_DYN_BITRATEand CBR/VBR/ABR to get aRateControl. A CQP/CRF or non-retunable top encoder still sits one priority below its lower one but never disables.Choices made
MoqRateControl::updatetakes the reservation, not a grant plus a probe flag, so a caller can't forget the probe gate.MoqReservation::probedtherefore stays unexported.Retargetdirectly with no encoder following. A localhost session's real grant would otherwise move the targets mid-test. The rule itself is covered bymoq_mux::rate's tests and model.Follow-ups
moq_publish_media_set_enabled, the media track's lower/priority, and a C rate control overmoq_reservation, withdoc/lib/c.MoqMediaTrackStreamProducercan't be passed as alower, and it has noset_enabled, so a ladder made only of byte-stream producers can't link priorities or disable a rung. Parity needs the stream producer to record its priority, to exportset_enabled, and alowertype that accepts either producer. Raised by CodeRabbit (r4436515610).Checks
On head
b4dff1fa37(main at622d7bc0c5merged):just ci origin/main(insidenix develop, viaquest gate) on95ce36573e: every module passed (check rs,test rs,check py,test py,check c,check cpp,check obs_compile,check go,check kt,check js,test js, and the lint modules).check dartfailed because the merged generated bindings were stale.0238c502f2regenerates them, andcheck dartthen passes. Swift was skipped locally because Linux has no Swift toolchain.b4dff1fa37is a conflict-free merge oforigin/mainthat touches onlymoq-quic,moq-uring, quest files, and the lockfile. None of these overlap this PR.quest check --base origin/main: ok.just obs test(TSan) onc672fbec30: every MoQOutput, moq_source, and settings test passes. The onlycpp/obschange since is main's01c6e7e80f(CMake qlog option), andcheck obs_compileandcheck cpppass on the merged tree.Land history
merge_conflict(MIGRATE.md, Kotlin aliases, quest Plan, SwiftMedia.swift): resolved here. Main's moq-dev/moq#7319 formatting gates reflowed the Swift and Kotlin, and main's moq-dev/moq#7334 mademoq-shaperstep its rate, so the quest Plan now uses that instead of asking for it.0b4f430067) at 16:41Z; this branch merges it with-s ours(same parents, this resolution kept) rather than force-pushing.test rsfailed (exit 101) on0b4f430067. The posted log is truncated before nextest's summary, so the failing test is not visible.test rspasses locally on the same tree content and on the newer base three times, so it looks like a flake or another batch member.dc718e72c4passed (5/5), and after this branch merged main at951cca678cthe full localjust cigate passed,test rsincluded. Nothing on this branch reproduces the batch failure, so the code is unchanged. The CodeRabbit thread onrs/moq-ffi/src/media.rs:375is refuted (reply) and listed under Follow-ups.40abd59716under the old landing flow, and the PR has conflicted with main since). Main has no equivalent change (moq-rate.hand the quest are still there), so the PR still applies. Mergedorigin/main(41f60ec46e).go/wrapper/MIGRATE.mdkeeps both entries, this PR'smedia.VideoInitnote and main's moq-dev/moq#7484 captures note.py/moq-rs/moq/types.pykeepsRateTargetand takes main's move ofRange(main now imports it withTimestamp). The Dart bindings were regenerated (0238c502f2), and main was merged again at622d7bc0c5(conflict-free). No new automated review findings were posted since the last iterate, and the one CodeRabbit thread stays refuted.Review
quest review), gpt-6.1-sol, medium effort, new session01a19f99(the whole branch againstorigin/mainat622d7bc0c5). The previous session01a19810is keyed to a local branch that another worktree has checked out, so this one starts fresh and reviews everything.95ce36573ef9ac9bace677e19df2f31530999dfa: no findings.b4dff1fa3762ecb94935cdc5fcd0591818442c90(the regenerated Dart bindings and a conflict-free merge of main): no findings.01a19810round 1 onc672fbec30: none. Session01a195f3round 1 ond7e63636f6: none. Session01a19158on11481709found one issue, fixed in92046c6bfd, then none. CodeRabbit'scpp/obs/src/moq-output.cpp:694finding was fixed ina7959e2e74, and itsdoc/bin/obs.md:49finding in11481709. Itsrs/moq-ffi/src/media.rs:375finding (a raw-stream producer aslower) is refuted on decision 2 (reply), and CodeRabbit withdrew it. It is listed under Follow-ups.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)