Skip to content

feat(ui): make stream framerate and bitrate configurable - #8

Open
alexander-clawthorne wants to merge 4 commits into
Producdevity:feat/geforce-nowfrom
alexander-clawthorne:feat/configurable-stream-quality
Open

alexander-clawthorne wants to merge 4 commits into
Producdevity:feat/geforce-nowfrom
alexander-clawthorne:feat/configurable-stream-quality

Conversation

@alexander-clawthorne

@alexander-clawthorne alexander-clawthorne commented Sep 29, 2026 •

Copy link
Copy Markdown

Following up on the Reddit thread where you said making these configurable made sense — the defaults are deliberately left alone so lower-end chips and wifi cards keep the behaviour they have now.

Based on feat/geforce-now, so it targets that branch rather than master.

What does this change?

Adds two rows to the settings screen, TARGET FRAMERATE (30/60) and MAX BITRATE (4/6/8/12/16/20 Mbps), so the GeForce NOW stream profile can be changed on device instead of being fixed at build time.

  • persistent_settings.zig — stores frames_per_second and max_bitrate_kbps with save/parse entries. Unknown keys are still skipped, so existing settings.tsv files load unchanged and remain readable by older builds.
  • handheld_ui.zig / handheld_ui.h — exposes both values to C through accessors mirroring the existing stream_width / stream_height pattern.
  • geforce_now/session_client.zig — reads the framerate when the client is created and uses it for stream-mode selection.
  • geforce_now/webrtc_session.zig — reads the bitrate ceiling at both request sites (requestBitrate and the NVST SDP answer), replacing the fixed maximum_bitrate_kbps constant, which is removed as it had no remaining references.
  • settings_view.zig — the two rows, plus row spacing adjusted from 48px to 46px so six rows fit above the footer.

Defaults are unchanged: 30 fps and 6000 kbps, matching the previous hard-coded values. Nothing changes for existing users unless they opt in. The Xbox path is untouched.

Two behaviours worth flagging for review:

  • Both values are negotiated at stream start, so a change applies to the next stream, not the running one. The settings screen states this.
  • sdp_protocol.zig derives the opening bid as max(4000, ceiling/4). With ceilings at or below 16000 that stays 4000 as before; at 20000 it becomes 5000. Happy to cap the choices at 16000 if you'd rather the initial request never move.

How did you test it?

Built with tools/bootstrap.sh && tools/zig.sh build release on an x86_64 Linux host and deployed to an Anbernic RG35XX-H (H700) running muOS 2508.2.

  • tools/zig.sh build test — passes
  • tools/zig.sh build fmt-check — passes
  • tools/zig.sh build release — passes

The 60 fps / 12 Mbps figures below come from a build carrying those values directly — the same profile the new settings select — captured with GREENOVERCAST_DEBUG=1 over several minutes of Control:

[118s] frames=7111/6852 source=1024x768 decoder=2 backpressure=0 decode_errors=0/0/0 queue=0/0
[119s] frames=7171/6912 source=1024x768 decoder=2 backpressure=0 decode_errors=0/0/0 queue=0/0
[120s] frames=7232/6972 source=1024x768 decoder=2 backpressure=0 decode_errors=0/0/0 queue=0/0

60 frames/second, cedar-h616 hardware decode, no decode errors, no backpressure, no queue growth. Also verified settings persist across restarts and that a pre-existing settings.tsv without the new keys still loads.

I have not tested on Rockchip/MPP hardware or the Miyoo Flip — only the H700 above.

Review follow-up (cubic)

All four cubic findings were valid. They're fixed as separate commits, following the focused fix(<scope>): pattern from #3:

  • 9e42628 fix(gfn): selectStreamMode overwrote the configured rate with the 30 fps constant and matched entitled resolutions against it. So in 52900e5, choosing 60 in settings still requested 30. The 60 fps log above came from a build with the value hard-coded, which skips that path. That's why it didn't show up. New test: stream mode selection keeps the configured frame rate (fails when the fix is reverted).
  • dbed9b6 fix(ui): persisted framerate/bitrate are only accepted when they're one of the offered choices; otherwise the default stays. The choice lists moved into persistent_settings.zig so the view and the parser share them. New test covers 0, 1 and u32 max.
  • bbf4d56 fix(gfn): the bitrate ceiling is clamped to 4000-20000 kbps once, before both the NVST answer and requestBitrate, and widened to u64 before the bps conversion.

Re-run after the fixes: build test, build fmt-check and build release all pass, and nm -D --undefined-only webrtc_stream | grep -c __aarch64_ is 0. The fixed build is deployed to the RG35XX-H with settings at 60 fps / 16 Mbps. On-device confirmation of the settings path is pending; I'll update here once it's run.

AI disclosure

Per CONTRIBUTING: this was written with AI assistance (Claude). I reviewed the diff, built it, and verified the behaviour on hardware myself. Happy to adjust anything — naming, the bitrate choices, or the row ordering.


Summary by cubic

Makes GeForce NOW stream framerate and bitrate configurable from the settings screen, keeping the previous defaults of 30 FPS and 6 Mbps so existing behavior is unchanged.

  • Adds TARGET FRAMERATE (30/60 FPS) and MAX BITRATE (4/6/8/12/16/20 Mbps) rows to the settings screen.
  • Changes apply when the next stream starts; the running stream is unaffected.
  • The configured framerate now carries into stream mode selection instead of being reset to 30 FPS.
  • The bitrate ceiling is clamped to 4000-20000 kbps before negotiation.
  • Settings files without these keys, or with values outside the offered choices, fall back to the defaults.
  • Xbox streaming is untouched.

Written for commit bbf4d56. Summary will update on new commits.

Review in cubic

Adds TARGET FRAMERATE and MAX BITRATE rows to the settings screen so the
GeForce NOW stream profile can be changed on device instead of being fixed at
build time. Defaults are unchanged (30 fps, 6000 kbps), so behaviour on
lower-end chips and wifi cards is preserved unless the user opts in.

- persistent_settings: store frames_per_second and max_bitrate_kbps with
  save/parse entries; unknown keys are still skipped, so existing settings
  files load unchanged and stay readable by older builds
- handheld_ui: expose both values to C through accessors that mirror the
  existing stream_width/stream_height pattern
- geforce_now: read the framerate when the session client is created, and the
  bitrate ceiling at both request sites, replacing the fixed constant
- settings_view: two new rows, framerate toggling 30/60 and bitrate cycling
  4/6/8/12/16/20 Mbps

Both values are negotiated when a stream starts, so a change applies to the
next stream rather than the running one. The settings screen says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 5d0fea3f-af22-49e7-ba2a-fa613988a63f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-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.

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/ui/persistent_settings.zig Outdated
Comment thread src/provider/geforce_now/session_client.zig
Comment thread src/ui/persistent_settings.zig Outdated
Comment thread src/provider/geforce_now/webrtc_session.zig Outdated
selectStreamMode reset the stream rate to the hardcoded 30 fps and matched
entitled resolutions against that constant, so a 60 fps setting never
reached the session request. Track the configured rate separately and use
it for both the fallback and the resolution match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only accept persisted framerate and bitrate values from the choices the
settings view offers; anything else keeps the default. The choice lists
now live in persistent_settings so the view and the parser share them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clamp the configured ceiling to 4000-20000 kbps once and use it for both
the NVST answer and the bitrate request, widening before the bps
conversion so it cannot overflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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