P2P camera system
Building a P2P Camera System
(Like Hikvision, TP-Link Tapo, Imou, Xiaomi, etc.)
Author: Personal Notes Prerequisites: - Python - Django - Networking Basics - Linux Server - Docker (Optional)
Goal
Create a system where
Camera -----> Internet
|
|
Registration Server
|
Mobile Application
|
|
Direct Camera Connection
without manually configuring port forwarding.
High Level Architecture
+----------------------+
| Django Cloud Server |
| Static IP |
+----------+-----------+
|
------------------+------------------
| |
Camera Registration Mobile App
| |
+------------Handshake----------------+
|
STUN / TURN Server
|
NAT Hole Punching
|
Direct P2P Stream
The Django server is NOT responsible for video streaming.
It only performs
- Device registration
- Authentication
- Signaling
- Online status
- Device discovery
Actual video goes directly between
Phone <---------> Camera
Components Required
1. Camera Device
Could be
- Raspberry Pi
- ESP32-CAM
- Android Phone
- IP Camera
- Custom Linux Board
Requirements
- Internet connection
- Unique Device ID
- Video Encoder
- TCP/UDP sockets
2. Django Server
You already have
✔ Hosted Server ✔ Static IP
Responsibilities
- User login
- Device registration
- JWT authentication
- Device ownership
- Online status
- Push notifications
- WebSocket signaling
Example Database
User
id
username
password
------------------------
Camera
id
uid
owner
last_ip
last_seen
online
------------------------
Session
id
camera
viewer
created_at
status
3. PostgreSQL
Store
- Users
- Cameras
- Sessions
- Tokens
- Device Settings
4. Redis
Used for
- WebSocket
- Online status
- Fast cache
- Pub/Sub
5. Django Channels
Needed for
Realtime signaling
Phone
|
WebSocket
|
Django
|
Camera
Messages
Offer
Answer
ICE Candidate
Heartbeat
Disconnect
6. STUN Server
Purpose
Find public IP and port.
Example
Camera
Private IP
192.168.0.22
↓
STUN
↓
Public IP
103.x.x.x:52342
Popular
- coturn
- Google's STUN
stun.l.google.com:19302
7. TURN Server
When P2P fails
Video passes through TURN.
Phone
↓
TURN Server
↓
Camera
Consumes bandwidth.
Recommended
Coturn
8. Video Streaming
Choices
MJPEG
Simple
Slow
RTSP
Most IP cameras
rtsp://camera/live
RTP
Professional
UDP based
WebRTC
Recommended
Supports
- Video
- Audio
- NAT traversal
- Encryption
Camera Boot Process
Camera Starts
↓
Generate UID
↓
Connect Internet
↓
Authenticate
↓
Send heartbeat every 30 seconds
↓
Wait for viewers
Heartbeat Example
{
"uid":"ABC123",
"ip":"192.168.1.22",
"firmware":"1.0.0",
"status":"online"
}
User Opens Mobile App
Login
↓
Load Camera List
↓
Select Camera
↓
Request Stream
Django Flow
User
↓
JWT
↓
Request Camera
↓
Find Camera
↓
Notify Camera
Camera Receives Request
Incoming Viewer
↓
Create WebRTC Offer
↓
Send SDP
↓
Exchange ICE
↓
Connect
NAT Hole Punching
Without P2P
Phone
↓
Cloud
↓
Camera
High latency.
With P2P
Phone
↓
Router
↓
Camera
Direct.
Signaling
Only signaling passes through Django.
Example
Phone
↓
Offer
↓
Django
↓
Camera
↓
Answer
↓
Django
↓
Phone
After that
Django is no longer involved.
WebRTC Objects
Offer
SDP
Answer
SDP
ICE Candidate
Possible network paths
Required Python Packages
Django
Django REST Framework
Django Channels
channels_redis
psycopg2
redis
PyJWT
uvicorn
gunicorn
django-cors-headers
Camera Software
Python
OpenCV
aiortc
asyncio
websockets
requests
or
C++
libwebrtc
OpenCV
FFmpeg
Video Encoding
Recommended
H264
Optional
H265
VP8
VP9
AV1
Authentication
Camera Login
UID
+
Secret Key
Example
POST
/api/device/login/
Returns
JWT Token
Device Registration
POST
/api/device/register/
Body
{
"uid":"ABC123",
"model":"ESP32",
"firmware":"1.0"
}
Viewer Authentication
JWT
↓
Check Ownership
↓
Allow Stream
Heartbeat API
POST
/api/heartbeat/
Every
20-30 seconds
Django APIs
POST /login/
POST /register/
POST /device/register/
POST /heartbeat/
GET /device/list/
POST /request-stream/
POST /disconnect/
GET /ice-config/
POST /webrtc/offer/
POST /webrtc/answer/
WebSocket Messages
Offer
{
"type":"offer",
"sdp":"..."
}
Answer
{
"type":"answer",
"sdp":"..."
}
ICE
{
"type":"candidate",
"candidate":"..."
}
Security
Always
✔ HTTPS
✔ WSS
✔ JWT
✔ Device Secret
✔ AES (optional)
✔ DTLS
✔ SRTP
Production Stack
Ubuntu
Nginx
Gunicorn
Django
Redis
PostgreSQL
Coturn
Docker
Prometheus
Grafana
Scaling
Single Server
Django
Redis
Postgres
↓
Multiple Django
↓
Load Balancer
↓
Redis Cluster
↓
Multiple TURN Servers
↓
CDN (Optional)
Recommended Project Structure
camera_cloud/
accounts/
devices/
signaling/
streaming/
api/
websocket/
heartbeat/
permissions/
notifications/
utils/
settings/
manage.py
Skills to Learn
Networking
- TCP
- UDP
- NAT
- Firewalls
- STUN
- TURN
- ICE
- WebRTC
- RTP
- RTSP
Backend
- Django REST Framework
- Django Channels
- JWT
- Redis
- PostgreSQL
Streaming
- FFmpeg
- OpenCV
- aiortc
- GStreamer (optional)
Linux
- Nginx
- Docker
- Systemd
- Coturn
Minimum Viable Product (MVP)
Phase 1: - Django authentication - Camera registration - Heartbeats - Device list
Phase 2: - Django Channels signaling - WebSocket communication
Phase 3: - STUN integration - WebRTC connection
Phase 4: - Live video streaming
Phase 5: - TURN fallback
Phase 6: - Recording - Motion detection - Push notifications - Multi-camera dashboard - Firmware updates - Cloud backup
Final Architecture
+-------------------------+
| Django Server |
| REST + WebSocket + JWT |
+-----------+-------------+
|
PostgreSQL
|
Redis
|
Django Channels
|
STUN / TURN (Coturn)
|
------------------------------------------------
| |
Camera 1 Camera 2
| |
+------------------- Internet -----------------+
|
Mobile App
|
Direct WebRTC Stream
Notes
- Django should not carry the video stream in production. It is used for signaling, authentication, and device management.
- WebRTC with STUN/TURN provides the best user experience for NAT traversal and encrypted, low-latency streaming.
- For many concurrent users, deploy dedicated TURN servers because relay traffic can consume significant bandwidth.