# WebRTC (/docs/reference/webrtc)





OpenNOW has two streaming clients that share Electron-owned session lifecycle and NVST signaling:

* **Web mode** (`streamClientMode: "web"`, default): the renderer owns Chromium `RTCPeerConnection`, media elements, data channels, stats, microphone, screenshots, and recordings.
* **Native mode** (experimental on supported desktop platforms): the Rust/GStreamer child process answers the server offer and handles WebRTC media/data channels natively. Main-process signaling remains shared, and OpenNOW may fall back to web mode for executable, backend, protocol, runtime, or media capability gaps.

## Source files [#source-files]

| Role                                       | File                                                                                                   |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| WebSocket signaling transport              | `opennow-stable/src/main/platforms/gfn/signaling.ts`                                                   |
| Signaling IPC coordination + native bridge | `opennow-stable/src/main/signaling/signalingCoordinator.ts`                                            |
| Chromium startup flags                     | `opennow-stable/src/main/index.ts`, `opennow-stable/src/main/videoAcceleration.ts`                     |
| Renderer peer connection + input           | `opennow-stable/src/renderer/src/platforms/gfn/webrtcClient.ts`                                        |
| SDP/NVST helpers                           | `opennow-stable/src/renderer/src/platforms/gfn/sdp.ts`                                                 |
| Codec capability diagnostics               | `opennow-stable/src/renderer/src/lib/codecDiagnostics.ts`                                              |
| Native executable/protocol lifecycle       | `opennow-stable/src/main/nativeStreamer/manager.ts`                                                    |
| Native input/surface helpers               | `opennow-stable/src/main/nativeStreamer/input.ts`, `opennow-stable/src/main/nativeStreamer/surface.ts` |
| Native protocol/types                      | `opennow-stable/src/shared/nativeStreamer.ts`, `native/opennow-streamer/src/protocol.rs`               |

## Signaling [#signaling]

The main process connects to the session signaling server:

```text
wss://{signalingServer}/nvst/sign_in?peer_id={name}&version=2
```

* Subprotocol: `x-nv-sessionid.{sessionId}`
* Origin: `https://play.geforcenow.com`
* Heartbeat: `{ hb: 1 }` every 5 seconds

After the `peer_info` init message, incoming signaling messages are classified as SDP offers, ICE candidates, or peer messages that may need ACKs. Offers and ICE are routed to the active streaming client. Answers, NVST SDP, and local ICE candidates are sent back through the same main-process signaling client.

Electron routes connect/disconnect, answer/ICE, native input, native render surface, native status, and Cloud G-Sync capability IPC through `SignalingCoordinator`. `GfnSignalingClient` remains the WebSocket transport; the coordinator decides whether incoming offers/ICE go to the renderer or native manager and sends answers/local ICE back through the client.

## Renderer peer connection [#renderer-peer-connection]

In web mode, the renderer:

1. Fixes server SDP placeholders such as `0.0.0.0` using the session server IP.
2. Creates `RTCPeerConnection` with GFN ICE servers.
3. Prefers the configured codec and normalized color quality.
4. Sets the remote offer and creates a local answer.
5. Waits for ICE gathering, then sends the answer plus NVST SDP.
6. Injects the manual media endpoint candidate from `mediaConnectionInfo` when present.
7. Attaches video/audio tracks to `<video>` and `<audio>` elements.

## Native answer path [#native-answer-path]

In experimental native mode, `SignalingCoordinator` sends the server offer to the Rust child through `NativeStreamerManager` with an `offer` command. The GStreamer backend uses `webrtcbin` to create the local answer and emits local ICE as protocol events. Electron still sends the answer and ICE through `GfnSignalingClient`, so CloudMatch, signaling auth, and session teardown stay centralized.

## NVST SDP [#nvst-sdp]

OpenNOW sends standard WebRTC SDP plus an NVIDIA NVST SDP blob. NVST SDP carries stream-quality attributes such as resolution, viewport, FPS, bitrate, codec, color quality, QoS/FEC, bandwidth estimation, and ICE credentials.

The NVST session describes these m-lines:

| m-line        | Direction     | Purpose                       |
| ------------- | ------------- | ----------------------------- |
| `video`       | receive-only  | Cloud GPU video RTP           |
| `audio`       | receive-only  | Game audio                    |
| `mic`         | send-only     | Microphone audio when enabled |
| `application` | bidirectional | Input data channels           |

## Data channels [#data-channels]

<DataChannelsTable />

The partially reliable threshold is read from the negotiated `a=ri.partialReliableThresholdMs` SDP attribute. Native mode creates compatible data channels in the child process and reports `input-ready` before Electron sends native input packets.

## Diagnostics [#diagnostics]

Renderer WebRTC diagnostics poll `RTCPeerConnection.getStats()` for connection state, codec, resolution, HDR/color, bitrate, RTT, jitter, packet loss, frame decode/render timing, data-channel pressure, lag classification, and microphone state.

The Settings codec diagnostics use Chromium `mediaCapabilities` plus WebRTC codec probing to show whether H.264, H.265, and AV1 decode/encode are available and whether the browser reports GPU-backed acceleration. Results are cached in session storage for the current renderer session. On Linux, OpenNOW shows an extra hint when diagnostics are software-only or H.265 is unavailable: AppImage diagnostics still depend on the host distro's VA-API stack, so proprietary NVIDIA systems may need `libva-nvidia-driver`/`nvidia-vaapi-driver` and distro codec packages even though OpenNOW enables NVIDIA VA-API flags on restart.

Native mode emits protocol events instead: `status`, `input-ready`, `shortcut`, `video-stall`, `video-transition`, `stats`, `log`, and `error`. See [Native Streamer](/docs/reference/native-streamer/) for experimental status, event fields, issue reporting, and fallback behavior.

## Chromium acceleration flags [#chromium-acceleration-flags]

At startup the main process configures Chromium/WebRTC for the renderer path:

| Platform  | Current acceleration behavior                                                                                                                               |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Windows   | D3D11 video decode and Media Foundation integration                                                                                                         |
| Linux x64 | VA-API decoder/encoder flags with driver checks relaxed, Linux GL accelerated decode, zero-copy GL decode, accelerated encode, and NVIDIA VA-API enablement |
| Linux ARM | V4L2/direct decoder flags                                                                                                                                   |
| macOS     | Native VideoToolbox path                                                                                                                                    |
| All       | MP4 MediaRecorder support, dav1d AV1 fallback, disabled mDNS candidates, unthrottled renderer/background behavior                                           |

`decoderPreference` and `encoderPreference` are read before Electron startup. `hardware` adds the corresponding force-enable Chromium switch, `software` adds the corresponding disable switch, and `auto` leaves Chromium to choose while still enabling the platform feature set. `ignore-gpu-blocklist` is always set so the GPU process does not silently blocklist available video acceleration.

These flags affect the renderer WebRTC path. Native mode uses the GStreamer platform paths documented in [Native Streamer](/docs/reference/native-streamer/).
