Repository navigation
librtmp2-server 0.6.3
What's Changed
- Update Rust crate libc to v0.2.190 by @renovate[bot] in #267
- Update Rust crate uuid to v1.27.0 by @renovate[bot] in #268
- fix(bug-hunter): full-scan fixes (2 confirmed bugs) by @AlexanderWagnerDev in #266
- Update Rust crate tokio to v1.53.2 - abandoned by @renovate[bot] in #269
- Update taiki-e/install-action digest to db3874b by @renovate[bot] in #271
- fix(bug-hunter): full-scan fixes (3 confirmed bugs, 1 reverted to manual review) by @AlexanderWagnerDev in #270
- Update taiki-e/install-action digest to 2849dd4 by @renovate[bot] in #272
- fix(bug-hunter): round 6 - cluster health/learner gate, preauth timeout, route rename, sink cleanup, CI exit codes by @AlexanderWagnerDev in #273
- fix(ci): build with --locked by @AlexanderWagnerDev in #274
- fix(bug-hunter): round 7 - subscription refcount guard, non-finite bandwidth config, stale CI diagnostics by @AlexanderWagnerDev in #275
- Update taiki-e/install-action digest to 24b35e7 by @renovate[bot] in #276
- ci(bench): cross-server sweep on every merge and release, compared with the last release by @AlexanderWagnerDev in #277
- fix(bench): build the librtmp2 client without --locked by @AlexanderWagnerDev in #278
- refactor(bench): keep the benchmark data on main instead of a bench-data branch by @AlexanderWagnerDev in #279
- chore(deps): update actions/upload-artifact action to v7.0.2 by @renovate[bot] in #282
- chore(deps): update actions/download-artifact action to v8.0.2 by @renovate[bot] in #281
- chore(deps): update taiki-e/install-action digest to 27cdd32 by @renovate[bot] in #280
- fix(bug-hunter): round 8 - relay restore on publish rename, bench sweep/nginx hardening by @AlexanderWagnerDev in #283
- chore(deps): update rust crate tokio-util to v0.7.20 by @renovate[bot] in #288
- chore(deps): update dtolnay/rust-toolchain digest to 686976e by @renovate[bot] in #287
- fix(logger): reject symlinked LOG_FILE on Unix (O_NOFOLLOW) by @cursor[bot] in #286
- fix(bug-hunter): round 9 - player-reservation, init-cache eviction and subscription-refcount fixes by @AlexanderWagnerDev in #285
- Benchmarks against the newest competitor releases (MediaMTX v1.21.2) by @AlexanderWagnerDev in #284
- docs: fill the Unreleased changelog and re-record the README terminal demo by @AlexanderWagnerDev in #289
- chore(deps): update taiki-e/install-action digest to be76f54 by @renovate[bot] in #290
- chore(deps): update rust crate uuid to v1.28.0 by @renovate[bot] in #291
- Pre-release audit for 0.6.3: release workflow, Docker build, proxy detection, docs by @AlexanderWagnerDev in #292
- release: depend on librtmp2 0.12.0 for 0.6.3 by @AlexanderWagnerDev in #293
Full Changelog: v0.6.2...v0.6.3
Benchmarks
Measured automatically for this release on a CI runner; the machine is described below. Raw data: bench-results-v0.6.3.json.
- Measured: 2026-10-14 22:00:08 UTC ·
b72fe6c· crate version 0.6.3 · workflow run - Built on: librtmp2 0.12.0
- CPU: AMD EPYC 9V45 96-Core Processor · 4 vCPUs
- RAM: 15.6 GiB
- System: Linux 6.17.0-1022-azure x86_64 · rustc 1.99.0 · GitHub-hosted ubuntu24 (image 20261004.327.1)
- Noise: shared CI VM — CPU model, neighbouring load and the runner image change between runs, so treat absolute numbers as indicative.
- Comparable vs release v0.6.5: ❌ different hardware (AMD EPYC 9V74 80-Core Processor, 4 vCPUs vs AMD EPYC 9V45 96-Core Processor, 4 vCPUs): only large changes (> 25 %) mean anything
http_api
| Benchmark | Time | Throughput | vs release v0.6.5 |
|---|---|---|---|
http_api/create_stream |
144.15 µs | — | 🟢 −48.7 % |
http_api/health |
91.80 µs | — | 🟢 −37.7 % |
http_api/list_streams |
566.5 ms | — | ⚪ +21.3 % |
🟢 faster · 🔴 slower · ⚪ within the noise band (5–25 % depending on how comparable the two environments are, plus both runs' Criterion confidence intervals). Lower time is better.
Cross-server sweep
Same RTMP client and ffmpeg source for every server, one server at a time: load viewers 500 1000 2000, publisher ffmpeg 1280x720@30 H.264 2.5 Mbps + AAC 128 kbps. One sweep per run, no repetitions — the shared runner makes single values noisy, so compare servers within this run rather than across runs.
Servers: librtmp2-server 0.6.3 (librtmp2 0.12.0) · MediaMTX v1.21.2 · LiveForge main @ 4e70fb3 · SRS v8.0-d0 · nginx-rtmp nginx 1.31.6 (nginx-rtmp-module @ 6c7719d)
librtmp2-server vs the baselines
| Metric | Now | vs release v0.6.5 |
|---|---|---|
| publish handshakes/s | 10,073 | 🟢 +41.3 % |
| publish handshake avg (ms) | 2.23 | 🟢 −33.4 % |
| publish handshake p95 (ms) | 6.54 | ⚪ +18.1 % |
| play handshakes/s | 11,891 | 🟢 +108.5 % |
| play handshake avg (ms) | 1.81 | 🟢 −52.7 % |
| play handshake p95 (ms) | 4.11 | 🟢 −57.8 % |
| join, 1 viewer: avg (ms) | 0.41 | 🟢 −28.1 % |
| join, 1 viewer: p95 (ms) | 0.41 | 🟢 −28.1 % |
| join, 25 viewers: avg (ms) | 1.07 | ⚪ −22.5 % |
| join, 25 viewers: p95 (ms) | 1.78 | ⚪ −14.8 % |
| join, 100 viewers: avg (ms) | 1.26 | 🟢 −58.7 % |
| join, 100 viewers: p95 (ms) | 2.20 | 🟢 −62.8 % |
| load, 500 viewers: join avg (ms) | 13.93 | ⚪ −10.9 % |
| load, 500 viewers: join p95 (ms) | 31.45 | ⚪ −20.2 % |
| load, 500 viewers: frames/viewer | 73.15 | ⚪ +0.1 % |
| load, 500 viewers: CPU (% of one core) | 26.30 | 🟢 −30.8 % |
| load, 500 viewers: peak RSS (MiB) | 22.20 | ⚪ −1.3 % |
| load, 1000 viewers: join avg (ms) | 8.44 | 🟢 −57.2 % |
| load, 1000 viewers: join p95 (ms) | 26.24 | 🟢 −50.5 % |
| load, 1000 viewers: frames/viewer | 73.15 | ⚪ +0.0 % |
| load, 1000 viewers: CPU (% of one core) | 51.90 | 🟢 −26.9 % |
| load, 1000 viewers: peak RSS (MiB) | 31.80 | ⚪ −1.9 % |
| load, 2000 viewers: join avg (ms) | 29.89 | 🟢 −65.6 % |
| load, 2000 viewers: join p95 (ms) | 99.52 | 🟢 −65.8 % |
| load, 2000 viewers: frames/viewer | 73.14 | ⚪ −0.1 % |
| load, 2000 viewers: CPU (% of one core) | 98.60 | ⚪ −11.9 % |
| load, 2000 viewers: peak RSS (MiB) | 52.80 | ⚪ −0.6 % |
Handshake latency
| Server | publish /s | avg ms | p95 | p99 | play /s | avg ms | p95 | p99 |
|---|---|---|---|---|---|---|---|---|
| librtmp2-server | 10,073 | 2.23 | 6.54 | 7.01 | 11,891 | 1.81 | 4.11 | 5.42 |
| MediaMTX | 9,114 | 2.74 | 4.78 | 6.03 | 8,462 | 2.44 | 4.21 | 6.75 |
| LiveForge | 9,904 | 2.23 | 3.86 | 5.13 | 8,376 | 2.84 | 5.30 | 5.88 |
| SRS | 594.6 | 47.32 | 51.71 | 51.79 | 625.9 | 45.92 | 50.90 | 51.17 |
| nginx-rtmp | 707.8 | 41.53 | 42.83 | 43.04 | 358.0 | 83.08 | 85.16 | 85.80 |
Join latency (avg / p95 ms)
| Server | 1 viewer | 25 viewers | 100 viewers |
|---|---|---|---|
| librtmp2-server | 0.41 / 0.41 | 1.07 / 1.78 | 1.26 / 2.20 |
| MediaMTX | 0.62 / 0.62 | 2.48 / 3.62 | 1.83 / 3.93 |
| LiveForge | 2.37 / 2.37 | 4.54 / 8.19 | 6.52 / 18.80 |
| SRS | 41.97 / 41.97 | 44.31 / 45.60 | 56.93 / 64.44 |
| nginx-rtmp | 82.02 / 82.02 | 82.27 / 82.88 | 84.52 / 87.66 |
Many viewers on one stream
| Viewers | Server | join avg / p95 ms | CPU % (one core) | peak RSS MiB | frames/viewer |
|---|---|---|---|---|---|
| 500 | librtmp2-server | 13.93 / 31.45 | 26.30 | 22.20 | 73.15 |
| 500 | MediaMTX | 20.08 / 37.89 | 62.80 | 112.6 | 73.12 |
| 500 | LiveForge | 65.19 / 124.8 | 40.20 | 96.00 | 73.10 |
| 500 | SRS | 146.8 / 175.2 | 5.70 | 139.6 | 72.38 |
| 500 | nginx-rtmp | 87.19 / 93.51 | 40.80 | 23.90 | 73.06 |
| 1000 | librtmp2-server | 8.44 / 26.24 | 51.90 | 31.80 | 73.15 |
| 1000 | MediaMTX | 30.14 / 70.42 | 127.5 | 163.4 | 73.08 |
| 1000 | LiveForge | 90.84 / 201.7 | 83.60 | 151.5 | 73.13 |
| 1000 | SRS | 408.6 / 1,133 | 10.10 | 184.2 | 72.96 |
| 1000 | nginx-rtmp | 106.5 / 136.4 | 88.50 | 29.80 | 73.08 |
| 2000 | librtmp2-server | 29.89 / 99.52 | 98.60 | 52.80 | 73.14 |
| 2000 | MediaMTX | 120.2 / 248.2 | 196.1 | 300.2 | 69.90 |
| 2000 | LiveForge | 400.3 / 1,058 | 151.4 | 275.7 | 73.07 |
| 2000 | SRS | 581.2 / 1,191 | 21.50 | 268.0 | 73.14 |
| 2000 | nginx-rtmp | 194.0 / 227.7 | 95.00 | 35.00 | 55.62 |
A competitor delivering fewer frames per viewer than the others was overloaded at that step (the delivered rate, not just latency, is the result).