WebRTC
Signaling, SDP negotiation, NVST SDP, data channels, diagnostics, and Chromium acceleration in OpenNOW
OpenNOW has two streaming clients that share Electron-owned session lifecycle and NVST signaling:
- Web mode (
streamClientMode: "web", default): the renderer owns ChromiumRTCPeerConnection, 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
| 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
The main process connects to the session signaling server:
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
In web mode, the renderer:
- Fixes server SDP placeholders such as
0.0.0.0using the session server IP. - Creates
RTCPeerConnectionwith GFN ICE servers. - Prefers the configured codec and normalized color quality.
- Sets the remote offer and creates a local answer.
- Waits for ICE gathering, then sends the answer plus NVST SDP.
- Injects the manual media endpoint candidate from
mediaConnectionInfowhen present. - Attaches video/audio tracks to
<video>and<audio>elements.
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
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
| Channel | Reliability | Traffic |
|---|---|---|
input_channel_v1 | ordered, reliable | Keyboard and control messages |
input_channel_partially_reliable | unordered, partially reliable | Mouse deltas and gamepad state |
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
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 for experimental status, event fields, issue reporting, and fallback behavior.
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.