SRTLA bonds multiple network connections together for live video streaming, providing increased bandwidth and redundancy.
This is a fork of the BELABOX SRTLA project, with contributions from IRLToolkit, IRLServer, OpenIRL, and CeraLive.
⚠️ The Csrtla_sendis deprecated and no longer shipped. Thesrtlapackage is now receiver-only (srtla_rec). The device-side sender has moved to the Rust fork srtla-send-rs (ADR-003), which installs/usr/bin/srtla_sendand is CLI- and telemetry-compatible. The C sender source and its test suite remain in this repo as the protocol reference and still build/run underctest— they are simply excluded from the installed package. To run the sender, install thesrtla-send-rspackage.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Encoder │────▶│ srtla_send │═══════════════▶│ srtla_rec │────▶│ SRT Server │
│ (SRT) │ │ │ Multiple IPs │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│
┌─────┴─────┐
▼ ▼ ▼
LTE LTE WiFi
1 2
- Combine bandwidth: 3× 5Mbps connections → ~15Mbps total
- Redundancy: One link fails, others continue
- Adaptive: Better links automatically get more traffic
- Link aggregation across multiple network connections
- Connection groups with per-connection quality tracking
- Cellular-resilient timeouts and NAT keepalive padding
- Broadcast ACK/NAK delivery across all connections in a group
- Batch packet I/O (
recvmmsg/sendmmsg) for low syscall overhead - Connection-recovery mode for temporary network issues
- Per-uplink telemetry via atomic JSON stats file (
--stats-file) - Cross-implementation compatibility matrix with automated harness
- Comprehensive docs (network setup, troubleshooting, protocol)
- TypeScript bindings for
srtla_send/srtla_rec
srtla_rec --srtla_port 5000 --srt_hostname 127.0.0.1 --srt_port 5001With CeraUI (recommended): The IP list is managed automatically. CeraUI detects network interfaces, writes the IP file, and signals srtla_send when interfaces change.
Standalone usage:
-
Create IP list file:
echo "10.0.0.10" > /tmp/srtla_ips # usb0 IP echo "10.0.1.10" >> /tmp/srtla_ips # usb1 IP echo "192.168.1.50" >> /tmp/srtla_ips # wlan0 IP
-
Start sender:
srtla_send 5000 relay.example.com 5001 /tmp/srtla_ips
-
Configure encoder to send SRT to
localhost:5000 -
When interfaces change, update the file and signal reload:
kill -HUP $(pidof srtla_send)
SRTLA will NOT work correctly without source-based routing!
Without it, all traffic goes through one interface regardless of which source IP is used.
See Network Setup Guide for step-by-step instructions.
mkdir build && cd build
cmake ..
make
sudo make installDependencies:
- CMake 3.16+
- C++17 compiler
- spdlog (fetched automatically via CMake)
- argparse (included in deps/)
| Document | Description |
|---|---|
| Network Setup | Start here! Routing config, IP list management |
| How It Works | Protocol details, architecture, congestion control, observability |
| Compatibility | Ecosystem research: which impls interop and why |
| Troubleshooting | Common issues and solutions |
| Extension Points | GroupIdentity hooks and extension surface |
| Connection Info Comparison | Connection metrics and comparison |
| Keepalive Improvements | Extended keepalive fix documentation |
Note: If using CeraUI, the IP list (
/tmp/srtla_ips) is managed automatically. See Managing the IP List for details.
Deprecated / not shipped by this package. The
srtla_sendbinary now ships in the srtla-send-rs package. The CLI below is preserved for reference and matched by the Rust fork.
srtla_send <listen_port> <srtla_host> <srtla_port> <ips_file> [--verbose]| Argument | Description | Default |
|---|---|---|
listen_port |
Port for local SRT encoder | 5000 |
srtla_host |
Remote SRTLA receiver hostname | 127.0.0.1 |
srtla_port |
Remote SRTLA receiver port | 5001 |
ips_file |
File with source IPs (one per line) | /tmp/srtla_ips |
--verbose |
Enable debug logging | off |
--stats-file <path> |
Write per-uplink telemetry JSON to <path> (opt-in; see Telemetry) |
off |
Signals:
SIGHUP: Reload IP list without restart. Connections already present in the new list are kept (no re-handshake, no disconnect); new IPs join the running group and dropped IPs are torn down. A reload that resolves to zero valid source IPs (empty, all-garbage, or unreadable file) is refused — the sender logs a parse error and keeps streaming on the existing links rather than dropping the stream.
srtla_rec --srtla_port <port> --srt_hostname <host> --srt_port <port> [--verbose] [--debug]| Argument | Description | Default |
|---|---|---|
--srtla_port |
Listen port for SRTLA connections | 5000 |
--srt_hostname |
Downstream SRT server | 127.0.0.1 |
--srt_port |
Downstream SRT port | 4001 |
--verbose |
Enable verbose logging | off |
--debug |
Enable debug logging | off |
srtla_reccreates a UDP socket for incoming SRTLA connections.- Clients register with
srtla_recand create connection groups. - Multiple connections can be added to a group.
- Data is received across all connections (via
recvmmsgbatches) and forwarded to the SRT server. - SRT control packets (ACK and NAK) are broadcast to every connection
in the group via
sendmmsgso a single bad link cannot stall retransmits. SRT handshakes go to the originating link only. - Small control packets are padded to 32 bytes via
pad_sendtoto keep cellular NAT mappings warm. - Inactive connections and groups are automatically cleaned up after
CONN_TIMEOUT/GROUP_TIMEOUTseconds.
- Sender (conn 0):
SRTLA_REG1(contains sender-generated random ID) - Receiver:
SRTLA_REG2(contains full ID with receiver-generated values) - Sender (conn 0):
SRTLA_REG2(with full ID) - Receiver:
SRTLA_REG3 - Additional connections follow a similar pattern
The receiver can send error responses:
SRTLA_REG_ERR: Operation temporarily failedSRTLA_REG_NGP: Invalid ID, group must be re-registered
Load distribution is driven by the sender (srtla_send), which scores
each connection on window size and in-flight packets and prefers better
links automatically. The receiver supports this by:
- Broadcasting ACK/NAK control packets to every connection in a group, so loss on the most-recent connection cannot stall retransmits.
- Tracking per-connection quality (
weight_percent, error points) for telemetry and operator visibility. - Padding small control packets to 32 bytes via
pad_sendto, so cellular NAT mappings remain warm.
Why no ACK throttling? Earlier CeraLive builds delayed SRTLA ACKs as a back-pressure mechanism. That created a positive feedback loop with senders (notably Moblin) that tie SRT window growth to ACK timing — throttled ACKs slowed window growth, the link looked worse, more throttling kicked in, audio glitches followed. Upstream removed the throttling and CeraLive aligned with that decision; SRTLA ACKs are now sent unconditionally every
RECV_ACK_INT(10) packets.
Connections with temporary problems are not disabled outright:
- Connections showing signs of recovery enter a "recovery mode".
- Those connections receive more frequent keepalive packets for a set
period (
RECOVERY_CHANCE_PERIOD, 5 seconds). - After successful recovery they are fully reactivated.
- Recovery attempts are abandoned after that period if unsuccessful.
Connection quality is assessed by:
- Bandwidth performance (actual vs expected throughput).
- Packet loss (higher loss -> more error points).
- Dynamic bandwidth evaluation against median / minimum thresholds.
- Grace period (
CONNECTION_GRACE_PERIOD, 10 s) before new connections accumulate penalties.
Weight levels:
- 100% (
WEIGHT_FULL): Optimal connection. - 85% (
WEIGHT_EXCELLENT): Excellent connection. - 70% (
WEIGHT_DEGRADED): Slightly impaired. - 55% (
WEIGHT_FAIR): Fair. - 40% (
WEIGHT_POOR): Severely impaired. - 10% (
WEIGHT_CRITICAL): Critically impaired.
Receiver tunables (all live in src/receiver_config.h):
| Parameter | Default | Description |
|---|---|---|
KEEPALIVE_PERIOD |
1 s | Interval for keepalive packets during recovery |
RECOVERY_CHANCE_PERIOD |
5 s | Period for connection recovery attempt |
CONN_QUALITY_EVAL_PERIOD |
5 s | Interval for evaluating connection quality |
RECV_ACK_INT |
10 packets | SRTLA ACK is emitted every N data packets |
GROUP_TIMEOUT |
30 s | Idle group is reaped after this period (cellular-resilient) |
CONN_TIMEOUT |
15 s | Per-connection inactivity timeout (cellular-resilient) |
MIN_ACCEPTABLE_TOTAL_BANDWIDTH_KBPS |
1000 | Minimum total bandwidth for acceptable streaming |
GOOD_CONNECTION_THRESHOLD |
50% | Threshold for a "good" connection |
CONNECTION_GRACE_PERIOD |
10 s | Grace period before applying penalties |
The tests/compat/matrix.yaml registry tracks tested sender/receiver pairs and their expected verdicts. The blocking tier must pass before any release.
# Build the compat helpers first (links system libsrt; default build unaffected)
cmake -B build -DBUILD_COMPAT_TESTS=ON && cmake --build build -j
# Run the full blocking tier
tests/compat/run-matrix.sh --tier blocking
# Run a single pair
tests/compat/run-matrix.sh --pair oursxours --duration 20Per-pair verdicts land in tests/compat/results/<pair>/result.json (gitignored). See Compatibility for the ecosystem research behind each entry.
srtla_send can publish per-uplink JSON snapshots to a file. Pass --stats-file <path> to enable it:
srtla_send 5000 relay.example.com 5001 /tmp/srtla_ips --stats-file /tmp/srtla-send-stats-5000.jsonThe file is rewritten atomically every 1000 ms via rename(2) — readers never see a torn document. When there are no active links the file still exists with "connections": [], so "running but idle" is distinct from "absent". The file is removed on clean shutdown.
The CeraUI backend reads this file via the readSenderTelemetry export in @ceralive/srtla. Full schema and staleness semantics are in ADR-001.
srtla_rec creates information files about active connections under /tmp/srtla-group-[PORT]. These files contain the client IP addresses connected to a specific socket.
- Routing tables added to
/etc/iproute2/rt_tables - DHCP hook installed for USB/Ethernet modems
- NetworkManager dispatcher installed for WiFi
- Public DNS configured
- UDP buffer sizes increased (
sysctl) - Firewall allows UDP traffic
- Source IPs file created
- Verified with
ip route get ... from <source_ip>
If you find SRTLA useful, consider supporting CeraLive development:
GNU Affero General Public License v3.0 (AGPL-3.0)
Copyright (C) 2020-2021 BELABOX project
Copyright (C) 2024 IRLToolkit Inc.
Copyright (C) 2024 OpenIRL
Copyright (C) 2025 IRLServer.com
Copyright (C) 2025 CeraLive
You can use, modify, and distribute this code according to the terms of the AGPL-3.0.