A comprehensive WebRTC demo showing the complete connection flow between a web browser and Python (aiortc) with detailed sequence diagrams, network topology visualization, and NAT detection.
-
Interactive 5-Column Sequence Diagram: Visual representation of the complete WebRTC flow
- WEB CLIENT, SIGNALING SERVER, STUN SERVER, TURN SERVER, PYTHON WEBRTC
- Animated arrows showing message flow with timing
- Real-time activation as connection progresses
-
Network Topology Visualization: Shows actual network layout
- Browser and Python server with their local/public IPs (dynamically detected)
- NAT routers with detected types
- Visual representation of why connections succeed or fail
-
ICE Candidate Analysis: Deep dive into WebRTC negotiation
- Lists all local and remote candidates with types (host, srflx, relay)
- Shows the actual selected candidate pair used for connection
- Explains connection path (direct P2P, STUN-assisted, or TURN relay)
-
Server-Side NAT Detection: Python server detects its own NAT type on startup
- Uses STUN to discover public IP
- Detects NAT presence and candidate types
- Results displayed in browser
-
Real-time Timeline Log: Shows exact timing (in ms) of each step
- Delta timestamps from connection start
- Color-coded by component
- Tracks ICE gathering, signaling, and connection states
-
Video Streaming: Color bars test pattern from Python to browser
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ WEB CLIENT │◄──────►│ SIGNALING │◄──────►│ PYTHON │
│ (Browser) │ HTTP │ SERVER │ Local │ WEBRTC │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
│ │
├──────────────► STUN SERVER ◄──────────────────┤
│ (stun.l.google.com) │
│ │
└──────────────► TURN SERVERS ◄─────────────────┘
(openrelay, numb.viagenie)
pip install -r requirements.txtpython server.pyThen open http://localhost:8085 in your browser.
- Python server starts and performs NAT detection
- Uses STUN to discover local and public IPs
- Detects presence of NAT and candidate types
- Results stored and sent to browser with answer
- Browser contacts STUN server to discover public IP
- Gathers host (local), srflx (STUN), and relay (TURN) candidates
- Waits up to 10 seconds for gathering to complete
- Displays all candidates in real-time
- Web client creates SDP offer with ICE candidates
- Sends offer to signaling server via HTTP POST
- Signaling server forwards to Python WebRTC peer
- Python peer contacts STUN server
- Gathers its own ICE candidates
- Waits up to 5 seconds for gathering
- Includes NAT detection results in answer
- Python creates SDP answer with ICE candidates + NAT info
- Sends back through signaling server
- Web client receives and applies answer
- Browser displays Python's NAT detection results
- Both peers try all candidate pairs
- Browser uses getStats() to see which pair succeeded
- Connection established when compatible pair found
- Analysis shows actual selected candidates and connection type
- NAT types updated based on connection success/failure
- Media flows directly peer-to-peer (or via relay)
Important: If you're accessing this demo through an SSH tunnel (e.g., ssh -L 8085:localhost:8085 remote-server), the WebRTC connection will likely fail because:
- The browser is on your local machine (e.g., 192.168.90.x)
- The Python server is on a remote machine (e.g., 192.168.86.x)
- ICE candidates contain local network addresses
- Peers can't reach each other's local IPs
Run both the server and browser on the same machine:
python server.py
# Open http://localhost:8085 locallyThe demo includes free TURN servers but they may not work reliably with aiortc. For production, use:
- Twilio TURN (paid, reliable)
- Coturn (self-hosted, free)
- xirsys (paid service)
Make sure the Python server can reach the browser's network or vice versa.
server.py- Python WebRTC server with signaling endpointsstatic/index.html- Web client with interactive diagramrequirements.txt- Python dependencies
- aiortc - WebRTC implementation for Python
- aiohttp - Async HTTP server for signaling
- aioice - ICE implementation and NAT detection
- av (PyAV) - Video frame handling
- numpy - Test pattern generation
- WebRTC API - Browser native WebRTC support
- RTCPeerConnection - Peer connection management
- getStats() - Detailed connection statistics and selected candidate pairs
- Pure JavaScript - No frameworks required
-
Start the server:
python server.py
Watch the console for NAT detection results.
-
Open the webpage:
- Direct:
http://localhost:8085 - SSH tunnel:
ssh -L 8089:localhost:8085 user@serverthenhttp://localhost:8089
- Direct:
-
Click "Start WebRTC Connection":
- Watch the sequence diagram animate in real-time
- See ICE candidates being gathered
- Monitor connection state changes
-
Analyze the results:
- Timeline Log: Shows exact timing of each step
- Network Topology: Your actual network layout with IPs
- ICE Analysis: Which candidates were used for connection
- NAT Types: Whether your network allows P2P
-
Test different scenarios:
- Same network: Should connect directly via host candidates
- Different networks: Will fail without TURN (demonstrates NAT problem)
- With TURN: Should work via relay (if TURN servers are up)
- host: Local IP address (direct connection, same network)
- srflx: Server reflexive (public IP discovered via STUN)
- relay: TURN relay address (fallback when NAT blocks direct connection)
- No NAT / Same Network: Direct connection possible, no traversal needed
- Full Cone / Port-Restricted NAT: Allows P2P with STUN assistance
- Symmetric NAT: Blocks unsolicited inbound, requires TURN relay
- Behind NAT (unknown): Detected but type determined by connection test
- Direct P2P (host → host): Both on same network, optimal
- STUN-assisted P2P (srflx → srflx): NAT traversal via public IPs
- TURN relay (relay): Symmetric NAT blocked direct, using relay server
Symptom: ICE state goes to "failed", analysis shows "No Compatible Path"
Diagnosis:
- Check Network Topology section - are browser and server on different networks?
- Check ICE Candidate Analysis - do you have overlapping networks or relay candidates?
Solutions:
- Use same network for both peers (recommended for testing)
- Configure reliable TURN server (required for production across different networks)
- If using SSH tunnel: signaling works, but media needs TURN relay
Symptom: Both on same network but connection fails
Diagnosis:
- Check for firewall blocking UDP traffic
- Verify host candidates are being generated
- Check browser console for errors
Solutions:
- Disable firewall temporarily to test
- Check that UDP ports are not blocked
- Ensure both peers have network connectivity
Symptom: Python NAT shows error message
Solutions:
- Check server logs for detailed error
- Verify STUN server is reachable from server
- Check network connectivity
- Check camera permissions in browser
- Verify Python server is sending video track (check server console)
- Python sends color bars test pattern (doesn't require camera)
- Check browser console for errors
Symptom: No relay candidates gathered, connection fails on different networks
Cause: Free TURN servers are unreliable and may not work with aiortc
Solutions:
- Use paid TURN service (Twilio, xirsys)
- Self-host Coturn server
- Test on same network (doesn't require TURN)
- Some network interfaces may timeout (40+ seconds)
- Demo includes 10-second browser timeout, 5-second Python timeout
- Can reduce timeout in code if needed
- IPv6 addresses may take longer to gather
MIT