Reference implementation and experiment artifacts accompanying the MMSys 2026 Special Session paper on Media-over-QUIC Transport (MOQT) ABR streaming with time-aligned switching, filtered/unfiltered client modes, and pluggable ABR composability.
This repository contains everything needed to reproduce the paper's figures end-to-end: a Draft-14-compliant MOQT publisher / relay / subscriber stack, the Mininet-based network harness, the parametrized experiment suite (E1–E6), and the Jupyter notebooks that turn raw results into the published figures.
| Path | Role |
|---|---|
| apps/publisher/ | Rust live publisher (FFmpeg-encoded ABR ladder over MOQT) |
| apps/relay/ | Rust MOQT relay with bounded per-track cache |
| apps/client-js/ | Browser subscriber (TypeScript/Vite) — filtered & unfiltered modes, ABR controller |
| apps/client/ | Native subscriber (Rust) |
| libs/moqtail-rs/ | Rust MOQT protocol library |
| libs/moqtail-ts/ | TypeScript MOQT protocol library |
| tests/network/ | Mininet harness — single-relay topology, link shaping, Playwright-driven Chromium |
| tests/experiments/ | Paper experiments E1–E6 (parametrized pytest, builds on tests/network/) |
| paper/ | Figure notebooks, Makefile, and figures/ outputs |
The full pipeline is:
prepare asset → run experiments → build figures
(once) (~3.5 h on Linux) (cd paper && make all)
See INSTALLATION.md for the full Linux-native setup (Ubuntu 24.04 tested). It covers system packages (FFmpeg dev libs, mkcert, weston for the headless harness), Rust, Node.js v18+, TLS certificates for WebTransport, and optional VAAPI hardware encoding.
The Mininet harness additionally requires Open vSwitch, Xvfb, Chromium, and
uv. One-shot setup:
sudo ./tests/network/setup.shThis also builds relay / publisher (release) and the client-js bundle.
All experiments use the first 60 s of Tears of Steel re-encoded to 720p H.264 with 1 s GOPs (low-latency convention; matches LoL+/CMCD). The script is idempotent — safe to re-run.
./scripts/prepare_tears_of_steel.shIt downloads Blender's 1080p H.264 master, scales/encodes once, and prints
the SHA-256 of the output for reproducibility. Cached at
data/video/.cache/; output at data/video/tears_of_steel_60s_720p.mp4.
./scripts/run-experiments.sh # all five experiments (~3.5 h)
./scripts/run-experiments.sh e1 e2 # selected experimentsThe wrapper rebuilds stale Rust binaries, runs each experiment under sudo
(Mininet requires root namespaces), and aggregates per-cell summaries.
Per-run artifacts land at:
tests/experiments/results/<test_id>/<timestamp>/
├── metrics.csv
├── relay.log
├── publisher.log
├── switch_records.json
├── abr_settings.json
├── cell_params.json
└── summary.json
Aggregates land at tests/experiments/results/<exp>/aggregate.csv and
aggregate_summary.csv — designed for pd.read_csv(...).pipe(...) workflows.
cd paper
uv sync
make allNotebook-driven figures execute against the aggregates from step 3; the
TikZ architecture figure compiles from figures/fig1_architecture.tex via
pdflatex. Outputs (PDF + PNG) land in paper/figures/.
To rebuild a single figure:
make figures/fig2_e2_e3_playhead_gap.pdfNotebooks are committed without cell outputs — strip with
.venv/bin/nbstripout notebooks/<name>.ipynb before staging, or install
the git filter once with .venv/bin/nbstripout --install.
| Exp | What it measures | Cells × Runs | Wall time | Figure |
|---|---|---|---|---|
| E1 | Baseline single-run smoke (5-rung 720p ladder, stable 10 Mbps, unfiltered live edge) | 1 × 1 | ~1.5 min | — (sanity only) |
| E2 | Naive (immediate) switch — PTS discontinuity under bandwidth step-down at filter delays 5/10/20/30 s | 4 × 5 | ~27 min | Fig 2, Fig 3a |
| E3 | Group-aligned switch — same conditions as E2, switching deferred to GOP boundary | 4 × 5 | ~27 min | Fig 2, Fig 3b |
| E4 | Cache-availability boundary — forced upswitch at filter delays 5/10/20/30/40 s with relay --cache-size 20 |
5 × 5 | ~33 min | Fig 4 |
| E5 | Unfiltered + naive ABR composability sweep (E5 was reserved at design time; added later) | — | — | Fig 6 |
| E6 | Filtered + aligned ABR composability — 8 ABR configs × 3 bandwidth profiles | 24 × 5 | ~2.7 h | Fig 5 |
Full per-experiment specs (parameters, run flow, assertions, summary fields) live in docs/superpowers/specs/2026-04-30-paper-experiments-design.md. The figure spec (panel layout, axes, captions, page-budget choices) is in docs/superpowers/specs/2026-05-03-paper-figures-design.md.
sudo uv --project tests/experiments run pytest \
tests/experiments/test_e2_naive_switch.py -vsudo uv run --project tests/network pytest tests/network/scenarios/ -vAvailable: test_bandwidth_recovery.py, test_gradual_ramp_down.py, test_high_latency.py, test_oscillation_resistance.py, test_packet_loss.py, test_publisher_degradation.py, test_sudden_drop.py, test_aligned_switch.py, test_naive_switch_discontinuity.py, test_filtered_connect.py. Topology, link profiles, and run parameters are in tests/network/config.yaml.
npm --prefix libs/moqtail-ts run build
cargo build --release
./scripts/run-stack.sh # default video
./scripts/run-stack.sh data/video/my.mp4 # custom video
./scripts/run-stack.sh stop| Component | URL |
|---|---|
| Relay | https://localhost:4433 |
| Client-JS | http://localhost:5173 |
See AUTHORS.
Contributions are welcome. See CONTRIBUTING.md. Bug reports, fixes, and documentation improvements via GitHub issues / PRs.