- CSS 92.9%
- HTML 7.1%
Converted 1 file(s) from Markdown to KOD (Koder Document) format. KOD is now the default document format on Koder Flow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| site | ||
| src | ||
| static | ||
| tests | ||
| web | ||
| .gitignore | ||
| kall.toml | ||
| LICENSE | ||
| README.kd | ||
_ __ ___ ____ _____ ____ _ __ _ _ _
| |/ // _ \| _ \| ____| _ \ | |/ / / \ | | | |
| ' /| | | | | | | _| | |_) | | ' / / _ \ | | | |
| . \| |_| | |_| | |___| _ < | . \ / ___ \| |___| |___
|_|\_\\___/|____/|_____|_| \_\ |_|\_\/_/ \_\_____|_____|
Koder Kall
Open-source, self-hosted video conferencing platform built for privacy, performance, and extensibility.
Features
Core Video Conferencing
- Real-time video and audio with SFU (Selective Forwarding Unit) architecture
- Simulcast with adaptive layer switching
- Dynacast: pause unseen video layers to save bandwidth
- Active speaker detection
- Screen sharing with audio
- Virtual backgrounds and noise suppression
Collaboration
- In-meeting chat with private messages, reactions, and file attachments
- Interactive whiteboard with drawing tools, shapes, and text
- Shared notes with real-time collaborative editing (OT-based)
- Polls with anonymous voting and audit-proof logging
Room Management
- Password-protected rooms
- Lobby / waiting room with admit/reject controls
- Breakout rooms with automatic return
- Room locking
- Configurable participant limits
- Host, co-host, guest, and viewer roles
Recording & Streaming
- Server-side composite recording (WebM, MP4)
- Individual track recording
- RTMP output to YouTube, Twitch, or custom endpoints
- Recording webhooks for post-processing
Security & Authentication
- JWT-based authentication with configurable claims
- Multiple auth modes: token, open, lobby
- Role-based permissions (host, co-host, guest, viewer)
- End-to-end encryption (E2EE) support
- DTLS/SRTP media encryption
AI Features
- Live transcription
- Real-time translation
- Meeting summary generation
- Noise cancellation (AI-powered)
- Auto-generated captions
Integrations
- REST API for room and participant management
- WebSocket protocol for real-time events
- Webhook notifications
- Embeddable via iframe or JavaScript SDK
- Prometheus metrics endpoint
- TURN/STUN server support
Quick Start
Prerequisites
- Koder Lang >= 2.0
- Redis >= 7.0 (for signaling)
- PostgreSQL >= 15 or SQLite (for persistence)
- TURN server (coturn recommended, optional for LAN-only)
Install
# Clone the repository
git clone https://flow.koder.dev/koder/koder-kall.git
cd koder-kall
# Install dependencies
kd install
# Generate default configuration
kd run setup
Configure
Copy and edit the configuration file:
cp kall.example.toml kall.toml
Set at minimum:
[server]
host = "0.0.0.0"
port = 7880
base_url = "https://kall.example.com"
[auth]
secret = "your-256-bit-secret-key-here"
[redis]
url = "redis://localhost:6379/0"
Run
# Development mode with auto-reload
kd run dev
# Production mode
kd run server --env production
The server starts at http://localhost:7880 by default.
Configuration Reference (kall.toml)
[server]
host = "0.0.0.0" # Bind address
port = 7880 # HTTP/WebSocket port
base_url = "https://kall.example.com"
tls_cert = "" # Path to TLS certificate (optional behind reverse proxy)
tls_key = "" # Path to TLS private key
log_level = "info" # trace, debug, info, warn, error
[auth]
secret = "" # JWT signing secret (required)
issuer = "koder-kall" # JWT issuer claim
mode = "token" # token, open, lobby
guest_ttl = 3600 # Guest token TTL in seconds
allowed_origins = ["*"] # CORS origins
[room]
default_max_participants = 100
max_rooms = 500
empty_room_timeout = 300 # Seconds before closing empty rooms
lobby_enabled = false # Global default for lobby
recording_enabled = false # Global default for recording
[media]
codecs = ["VP8", "VP9", "H264", "opus"]
simulcast = true
dynacast = true
max_bitrate = 3_000_000 # Maximum video bitrate in bps
screen_share_bitrate = 5_000_000
audio_channels = 1
audio_sample_rate = 48000
[redis]
url = "redis://localhost:6379/0"
pool_size = 10
[database]
driver = "sqlite" # sqlite, postgres
url = "kall.db" # SQLite file path or PostgreSQL connection string
[turn]
enabled = false
host = ""
port = 3478
username = ""
credential = ""
tls = false
[recording]
enabled = false
output_dir = "./recordings"
format = "webm" # webm, mp4
composite = true # true = single file, false = per-track
[rtmp]
enabled = false
max_streams = 5
[webhooks]
enabled = false
timeout = 10 # HTTP timeout in seconds
retry_count = 3
signing_secret = "" # HMAC-SHA256 signing secret
[ai]
transcription = false
translation = false
summary = false
noise_cancellation = false
provider = "" # Provider-specific config
api_key = ""
[metrics]
enabled = true
endpoint = "/metrics" # Prometheus metrics path
CLI Commands
kd run server # Start the Koder Kall server
kd run server --env production # Start in production mode
kd run dev # Start with auto-reload
kd run setup # Generate default config
kd run migrate # Run database migrations
kd run token # Generate a test JWT token
--room ROOM_ID # Target room
--identity USER_ID # User identity
--name NAME # Display name
--role ROLE # host, co_host, guest, viewer
--ttl SECONDS # Token time-to-live
kd run rooms # List active rooms
kd run rooms:close ROOM_ID # Force-close a room
kd run stats # Show server statistics
kd test # Run the test suite
kd test tests/room_test.kd # Run a specific test file
REST API Reference
All API endpoints require authentication via the Authorization header:
Authorization: Bearer <api-key>:<api-secret>
Health
GET /health
Response 200:
{
"status": "ok",
"version": "1.0.0",
"uptime_seconds": 86400
}
Rooms
Create Room
POST /rooms
Content-Type: application/json
{
"name": "Team Standup",
"max_participants": 20,
"password": "optional-password",
"lobby_enabled": true,
"recording_enabled": false
}
Response 201:
{
"id": "rm_a1b2c3d4",
"name": "Team Standup",
"slug": "team-standup-a1b2",
"max_participants": 20,
"lobby_enabled": true,
"created_at": "2026-03-16T10:00:00Z"
}
List Rooms
GET /rooms
GET /rooms?status=active&limit=50&offset=0
Response 200:
{
"rooms": [...],
"total": 12
}
Get Room
GET /rooms/:id
Response 200:
{
"id": "rm_a1b2c3d4",
"name": "Team Standup",
"status": "active",
"participant_count": 5,
"created_at": "2026-03-16T10:00:00Z"
}
Delete Room
DELETE /rooms/:id
Response 204 (no content).
Participants
List Participants
GET /rooms/:id/participants
Response 200:
{
"participants": [
{
"identity": "user-1",
"name": "Alice",
"role": "host",
"joined_at": "2026-03-16T10:01:00Z",
"tracks": { "audio": true, "video": true, "screen": false }
}
]
}
Kick Participant
POST /rooms/:id/kick
Content-Type: application/json
{ "identity": "user-1" }
Mute Participant
POST /rooms/:id/mute
Content-Type: application/json
{ "identity": "user-1", "track_type": "audio" }
Tokens
Generate Token
POST /tokens
Content-Type: application/json
{
"room": "rm_a1b2c3d4",
"identity": "user-1",
"name": "Alice",
"role": "host",
"ttl": 86400
}
Response 200:
{
"token": "eyJhbGciOi..."
}
Webhooks
Register Webhook
POST /webhooks
Content-Type: application/json
{
"url": "https://example.com/hook",
"events": ["room.created", "room.closed", "participant.joined", "participant.left", "recording.ready"]
}
List Webhooks
GET /webhooks
Delete Webhook
DELETE /webhooks/:id
Statistics
GET /stats
Response 200:
{
"rooms": 12,
"participants": 87,
"tracks": { "audio": 87, "video": 64, "screen": 3 },
"uptime_seconds": 86400,
"memory_mb": 512
}
WebSocket Protocol
Connect to the signaling server:
wss://kall.example.com/ws?token=<jwt-token>
Messages (Client to Server)
{"type": "join", "room": "rm_a1b2c3d4"}
{"type": "leave"}
{"type": "offer", "sdp": "..."}
{"type": "answer", "sdp": "..."}
{"type": "candidate", "candidate": {...}}
{"type": "mute", "track": "audio"}
{"type": "unmute", "track": "audio"}
{"type": "chat", "text": "Hello!", "to": null}
{"type": "chat", "text": "Private msg", "to": "user-2"}
{"type": "reaction", "emoji": "thumbsup", "message_id": "msg-1"}
{"type": "subscribe", "track_id": "tr_abc", "layer": "medium"}
{"type": "unsubscribe", "track_id": "tr_abc"}
Messages (Server to Client)
{"type": "joined", "room": "rm_a1b2c3d4", "participants": [...]}
{"type": "participant_joined", "identity": "user-2", "name": "Bob"}
{"type": "participant_left", "identity": "user-2"}
{"type": "offer", "sdp": "...", "from": "user-2"}
{"type": "answer", "sdp": "...", "from": "user-2"}
{"type": "candidate", "candidate": {...}, "from": "user-2"}
{"type": "track_published", "track_id": "tr_abc", "kind": "video", "from": "user-2"}
{"type": "track_unpublished", "track_id": "tr_abc", "from": "user-2"}
{"type": "active_speaker", "identity": "user-1"}
{"type": "chat", "id": "msg-1", "from": "user-2", "text": "Hello!", "timestamp": 1710583200}
{"type": "muted", "identity": "user-1", "track": "audio", "by": "host-1"}
{"type": "kicked", "identity": "user-1", "by": "host-1"}
{"type": "room_closed"}
{"type": "error", "code": "auth_failed", "message": "Invalid token"}
Authentication Modes
Token Mode (default)
All participants must present a valid JWT to join. Tokens are generated server-side via the REST API or CLI.
kd run token --room rm_abc --identity user-1 --name "Alice" --role host --ttl 86400
Open Mode
Anyone can join any room without authentication. Suitable for public events or development.
[auth]
mode = "open"
Lobby Mode
Participants enter a waiting room. The host must admit or reject each one.
[auth]
mode = "lobby"
Lobby actions via WebSocket:
{"type": "lobby_admit", "identity": "guest-1"}
{"type": "lobby_reject", "identity": "guest-1", "reason": "Not invited"}
{"type": "lobby_admit_all"}
Recording Setup
Server-Side Recording
[recording]
enabled = true
output_dir = "/var/lib/koder-kall/recordings"
format = "webm"
composite = true
Start/stop recording via API:
POST /rooms/:id/recording/start
POST /rooms/:id/recording/stop
A recording.ready webhook is fired when the file is available.
Individual Track Recording
Set composite = false to record each participant's audio and video as separate files, useful for post-production editing.
RTMP Streaming
Stream a room to external platforms:
POST /rooms/:id/rtmp/start
Content-Type: application/json
{
"url": "rtmp://live.twitch.tv/app/STREAM_KEY"
}
Stop:
POST /rooms/:id/rtmp/stop
TURN/STUN Configuration
For participants behind restrictive NATs or firewalls, configure a TURN server:
[turn]
enabled = true
host = "turn.example.com"
port = 3478
username = "koder-kall"
credential = "turn-secret"
tls = true
Recommended: coturn with long-term credentials.
STUN is used automatically (stun:stun.l.google.com:19302 as fallback).
AI Features
Enable AI-powered capabilities:
[ai]
transcription = true
translation = true
summary = true
noise_cancellation = true
provider = "koder-ai"
api_key = "your-ai-api-key"
- Transcription: Real-time speech-to-text displayed as captions
- Translation: Translate captions to participant's preferred language
- Summary: Auto-generated meeting summary available after the call
- Noise cancellation: ML-based background noise removal
Embed API
Embed Koder Kall in any web application:
iframe
<iframe
src="https://kall.example.com/embed?room=rm_abc&token=JWT_TOKEN"
width="800"
height="600"
allow="camera; microphone; display-capture; autoplay"
></iframe>
JavaScript SDK
<script src="https://kall.example.com/sdk/koder-kall.js"></script>
<script>
const kall = new KoderKall({
url: "wss://kall.example.com",
token: "JWT_TOKEN",
container: document.getElementById("meeting"),
});
kall.on("connected", () => console.log("Connected"));
kall.on("participant_joined", (p) => console.log(p.name + " joined"));
kall.on("disconnected", () => console.log("Disconnected"));
kall.connect();
</script>
Webhooks
Register webhooks to receive real-time notifications:
Available Events
| Event | Description |
|---|---|
room.created | A new room was created |
room.closed | A room was closed |
participant.joined | A participant joined a room |
participant.left | A participant left a room |
recording.started | Recording started |
recording.ready | Recording file is available |
rtmp.started | RTMP stream started |
rtmp.stopped | RTMP stream stopped |
Payload Format
{
"event": "participant.joined",
"timestamp": "2026-03-16T10:01:00Z",
"room_id": "rm_a1b2c3d4",
"data": {
"identity": "user-1",
"name": "Alice",
"role": "host"
}
}
Signature Verification
Each webhook request includes an X-Kall-Signature header:
X-Kall-Signature: sha256=<HMAC-SHA256 hex digest>
Verify by computing HMAC-SHA256(signing_secret, request_body).
Prometheus Metrics
Metrics are exposed at /metrics (configurable) in Prometheus format:
# HELP koder_kall_rooms_active Number of active rooms
# TYPE koder_kall_rooms_active gauge
koder_kall_rooms_active 12
# HELP koder_kall_participants_total Total participants across all rooms
# TYPE koder_kall_participants_total gauge
koder_kall_participants_total 87
# HELP koder_kall_tracks_total Total published tracks by kind
# TYPE koder_kall_tracks_total gauge
koder_kall_tracks_total{kind="audio"} 87
koder_kall_tracks_total{kind="video"} 64
koder_kall_tracks_total{kind="screen"} 3
# HELP koder_kall_bandwidth_bytes_total Total bandwidth in bytes
# TYPE koder_kall_bandwidth_bytes_total counter
koder_kall_bandwidth_bytes_total{direction="ingress"} 1073741824
koder_kall_bandwidth_bytes_total{direction="egress"} 8589934592
# HELP koder_kall_http_requests_total Total HTTP API requests
# TYPE koder_kall_http_requests_total counter
koder_kall_http_requests_total{method="GET",status="200"} 15432
# HELP koder_kall_ws_connections_active Active WebSocket connections
# TYPE koder_kall_ws_connections_active gauge
koder_kall_ws_connections_active 87
Architecture Overview
+------------------+
| Load Balancer |
+--------+---------+
|
+------------+------------+
| |
+-------v-------+ +--------v------+
| Koder Kall | | Koder Kall |
| Instance 1 | | Instance 2 |
+---+-------+---+ +---+-------+---+
| | | |
+--------v--+ +--v--------+ +---v-----+ |
| SFU Router| | HTTP API | |SFU Router| |
+-----------+ +-----------+ +----------+ |
| | | |
+---+---+-------+-------+---+---+
| | |
+-----v---+ +----v----+ +----v----+
| Redis | | DB | | Object |
| (signal)| |(rooms, | | Storage |
| | | users) | |(records)|
+---------+ +---------+ +---------+
Components:
- SFU Router: Handles WebRTC media routing. One router per room. Forwards audio/video tracks between participants without mixing.
- HTTP API: RESTful API for room management, token generation, and administration.
- WebSocket Signaling: Real-time signaling for WebRTC negotiation, chat, and control messages.
- Redis: Pub/sub for inter-instance signaling and shared state in multi-node deployments.
- Database: Persistent storage for room configurations, user data, and session history.
- Object Storage: Stores recordings and file attachments.
Development Guide
Project Structure
koder-kall/
src/
koder_kall/
api.kd # REST API handlers
auth.kd # Authentication & JWT
chat.kd # Chat system
lobby.kd # Lobby / waiting room
participant.kd # Participant model
room.kd # Room management
session.kd # Session tracking
sfu/
router.kd # SFU media router
track.kd # Audio/video tracks
transport.kd # WebRTC transports
collab/
whiteboard.kd # Whiteboard
shared_notes.kd # Collaborative notes
poll.kd # Polls & voting
ws/
handler.kd # WebSocket handler
protocol.kd # Message protocol
tests/
room_test.kd
auth_test.kd
chat_test.kd
api_test.kd
sfu_test.kd
collab_test.kd
kall.example.toml
README.md
Running Tests
# All tests
kd test
# Specific file
kd test tests/room_test.kd
# With verbose output
kd test --verbose
# With coverage
kd test --coverage
Code Style
- Follow Koder Lang conventions (Ruby-like style)
- 2-space indentation
- snake_case for methods and variables
- PascalCase for classes and modules
- Maximum line length: 120 characters
License
MIT License. See LICENSE for details.