A professional, scalable solution for streaming multiple ONVIF IP cameras through web browsers using centralized media gateway architecture.
┌─────────────────┐ WebSocket ┌──────────────────┐ RTSP ┌──────────────────┐
│ React App │◄────────────────►│ Media Gateway │◄─────────────│ 8 ONVIF Cameras │
│ (Your Server) │ Port 8080 │ (Camera Network) │ UDP/TCP │ (Private Network)│
└─────────────────┘ └──────────────────┘ └──────────────────┘
- 🏗️ Centralized Processing: Single media gateway handles all camera streams
- 🔐 Secure: Cameras stay on private network, only gateway port exposed
- 📱 Cross-Platform: Works on desktop, tablet, and mobile browsers
- ⚡ Low Latency: Real-time streaming with minimal delay
- 📊 Bandwidth Optimized: 5 quality presets from 150KB/s to 3MB/s
- 🔄 Scalable: Up to 8 concurrent camera streams per gateway
cd gateway/
npm installEdit config/cameras.js with your camera details:
{
id: 1,
name: 'Front Door Camera',
rtsp: 'rtsp://admin:PASSWORD@192.168.10.192:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif',
enabled: true
}Test and start:
npm run test # Test camera connections
npm start # Start gateway servercd client/
npm installUpdate gateway URL in src/App.js:
const [gatewayUrl, setGatewayUrl] = useState('http://YOUR_GATEWAY_IP:8080');Start the app:
npm start # Development
npm run build # Production# On gateway server
sudo ufw allow 8080/tcp
sudo ufw allow from YOUR_REACT_SERVER_IP to any port 8080- Gateway:
http://gateway-ip:8080/health - React App: Select "Gateway Mode" and enter gateway URL
- Test cameras individually before starting streams
onvif-webrtc-viewer/
├── gateway/ # 🏗️ Media Gateway Server
│ ├── src/
│ │ ├── gateway.js # Main server application
│ │ └── test-cameras.js # Camera connection tester
│ ├── config/
│ │ ├── cameras.js # Camera definitions (8 cameras)
│ │ └── environment.js # Server configuration
│ ├── public/
│ │ └── index.html # Gateway status dashboard
│ ├── logs/ # Server logs
│ └── package.json
│
├── client/ # ⚛️ React Application
│ ├── src/
│ │ ├── components/
│ │ │ ├── GatewayCameraGrid.js # Multi-camera dashboard
│ │ │ ├── GatewayCameraViewer.js # Individual camera viewer
│ │ │ └── CameraViewer.js # Local mode viewer
│ │ ├── App.js # Main application (dual mode)
│ │ └── index.css # Styling
│ └── package.json
│
├── server/ # 🏠 Local Mode Server (development)
└── README.md # This file
Use Case: Production deployment with multiple cameras on remote network
Architecture:
- Media Gateway on camera network server
- React App on separate public server
- Single WebSocket connection (port 8080)
- Supports 8 concurrent camera streams
Benefits:
- ✅ Centralized media processing
- ✅ Bandwidth optimization
- ✅ Single public endpoint
- ✅ Secure camera network isolation
Use Case: Testing and development with single cameras
Architecture:
- Direct RTSP connection from React app
- No intermediate gateway required
- Good for single camera testing
Benefits:
- ✅ Simple setup
- ✅ Direct camera access
⚠️ Limited scalability
Configure bandwidth usage based on your network capacity:
| Preset | Resolution | FPS | Bandwidth | Use Case |
|---|---|---|---|---|
| Ultra Low | 320×240 | 8 | ~150 KB/s | Mobile, poor connection |
| Low | 480×360 | 10 | ~300 KB/s | Low bandwidth |
| Medium | 640×480 | 15 | ~500 KB/s | Default, balanced |
| High | 1280×720 | 20 | ~1.5 MB/s | High quality viewing |
| Ultra High | 1920×1080 | 25 | ~3 MB/s | Maximum quality |
- 1 Camera Medium: ~500 KB/s
- 4 Cameras Medium: ~2 MB/s
- 8 Cameras Medium: ~4 MB/s
- 8 Cameras High: ~12 MB/s
// Connect to gateway
const socket = io('http://gateway-ip:8080');
// Get available cameras
socket.emit('get-cameras');
socket.on('cameras-list', ({ cameras, qualityPresets }) => {
// Handle camera list
});
// Start camera stream
socket.emit('start-camera', { cameraId: 1, quality: 'medium' });
// Receive video frames
socket.on('camera-frame', ({ cameraId, frame, timestamp }) => {
// frame is base64-encoded JPEG
// Display using Canvas API
});
// Handle stream events
socket.on('camera-started', ({ cameraId, quality }));
socket.on('camera-stopped', ({ cameraId }));
socket.on('camera-error', ({ cameraId, error }));| Endpoint | Description | Response |
|---|---|---|
GET /health |
Server health check | Status, uptime, camera count |
GET /api/cameras |
Camera list and status | Camera details, streaming status |
GET /api/stats |
Detailed statistics | Server metrics, stream info |
const CAMERAS = [
{
id: 1,
name: 'Front Door Camera',
location: 'Entrance',
rtsp: 'rtsp://admin:PASSWORD@192.168.10.192:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif',
type: 'ONVIF',
resolution: '1920x1080',
fps: 30,
enabled: true
},
// ... Configure up to 8 cameras
];const ENV_CONFIG = {
PORT: 8080,
HOST: '0.0.0.0',
MAX_CONCURRENT_STREAMS: 8,
DEFAULT_QUALITY: 'medium',
RTSP_TRANSPORT: 'udp', // or 'tcp'
ALLOWED_ORIGINS: ['http://your-react-app.com']
};# Gateway server status
curl http://gateway-ip:8080/health
# Camera connection test
cd gateway && npm run test
# View live logs
tail -f gateway/logs/gateway.log🚨 "Failed to connect to gateway"
- Verify gateway server is running
- Check firewall allows port 8080
- Test network connectivity between servers
🚨 "Camera won't stream"
- Test RTSP URL:
ffmpeg -i "rtsp://..." -t 5 -f null - - Verify camera credentials and IP
- Check UDP vs TCP transport settings
🚨 "High CPU usage"
- Reduce stream quality to 'low' or 'medium'
- Limit concurrent streams
- Monitor with
htopandps aux | grep ffmpeg
# Test individual camera RTSP
ffmpeg -rtsp_transport udp -i "rtsp://admin:pass@ip:554/path" -t 10 -f null -
# Check running processes
ps aux | grep -E "(node|ffmpeg)"
# Monitor network
netstat -tlnp | grep 8080
iftop -i eth0
# Check resources
htop
free -h- Deploy gateway on same network as cameras
- Only expose port 8080 to React app server
- Use strong camera credentials
- Consider VPN for remote access
- Regular security updates
- Start with 'medium' quality, adjust as needed
- Monitor CPU usage with multiple streams
- Use hardware acceleration if available
- Implement stream auto-cleanup (30s timeout)
- Use process manager (PM2, systemd)
- Set up log rotation
- Monitor disk space for logs
- Configure automated backups
- Health check monitoring
| Component | Minimum | Recommended | Notes |
|---|---|---|---|
| Gateway Server | 2 CPU, 2GB RAM | 4 CPU, 4GB RAM | FFmpeg intensive |
| React Server | 1 CPU, 1GB RAM | 2 CPU, 2GB RAM | Static files mainly |
| Storage | 5GB free | 10GB free | Logs, temp files |
| Network | 10 Mbps | 100+ Mbps | Depends on quality |
| OS | Ubuntu 18+ | Ubuntu 20+ | Linux preferred |
- Node.js 14+ installed
- Gateway code deployed
- Camera URLs configured in
config/cameras.js - Dependencies installed (
npm install) - Camera connections tested (
npm run test) - Port 8080 opened in firewall
- Gateway started (
npm start) - Health endpoint accessible
- Node.js 14+ installed
- React app code deployed
- Gateway URL updated in
src/App.js - Dependencies installed (
npm install) - Production build created (
npm run build) - Web server configured (nginx/apache)
- SSL certificate (optional)
- React app can reach gateway health endpoint
- WebSocket connection established
- Camera list loads successfully
- Individual camera streams work
- Multiple camera streams work
- Quality settings function properly
- Error handling works (disconnect/reconnect)
- 8 cameras covering office areas
- Gateway on office network server
- Remote monitoring from mobile/desktop
- Medium quality for bandwidth efficiency
- 4-6 cameras around property
- Gateway on home NAS/server
- Remote access while traveling
- High quality on local network, low when remote
- Multiple cameras on factory floor
- Dedicated monitoring workstation
- 24/7 operation requirements
- Ultra high quality for detail inspection
- Gateway Documentation: gateway/README.md
- ONVIF Specification: ONVIF Official Site
- FFmpeg Documentation: FFmpeg Docs
- React Documentation: React Official Docs
- Socket.io Guide: Socket.io Docs
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Architecture Questions: Check this README and gateway documentation
- Camera Issues: Use
npm run testfor connectivity troubleshooting - Performance Issues: Monitor with provided debug commands
- Integration Help: See WebSocket API examples above
ONVIF WebRTC Camera Viewer - Professional IP Camera Streaming Solution
Built with ❤️ using React, Node.js, WebRTC, and FFmpeg