Skip to content

Commit 125fcca

Browse files
committed
Tighten local WebRTC recovery
1 parent 7f74f82 commit 125fcca

2 files changed

Lines changed: 26 additions & 9 deletions

File tree

client/src/features/stream/streamWorkerClient.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ const HAVE_CURRENT_DATA = 2;
1212
const WEBRTC_CONTROL_CHANNEL_LABEL = "simdeck-control";
1313
const WEBRTC_TELEMETRY_CHANNEL_LABEL = "simdeck-telemetry";
1414
const WEBRTC_FIRST_FRAME_TIMEOUT_MS = 10000;
15-
const WEBRTC_STALLED_FRAME_TIMEOUT_MS = 60000;
16-
const WEBRTC_RECEIVER_BUFFER_SECONDS = 0.06;
15+
const WEBRTC_STALLED_FRAME_TIMEOUT_MS = 15000;
16+
const WEBRTC_REMOTE_RECEIVER_BUFFER_SECONDS = 0.06;
1717
const WEBRTC_DISCONNECTED_GRACE_MS = 30000;
1818
const WEBRTC_RECONNECT_BASE_DELAY_MS = 3000;
1919
const WEBRTC_RECONNECT_MAX_DELAY_MS = 10000;
@@ -146,7 +146,10 @@ class WebRtcStreamClient implements StreamClientBackend {
146146
direction: "recvonly",
147147
});
148148
configureReceiverCodecPreferences(transceiver);
149-
configureLowLatencyReceiver(transceiver.receiver);
149+
configureLowLatencyReceiver(
150+
transceiver.receiver,
151+
target.remote ? WEBRTC_REMOTE_RECEIVER_BUFFER_SECONDS : null,
152+
);
150153
const controlChannel = peerConnection.createDataChannel(
151154
WEBRTC_CONTROL_CHANNEL_LABEL,
152155
{
@@ -181,7 +184,10 @@ class WebRtcStreamClient implements StreamClientBackend {
181184
}
182185
event.track.contentHint = "motion";
183186
for (const receiver of peerConnection.getReceivers()) {
184-
configureLowLatencyReceiver(receiver);
187+
configureLowLatencyReceiver(
188+
receiver,
189+
target.remote ? WEBRTC_REMOTE_RECEIVER_BUFFER_SECONDS : null,
190+
);
185191
}
186192
const stream = event.streams[0] ?? new MediaStream([event.track]);
187193
const video = document.createElement("video");
@@ -441,7 +447,12 @@ class WebRtcStreamClient implements StreamClientBackend {
441447
return;
442448
}
443449
if (frameAgeMs > WEBRTC_STALLED_FRAME_TIMEOUT_MS) {
444-
this.postDiagnostics(target, "video-frame-watchdog-stalled");
450+
this.handleConnectionError(
451+
target,
452+
generation,
453+
new Error("WebRTC video stalled after rendering frames."),
454+
);
455+
return;
445456
}
446457
this.scheduleFrameWatchdog(target, generation);
447458
},
@@ -782,16 +793,22 @@ function postWebRtcOffer(
782793
);
783794
}
784795

785-
function configureLowLatencyReceiver(receiver: RTCRtpReceiver) {
796+
function configureLowLatencyReceiver(
797+
receiver: RTCRtpReceiver,
798+
bufferSeconds: number | null,
799+
) {
800+
if (!bufferSeconds || bufferSeconds <= 0) {
801+
return;
802+
}
786803
const lowLatencyReceiver = receiver as RTCRtpReceiver & {
787804
jitterBufferTarget?: number;
788805
playoutDelayHint?: number;
789806
};
790807
if ("jitterBufferTarget" in lowLatencyReceiver) {
791-
lowLatencyReceiver.jitterBufferTarget = WEBRTC_RECEIVER_BUFFER_SECONDS;
808+
lowLatencyReceiver.jitterBufferTarget = bufferSeconds;
792809
}
793810
if ("playoutDelayHint" in lowLatencyReceiver) {
794-
lowLatencyReceiver.playoutDelayHint = WEBRTC_RECEIVER_BUFFER_SECONDS;
811+
lowLatencyReceiver.playoutDelayHint = bufferSeconds;
795812
}
796813
}
797814

docs/guide/video.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ The WebRTC path favors freshness: stale frames are dropped and the sender reques
7878
A few practical guidelines:
7979

8080
- **Start on the default for local preview.** `auto` lets VideoToolbox choose without requiring the shared hardware encoder.
81-
- **Switch to `software` when the hardware encoder stalls or is unavailable.** The encoder scales the longest edge to 1600 pixels, can climb toward 90 fps for local preview, and backs off dynamically under encode latency.
81+
- **Switch to `software` when the hardware encoder stalls or is unavailable.** The encoder scales the longest edge to 1600 pixels, can climb toward 60 fps, and backs off dynamically under encode latency.
8282
- **Studio providers default to software H.264 plus `--stream-quality smooth`.** This profile uses a 1170-pixel longest edge, allows up to 60 fps, raises the bitrate budget to reduce compression artifacts, and lets multiple provider sessions share CPU cores without depending on one hardware encoder.
8383
- **The remote browser renders the live stream as a native `<video>` element.** The canvas remains for input geometry, but it is not in the live per-frame render path and does not preserve stale frames during reconnects.
8484
- **Use `--stream-quality ci-software` for denser virtualized CI Macs.** This profile uses software H.264 at a 960-pixel longest edge, targets 24 fps, lowers bitrate pressure, and favors fresh frames over full-resolution sharpness.

0 commit comments

Comments
 (0)