Skip to content

feat: SRTLA support#5811

Open
thejoeejoee wants to merge 13 commits into
bluenviron:mainfrom
thejoeejoee:feat/srtla-support
Open

feat: SRTLA support#5811
thejoeejoee wants to merge 13 commits into
bluenviron:mainfrom
thejoeejoee:feat/srtla-support

Conversation

@thejoeejoee
Copy link
Copy Markdown

@thejoeejoee thejoeejoee commented May 29, 2026

Adds an SRTLA (SRT Link Aggregation) receiver server that accepts bonded connections from BELABOX-compatible encoders and proxies aggregated traffic to the local SRT server.

What

  • Full SRTLA protocol implementation: REG1/REG2/REG3 handshake, keepalive, multi-connection aggregation with per-connection ACKs
  • SRTLA↔SRT correlation: when SRT accepts a connection from the SRTLA backend, the group is labeled with the stream path
  • Path-labeled Prometheus metrics: srtla_groups, srtla_groups_conns_active, srtla_groups_bytes_received, srtla_groups_bytes_forwarded
  • Enriched lifecycle logging with group short ID in all events
  • IPv6/dual-stack support with family-aware loopback resolution
  • Configuration via srtla / srtlaAddress in mediamtx.yml

Config

srtla: yes
srtlaAddress: :5000

Closes #3029

Implements SRTLA (SRT Link Aggregation) protocol receiver as a UDP
proxy server that aggregates multiple sender connections into a
single SRT stream, enabling mobile IRL streaming over bonded
network links (BELABOX, IRL Pro, Moblin).

Resolves bluenviron#3029
Match BELABOX receiver behavior: broadcast SRT ACKs to all
connections, send other packets only to the most recently
active SRTLA address. Also adds config validation and matches
upstream maxConnsPerGroup=8.
Wire SRTLA groups to their corresponding SRT connections for:
- Per-path metrics (bytes_received, bytes_forwarded, conns_active)
- Enriched logging with stream path context
- Lifecycle coupling (SRT close triggers SRTLA group teardown)

Use interfaceIsEmpty() for nil-safe metrics check matching SRT pattern.
Address review findings:
- Lazy srtConn creation on first data packet (not during REG1)
- sendReg2/sendReg3 return errors with state rollback on failure
- IPv6 loopback resolution for dual-stack/IPv6-only setups
- Close() atomically clears maps, preventing post-close state leaks
- All network I/O moved outside mutex
- cleanup() repairs lastAddr when timed-out conn was current target
- All send errors logged with context
- Shutdown race fix: closed check + wg.Add inside mutex
- 13 regression tests (including IPv6 loopback resolution)
@thejoeejoee
Copy link
Copy Markdown
Author

  • is SRT-SRTLA linker worth it? adds a lot of correlation code, but adds debugging/metrics benefits
  • receiver only, no sender — follow-up if needed
  • group timeout 30s hardcoded — should probably be configurable, but fine for now
  • address-based correlation is fragile behind NAT — if SRT conn comes from different IP than SRTLA reg, it won't match. in practice this works because both go through the same UDP socket on localhost, but worth knowing
  • no max groups/conns limit — could be DoS vector in theory

@thejoeejoee
Copy link
Copy Markdown
Author

thejoeejoee commented May 29, 2026

2026/05/29 14:29:32 INF MediaMTX dev, darwin, arm64
2026/05/29 14:29:32 INF [RTSP] listener opened on :8554 (TCP/RTSP), :8000 (UDP/RTP), :8001 (UDP/RTCP)
2026/05/29 14:29:32 INF [RTMP] listener opened on :1935 (TCP/RTMP)
2026/05/29 14:29:32 INF [HLS] listener opened on :8888 (TCP/HTTP)
2026/05/29 14:29:32 INF [WebRTC] listener opened on :8889 (TCP/HTTP), :8189 (UDP/ICE)
2026/05/29 14:29:32 INF [SRT] listener opened on :8890 (UDP)
2026/05/29 14:29:32 INF [SRTLA] listener opened on :8891 (UDP)
^[2026/05/29 14:33:18 INF [SRT] [conn [::1]:52107] opened
2026/05/29 14:33:18 INF [path mystream] stream is available and online, 2 tracks (H264, MPEG-4 Audio)
2026/05/29 14:33:18 INF [SRT] [conn [::1]:52107] is publishing to path 'mystream'
2026/05/29 14:33:46 INF [RTMP] [conn [::1]:49652] opened
2026/05/29 14:33:46 INF [RTMP] [conn [::1]:49652] is reading from path 'mystream', 2 tracks (H264, MPEG-4 Audio)
$ srtla_send 5000 127.0.0.1 8891 ./ips
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 -f lavfi -i sine=frequency=1000 -c:v libx264 -preset ultrafast -tune zerolatency -c:a aac -f mpegts "srt://127.0.0.1:5000?streamid=publish:mystream&pkt_size=1316"
Input #0, lavfi, from 'testsrc=size=1280x720:rate=30':
  Duration: N/A, start: 0.000000, bitrate: N/A
  Stream #0:0: Video: wrapped_avframe, rgb24, 1280x720 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 30 tbn
Input #1, lavfi, from 'sine=frequency=1000':
  Duration: N/A, start: 0.000000, bitrate: 705 kb/s
  Stream #1:0: Audio: pcm_s16le, 44100 Hz, mono, s16, 705 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (wrapped_avframe (native) -> h264 (libx264))
  Stream #1:0 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
[libx264 @ 0x155e07df0] using SAR=1/1
[libx264 @ 0x155e07df0] using cpu capabilities: ARMv8 NEON DotProd I8MM
[libx264 @ 0x155e07df0] profile High 4:4:4 Predictive, level 3.1, 4:4:4, 8-bit
Output #0, mpegts, to 'srt://127.0.0.1:5000?streamid=publish:mystream&pkt_size=1316':
  Metadata:
    encoder         : Lavf62.12.101
  Stream #0:0: Video: h264, yuv444p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 90k tbn
    Metadata:
      encoder         : Lavc62.28.101 libx264
    Side data:
      CPB properties: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
  Stream #0:1: Audio: aac (LC), 44100 Hz, mono, fltp, 69 kb/s
    Metadata:
      encoder         : Lavc62.28.101 aac
frame= 4411 fps= 30 q=15.0 size=    7522KiB time=00:02:27.03 bitrate= 419.1kbits/s speed=   1x elapsed=0:02:26.51
❯ ffprobe "rtmp://localhost:1935/mystream"
Input #0, flv, from 'rtmp://localhost:1935/mystream':
  Duration: N/A, start: 171.061000, bitrate: N/A
  Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv444p(progressive), 1280x720 [SAR 1:1 DAR 16:9], 30.30 fps, 30 tbr, 1k tbn, start 175.000000
  Stream #0:1: Audio: aac (LC), 44100 Hz, mono, fltp, start 171.061000
# SRTLA groups
srtla_groups{id="21...",path="mystream"} 1
srtla_groups_conns_active{id="21...",path="mystream"} 1
srtla_groups_bytes_received{id="21...",path="mystream"} 843368
srtla_groups_bytes_forwarded{id="21...",path="mystream"} 843368

@thejoeejoee thejoeejoee marked this pull request as ready for review May 29, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: SRTLA Support

1 participant