Skip to content

feat(liveion): source quality tiers and manual bitrate switching - #437

Open
a-wing wants to merge 1 commit into
mainfrom
feat/source-bitrate-tiers
Open

feat(liveion): source quality tiers and manual bitrate switching#437
a-wing wants to merge 1 commit into
mainfrom
feat/source-bitrate-tiers

Conversation

@a-wing

@a-wing a-wing commented Sep 7, 2026

Copy link
Copy Markdown
Member

Background

Main already has the network-driven adaptive bitrate loop (issue #409): WHEP subscriber RTCP feedback (TWCC / RR loss) is sampled per subscriber, and a per-stream AIMD controller retunes the shared hardware encoder through StreamSource::set_bitrate → livehal EncoderBackend::setBitrate. Until now only the rkmpp backend implemented runtime retuning, and there was no way to drive the encoder bitrate by hand.

What this PR adds

livehal: v4l2-m2m runtime retune

  • V4l2M2mEncoder::setBitrate()VIDIOC_S_CTRL / V4L2_CID_MPEG_VIDEO_BITRATE on the running device, joining rkmpp. RDK X5 stays unsupported (needs on-device verification).

Config: named quality tiers at source level

[[stream.pi-cam.sources.tiers]]
name = "low"
bitrate = 600000
  • Tiers sit next to capture/encoder (not inside the encoder block) because a quality tier spans both: bitrate retunes the encoder, while resolution/framerate tiers would also reconfigure the capture (livehal has no scaler stage). Reserved per-tier width/height/fps fields exist in the schema but are rejected by validation until the encoder-rebuild path lands — today tiers are bitrate-only presets, validated unique, non-zero, and ≤ encoder.bitrate.
  • When tiers are declared, the AIMD floor defaults to the lowest tier (explicit min_bitrate still wins). Old configs are unaffected.

API: /api/sources/{stream}/bitrate

  • GET — drive mode (adaptive/manual/fixed), current bitrate, active override and tier match, configured tiers.
  • POST{ "tier": "mid" } or { "bitrate": 1500000 } (exactly one; 400 on both/neither/unknown tier, 404 without a source, 409 when the backend cannot retune).
  • DELETE — clears the manual override; the AIMD controller resumes from the held value, fixed sources just drop the marker.
  • A per-stream BitrateControl is now created for every native source (not only adaptive ones) so manual/auto coordination and state reporting behave uniformly.

WebUI

  • Per-stream Bitrate button in the streams table opens a dialog (lazy GET): mode badge + current bitrate, tier buttons with active highlight, raw bps input, resume/clear-override action, graceful empty state for streams without an encoder source (also covers liveman, which does not proxy /api/sources).

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --features source-all,webui,net4mqtt,recorder,cascade,whepwright,rtsp,target-whip,native-source,capture-v4l2,encoder-v4l2-m2m -- -D warnings
  • cargo test -p liveion ... --lib — 216 passed (11 new: tier validation, TOML tiers roundtrip, tier resolution, bitrate-info modes)
  • cargo test --features source --test tests — incl. extended bitrate-API smoke test (400/404 paths)
  • pnpm run lint, pnpm run typecheck, pnpm -r build
  • Hardware end-to-end (POST actually retuning a live encoder) needs a V4L2/MPP device — not verifiable on the dev machine; to be exercised on RK3588 / RPi.

Build on the AIMD adaptive-bitrate loop (issue #409):

- livehal: implement runtime setBitrate for the v4l2-m2m encoder via
  VIDIOC_S_CTRL V4L2_CID_MPEG_VIDEO_BITRATE (rkmpp already had it)
- config: named quality tiers at source level
  ([[stream.<name>.sources.tiers]], bitrate-only presets; reserved
  width/height/fps fields are rejected until the encoder rebuild path
  lands). The AIMD floor defaults to the lowest tier when tiers are
  declared; explicit min_bitrate still wins
- api: GET/POST/DELETE /api/sources/{stream}/bitrate — query the drive
  mode (adaptive/manual/fixed), switch by raw bitrate or tier name,
  clear the override. A per-stream BitrateControl (now created for
  every native source) suspends the AIMD controller on manual sets
- webui: per-stream Bitrate dialog with tier buttons, raw bps input
  and resume/clear actions

Docs (EN/ZH), conf example and tests updated.
@codecov

codecov Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 47.78761% with 177 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
liveion/src/route/source.rs 4.80% 99 Missing ⚠️
liveion/src/stream/source/manager.rs 65.71% 48 Missing ⚠️
liveion/src/error.rs 0.00% 18 Missing ⚠️
liveion/src/stream/source/adaptive_bitrate.rs 86.15% 9 Missing ⚠️
liveion/src/stream/source/mod.rs 50.00% 3 Missing ⚠️
Files with missing lines Coverage Δ
liveion/src/config.rs 94.45% <ø> (ø)
liveion/src/stream/manager.rs 82.72% <100.00%> (+0.07%) ⬆️
liveion/src/stream/source/mod.rs 84.48% <50.00%> (-1.24%) ⬇️
liveion/src/stream/source/adaptive_bitrate.rs 80.00% <86.15%> (+2.42%) ⬆️
liveion/src/error.rs 47.36% <0.00%> (-21.87%) ⬇️
liveion/src/stream/source/manager.rs 73.56% <65.71%> (-4.30%) ⬇️
liveion/src/route/source.rs 6.30% <4.80%> (-1.17%) ⬇️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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