Real-time video conferencing and meeting platform written in Koder Lang
  • CSS 92.9%
  • HTML 7.1%
Find a file
Rodrigo Mendonça 5f962a1f11 Convert .md files to KOD format (.kd)
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>
2026-03-21 21:01:47 -03:00
site feat: add site with landing page, join, dashboard and Koder ID auth 2026-03-16 21:29:01 -03:00
src feat: add site with landing page, join, dashboard and Koder ID auth 2026-03-16 21:29:01 -03:00
static feat: implement Koder Kall video conferencing platform 2026-03-16 21:06:08 -03:00
tests feat: implement Koder Kall video conferencing platform 2026-03-16 21:06:08 -03:00
web feat: implement Koder Kall video conferencing platform 2026-03-16 21:06:08 -03:00
.gitignore add .gitignore and MIT license 2026-03-16 21:15:18 -03:00
kall.toml feat: implement Koder Kall video conferencing platform 2026-03-16 21:06:08 -03:00
LICENSE add .gitignore and MIT license 2026-03-16 21:15:18 -03:00
README.kd Convert .md files to KOD format (.kd) 2026-03-21 21:01:47 -03:00

 _  __ ___  ____  _____ ____    _  __    _    _     _
| |/ // _ \|  _ \| ____|  _ \  | |/ /   / \  | |   | |
| ' /| | | | | | |  _| | |_) | | ' /   / _ \ | |   | |
| . \| |_| | |_| | |___|  _ <  | . \  / ___ \| |___| |___
|_|\_\\___/|____/|_____|_| \_\ |_|\_\/_/   \_\_____|_____|

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

EventDescription
room.createdA new room was created
room.closedA room was closed
participant.joinedA participant joined a room
participant.leftA participant left a room
recording.startedRecording started
recording.readyRecording file is available
rtmp.startedRTMP stream started
rtmp.stoppedRTMP 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.