Skip to content

Latest commit

 

History

History
325 lines (243 loc) · 9.24 KB

File metadata and controls

325 lines (243 loc) · 9.24 KB

WebRTC Connection Issues - Diagnosis and Fixes

Problem Summary

WebRTC connections were getting stuck in the "connecting" state with the following symptoms:

  1. ICE Connection State: new => checking => connected (stuck in checking)
  2. STUN Binding Timeout: STUN binding request timed out (error code 701)
  3. IPv6 Issues: Browser attempting to use IPv6 addresses that timeout
  4. Missing ICE Candidate: Local candidate showing as "(not set)"

Root Causes Identified

1. Missing ICE Candidate Handler (Critical)

The WebRTC client code was missing the onicecandidate event handler. This meant:

  • ICE candidates generated by the browser were not being logged or sent
  • The connection couldn't properly establish NAT traversal
  • No visibility into ICE candidate gathering process

2. Limited STUN Server Configuration

  • Only using a single STUN server (stun.l.google.com:19302)
  • No redundancy if the primary STUN server fails or times out
  • IPv6 STUN requests timing out without fallback

3. Insufficient Logging

  • No visibility into ICE gathering state changes
  • No timeout detection for stuck connections
  • Limited debugging information for connection failures

4. Configuration Issues

  • Incorrect RTCPeerConnection configuration properties
  • No connection timeout handling
  • Missing detailed logging at critical connection stages

Fixes Implemented

1. Added ICE Candidate Handling (web/js/components/preact/WebRTCVideoCell.jsx)

// Handle ICE candidates - critical for NAT traversal
pc.onicecandidate = (event) => {
  if (event.candidate) {
    console.log(`ICE candidate for stream ${stream.name}:`, event.candidate.candidate);
    // Candidates are included in SDP for go2rtc
  } else {
    console.log(`ICE gathering complete for stream ${stream.name}`);
  }
};

Why this matters: ICE candidates are essential for establishing peer-to-peer connections through NAT/firewalls. Without proper handling, connections will fail.

2. Added ICE Gathering State Monitoring

pc.onicegatheringstatechange = () => {
  console.log(`ICE gathering state for stream ${stream.name}: ${pc.iceGatheringState}`);
};

Why this matters: Provides visibility into the ICE gathering process, helping diagnose when and why gathering fails.

3. Added Connection Timeout Detection

const connectionTimeout = setTimeout(() => {
  if (peerConnectionRef.current && 
      peerConnectionRef.current.iceConnectionState !== 'connected' && 
      peerConnectionRef.current.iceConnectionState !== 'completed') {
    console.error(`WebRTC connection timeout for stream ${stream.name}`);
    setError('Connection timeout. Check network/firewall settings.');
    setIsLoading(false);
  }
}, 30000); // 30 second timeout

Why this matters: Prevents connections from hanging indefinitely, provides clear error messages to users.

4. Fixed RTCPeerConnection Configuration

Before:

const pc = new RTCPeerConnection({
  iceTransports: 'all',  // Wrong property name
  bundlePolicy: 'balanced',
  rtcpCnameCpn: 'LightNVR',  // Non-standard
  rtcpCnameRtp: 'LightNVR',  // Non-standard
  iceCandidatePoolSize: 0,
  iceServers: [...]
});

After:

const pc = new RTCPeerConnection({
  iceTransportPolicy: 'all',  // Correct property name
  bundlePolicy: 'balanced',
  rtcpMuxPolicy: 'require',  // Standard property
  iceCandidatePoolSize: 0,
  iceServers: [...]
});

Why this matters: Using correct WebRTC API properties ensures proper browser behavior.

5. Enhanced STUN Server Configuration (src/video/go2rtc/go2rtc_process.c)

Before:

ice_servers:
  - urls:
    - "stun:stun.l.google.com:19302"
    - "stun:stun1.l.google.com:19302"

After:

ice_servers:
  - urls:
    - "stun:stun.l.google.com:19302"
    - "stun:stun1.l.google.com:19302"
    - "stun:stun2.l.google.com:19302"
    - "stun:stun3.l.google.com:19302"
    - "stun:stun4.l.google.com:19302"

Why this matters: Multiple STUN servers provide redundancy. If one times out (especially on IPv6), others can succeed.

6. Updated WebRTC Config API (src/web/api_handlers_go2rtc_proxy.c)

The /api/webrtc/config endpoint now returns all STUN servers to the client:

{
  "iceServers": [{
    "urls": [
      "stun:stun.l.google.com:19302",
      "stun:stun1.l.google.com:19302",
      "stun:stun2.l.google.com:19302",
      "stun:stun3.l.google.com:19302",
      "stun:stun4.l.google.com:19302"
    ]
  }]
}

7. Improved Logging Throughout Connection Process

Added detailed logging at each stage:

  • Offer creation
  • Local description setting
  • ICE gathering state changes
  • Remote description setting
  • Connection state transitions

Testing the Fixes

1. Restart lightNVR

After rebuilding, restart the service:

sudo systemctl restart lightnvr
# or if running manually:
sudo killall lightnvr
sudo ./lightnvr

2. Check Browser Console

Open the browser console (F12) and look for:

Initializing WebRTC connection for stream <name>
Created offer for stream <name>
Set local description for stream <name>, waiting for ICE gathering...
ICE gathering state for stream <name>: gathering
ICE candidate for stream <name>: candidate:...
ICE gathering state for stream <name>: complete
Sending offer to server for stream <name>
Received answer from server for stream <name>
Set remote description for stream <name>, ICE state: checking
ICE connection state for stream <name>: connected
Track received for stream <name>
Video playing for stream <name>

3. Monitor for Errors

Watch for these specific issues:

  • STUN timeout: Should now try multiple servers
  • Connection timeout: Will show clear error after 30 seconds
  • ICE gathering stuck: Will be visible in logs

Network Requirements

Firewall/NAT Configuration

For WebRTC to work properly, ensure:

  1. UDP Port 8555 is accessible (WebRTC media)
  2. TCP Port 1984 is accessible (go2rtc API)
  3. TCP Port 8080 is accessible (lightNVR web interface)

Local Network (No External Access)

If only using on local network, you can disable STUN in config/lightnvr.ini:

[go2rtc]
webrtc_enabled = true
webrtc_listen_port = 8555
stun_enabled = false

External Access / Complex NAT

If accessing from outside your network or behind complex NAT:

[go2rtc]
webrtc_enabled = true
webrtc_listen_port = 8555
stun_enabled = true
stun_server = stun.l.google.com:19302

# Optional: Specify your external IP if auto-detection fails
external_ip = YOUR.EXTERNAL.IP.ADDRESS

Common Issues and Solutions

Issue: "STUN binding request timed out"

Cause: STUN server unreachable (firewall, IPv6 issues, network problems)

Solutions:

  1. Check firewall allows UDP traffic to STUN servers
  2. Try disabling IPv6 in browser if IPv6 connectivity is poor
  3. Use custom STUN server on your network
  4. For local-only use, disable STUN entirely

Issue: Connection stuck in "checking" state

Cause: ICE candidates not being exchanged properly

Solutions:

  1. Check browser console for ICE candidate logs
  2. Verify port 8555 is accessible
  3. Check go2rtc logs: journalctl -u lightnvr -f
  4. Verify go2rtc config: cat /etc/lightnvr/go2rtc/go2rtc.yaml

Issue: "Connection timeout" after 30 seconds

Cause: Cannot establish connection within timeout period

Solutions:

  1. Check network connectivity
  2. Verify all required ports are open
  3. Check if go2rtc is running: ps aux | grep go2rtc
  4. Review go2rtc logs for errors
  5. Try local network first before external access

Issue: IPv6 addresses causing problems

Cause: Browser prefers IPv6 but IPv6 connectivity is poor

Solutions:

  1. Disable IPv6 in browser (chrome://flags/#disable-ipv6)
  2. Configure router to prefer IPv4
  3. Use IPv4-only STUN servers
  4. Set explicit external IPv4 address in config

Additional Recommendations

1. Consider Adding TURN Server

For the most reliable connections through restrictive NATs/firewalls, consider adding a TURN server:

[go2rtc]
ice_servers = stun:stun.l.google.com:19302,turn:your-turn-server:3478

Free TURN servers:

2. Monitor Connection Quality

The code includes connection quality monitoring. Watch for:

  • Packet loss
  • Jitter
  • Bitrate fluctuations

3. Enable Debug Logging

For detailed troubleshooting, enable debug logging in config/lightnvr.ini:

[general]
log_level = 3  ; 0=ERROR, 1=WARN, 2=INFO, 3=DEBUG

Files Modified

  1. web/js/components/preact/WebRTCVideoCell.jsx - Client-side WebRTC handling
  2. src/video/go2rtc/go2rtc_process.c - go2rtc configuration generation
  3. src/web/api_handlers_go2rtc_proxy.c - WebRTC config API endpoint

Next Steps

  1. Rebuild and restart lightNVR (already done)
  2. Test connections from browser console
  3. Monitor logs for any remaining issues
  4. Adjust configuration based on your network setup
  5. Consider TURN server if issues persist through restrictive NATs

References