Design Documentation
This document describes the system architecture, module breakdown, data flow, and extension points of live-webrtc-go for architectural review and secondary development.
Table of Contents
- Design Documentation
- System Architecture
- Architecture Overview
- Request Processing Chain
- Core Concepts
- Room
- Track Fanout
- PeerConnection
- Module Details
- cmd/server
- internal/config
- internal/api
- internal/sfu
- internal/metrics
- internal/uploader
- Data Flow
- Publishing Flow (WHIP)
- Playback Flow (WHEP)
- Disconnection
- Authentication System
- Token Authentication
- JWT Authentication
- Recording and Upload
- Recording Format
- File Naming
- Upload Flow
- Observability
- Prometheus Metrics
- OpenTelemetry Tracing
- Health Check
- Extension Points
- 1. Multi-instance Deployment
- 2. Media Processing
- 3. Authentication Extensions
- 4. Storage Extensions
- Performance Considerations
- Memory Usage
- CPU Usage
- Optimization Suggestions
System Architecture
Architecture Overview
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| ┌─────────────────────────────────────┐
│ HTTP Server :8080 │
│ │
┌──────────┐ │ ┌─────────┐ ┌─────────────┐ │
│ Publisher│ ──WHIP──▶│ │ Auth │───▶│ SFU │ │
│(OBS/Web) │ │ │Middleware│ │ Manager │ │
└──────────┘ │ └─────────┘ └──────┬──────┘ │
│ │ │
┌──────────┐ │ ┌───────────────┤ │
│ Viewer │ ◀──WHEP──│ │ │ │
│(Browser) │───────▶ │ ▼ ▼ │
└──────────┘ │ ┌─────────────┐ ┌───────────┐ │
│ │ Room │ │ Recording │ │
│ │ (Fanout) │ │ & Upload │ │
│ └──────┬──────┘ └─────┬─────┘ │
└────────┼──────────────┼────────────┘
│ │
┌─────────▼──────────────▼───────────┐
│ Object Storage │
│ (S3/MinIO) │
└────────────────────────────────────┘
|
Request Processing Chain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| HTTP Request
│
▼
┌─────────────┐
│ CORS │ ← ALLOWED_ORIGIN
└──────┬──────┘
│
▼
┌─────────────┐
│ Rate Limiter│ ← RATE_LIMIT_RPS, RATE_LIMIT_BURST
└──────┬──────┘
│
▼
┌─────────────┐
│ Auth │ ← AUTH_TOKEN / ROOM_TOKENS / JWT_SECRET
└──────┬──────┘
│
▼
┌─────────────┐
│ Handler │ → Business Logic
└─────────────┘
|
Core Concepts
Room
The Room is the core abstraction of the SFU. Each room:
- Has at most one Publisher
- Can have multiple Subscribers
- Has independent Track Fanout logic
- Can have its own authentication token
Track Fanout
When a publisher pushes media tracks, the system creates a Track Fanout:
- Read RTP packets from the publisher’s PeerConnection
- Copy and distribute to all subscribers
- Optionally write to recording files
PeerConnection
Each WebRTC connection:
- Publisher: Receives media tracks
- Subscriber: Sends media tracks
- ICE negotiation completed through WHIP/WHEP protocols
Module Details
cmd/server
Responsibility: Application entry point, service initialization
1
2
3
4
5
6
7
8
9
| // main.go main flow
1. config.Load() // Load configuration
2. uploader.Init() // Initialize uploader
3. sfu.NewManager() // Create room manager
4. api.NewHTTPHandlers() // Create HTTP handlers
5. RegisterRoutes() // Register routes
6. otel.InitTracer() // Initialize tracing
7. http.Server.Listen() // Start server
8. Graceful Shutdown // Graceful exit
|
internal/config
Responsibility: Environment variable parsing and defaults
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| ┌─────────────────────────────────────┐
│ Config │
├─────────────────────────────────────┤
│ HTTPAddr string │
│ AllowedOrigin string │
│ AuthToken string │
│ RoomTokens map[string]string │
│ JWTSecret string │
│ RecordEnabled bool │
│ RecordDir string │
│ S3Endpoint string │
│ RateLimitRPS float64 │
│ STUN/TURN []string │
│ ... │
└─────────────────────────────────────┘
|
internal/api
Responsibility: HTTP request handling
| File |
Function |
handlers.go |
WHIP/WHEP/Rooms/Records/Admin endpoint handling |
middleware.go |
CORS, rate limiting, Token/JWT authentication |
routes.go |
URL routing, parameter extraction, room name validation |
Authentication Priority:
1
2
3
4
5
6
7
| 1. Room-specific Token (ROOM_TOKENS)
↓ (not found or failed)
2. Global Token (AUTH_TOKEN)
↓ (not found or failed)
3. JWT (JWT_SECRET)
↓ (not found or failed)
4. Allow (no auth configured)
|
internal/sfu
Responsibility: WebRTC SFU core logic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| ┌─────────────────────────────────────────────────────┐
│ Manager │
│ - Manage all Room instances │
│ - Create/Delete Room │
│ - Count rooms │
└──────────────────────┬──────────────────────────────┘
│ 1:N
▼
┌─────────────────────────────────────────────────────┐
│ Room │
│ - Publisher PeerConnection │
│ - Subscriber PeerConnections │
│ - TrackFeeds (TrackFanout map) │
└──────────────────────┬──────────────────────────────┘
│ 1:N
▼
┌─────────────────────────────────────────────────────┐
│ TrackFanout │
│ - Remote Track (from publisher) │
│ - Local Tracks (to subscribers) │
│ - readLoop: RTP distribution │
│ - Optional: Recorder (IVF/OGG writer) │
└─────────────────────────────────────────────────────┘
|
Key Methods:
| Method |
Purpose |
Manager.Publish() |
Create room, establish publisher connection |
Manager.Subscribe() |
Create subscriber connection, bind existing tracks |
Room.attachTrackFeed() |
Distribute new track to all subscribers |
TrackFanout.readLoop() |
RTP packet reading and distribution loop |
internal/metrics
Responsibility: Prometheus metrics exposure
| Metric |
Type |
Description |
live_rooms |
Gauge |
Active room count |
live_subscribers |
GaugeVec |
Subscribers per room |
rtp_bytes_total |
CounterVec |
Total RTP bytes |
rtp_packets_total |
CounterVec |
Total RTP packets |
internal/uploader
Responsibility: S3/MinIO file upload
1
2
3
4
5
6
| Upload Flow:
1. Check Enabled() → client != nil
2. Open local file
3. Build object key (prefix + filename)
4. client.PutObject()
5. (Optional) Delete local file
|
Data Flow
Publishing Flow (WHIP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| 1. Publisher → POST /api/whip/publish/{room}
│
2. HTTPHandlers.ServeWHIPPublish()
│ ├─ CORS check
│ ├─ Rate limit check
│ └─ Authentication check
│
3. Manager.Publish(roomName, sdpOffer)
│ ├─ getOrCreateRoom()
│ └─ Room.Publish(sdpOffer)
│
4. Room.Publish()
│ ├─ Create MediaEngine + Interceptors
│ ├─ NewPeerConnection(ICEConfig)
│ ├─ SetRemoteDescription(offer)
│ ├─ CreateAnswer()
│ ├─ SetLocalDescription(answer)
│ └─ OnTrack: attachTrackFeed()
│
5. Return SDP Answer
│
6. TrackFanout.readLoop() runs continuously
│ ├─ Read RTP from Remote Track
│ ├─ Write to recorder (if enabled)
│ └─ Distribute to all Local Tracks
|
Playback Flow (WHEP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 1. Viewer → POST /api/whep/play/{room}
│
2. HTTPHandlers.ServeWHEPPlay()
│ ├─ CORS/Rate limit/Authentication check
│ └─ Manager.Subscribe()
│
3. Manager.Subscribe(roomName, sdpOffer)
│ └─ Room.Subscribe(sdpOffer)
│
4. Room.Subscribe()
│ ├─ Check subscriber limit
│ ├─ NewPeerConnection()
│ ├─ Iterate existing TrackFeeds
│ │ └─ TrackFanout.attachToSubscriber()
│ ├─ SetRemoteDescription/CreateAnswer
│ └─ OnICEStateChange: removeSubscriber()
│
5. Return SDP Answer
|
Disconnection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| ICE State Change (Failed/Disconnected/Closed)
│
▼
┌─────────────────────────────────────┐
│ Publisher Disconnect │
├─────────────────────────────────────┤
│ 1. closePublisher() │
│ 2. Close all TrackFanouts │
│ 3. Upload recording files │
│ 4. Clear subscriber list │
│ 5. pruneIfEmpty() │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Subscriber Disconnect │
├─────────────────────────────────────┤
│ 1. removeSubscriber() │
│ 2. Remove binding from TrackFanouts │
│ 3. Close PeerConnection │
│ 4. pruneIfEmpty() │
└─────────────────────────────────────┘
|
Authentication System
Token Authentication
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| Priority 1: Room Token (ROOM_TOKENS)
┌─────────────────────────────────────┐
│ ROOM_TOKENS="room1:abc;room2:def" │
│ │
│ Access room1 → Check token == "abc" │
│ Access room2 → Check token == "def" │
│ Access room3 → Fallback to Global Token │
└─────────────────────────────────────┘
Priority 2: Global Token (AUTH_TOKEN)
┌─────────────────────────────────────┐
│ AUTH_TOKEN="secret123" │
│ │
│ All rooms use the same token │
└─────────────────────────────────────┘
|
JWT Authentication
1
2
3
4
5
6
7
8
9
10
11
| // JWT Claims structure
type roomClaims struct {
Room string `json:"room,omitempty"` // Restrict to room
Role string `json:"role,omitempty"` // "admin" role
Admin any `json:"admin,omitempty"` // true/1 for admin
jwt.RegisteredClaims
}
// Use cases
1. Room access: claims.Room == room or claims.Room == ""
2. Admin API: claims.Role == "admin" or claims.Admin == true
|
Recording and Upload
| Codec |
File Format |
Writer |
| Opus |
.ogg |
oggwriter (48kHz, 2ch) |
| VP8 |
.ivf |
ivfwriter |
| VP9 |
.ivf |
ivfwriter |
File Naming
1
2
3
| {room}_{trackID}_{unixTimestamp}.{ext}
Example: demo_video0_1710123456.ivf
|
Upload Flow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| Room.closePublisher()
│
▼
TrackFanout.close() → Return recording file path
│
▼
uploader.Enabled()?
│ Yes
▼
go uploadRecording(path)
│
▼
Upload(ctx, path)
├─ PutObject(S3Bucket, objectKey, file)
└─ (Optional) os.Remove(localFile)
|
Observability
Prometheus Metrics
1
2
3
4
5
6
7
8
9
10
11
| # Active room count
live_rooms
# Subscribers per room
live_subscribers{room="demo"}
# RTP bytes (cumulative)
live_rtp_bytes_total{room="demo"}
# RTP packets (cumulative)
live_rtp_packets_total{room="demo"}
|
OpenTelemetry Tracing
1
2
3
4
5
6
7
| Environment variables:
OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_SERVICE_NAME=live-webrtc-go
Traced spans:
- HTTP Handler: {method} {path}
|
Health Check
1
| GET /healthz → "ok" (200 OK)
|
Extension Points
1. Multi-instance Deployment
Current room state is in memory. For multi-instance deployment:
- External storage (Redis/Database) for room mappings
- Session affinity (Sticky Session)
- Or client-side redirection
Can be inserted before TrackFanout.readLoop():
- Transcoding (FFmpeg integration)
- Simulcast / Multiple bitrates
- Screenshots / Watermarks
3. Authentication Extensions
Extend in middleware.go:
- OAuth2 integration
- Webhook callback validation
- IP whitelist
4. Storage Extensions
Implement rtpWriter interface:
1
2
3
4
| type rtpWriter interface {
WriteRTP(*rtp.Packet) error
Close() error
}
|
Supports:
- Real-time repackaging (MP4)
- Streaming upload (without local storage)
- CDN push
Memory Usage
- Each TrackFanout: ~1-2 MB (RTP buffer)
- Each subscriber: ~1500 bytes (MTU buffer)
- Recording buffer: Depends on write frequency
CPU Usage
- RTP packet processing: Main loop in
readLoop()
- Codec negotiation: Only during connection establishment
- Metrics update: Per RTP packet
Optimization Suggestions
- Zero-copy RTP forwarding (requires TrackFanout modification)
- Batch metrics updates
- Connection pooling (multi-room scenarios)
- SIMD optimization (large number of subscribers)