Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 30 additions & 30 deletions docs/core-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -825,8 +825,12 @@ CloudMatch chroma enums are `0` for 4:2:0 and `1` for 4:4:4; NVST chroma-format
When present, `session.negotiatedStreamProfile.codec` takes precedence over the numeric
feature-map codec. H.264/AVC and H.265/HEVC names normalize to `H264` and `H265`;
`AV1` remains unchanged. An explicit null or unsupported codec stays unknown rather
than falling back to a requested codec. When the server omits every codec field, a new
allocation retains the exact codec sent in that allocation's request. Polling, direct-server
than falling back to a requested codec. The request itself names no codec: like the
official client, codec selection stays client-side and reaches the seat in the RTSP
ANNOUNCE (`x-nv-vqos` bit-stream format), so a negotiated codec is only ever
server-reported (echo, finalized features, or a direct profile). When the server omits
every codec field, downstream stages resolve the codec from current saved preferences
instead. Polling, direct-server
responses, claims, and ad updates preserve that evidence only for the same session ID.
`codecSource` distinguishes `request`, `server`, and `unreported`; a reported codec supersedes
the request and remains authoritative in later partial responses. Unknown discovered sessions
Expand All @@ -840,33 +844,24 @@ reducing chroma; an explicit incompatible codec remains an error.

The native context preserves the resolved profile and codec provenance. Its accepted
`enableHdr` initializes the native HDR mode (missing means false). Invalid accepted HDR
profiles are rejected before stream startup. NVST color negotiation uses literal bit depth
`8` or `10`, `chromaFormat=0` for 4:2:0 or `1` for 4:4:4, and
`dynamicRangeMode=0` for SDR or `1` for HDR. The NVST chroma enum is distinct from the
elementary video's `chroma_format_idc` values `1` and `3`; CloudMatch's existing bit-depth
enum remains `0` or `1`.

These native values follow the built-in conversion and serializer in the official Linux
GeForce NOW 2.0.84.127 `libBifrost2.so`, SHA-256
`8400714f98b7db928ef4377515b1ed35be12523b7fa306566e776b76965537c9`.
The application-to-NVST chroma conversion is at ELF address `0x1f5d50`, and the unchanged
byte reaches the SDP formatter through `0x4e0fc5` and `0x3792c5`.

The main DESCRIBE SDP supplies a comparison baseline, not replacement client preferences.
Its defaults are 8-bit 4:2:0 SDR. Once color attributes or the native-bundle configuration
are recognized, ANNOUNCE omits color values equal to that baseline. The `;;` new-features
suffix overrides the selected bit depth, chroma and dynamic-range mode before ANNOUNCE.
One resolved configuration feeds both the wire values and the media runtime, so a server
downgrade or upgrade cannot leave the decoder expecting the old color format. The stored
CloudMatch profile and user preferences are not rewritten.

Overrides are restricted to these primary-stream color attributes. Malformed or conflicting
values fail with `nvst-color-invalid`; unsupported depth, chroma, dynamic range or codec
combinations fail with `nvst-color-unsupported` before ANNOUNCE. Existing media-runtime
hardware and output checks remain in place. Full SDP must not be logged because it contains ICE
credentials and encryption material. The earlier Mac-reference claim of NVST chroma `1/3`
does not describe this built-in mapping; a captured final value must also be checked for
server overrides and the actual selected stream format.
profiles are rejected before stream startup. NVST ANNOUNCE states color explicitly on
every session using literal bit depth `8` or `10` with `chroma_format_idc`
(`chromaFormat=1` for 4:2:0, `3` for 4:4:4); `dynamicRangeMode=1` is sent for HDR
only, and SDR omits the line. This matches the vendor capture of a `10bit_420`
session (`bitDepth:10 chromaFormat:1`) and the working third-party reference
clients: a lone `bitDepth` line is never sent, because seats cannot initialize
an encoder from an incomplete color spec. The internal 0/1 chroma value from the
client's app-to-NVST conversion is mapped back to idc at SDP emission and never
reaches the wire. CloudMatch keeps its own bit-depth enum (`0` or `1`) with
chroma `0`/`1`.

The ANNOUNCE also carries the encoder identity the seat reads before
initializing (`maxCodecProfile`/`maxCodecLevel` and the `maxH264` pair, profile
3 / level 61, as captured). One resolved configuration feeds the wire values,
the media runtime, and the decoder, so a server color choice cannot leave the
decoder expecting a different format. The stored CloudMatch profile and user
preferences are not rewritten. Full SDP must not be logged because it contains
ICE credentials and encryption material.

After an update check, `updater.highlights.get` returns the latest published
release notes for the selected channel, even when that release is equal to or
Expand Down Expand Up @@ -975,7 +970,12 @@ pre-opt-in settings receive a one-time reset of automatic switching only;
explicit subsequent opt-ins and the independent startup preference are preserved.
Existing microphone device selections are cleared only when explicitly selecting Open
microphone; that write likewise reports `"changes":{"microphoneDeviceId":""}` so the
shell follows the system-default capture selection.
shell follows the system-default capture selection. Setting `colorQuality` repairs an
explicitly saved `codec` (or `fallbackCodec`) the new color mode cannot use toward
`auto` in the same save — H.264 is 8-bit 4:2:0 only, AV1 is 4:2:0 only — and reports
the repair in `changes`. Explicit `codec`/`fallbackCodec` selections the saved color
cannot use are rejected as `invalid_setting` instead; unknown spellings still clamp
to Auto.

`onboardingCompleted` is a persisted boolean, defaulting to `false` for a new
profile or an unreadable or malformed settings file. A valid existing settings
Expand Down
31 changes: 14 additions & 17 deletions docs/streamer-comparison/video.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Overview

Both clients decode HEVC or H.264 on Windows with D3D11 and present with a tearing-allowed flip swapchain. Official GFN on this machine ran 10-bit HEVC at 2560×1440@120 for about 76 minutes. OpenNOW's native CloudMatch path forces 8-bit 4:2:0 before the seat is created, then presents 8-bit BGRA even if a 10-bit bitstream arrives.
Both clients decode HEVC or H.264 on Windows with D3D11 and present with a tearing-allowed flip swapchain. Official GFN on this machine ran 10-bit HEVC at 2560×1440@120 for about 76 minutes. OpenNOW's native CloudMatch path requests the saved color depth/chroma and validates it against local decode before the seat is created.

Recovery is the other split. Official GFN NACKs, then flushes a stalled decode queue, then sends IDR, then invalidates references and can freeze the display on a bad ref. OpenNOW NACKs, then sends RTCP PLI plus control `0x302`. It has no reference-invalidation command.

Expand All @@ -22,28 +22,25 @@ If you stream on OpenNOW today, you get the official two-socket video path with

The user changes `resolution`, `fps`, `codec`, `maxBitrateMbps`, and `colorQuality` in Qt. Those values land in `%APPDATA%/OpenNOW/settings.json`. Launch does not resend the profile. `session.create` re-reads the store.

`cloudmatch.rs` `build_create_body` maps the store onto NVIDIA `sessionRequestData`.

On the native path it then overwrites color:

```
if native {
bit_depth = 0;
chroma = 0;
}
```

`trueHdr` is forced false. `maxBitrateKbps` is omitted from the feature bag. Bitrate still reaches the streamer later through ANNOUNCE `x-nv-vqos` and `MediaStreamConfig`.

`codec: "auto"` on native requests H.264 on purpose so CloudMatch cannot pick AV1 or HEVC before local decode is known. Official Auto is wire `0` and this machine still selected HEVC.
`cloudmatch.rs` `build_create_body` maps the store onto NVIDIA `sessionRequestData`,
field-for-field with the official client's request builder: monitor geometry plus
`requestedStreamingFeatures` with `reflex`, `bitDepth`, `cloudGsync`, `enabledL4S`,
`mouseMovementFlags`, `trueHdr`, `supportedHidDevices`, `profile`,
`fallbackToLogicalResolution`, `hidDevices`, `chromaFormat`, and the
prefilter/HUD tunables. Color follows the saved preference constrained by codec
(H.264 stays 8-bit 4:2:0, AV1 stays 4:2:0); `trueHdr` is set only for a validated
HDR request. Codec, bitrate ceiling, vsync, channel count, QoS policy, touch
support, and the dynamic quality policy are omitted from the feature bag: the
official client resolves the codec locally and carries bitrate/policy purely in
the RTSP ANNOUNCE (`x-nv-vqos` and `MediaStreamConfig`).

Desktop AUTO FPS writes `0`. Core resolves the request through `frame_rate::request_frame_rate`: a missing `fps` defaults to 60 and any present value clamps to the 30–360 request range, so the stored AUTO `0` clamps to 30. Resolution then caps that at 360 for 1920x1080 and 1920x1200 and 240 elsewhere, and rates above 240 additionally need an entitlement at least that high plus a confirmed hardware decoder for the selected codec, otherwise they fall back to the entitlement capped at 240, or to 240 when no entitlement is reported.

`OPENNOW_NATIVE_VIDEO_BACKEND` comes from `nativeVideoBackend` and `decoderPreference`. Auto prefers D3D12 for H.264 and H.265 when the probe succeeds. AV1 auto stays on D3D11 because D3D11-on-12 would flush every frame.

`saveBandwidth` selects the NVIDIA `dynamicStreamingMode` policy requested at `session.create`. The official shared settings schema defines `0` off/do-not-adjust, `1` prefer-FPS, `2` prefer-resolution, and `3` on, and the official client passes the selected profile value into the streaming start request. OpenNOW exposes the bandwidth-saving half of that policy as one toggle and requests `1` (prefer-FPS) when it is on, matching the official Data Saver, Balanced, and Competitive profiles. Off requests `0`, so the request is unchanged.
`saveBandwidth` selects the NVIDIA `dynamicStreamingMode` policy announced at RTSP ANNOUNCE time. The official shared settings schema defines `0` off/do-not-adjust, `1` prefer-FPS, `2` prefer-resolution, and `3` on. The official client never sends this policy to CloudMatch — it exists only as the `x-nv-vqos` ANNOUNCE value resolved from live settings — and OpenNOW matches that: `1` (prefer-FPS) when the toggle is on, matching the official Data Saver, Balanced, and Competitive profiles, else `0`. A server-finalized policy in the negotiated profile, when present, still wins over the live setting.

The request is remembered per session, not per preference. `negotiatedStreamProfile.dynamicStreamingMode` is resolved from the session's own feature bag (finalized overrides the requested echo, out-of-range falls back to unreported), and NVST ANNOUNCE reads only that. RESUME omits requested streaming features by design, so a resumed session keeps the policy it was created with, and toggling the setting mid-session cannot change the wire policy of the running session.
The negotiated value, when the server reports one, is resolved from the session's own feature bag (finalized overrides the requested echo, out-of-range falls back to unreported). Toggling the setting mid-session cannot change the wire policy of the running session; it applies at the next ANNOUNCE.

At the streamer, ANNOUNCE sends `x-nv-vqos[0].dynamicStreamingMode` with that policy and `x-nv-vqos[0].dfc.adjustResAndFps` as the binary enable that follows it (`1` whenever the policy is non-zero). `x-nv-vqos[0].drc.enable` and the `resControl` attributes keep their existing values: `drc` is the separate bitrate axis, and the `resControl` attributes are not emitted by OpenNOW at all, so omitting them inherits the streamer default rather than overriding it.

Expand Down
6 changes: 5 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3359,7 +3359,11 @@
"s_qt_update_failed": "Update could not be completed",
"s_qt_backend_auto_description": "Auto uses DX11 hardware decoding. DX12 and Vulkan texture sharing are not supported by the Windows stream view yet. Applies to the next stream.",
"s_qt_backend_description": "Choose a supported decoder. Auto never falls back to software. Applies to the next stream.",
"s_qt_codec_unavailable": "Not supported by the detected native decoder",
"s_qt_codec_unavailable": "Not supported by the detected decoder or the selected color quality",
"s_qt_color_requires_ultimate": "Requires an Ultimate membership",
"s_qt_color_requires_premium": "Requires a Performance or Ultimate membership",
"s_qt_color_win_mac_only": "Available in the Windows and macOS apps",
"s_qt_hdr_requires_premium": "HDR10 requires a Performance or Ultimate membership.",
"s_qt_backend_auto": "Auto (recommended)",
"s_qt_backend_auto_detail": "Use a supported native backend",
"s_qt_backend_checking": "Checking hardware…",
Expand Down
Loading
Loading