# Native Streamer (/docs/reference/native-streamer)







The native streamer is an optional Rust child process used when `streamClientMode` is set to native mode on a supported desktop platform. It is supervised by Electron and communicates over JSON-lines protocol version `3`.

<Callout type="warning" title="Native streaming is experimental">
  Native streaming is experimental and may have platform-specific bugs, missing media capabilities, or fallback behavior. OpenNOW defaults to the web streamer unless native mode is explicitly enabled. Report native-streamer issues on [GitHub Issues](https://github.com/OpenCloudGaming/OpenNOW/issues) or [Discord](https://discord.gg/8EJYaJcNfD).
</Callout>

<Callout type="info" title="Current platform support">
  The app accepts native mode on Windows, macOS, and Linux. Windows has the most complete path, including OS-level native input capture and the optional external renderer; macOS and Linux depend on their packaged or system GStreamer runtime and may fall back sooner when codec, decoder, input, or rendering capabilities are missing.
</Callout>

## Settings [#settings]

| Setting                        | Default/effective behavior                     | Purpose                                                                                                                             |
| ------------------------------ | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `streamClientMode`             | `"web"`                                        | Default renderer WebRTC path; experimental native mode opts into the child process on supported desktop platforms                   |
| `nativeStreamerBackend`        | `"gstreamer"`; compatibility forces this value | Backend requested through `OPENNOW_NATIVE_STREAMER_BACKEND` when needed                                                             |
| `nativeVideoBackend`           | `"auto"`                                       | Normalized to `auto`, `d3d11`, `d3d12`, or `vulkan`                                                                                 |
| `nativeStreamerExecutablePath` | `""`                                           | Optional user-selected executable path                                                                                              |
| `nativeCloudGsyncMode`         | `"auto"`                                       | Forwarded to native child as Cloud G-Sync/VRR mode                                                                                  |
| `nativeD3dFullscreenMode`      | `"auto"`                                       | Windows D3D fullscreen behavior                                                                                                     |
| `nativeExternalRenderer`       | `false`; honored only on Windows               | Use a separate native renderer window instead of the internal child-surface path                                                    |
| `showNativeStreamerStats`      | `false`                                        | For native streaming, forwards the current render surface with `showStats: true` so the native renderer shows its own stats overlay |
| `enableCloudGsync`             | `false`                                        | User-facing Cloud G-Sync/VRR preference                                                                                             |

If native startup fails, protocol versions mismatch, the backend reports `stub`, or required platform media support is missing, OpenNOW falls back to the renderer WebRTC client with a diagnostic reason.

Enabling native streaming from Settings opens an explicit experimental-feature confirmation before `streamClientMode` is changed to `"native"`. The setting only applies to new sessions. The regular `F3` stats HUD is an Electron overlay and is hidden while the external native renderer is active; `showNativeStreamerStats` controls the native renderer's own diagnostics overlay instead. In native mode on Windows, the native input bridge captures configured app shortcuts and reports them back to Electron so stop-stream, overlay, fullscreen, stats, microphone, screenshot, and recording actions still work while the native window has focus.

## Backend selection [#backend-selection]

The Rust binary reads `OPENNOW_NATIVE_STREAMER_BACKEND`. Valid runtime backend names are:

| Backend     | Behavior                                                              |
| ----------- | --------------------------------------------------------------------- |
| `gstreamer` | Uses GStreamer `webrtcbin` when the binary was built with the feature |
| `stub`      | Reports capabilities but cannot stream                                |

When no backend is requested, the compiled default is `gstreamer` if the binary has the feature, otherwise `stub`. Unknown or unavailable backends return stub capabilities with `requestedBackend` and `fallbackReason`.

## Source modules [#source-modules]

The Rust GStreamer path is split across focused source modules: `gstreamer_backend.rs` coordinates backend state, `gstreamer_pipeline.rs` builds and negotiates the `webrtcbin` pipeline, `gstreamer_input.rs` owns data channels/native input, `gstreamer_liveness.rs` emits stall diagnostics, `gstreamer_platform.rs` selects platform decode/render paths, `gstreamer_transitions.rs` tracks video path transitions, and `gstreamer_config.rs` normalizes backend configuration.

## Protocol v3 [#protocol-v3]

Electron sends newline-delimited JSON commands on stdin and reads responses/events from stdout.

| Commands           | Purpose                                                   |
| ------------------ | --------------------------------------------------------- |
| `hello`            | Version handshake; returns `ready` capabilities           |
| `start`            | Provide session context before negotiation                |
| `offer`            | Send server SDP offer and session context; returns answer |
| `remote-ice`       | Add server ICE candidate                                  |
| `input`            | Send encoded input packet                                 |
| `surface`          | Update native render surface/window info                  |
| `bitrate`          | Update max bitrate limit                                  |
| `update-shortcuts` | Refresh native-window shortcut bindings while streaming   |
| `stop`             | Stop the native session                                   |

| Responses | Purpose                                                   |
| --------- | --------------------------------------------------------- |
| `ready`   | Capabilities, protocol version, backend, fallback details |
| `ok`      | Command accepted                                          |
| `answer`  | WebRTC/NVST answer payload for signaling                  |
| `error`   | Command failure                                           |

| Events             | Purpose                                                                       |
| ------------------ | ----------------------------------------------------------------------------- |
| `log`              | Native log line                                                               |
| `status`           | `starting`, `ready`, `streaming`, or `stopped`                                |
| `local-ice`        | Candidate to send through main-process signaling                              |
| `input-ready`      | Native data channels are ready for input                                      |
| `shortcut`         | Native renderer matched a configured app shortcut and asks Electron to run it |
| `video-stall`      | Liveness/stall diagnostics and recovery attempt data                          |
| `video-transition` | Decoder/render path transition                                                |
| `stats`            | Native stream telemetry                                                       |
| `error`            | Async backend error                                                           |

## Executable lookup [#executable-lookup]

Electron starts the selected native executable and sets protocol/video environment variables for the child on supported native-streaming platforms.

Lookup order:

1. `OPENNOW_NATIVE_STREAMER` environment override.
2. `nativeStreamerExecutablePath` from settings.
3. Packaged app path: `resources/native/opennow-streamer/<platformKey>/opennow-streamer(.exe)`.
4. Development paths: `native/opennow-streamer/bin`, `native/opennow-streamer/dist`, and `native/opennow-streamer/target/{release,debug}`.

Packaged binaries are copied by `npm run native:build` into `native/opennow-streamer/bin`, including platform-specific directories such as `win32-x64`, `darwin-arm64`, `linux-x64`, or `linux-arm64`.

On unsupported platforms, the manager returns the unsupported status before probing executable lookup or GStreamer runtime state.

## GStreamer dependencies and runtime layout [#gstreamer-dependencies-and-runtime-layout]

`npm run native:build` builds a release Rust binary. By default it enables the `gstreamer` feature and verifies GStreamer capabilities. `OPENNOW_NATIVE_STREAMER_FEATURES=none` disables optional features.

Release packaging behavior:

<GStreamerRuntimeStrategyTable />

Linux package builds use distro GStreamer dependencies, and native mode requires those packages to match the host GPU/driver stack. Install GStreamer base/good/bad/ugly/libav plugins plus hardware packages such as VAAPI, V4L2, GL, Vulkan, and distro driver packages where available.

## Platform video paths [#platform-video-paths]

<NativePlatformVideoPathsTable />

The backend logs selected decoder, renderer, memory mode, and fallback path at startup. D3D presentation limiting can be used to avoid stale-frame buildup when D3D11 is forced for high-FPS sessions.

## Environment variables [#environment-variables]

<NativeEnvironmentVariablesTable />

Build variables: `OPENNOW_NATIVE_STREAMER_FEATURES`, `OPENNOW_NATIVE_STREAMER_TARGET`, `OPENNOW_NATIVE_STREAMER_PLATFORM_KEY`, and `OPENNOW_BUNDLE_GSTREAMER_RUNTIME`.

## Diagnostics and fallback [#diagnostics-and-fallback]

The native manager validates the protocol handshake and backend capabilities before streaming. Runtime events surface status, input readiness, local ICE, video stalls, video transitions, stats, logs, and errors.

Fallback is expected and intentional when:

* The executable cannot be found or started.
* Protocol version is not `3`.
* The binary reports `stub` because GStreamer was not compiled in.
* A requested backend is unknown or unavailable.
* Required GStreamer plugins or platform decoders are missing.
* The app is running on an unsupported desktop platform, or the platform's required GStreamer/runtime pieces are unavailable.
* Native streaming errors before a usable session is established.

In those cases, OpenNOW returns to the web streamer path rather than leaving the user in a partial stream state.
