media streaming framework and teleconferencing system written in rust
See the codevideocall.rs is an open-source, low-latency video conferencing platform and streaming API written entirely in Rust. It is a WebRTC alternative built on WebTransport (HTTP/3 and QUIC) with an automatic WebSocket fallback, and it runs in the browser, on native devices through a command-line client, and on mobile through iOS and Android SDKs. It is self-hostable, dual-licensed under MIT and Apache-2.0, and built for real-time video streaming from robots, drones, and embedded Linux boards (Raspberry Pi, Jetson) as well as conventional browser-to-browser calls.
Website | Documentation | Discord | Crates.io
Project status: Beta. Actively developed and used in production for non-critical workloads.
videocall.rs gives you the building blocks for real-time video communication without the WebRTC stack. It is aimed at three audiences:
videocall-cli and the mobile SDKs.The same core powers browser calls at videocall.rs.
videocall-cli for headless streaming, and videocall-sdk bindings for iOS and Android.For most server-mediated video use cases, yes. videocall.rs does not use WebRTC's peer-connection stack. Media flows over WebTransport (QUIC/HTTP3), or a WebSocket fallback, to a Rust server that forwards packets to other participants through NATS. You give up WebRTC's mature browser SFU ecosystem, but you also drop ICE, STUN/TURN, and SDP negotiation entirely.
Yes. The repository ships Helm charts for Kubernetes and a fully native local dev stack. Production container images are built reproducibly with Nix. See Getting Started and the architecture document.
Yes, on Chromium-based browsers (Chrome, Edge, Brave) and Safari (macOS and iOS). Firefox is not currently supported. See Browser compatibility.
Those stacks are WebRTC selective-forwarding units. videocall.rs forwards media over WebTransport/QUIC instead of WebRTC, is written entirely in Rust (server, browser client, and native client), and requires no STUN/TURN/ICE infrastructure. See How it compares.
Yes. videocall-cli is a headless native client that streams from a camera on Raspberry Pi, Jetson Nano, and other embedded Linux devices. See CLI-based streaming.
Media is encrypted in transit. WebSocket connections use TLS 1.3, and WebTransport uses QUIC's built-in TLS 1.3 encryption, so media is protected between each client and the relay. The relay server forwards media between participants; it is not end-to-end encrypted.
WebTransport is the core technology that sets videocall.rs apart. Built on HTTP/3 and QUIC, it provides multiplexed, bidirectional streams and datagrams with modern congestion control. Choosing it over WebRTC has concrete consequences:
videocall.rs still runs a forwarding server, so it is architecturally closer to an SFU than to peer-to-peer WebRTC. The difference is that the transport and signaling are radically simpler: no ICE, no TURN, no SDP. For a deep dive, see the architecture document.
An honest, verifiable comparison with widely used WebRTC-based stacks. All four are open source and server-mediated (SFU-style); the differences are in transport and implementation language.
| Project | Media transport | Signaling / NAT traversal | Core language | License |
|---|---|---|---|---|
| videocall.rs | WebTransport (QUIC/HTTP3), WebSocket fallback | QUIC handshake, no ICE/STUN/TURN | Rust (server, browser, native) | MIT / Apache-2.0 |
| LiveKit | WebRTC | ICE / STUN / TURN | Go | Apache-2.0 |
| Jitsi Videobridge | WebRTC | ICE / STUN / TURN | Java | Apache-2.0 |
| mediasoup | WebRTC | ICE / STUN / TURN | C++ core, Node.js / Rust API | ISC |
videocall.rs is the youngest of these and does not yet match their breadth of client SDKs, recording, and ecosystem integrations. Its advantage is a simpler transport and a single-language (Rust) codebase from server to browser.
| Browser | Support |
|---|---|
| Chrome | Yes |
| Brave | Yes |
| Edge | Yes |
| Safari (macOS, iOS) | Yes |
| Firefox | No |
videocall.rs follows a microservices architecture in which clients connect over WebSocket or WebTransport and servers exchange media through a NATS pub/sub backbone.
graph TD
Clients[Clients<br>Browsers, Mobile, CLI] -->|WebSocket| ActixAPI[Actix API<br>WebSocket]
Clients -->|WebTransport| WebTransportServer[WebTransport<br>Server]
ActixAPI --> NATS[NATS<br>Messaging]
WebTransportServer --> NATS
Primary components:
websocket_server, webtransport_server, metrics) built on Actix Web.For details, including connection flows, message routing, and the encryption model, see the architecture document.
Development is fully native: the entire dev stack (postgres, NATS, prometheus, grafana, and the Rust services) runs as host processes supervised by process-compose, with hot reload everywhere. Docker only appears when you want to run the images, which are built by Nix. There are no Dockerfiles in the dev workflow. See docs/nix-architecture.md.
trusted-users so builds can pull the project's public binary cache instead of compiling everything locally. Until then Nix prints ignoring untrusted substituter 'https://videocall-rs.cachix.org' (harmless, but slow):
echo "trusted-users = root $USER" | sudo tee -a /etc/nix/nix.conf
sudo pkill nix-daemon
docker run a published image locally.git clone https://github.com/security-union/videocall-rs.git
cd videocall-rs
make dev
That's it. make dev opens the process-compose TUI running the whole stack as native processes:
| Process | What | Port |
|---|---|---|
postgres | postgresql from nixpkgs, state in .data/postgres | 5432 |
nats | nats-server with JetStream, state in .data/nats | 4222 / 8222 |
meeting-api | dbmate migrations, then cargo watch | 8081 |
websocket / webtransport | cargo watch | 8080 / 4433 udp |
metrics / server-stats | cargo watch | 9091 / 9092 |
dioxus-ui | tailwind watch + trunk serve | 3001 |
prometheus / grafana | native, same dashboards/config as the container stack | 9090 / 3000 |
Services wait for middleware health (compose-style depends_on), recompile and restart instantly on save, and the TUI can restart individual processes on demand. Open http://localhost:3001 and navigate to a meeting at http://localhost:3001/meeting/<username>/<meeting-id>.
To stop: quit the TUI (F10 / Ctrl-C), or run make dev-down from another terminal. The TUI needs an interactive terminal; for scripted or headless use run nix-shell default.nix -A shells.dev --run "dev-stack -t=false".
Prefer one service per terminal? make dev-middleware starts just postgres/nats/prometheus/grafana; then make dev-websocket, make dev-meeting-api, make dev-ui, and so on run a single watcher each (these also work with plain rustup plus cargo-watch).
Overriding environment variables: every process in make dev sees env layered as built-in defaults < .env < .env.local, both untracked. Copy .env-sample to .env for documented knobs (OAuth, service URLs, JWT secret); put personal or secret overrides in .env.local, which is gitignored and never checked in.
Nothing local needs Docker: development, tests, and e2e all run native. The container images exist for Kubernetes. CI builds and publishes them from release.nix on every merge. To build one locally (for example, to debug an image's entrypoint with docker run):
make image-websocket-server # nix-build one image and docker-load it
make images # all of them
On Linux the images build natively; on macOS the service binaries are cross-compiled to aarch64-unknown-linux-musl with no VM and no remote builder. The first macOS build compiles a musl cross-toolchain (one-time, tens of minutes); after that it is cached in the Nix store.
Both stacks read the same files: make dev layers .env then .env.local into every process. To enable Google login, create a .env from the sample and fill in credentials (or keep secrets in .env.local):
cp .env-sample .env
http://localhost:8081/login/callback as an authorized redirect URI..env.Without OAuth credentials the app runs with auth bypassed for local development.
Platform notes:
.env (not .env-sample):
DIOXUS_SERVE_PORT=8088
AFTER_LOGIN_URL=http://localhost:8088
ALLOWED_REDIRECT_URLS=http://localhost:8088
Then access the app at http://localhost:8088.API_BASE_URL, OAUTH_REDIRECT_URL, or similar variables exported in your shell profile (~/.bashrc, ~/.zshrc), they override .env values. Remove them from your profile before running make dev.The build system is native Nix, no flakes: default.nix (entry point), shell.nix (dev shells), release.nix (CI artifacts: packages and Docker images). Dependency pins live in nix/tamal/ and are managed by nixtamal; evaluating them needs plain Nix only. Full design: docs/nix-architecture.md. Coming from the old Docker dev environment? See docs/migrating-from-docker.md.
nix-shell # default dev shell (frontend toolchain)
nix-shell default.nix -A shells.backend-dev # backend toolchain + cargo-watch + dbmate
nix-build release.nix -A packages.websocket-server # a single service binary (static musl)
make image-websocket-server # its Docker image, loaded into the daemon
make pins-update # refresh nixtamal pins (nix/tamal/)
The frontend is configured at runtime via a window.__APP_CONFIG object provided by a config.js file. The file is copied by Trunk and loaded at /config.js by dioxus-ui/index.html.
make dev and make dev-ui run scripts/start-dioxus.sh, which writes dioxus-ui/scripts/config.js from the environment before Trunk starts. To point the UI somewhere custom, override the relevant env vars in .env.local (see scripts/start-dioxus.sh for the keys) rather than editing the generated file. The Nix-built videocall/dioxus-ui image does the same at container startup via its entrypoint.helm/videocall-ui/templates/configmap-configjs.yaml renders config.js from .Values.runtimeConfig. Define runtimeConfig in your values file and deploy or upgrade.The vadThreshold config parameter controls how sensitive speaking detection is. It sets the minimum RMS audio level that counts as "speaking," used for tile border glow, peer-list mic glow, and self-video glow indicators.
window.__APP_CONFIG = Object.freeze({
// ... other config ...
vadThreshold: 0.02 // default
});
| Value | Sensitivity | Use case |
|---|---|---|
0.01 | High: picks up quiet speech and background noise | Quiet environments, soft speakers |
0.02 | Medium (default): good balance for most setups | General use |
0.05 | Low: only triggers on louder speech | Noisy environments, reduces false positives |
0.10 | Very low: requires loud or close speech | Very noisy environments |
The threshold can also be set via the VAD_THRESHOLD environment variable (see scripts/start-dioxus.sh) or via runtimeConfig.vadThreshold in Helm values.
http://<server-address>/meeting/<username>/<meeting-id>
For headless devices like a Raspberry Pi:
# Install the CLI tool
cargo install videocall-cli
# Stream from a camera
videocall-cli stream \
--user-id <your-user-id> \
--video-device-index 0 \
--meeting-id <meeting-id> \
--resolution 1280x720 \
--fps 30 \
--frame-format NV12 \
--bitrate-kbps 500
The CLI joins an existing meeting; create the call from a browser first. For all options, see the videocall-cli README.
videocall.rs includes a meeting management system with ownership, waiting rooms, and host controls.
Workflow: navigating to /meeting/{meeting-id} creates the meeting and makes you the owner if it does not exist. Owners see "Start Meeting," others see "Join Meeting." Non-owners wait for admission; admitted participants are auto-joined and can then manage the waiting room.
Meeting management requires the FEATURE_MEETING_MANAGEMENT flag (see Feature flags):
export FEATURE_MEETING_MANAGEMENT=true
Details: Meeting Ownership & Workflow and Meeting API Reference.
videocall.rs is engineered for real-time streaming across a range of hardware and networks:
Implementation choices that support this:
Design goals still in progress (minimizing data copies on the media path, further congestion-control tuning) are tracked in the architecture document. Detailed benchmarking guidelines are a work in progress.
For the full model, see the security architecture and the security documentation.
videocall.rs uses environment-based feature flags to enable optional or experimental functionality at runtime. Flags are loaded lazily on first access and can be overridden for testing.
Flags are set via environment variables with the FEATURE_ prefix:
export FEATURE_MEETING_MANAGEMENT=true
# or, with Docker:
docker run -e FEATURE_MEETING_MANAGEMENT=true ...
| Flag | Environment variable | Description | Default |
|---|---|---|---|
| Meeting Management | FEATURE_MEETING_MANAGEMENT | Meeting lifecycle management: creation, tracking, host controls | false |
Truthy values (case-insensitive) are true, 1, and yes. Any other value, or an unset variable, is treated as false.
The Dioxus frontend uses a three-layer testing pyramid, all running in a real browser via wasm-bindgen-test:
| Layer | What it covers | Example |
|---|---|---|
| Unit | MediaDeviceList logic: hot-plug, fallback, device switching | videocall-client/src/media_devices/media_device_list.rs |
| Component | Isolated Dioxus components with mock MediaDeviceInfo objects | dioxus-ui/tests/device_selector.rs, dioxus-ui/tests/video_control_buttons.rs |
| Integration | Real Chrome fake devices rendered through the full pipeline | dioxus-ui/tests/device_integration.rs |
# Run UI component tests natively (requires Chrome + chromedriver)
cd dioxus-ui
CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown
CI runs these via .github/workflows/wasm-test.yaml. For the full guide, see dioxus-ui/README.md.
The actix-api crate has unit and integration tests that run against real PostgreSQL and NATS instances, started natively by make check-backend. Coverage includes session management, WebSocket and WebTransport meeting lifecycles, packet classification, the metrics server, and feature-flag behavior.
Tests use #[serial_test::serial] because they share a database, and each cleans up its own data. Everything runs natively, no Docker: make check-backend starts postgres 18 and NATS (JetStream) from nixpkgs under process-compose in a throwaway data dir, runs dbmate migrations, then clippy, fmt, and cargo test in the pinned nix-shell.
make check-backend # all backend tests (native postgres/NATS, fresh state per run)
make check-backend-sqlite # same, against the SQLite meeting-api backend
make check-backend-down # stop the test middleware and delete its state
CI runs these via .github/workflows/cargo-test.yaml on PRs touching actix-api/, videocall-types/, or protobuf/. Full guide: actix-api/TESTING.md.
Full browser-based end-to-end tests using Playwright. Tests run against the Dioxus UI, verifying meeting flows in real browsers; authentication is bypassed via JWT cookie injection, so no OAuth setup is needed.
The E2E stack runs natively, no Docker (e2eStack in nix/dev-stack.nix): postgres and NATS from nixpkgs, the meeting-api and websocket servers, and the Nix-built release UI dist served by caddy, which is the same payload the production images ship. Tests run automatically on pushes to main and can be triggered manually from the GitHub Actions page. See the e2e-* targets in the Makefile.
| Quarter | Release | Deliverable |
|---|---|---|
| Q2 2023 | 0.5.0 | JWT authentication & SSO |
| Q3 2023 | 0.6.0 | Safari browser support |
| Q4 2023 | 0.7.0 | Native mobile SDKs |
| Q3 2024 | — | videocall.rs website launched, with Matomo analytics for self-hosted usage insight (#169, #170) |
| Q3 2024 | — | Postgres made optional and a DigitalOcean deployment path documented, plus WebTransport connection fixes (#163, #165) |
| Q4 2024 | — | videocall-daemon released: headless streaming for robotics and embedded targets (#176) |
| Q4 2024 | — | macOS builds for the daemon and Ubuntu 24 base images (#177, #173) |
| Q1 2025 | videocall-client 1.0.0 | Whole workspace published to crates.io at 1.0.0 with release-plz automation; daemon renamed to videocall-cli (#222, #212, #185) |
| Q1 2025 | videocall-client 1.1.6 | In-call diagnostics panel, Yew UI redesign, and multi-peer bitrate control (#206, #196, #242) |
| Q2 2025 | videocall-sdk 0.1.0 | iOS and Android bindings shipped as videocall-sdk (#253) |
| Q2 2025 | videocall-codecs 0.1.1 | Full Safari support via a WASM Opus encoder, plus the videocall-codecs crate with a jitter-buffered decoder (#266, #282, #285) |
| Q3 2025 | neteq 0.1.0 | NetEQ adaptive audio jitter buffer ported to Rust/WASM and rolled out to every browser through an AudioWorklet (#305, #310, #315) |
| Q3 2025 | videocall-cli 3.0.0 | Prometheus + Grafana diagnostics and multi-region HA; CLI drops raw QUIC in favor of WebTransport (#365, #325, #410) |
| Q4 2025 | videocall-client 1.1.28 | End-to-end OAuth / SSO sign-in with configurable cookie domain (#471, #485) |
| Q4 2025 | videocall-client 1.1.29 | Meeting ownership behind a feature flag, and a NetEQ overhaul with WebCodecs support (#503, #466) |
| Q1 2026 | videocall-client 4.0.5 | Dioxus UI became the sole frontend and Yew was removed; WebTransport server consolidated onto an actor model (#646, #788, #551) |
| Q1 2026 | videocall-types 5.0.0 | Nix-based builds across backend, UI, and website; per-PR preview environments; Playwright E2E suite (#639, #672, #714) |
| Q1 2026 | videocall-client 4.0.5 | Adaptive quality stack: PID-driven encoder adaptation, PLI keyframe requests, and decoder visibility skipping (#758, #761, #762) |
| Q2 2026 | videocall-cli 4.0.0 | Pure-Rust audio: audiopus-sys/libopus removed workspace-wide in favor of ropus (#872) |
| Q2 2026 | videocall-types 6.0.0 | Dioxus UI Helm chart with relay Prometheus annotations, reworked screen sharing, and audio-level re-render fixes (#757, #817, #816) |
| Q3 2026 | unreleased | Pure-Rust VP9 encoder and decoder: C libvpx removed from videocall-cli and the bot (#884) |
| Q3 2026 | unreleased | SQLite available as an optional database backend for meeting-api, alongside Postgres (#802) |
Contributions are welcome.
See the Contributing Guidelines for details.
cargo test + wasm-bindgen-test (browser UI tests) + Playwright (E2E).The repo ships its hooks in githooks/ (currently pre-push: cargo clippy -D warnings and cargo fmt --check). Enable them once per clone:
git config core.hooksPath githooks
Hosting for the public videocall.rs instance is supported by DigitalOcean. Using this referral link helps fund the project:
Dual-licensed under the MIT License and the Apache License 2.0. See LICENSE-MIT and LICENSE-APACHE for details.
(top 24 of 39)
945 followers · starred Jul 2023
673 followers · starred Aug 2023
507 followers · starred Oct 2022
36 followers · starred Jan 2026
media streaming framework and teleconferencing system written in rust
See the codevideocall.rs is an open-source, low-latency video conferencing platform and streaming API written entirely in Rust. It is a WebRTC alternative built on WebTransport (HTTP/3 and QUIC) with an automatic WebSocket fallback, and it runs in the browser, on native devices through a command-line client, and on mobile through iOS and Android SDKs. It is self-hostable, dual-licensed under MIT and Apache-2.0, and built for real-time video streaming from robots, drones, and embedded Linux boards (Raspberry Pi, Jetson) as well as conventional browser-to-browser calls.
Website | Documentation | Discord | Crates.io
Project status: Beta. Actively developed and used in production for non-critical workloads.
videocall.rs gives you the building blocks for real-time video communication without the WebRTC stack. It is aimed at three audiences:
videocall-cli and the mobile SDKs.The same core powers browser calls at videocall.rs.
videocall-cli for headless streaming, and videocall-sdk bindings for iOS and Android.For most server-mediated video use cases, yes. videocall.rs does not use WebRTC's peer-connection stack. Media flows over WebTransport (QUIC/HTTP3), or a WebSocket fallback, to a Rust server that forwards packets to other participants through NATS. You give up WebRTC's mature browser SFU ecosystem, but you also drop ICE, STUN/TURN, and SDP negotiation entirely.
Yes. The repository ships Helm charts for Kubernetes and a fully native local dev stack. Production container images are built reproducibly with Nix. See Getting Started and the architecture document.
Yes, on Chromium-based browsers (Chrome, Edge, Brave) and Safari (macOS and iOS). Firefox is not currently supported. See Browser compatibility.
Those stacks are WebRTC selective-forwarding units. videocall.rs forwards media over WebTransport/QUIC instead of WebRTC, is written entirely in Rust (server, browser client, and native client), and requires no STUN/TURN/ICE infrastructure. See How it compares.
Yes. videocall-cli is a headless native client that streams from a camera on Raspberry Pi, Jetson Nano, and other embedded Linux devices. See CLI-based streaming.
Media is encrypted in transit. WebSocket connections use TLS 1.3, and WebTransport uses QUIC's built-in TLS 1.3 encryption, so media is protected between each client and the relay. The relay server forwards media between participants; it is not end-to-end encrypted.
WebTransport is the core technology that sets videocall.rs apart. Built on HTTP/3 and QUIC, it provides multiplexed, bidirectional streams and datagrams with modern congestion control. Choosing it over WebRTC has concrete consequences:
videocall.rs still runs a forwarding server, so it is architecturally closer to an SFU than to peer-to-peer WebRTC. The difference is that the transport and signaling are radically simpler: no ICE, no TURN, no SDP. For a deep dive, see the architecture document.
An honest, verifiable comparison with widely used WebRTC-based stacks. All four are open source and server-mediated (SFU-style); the differences are in transport and implementation language.
| Project | Media transport | Signaling / NAT traversal | Core language | License |
|---|---|---|---|---|
| videocall.rs | WebTransport (QUIC/HTTP3), WebSocket fallback | QUIC handshake, no ICE/STUN/TURN | Rust (server, browser, native) | MIT / Apache-2.0 |
| LiveKit | WebRTC | ICE / STUN / TURN | Go | Apache-2.0 |
| Jitsi Videobridge | WebRTC | ICE / STUN / TURN | Java | Apache-2.0 |
| mediasoup | WebRTC | ICE / STUN / TURN | C++ core, Node.js / Rust API | ISC |
videocall.rs is the youngest of these and does not yet match their breadth of client SDKs, recording, and ecosystem integrations. Its advantage is a simpler transport and a single-language (Rust) codebase from server to browser.
| Browser | Support |
|---|---|
| Chrome | Yes |
| Brave | Yes |
| Edge | Yes |
| Safari (macOS, iOS) | Yes |
| Firefox | No |
videocall.rs follows a microservices architecture in which clients connect over WebSocket or WebTransport and servers exchange media through a NATS pub/sub backbone.
graph TD
Clients[Clients<br>Browsers, Mobile, CLI] -->|WebSocket| ActixAPI[Actix API<br>WebSocket]
Clients -->|WebTransport| WebTransportServer[WebTransport<br>Server]
ActixAPI --> NATS[NATS<br>Messaging]
WebTransportServer --> NATS
Primary components:
websocket_server, webtransport_server, metrics) built on Actix Web.For details, including connection flows, message routing, and the encryption model, see the architecture document.
Development is fully native: the entire dev stack (postgres, NATS, prometheus, grafana, and the Rust services) runs as host processes supervised by process-compose, with hot reload everywhere. Docker only appears when you want to run the images, which are built by Nix. There are no Dockerfiles in the dev workflow. See docs/nix-architecture.md.
trusted-users so builds can pull the project's public binary cache instead of compiling everything locally. Until then Nix prints ignoring untrusted substituter 'https://videocall-rs.cachix.org' (harmless, but slow):
echo "trusted-users = root $USER" | sudo tee -a /etc/nix/nix.conf
sudo pkill nix-daemon
docker run a published image locally.git clone https://github.com/security-union/videocall-rs.git
cd videocall-rs
make dev
That's it. make dev opens the process-compose TUI running the whole stack as native processes:
| Process | What | Port |
|---|---|---|
postgres | postgresql from nixpkgs, state in .data/postgres | 5432 |
nats | nats-server with JetStream, state in .data/nats | 4222 / 8222 |
meeting-api | dbmate migrations, then cargo watch | 8081 |
websocket / webtransport | cargo watch | 8080 / 4433 udp |
metrics / server-stats | cargo watch | 9091 / 9092 |
dioxus-ui | tailwind watch + trunk serve | 3001 |
prometheus / grafana | native, same dashboards/config as the container stack | 9090 / 3000 |
Services wait for middleware health (compose-style depends_on), recompile and restart instantly on save, and the TUI can restart individual processes on demand. Open http://localhost:3001 and navigate to a meeting at http://localhost:3001/meeting/<username>/<meeting-id>.
To stop: quit the TUI (F10 / Ctrl-C), or run make dev-down from another terminal. The TUI needs an interactive terminal; for scripted or headless use run nix-shell default.nix -A shells.dev --run "dev-stack -t=false".
Prefer one service per terminal? make dev-middleware starts just postgres/nats/prometheus/grafana; then make dev-websocket, make dev-meeting-api, make dev-ui, and so on run a single watcher each (these also work with plain rustup plus cargo-watch).
Overriding environment variables: every process in make dev sees env layered as built-in defaults < .env < .env.local, both untracked. Copy .env-sample to .env for documented knobs (OAuth, service URLs, JWT secret); put personal or secret overrides in .env.local, which is gitignored and never checked in.
Nothing local needs Docker: development, tests, and e2e all run native. The container images exist for Kubernetes. CI builds and publishes them from release.nix on every merge. To build one locally (for example, to debug an image's entrypoint with docker run):
make image-websocket-server # nix-build one image and docker-load it
make images # all of them
On Linux the images build natively; on macOS the service binaries are cross-compiled to aarch64-unknown-linux-musl with no VM and no remote builder. The first macOS build compiles a musl cross-toolchain (one-time, tens of minutes); after that it is cached in the Nix store.
Both stacks read the same files: make dev layers .env then .env.local into every process. To enable Google login, create a .env from the sample and fill in credentials (or keep secrets in .env.local):
cp .env-sample .env
http://localhost:8081/login/callback as an authorized redirect URI..env.Without OAuth credentials the app runs with auth bypassed for local development.
Platform notes:
.env (not .env-sample):
DIOXUS_SERVE_PORT=8088
AFTER_LOGIN_URL=http://localhost:8088
ALLOWED_REDIRECT_URLS=http://localhost:8088
Then access the app at http://localhost:8088.API_BASE_URL, OAUTH_REDIRECT_URL, or similar variables exported in your shell profile (~/.bashrc, ~/.zshrc), they override .env values. Remove them from your profile before running make dev.The build system is native Nix, no flakes: default.nix (entry point), shell.nix (dev shells), release.nix (CI artifacts: packages and Docker images). Dependency pins live in nix/tamal/ and are managed by nixtamal; evaluating them needs plain Nix only. Full design: docs/nix-architecture.md. Coming from the old Docker dev environment? See docs/migrating-from-docker.md.
nix-shell # default dev shell (frontend toolchain)
nix-shell default.nix -A shells.backend-dev # backend toolchain + cargo-watch + dbmate
nix-build release.nix -A packages.websocket-server # a single service binary (static musl)
make image-websocket-server # its Docker image, loaded into the daemon
make pins-update # refresh nixtamal pins (nix/tamal/)
The frontend is configured at runtime via a window.__APP_CONFIG object provided by a config.js file. The file is copied by Trunk and loaded at /config.js by dioxus-ui/index.html.
make dev and make dev-ui run scripts/start-dioxus.sh, which writes dioxus-ui/scripts/config.js from the environment before Trunk starts. To point the UI somewhere custom, override the relevant env vars in .env.local (see scripts/start-dioxus.sh for the keys) rather than editing the generated file. The Nix-built videocall/dioxus-ui image does the same at container startup via its entrypoint.helm/videocall-ui/templates/configmap-configjs.yaml renders config.js from .Values.runtimeConfig. Define runtimeConfig in your values file and deploy or upgrade.The vadThreshold config parameter controls how sensitive speaking detection is. It sets the minimum RMS audio level that counts as "speaking," used for tile border glow, peer-list mic glow, and self-video glow indicators.
window.__APP_CONFIG = Object.freeze({
// ... other config ...
vadThreshold: 0.02 // default
});
| Value | Sensitivity | Use case |
|---|---|---|
0.01 | High: picks up quiet speech and background noise | Quiet environments, soft speakers |
0.02 | Medium (default): good balance for most setups | General use |
0.05 | Low: only triggers on louder speech | Noisy environments, reduces false positives |
0.10 | Very low: requires loud or close speech | Very noisy environments |
The threshold can also be set via the VAD_THRESHOLD environment variable (see scripts/start-dioxus.sh) or via runtimeConfig.vadThreshold in Helm values.
http://<server-address>/meeting/<username>/<meeting-id>
For headless devices like a Raspberry Pi:
# Install the CLI tool
cargo install videocall-cli
# Stream from a camera
videocall-cli stream \
--user-id <your-user-id> \
--video-device-index 0 \
--meeting-id <meeting-id> \
--resolution 1280x720 \
--fps 30 \
--frame-format NV12 \
--bitrate-kbps 500
The CLI joins an existing meeting; create the call from a browser first. For all options, see the videocall-cli README.
videocall.rs includes a meeting management system with ownership, waiting rooms, and host controls.
Workflow: navigating to /meeting/{meeting-id} creates the meeting and makes you the owner if it does not exist. Owners see "Start Meeting," others see "Join Meeting." Non-owners wait for admission; admitted participants are auto-joined and can then manage the waiting room.
Meeting management requires the FEATURE_MEETING_MANAGEMENT flag (see Feature flags):
export FEATURE_MEETING_MANAGEMENT=true
Details: Meeting Ownership & Workflow and Meeting API Reference.
videocall.rs is engineered for real-time streaming across a range of hardware and networks:
Implementation choices that support this:
Design goals still in progress (minimizing data copies on the media path, further congestion-control tuning) are tracked in the architecture document. Detailed benchmarking guidelines are a work in progress.
For the full model, see the security architecture and the security documentation.
videocall.rs uses environment-based feature flags to enable optional or experimental functionality at runtime. Flags are loaded lazily on first access and can be overridden for testing.
Flags are set via environment variables with the FEATURE_ prefix:
export FEATURE_MEETING_MANAGEMENT=true
# or, with Docker:
docker run -e FEATURE_MEETING_MANAGEMENT=true ...
| Flag | Environment variable | Description | Default |
|---|---|---|---|
| Meeting Management | FEATURE_MEETING_MANAGEMENT | Meeting lifecycle management: creation, tracking, host controls | false |
Truthy values (case-insensitive) are true, 1, and yes. Any other value, or an unset variable, is treated as false.
The Dioxus frontend uses a three-layer testing pyramid, all running in a real browser via wasm-bindgen-test:
| Layer | What it covers | Example |
|---|---|---|
| Unit | MediaDeviceList logic: hot-plug, fallback, device switching | videocall-client/src/media_devices/media_device_list.rs |
| Component | Isolated Dioxus components with mock MediaDeviceInfo objects | dioxus-ui/tests/device_selector.rs, dioxus-ui/tests/video_control_buttons.rs |
| Integration | Real Chrome fake devices rendered through the full pipeline | dioxus-ui/tests/device_integration.rs |
# Run UI component tests natively (requires Chrome + chromedriver)
cd dioxus-ui
CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown
CI runs these via .github/workflows/wasm-test.yaml. For the full guide, see dioxus-ui/README.md.
The actix-api crate has unit and integration tests that run against real PostgreSQL and NATS instances, started natively by make check-backend. Coverage includes session management, WebSocket and WebTransport meeting lifecycles, packet classification, the metrics server, and feature-flag behavior.
Tests use #[serial_test::serial] because they share a database, and each cleans up its own data. Everything runs natively, no Docker: make check-backend starts postgres 18 and NATS (JetStream) from nixpkgs under process-compose in a throwaway data dir, runs dbmate migrations, then clippy, fmt, and cargo test in the pinned nix-shell.
make check-backend # all backend tests (native postgres/NATS, fresh state per run)
make check-backend-sqlite # same, against the SQLite meeting-api backend
make check-backend-down # stop the test middleware and delete its state
CI runs these via .github/workflows/cargo-test.yaml on PRs touching actix-api/, videocall-types/, or protobuf/. Full guide: actix-api/TESTING.md.
Full browser-based end-to-end tests using Playwright. Tests run against the Dioxus UI, verifying meeting flows in real browsers; authentication is bypassed via JWT cookie injection, so no OAuth setup is needed.
The E2E stack runs natively, no Docker (e2eStack in nix/dev-stack.nix): postgres and NATS from nixpkgs, the meeting-api and websocket servers, and the Nix-built release UI dist served by caddy, which is the same payload the production images ship. Tests run automatically on pushes to main and can be triggered manually from the GitHub Actions page. See the e2e-* targets in the Makefile.
| Quarter | Release | Deliverable |
|---|---|---|
| Q2 2023 | 0.5.0 | JWT authentication & SSO |
| Q3 2023 | 0.6.0 | Safari browser support |
| Q4 2023 | 0.7.0 | Native mobile SDKs |
| Q3 2024 | — | videocall.rs website launched, with Matomo analytics for self-hosted usage insight (#169, #170) |
| Q3 2024 | — | Postgres made optional and a DigitalOcean deployment path documented, plus WebTransport connection fixes (#163, #165) |
| Q4 2024 | — | videocall-daemon released: headless streaming for robotics and embedded targets (#176) |
| Q4 2024 | — | macOS builds for the daemon and Ubuntu 24 base images (#177, #173) |
| Q1 2025 | videocall-client 1.0.0 | Whole workspace published to crates.io at 1.0.0 with release-plz automation; daemon renamed to videocall-cli (#222, #212, #185) |
| Q1 2025 | videocall-client 1.1.6 | In-call diagnostics panel, Yew UI redesign, and multi-peer bitrate control (#206, #196, #242) |
| Q2 2025 | videocall-sdk 0.1.0 | iOS and Android bindings shipped as videocall-sdk (#253) |
| Q2 2025 | videocall-codecs 0.1.1 | Full Safari support via a WASM Opus encoder, plus the videocall-codecs crate with a jitter-buffered decoder (#266, #282, #285) |
| Q3 2025 | neteq 0.1.0 | NetEQ adaptive audio jitter buffer ported to Rust/WASM and rolled out to every browser through an AudioWorklet (#305, #310, #315) |
| Q3 2025 | videocall-cli 3.0.0 | Prometheus + Grafana diagnostics and multi-region HA; CLI drops raw QUIC in favor of WebTransport (#365, #325, #410) |
| Q4 2025 | videocall-client 1.1.28 | End-to-end OAuth / SSO sign-in with configurable cookie domain (#471, #485) |
| Q4 2025 | videocall-client 1.1.29 | Meeting ownership behind a feature flag, and a NetEQ overhaul with WebCodecs support (#503, #466) |
| Q1 2026 | videocall-client 4.0.5 | Dioxus UI became the sole frontend and Yew was removed; WebTransport server consolidated onto an actor model (#646, #788, #551) |
| Q1 2026 | videocall-types 5.0.0 | Nix-based builds across backend, UI, and website; per-PR preview environments; Playwright E2E suite (#639, #672, #714) |
| Q1 2026 | videocall-client 4.0.5 | Adaptive quality stack: PID-driven encoder adaptation, PLI keyframe requests, and decoder visibility skipping (#758, #761, #762) |
| Q2 2026 | videocall-cli 4.0.0 | Pure-Rust audio: audiopus-sys/libopus removed workspace-wide in favor of ropus (#872) |
| Q2 2026 | videocall-types 6.0.0 | Dioxus UI Helm chart with relay Prometheus annotations, reworked screen sharing, and audio-level re-render fixes (#757, #817, #816) |
| Q3 2026 | unreleased | Pure-Rust VP9 encoder and decoder: C libvpx removed from videocall-cli and the bot (#884) |
| Q3 2026 | unreleased | SQLite available as an optional database backend for meeting-api, alongside Postgres (#802) |
Contributions are welcome.
See the Contributing Guidelines for details.
cargo test + wasm-bindgen-test (browser UI tests) + Playwright (E2E).The repo ships its hooks in githooks/ (currently pre-push: cargo clippy -D warnings and cargo fmt --check). Enable them once per clone:
git config core.hooksPath githooks
Hosting for the public videocall.rs instance is supported by DigitalOcean. Using this referral link helps fund the project:
Dual-licensed under the MIT License and the Apache License 2.0. See LICENSE-MIT and LICENSE-APACHE for details.
(top 24 of 39)
945 followers · starred Jul 2023
673 followers · starred Aug 2023
507 followers · starred Oct 2022
36 followers · starred Jan 2026