


[RU](settings.ru.md) / **EN**
# Settings
> **Important:** always check whether the video call service you need is on the allow lists. If it is not there, use another one. A list of all allow-listed services will be published soon.
## Compatibility matrix
| Transport | telemost | wbstream | jitsi |
|-----------|:--------:|:--------:|:-----:|
| datachannel | - | ~ | + |
| vp8channel | + | + | ~ |
| seichannel | - | + | ~ |
| videochannel | + | + | ~ |
**Legend:**
- `+` - works (passes E2E tests)
- `-` - does not work / not supported (fails E2E tests)
- `~` - unstable (may work)
**Telemost:** only vp8channel passes stably. DataChannel was removed from Telemost. seichannel is not supported. videochannel is slow.
**WBStream:** all transports except datachannel work. DataChannel does not work in the normal guest flow without being granted moderator - WB Stream issues tokens with `canPublishData=false`, and DC does not route data.
**Jitsi:** datachannel passes stably - it is implemented on top of the colibri-ws bridge channel and sends bytes via an `EndpointMessage{raw}` broadcast. It fits self-hosted and public Jitsi Meet instances without authentication (`https://meet.small-dm.ru/...`, `https://meet1.arbitr.ru/...`, `https://meet.handyweb.org/...`, `https://meet.jit.si/...`, etc.). Check in a browser which of the servers is reachable in your network. Video transports (vp8channel, seichannel, videochannel) expose a sendable VideoTrack through the pion PeerConnection after the Jingle session-accept, but Jicofo requires additional protocol steps (LastN, ReceiverVideoConstraints, source-add) to route video - that is why they are marked `~`.
**Jitsi + seichannel - a separate caveat.** SEI NAL units ride along inside the H.264 video stream, and Jicofo on self-hosted instances (for example `meet.small-dm.ru`, `meet1.arbitr.ru`) periodically cuts/delays upstream video when there is formally no receiver in the room - for us this looks like a `seichannel ack timeout` while the PeerConnection is formally alive. In steady state the transport works, but the e2e matrix marks it `Unstable` (it flaps): a green or red result in CI is enough, the test suite does not fail on it. For reliable data transfer over jitsi, prefer `datachannel` or `vp8channel`.
**Recommended combination: `jitsi + datachannel`** - works stably on any self-hosted or public Jitsi Meet (for example `meet.small-dm.ru`, `meet1.arbitr.ru` or `meet.handyweb.org` - check which one is reachable in your network), needs no registration, simple room creation. Alternative: `wbstream + vp8channel` - stable for commercial scenarios, needs no special rights.
Speed in descending order: `datachannel` > `vp8channel` > `seichannel` > `videochannel`
---
## Required YAML config fields
| YAML field | What to enter |
|-----------|-------------|
| `mode` | `srv` on the server, `cnc` on the client, `gen` to generate a Room ID |
| `auth.provider` | `telemost`, `wbstream`, `jitsi` or `none` |
| `net.transport` | `datachannel`, `vp8channel`, `seichannel` or `videochannel` |
| `room.id` | Room ID |
| `crypto.key` or `crypto.key_file` | Encryption key, hex 64 chars. Generate: `openssl rand -hex 32` |
| `data` | Always `data` |
| `net.dns` | DNS server, e.g. `8.8.8.8:53` |
---
## Optional fields
| YAML field | Description |
|-----------|----------|
| `debug` | `true` for verbose connection logs |
| `profiles` | List of failover profiles for `srv`/`cnc` |
| `failover.retry_delay` | Pause before the next profile, e.g. `2s` |
| `failover.max_cycles` | How many full passes over the profiles to make; `0` = unlimited |
| `liveness.interval` | Ping interval over the control stream, default `10s` |
| `liveness.timeout` | How long to wait for a pong, default `5s` |
| `liveness.failures` | How many pongs may be missed before a rebuild, default `3` |
| `lifecycle.max_session_duration` | Planned session rebuild after the given time, e.g. `6h`; if unset, disabled |
| `traffic.max_payload_size` | Limit on the encrypted wire-message size; `0` = transport limit |
| `traffic.min_delay` / `.max_delay` | Optional send pacing, e.g. `5ms` / `30ms` |
`crypto.key_file` is read relative to the YAML file. Do not set `crypto.key` and `crypto.key_file` at the same time.
If `profiles` is set, the top-level fields become shared defaults, and each
profile overrides only its own `auth`, `room`, `net`, `engine` and
transport/liveness settings. The profile order must match on server and client.
`liveness` checks the encrypted smux control stream after the handshake,
not just the WebRTC/provider connection status. If a pong does not arrive
several times in a row, the current smux session is rebuilt.
`lifecycle.max_session_duration` limits the duration of a single call /
provider session. When the timer expires, the current `srv` or `cnc` session
closes and starts again with the same config. While this setting is enabled,
a clean session end is also restarted so the second peer can catch up with the
planned rebuild. Value format: `30m`, `2h`, `6h`; `0s` and negative values are
not accepted.
`traffic` adds a common wrapper over the chosen transport. It can limit the
encrypted message size and add a small delay before sending. Data is not
truncated: if a message does not fit the effective limit, send returns an
explicit error. When `max_payload_size` is set, the smux frame size is also
reduced by the crypto overhead; with `0` the chosen transport limit remains.
Use the same traffic settings on both sides.
---
## mode: gen
`gen` is kept for auth providers that can create rooms through an API.
Currently the built-in providers do not support room auto-creation through `olcrtc`.
For `telemost` and `wbstream`, create a room through the service site and paste
its ID into `room.id`. For `jitsi`, specify the room URL.
---
## Server-only fields (`mode: srv`)
| YAML field | Description |
|-----------|----------|
| `socks.proxy_addr` | Address of the SOCKS5 proxy for the server outbound traffic |
| `socks.proxy_port` | Port of that proxy |
| `socks.proxy_user` | Login for upstream-proxy authentication (optional) |
| `socks.proxy_pass` | Password for upstream-proxy authentication (optional) |
If `socks.proxy_user` is empty, the server reaches the proxy without authentication (method `0x00`).
If it is set, username/password auth per RFC 1929 is used (`proxy_pass` is optional and may be empty).
---
## Client-only fields (`mode: cnc`)
| YAML field | Description | Default |
|-----------|----------|:------------:|
| `socks.host` | Which address to start SOCKS5 on | `127.0.0.1` |
| `socks.port` | Which port to start SOCKS5 on | `1080` |
| `socks.user` | Login for incoming SOCKS5 connections (optional) | - |
| `socks.pass` | Password for incoming SOCKS5 connections (optional) | - |
If `socks.user` is not set, authentication is disabled (any local client may connect).
If it is set, the client accepts only connections with the correct login and password (RFC 1929).
If `socks.host` is not loopback (`127.0.0.1`, `::1`, `localhost`), `socks.user` and `socks.pass` are required.
This protects against accidentally opening a SOCKS5 proxy on the local network or the internet.
---
## datachannel
No extra fields - everything is default.
---
## vp8channel
**Recommended: `fps: 30`, `batch_size: 64`** (lower FPS reduces CPU load, larger batch = higher speed)
| YAML field | Description | Default |
|-----------|----------|:------------:|
| `vp8.fps` | VP8 stream FPS | `30` |
| `vp8.batch_size` | Frames per tick | `64` |
| `vp8.max_bytes_per_sec` | Wire byte-rate probe ceiling, bytes/sec | `1000000` |
The wire rate is paced by a delay-based adaptive controller that auto-discovers each SFU's policer knee at runtime. The policer queues before it drops, so the path RTT inflates ahead of the throughput collapse; the pacer probes the rate up while RTT stays near the path baseline and backs off once it inflates, settling just under the knee on its own. There is nothing to hand-measure per service.
`vp8.max_bytes_per_sec` only caps how high the controller may probe (default 1000000, ~1 MB/s). Lower it to hard-limit a path; `0` keeps the built-in cap. A fresh session starts probing from 400 KB/s (the previous conservative default), so a healthy path only ramps up from the old operating point.
---
## seichannel
**Recommended: `fps: 30`, `batch_size: 64`, `fragment_size: 900`, `ack_timeout_ms: 2000`**
| YAML field | Description | Default |
|-----------|----------|:------------:|
| `sei.fps` | H264 stream FPS | `30` |
| `sei.batch_size` | Frames per tick | `64` |
| `sei.fragment_size` | Fragment size in bytes | `900` |
| `sei.ack_timeout_ms` | ACK timeout in milliseconds | `2000` |
---
## videochannel
**Recommended: `codec: qrcode`, `width: 1080`, `height: 1080`, `fps: 30`, `bitrate: "5000k"`, `hw: none`**
| YAML field | Description | Default |
|-----------|----------|:------------:|
| `video.codec` | `qrcode` or `tile` | `qrcode` |
| `video.width` | Width in pixels | `1920` |
| `video.height` | Height in pixels | `1080` |
| `video.fps` | FPS | `30` |
| `video.bitrate` | Bitrate, e.g. `"2M"` or `"5000k"` | `"2M"` |
| `video.hw` | Hardware acceleration: `none` or `nvenc` | `none` |
| `video.qr_recovery` | QR error correction: `low` / `medium` / `high` / `highest` | `low` |
| `video.qr_size` | QR fragment size in bytes, `0` = auto | `0` |
| `video.tile_module` | Tile size in pixels 1..270 (`tile` only) | `4` |
| `video.tile_rs` | Reed-Solomon parity % 0..200 (`tile` only) | `20` |
| `ffmpeg` | Path to the ffmpeg executable | `ffmpeg` |
For codec `tile` exactly `1080x1080` is required.
---
## Ready-made configs
### wbstream + datachannel (does not work in the normal guest flow)
WB Stream DataChannel **does not work** in the normal guest flow - WB Stream issues tokens with `canPublishData=false`, and DC does not route data. This mode is marked as expected fail in E2E tests. For normal use pick `vp8channel`, `seichannel` or `videochannel`.
```yaml
# the room ID must be created manually via https://stream.wb.ru
# server.yaml
mode: srv
auth:
provider: wbstream
room:
id: "