Skip to main content

Streaming Stability Improvements (February 2026)

Commit: 14a1e1bbe558c0626a78f3d6e93197eb2e5d1a96
Author: Shaw (@lalalune)

Summary

Improved RTMP streaming reliability and WebGPU renderer initialization through increased stability thresholds, soft CDP recovery, and best-effort GPU limit negotiation.

Changes

1. CDP Stall Threshold

Increased: 2 → 4 intervals (60s → 120s before restart)
Rationale: 2-interval threshold caused false restarts during legitimate pauses (loading screens, scene transitions). 4 intervals provides better tolerance for temporary stalls while still detecting real hangs. Impact:
  • Fewer false restarts
  • More stable long-running streams
  • Better handling of scene complexity spikes

2. Soft CDP Recovery

Added: Restart screencast without browser/FFmpeg teardown
Benefits:
  • No stream interruption during recovery
  • Faster recovery (no browser restart overhead)
  • Preserves browser state (cookies, localStorage)
Fallback: Full restart if soft recovery fails after 3 attempts

3. FFmpeg Restart Attempts

Increased: 5 → 8 attempts
Rationale: FFmpeg can fail transiently due to:
  • Network hiccups
  • RTMP server temporary unavailability
  • Encoder initialization delays
8 attempts provides better resilience without infinite retry loops.

4. Capture Recovery Max Failures

Increased: 2 → 4 failures before full teardown
Rationale: Allows more soft recovery attempts before giving up and doing full browser/FFmpeg restart.

5. WebGPU Best-Effort Initialization

Added: Retry with default limits if GPU rejects custom limits
Rationale: Some GPUs reject custom limits even if they support the feature. Best-effort approach tries custom limits first, falls back to defaults if rejected. Result: Always WebGPU (never falls back to WebGL in this path).

6. WebGL Fallback for Streaming

Added: Automatic WebGL fallback when WebGPU fails or is disabled
Query Params:
  • ?page=stream&forceWebGL=1 - Force WebGL
  • ?page=stream&disableWebGPU=1 - Disable WebGPU
Environment Variable:
Use Cases:
  • Docker containers (WebGPU often unavailable)
  • Vast.ai instances (GPU passthrough issues)
  • Headless browsers (software rendering)

7. Swiftshader ANGLE Backend

Updated: ecosystem.config.cjs to use swiftshader for reliable software rendering
Rationale: Swiftshader provides reliable software rendering when GPU is unavailable or unstable.

Configuration

Environment Variables

packages/server/.env:

Tuning Guide

Aggressive (fast recovery, more restarts):
Conservative (fewer restarts, longer tolerance):
Headless/Docker (reliable software rendering):

Debugging

Check CDP Stall Detection

Check FFmpeg Restart Attempts

Check WebGPU Initialization

Monitor Stream Health

Performance Impact

CDP Recovery

Soft Recovery:
  • Time: ~2-5 seconds
  • Stream gap: None (screencast restarts, FFmpeg continues)
  • Browser state: Preserved
Full Restart:
  • Time: ~10-20 seconds
  • Stream gap: 5-10 seconds (browser + FFmpeg restart)
  • Browser state: Lost (fresh browser instance)

WebGPU vs WebGL

WebGPU (preferred):
  • Better performance
  • Lower CPU usage
  • More features (compute shaders)
WebGL (fallback):
  • More compatible (works in Docker/headless)
  • Slightly higher CPU usage
  • Proven reliability with software rendering

Known Issues

WebGPU Fails in Docker

Symptom: WebGPU initialization fails in Docker containers Cause: GPU passthrough not configured or unavailable Solution: Use WebGL fallback:

CDP Stalls During Scene Transitions

Symptom: CDP stalls during arena transitions or complex scenes Cause: Browser busy with rendering, doesn’t respond to CDP in time Solution: Increase threshold:

FFmpeg Crashes on Startup

Symptom: FFmpeg fails to start, restarts repeatedly Cause: RTMP server unavailable or invalid stream key Solution:
  1. Verify RTMP server is running
  2. Check stream key is correct
  3. Test with local nginx-rtmp:

Testing

Local RTMP Test

Headless Rendering Test

Stability Test

Modified

  • packages/server/src/streaming/browser-capture.ts - CDP stall detection
  • packages/server/src/streaming/stream-capture.ts - FFmpeg restart logic
  • packages/shared/src/utils/rendering/RendererFactory.ts - WebGPU/WebGL fallback
  • ecosystem.config.cjs - Swiftshader ANGLE backend

Configuration

  • packages/server/.env.example - Environment variable documentation
  • .github/workflows/deploy-vast.yml - CI/CD deployment

References