CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
Every call in the web client now goes through MatrixRTC with a LiveKit
SFU, the model Element Call and Element X use; the legacy 1:1 m.call.*
calls are gone. In a room of two the other person is rung and can answer
or decline; in a bigger room a banner offers to join the call. Calls show
a grid of participant tiles with mute, camera, screen sharing and leave,
and media is end-to-end encrypted in encrypted rooms.
Server:
- MSC4140 delayed events (send/state with a delay, plus the
delayed_events list/restart/cancel/send API), stored and scheduled, so
a member whose client drops off is taken out of the call.
- POST /user/{userId}/openid/request_token, which lk-jwt-service uses to
hand out LiveKit tokens.
- org.matrix.msc4143.rtc_foci in /.well-known/matrix/client, configured
under client_api.rtc.
- Room presets let members send call membership state.
- Migration 0014 for both SQL dialects.
Deploy: LiveKit and lk-jwt-service in compose (calls.yml) and the helm
chart. Docs: docs/calls.md, configuration and deployment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
4.5 KiB
YAML
118 lines
4.5 KiB
YAML
# Calls for a local Warp: a LiveKit SFU and the LiveKit JWT service
|
|
# (lk-jwt-service), layered over docker-compose.yml.
|
|
#
|
|
# cd deploy/compose
|
|
# docker compose -f docker-compose.yml -f calls.yml --profile web up -d --build
|
|
#
|
|
# Then open http://localhost:8080 in a few browsers (or private windows),
|
|
# sign in as different users, and press the voice or video call button in
|
|
# a room: in a room of two it rings the other person.
|
|
#
|
|
# How the pieces find each other:
|
|
#
|
|
# browser ── /.well-known/matrix/client ──▶ warp rtc_foci: http://localhost:8070
|
|
# browser ── openid/request_token ────────▶ warp an OpenID token
|
|
# browser ── POST /sfu/get ───────────────▶ jwt {url, jwt} for the LiveKit room
|
|
# jwt ───── /_matrix/federation/v1/openid/userinfo ─▶ warp (https://<server_name>:8448)
|
|
# browser ── ws://localhost:7880 + UDP 7882 ─▶ livekit
|
|
#
|
|
# The JWT service checks a token by asking the user's homeserver over the
|
|
# federation port, with TLS. To make that work with the default server name
|
|
# "localhost", warp gets a federation listener on :8448 with a self-signed
|
|
# certificate, and the JWT service and LiveKit share warp's network
|
|
# namespace, so that "localhost" means warp for all three. This is a local
|
|
# setup: in production, give each its own hostname and real certificates
|
|
# (see docs/calls.md).
|
|
|
|
services:
|
|
# Makes the self-signed certificate for warp's federation listener once.
|
|
calls-cert:
|
|
image: alpine:3.21
|
|
restart: "no"
|
|
entrypoint: ["/bin/sh", "-c"]
|
|
command:
|
|
- >-
|
|
test -f /tls/tls.crt ||
|
|
(apk add --no-cache openssl >/dev/null &&
|
|
openssl req -x509 -newkey rsa:2048 -nodes -days 3650
|
|
-subj "/CN=$${WARP_SERVER_NAME}" -addext "subjectAltName=DNS:$${WARP_SERVER_NAME}"
|
|
-keyout /tls/tls.key -out /tls/tls.crt &&
|
|
chmod 644 /tls/tls.key /tls/tls.crt)
|
|
environment:
|
|
WARP_SERVER_NAME: ${WARP_SERVER_NAME:-localhost}
|
|
volumes:
|
|
- warp-tls:/tls
|
|
|
|
warp:
|
|
depends_on:
|
|
calls-cert:
|
|
condition: service_completed_successfully
|
|
environment:
|
|
WARP_RTC_LIVEKIT_SERVICE_URL: ${WARP_LIVEKIT_JWT_PUBLIC_URL:-http://localhost:8070}
|
|
WARP_LISTEN_FEDERATION_ADDRESS: ":8448"
|
|
WARP_TLS_CERT_FILE: /tls/tls.crt
|
|
WARP_TLS_KEY_FILE: /tls/tls.key
|
|
volumes:
|
|
- warp-tls:/tls:ro
|
|
# LiveKit and the JWT service live in this container's network
|
|
# namespace, so their ports are published here.
|
|
ports:
|
|
- "8070:8070" # lk-jwt-service
|
|
- "7880:7880" # LiveKit signalling (WebSocket)
|
|
- "7881:7881" # LiveKit media over TCP, the fallback
|
|
- "7882:7882/udp" # LiveKit media over UDP
|
|
|
|
livekit:
|
|
image: livekit/livekit-server:v1.13.7
|
|
restart: unless-stopped
|
|
network_mode: service:warp
|
|
depends_on:
|
|
- warp
|
|
environment:
|
|
# node_ip is what LiveKit tells browsers to send media to. 127.0.0.1
|
|
# works for browsers on this machine; set LIVEKIT_NODE_IP to the
|
|
# machine's LAN address to call from other devices.
|
|
LIVEKIT_CONFIG: |
|
|
port: 7880
|
|
bind_addresses: [""]
|
|
rtc:
|
|
tcp_port: 7881
|
|
udp_port: 7882
|
|
use_external_ip: false
|
|
node_ip: ${LIVEKIT_NODE_IP:-127.0.0.1}
|
|
room:
|
|
auto_create: false
|
|
keys:
|
|
${LIVEKIT_KEY:-warp}: ${LIVEKIT_SECRET:-warp-local-livekit-secret-change-me-0123456789}
|
|
logging:
|
|
level: info
|
|
|
|
livekit-jwt:
|
|
image: ghcr.io/element-hq/lk-jwt-service:0.8.0
|
|
restart: unless-stopped
|
|
network_mode: service:warp
|
|
depends_on:
|
|
- warp
|
|
- livekit
|
|
environment:
|
|
LIVEKIT_JWT_BIND: ":8070"
|
|
# The URL handed to browsers, and the one the service creates rooms
|
|
# through: both reach LiveKit at localhost here.
|
|
LIVEKIT_URL: ${LIVEKIT_PUBLIC_URL:-ws://localhost:7880}
|
|
LIVEKIT_KEY: ${LIVEKIT_KEY:-warp}
|
|
LIVEKIT_SECRET: ${LIVEKIT_SECRET:-warp-local-livekit-secret-change-me-0123456789}
|
|
# Users of this server may create call rooms on the SFU.
|
|
LIVEKIT_FULL_ACCESS_HOMESERVERS: ${WARP_SERVER_NAME:-localhost}
|
|
# warp's federation certificate is self-signed.
|
|
LIVEKIT_INSECURE_SKIP_VERIFY_TLS: YES_I_KNOW_WHAT_I_AM_DOING
|
|
|
|
web:
|
|
environment:
|
|
# The browser connects to the JWT service and to LiveKit directly.
|
|
WARP_WEB_CALL_ORIGINS: >-
|
|
${WARP_LIVEKIT_JWT_PUBLIC_URL:-http://localhost:8070}
|
|
${LIVEKIT_PUBLIC_URL:-ws://localhost:7880}
|
|
|
|
volumes:
|
|
warp-tls:
|