moq-cli 0.12.8

Media over QUIC
[package]
name = "moq-cli"
description = "Media over QUIC"
authors = ["Luke Curley <kixelated@gmail.com>"]
repository = "https://github.com/moq-dev/moq"
license = "MIT OR Apache-2.0"

version = "0.12.8"
edition = "2024"
# Depends on moq-relay, whose sysinfo 0.39 needs 1.95, above the 1.91 workspace
# floor. This binary is an application, so the bump stays here rather than
# raising the libraries others build on.
rust-version = "1.95"

keywords = ["quic", "http3", "webtransport", "media", "live"]
categories = ["multimedia", "network-programming", "web-programming"]

# The package is `moq-cli`, but the binary it ships is `moq`.
[[bin]]
name = "moq"
path = "src/main.rs"
# `libmoq`'s staticlib is also named `moq`, so a `cargo doc` selecting both renders
# them to `target/doc/moq` and the two rustdoc processes race to clean it (#3094).
# This binary's page is the one to give up: nothing links it, and a bin target has
# no public API to render, whereas docs.rs/libmoq is the published C API reference.
doc = false

[features]
default = ["iroh", "cluster-lan", "noq", "websocket", "nvidia"]
iroh = ["moq-tokio/iroh"]
# LAN discovery and meshing (`--cluster-lan`).
cluster-lan = ["moq-relay/cluster-lan"]
jemalloc = ["moq-tokio/jemalloc"]
noq = ["moq-tokio/noq"]
# qlog trace capture (`--client-quic-qlog <DIR>`). Off by default: it compiles the
# qlog machinery into the enabled backends and is only wanted for debugging or
# congestion-control testing.
qlog = ["moq-tokio/qlog"]
websocket = ["moq-tokio/websocket"]
# Device capture (camera + microphone) + encode/publish. Off by default because
# it pulls in moq-video + moq-audio capture: on Linux the microphone needs
# ALSA/libasound at build time through cpal (the camera needs nothing, moq-v4l
# checks its bindings in), plus binary size. macOS/Windows use OS frameworks, no
# extra install. H.264 is vendored static (openh264), so no system ffmpeg/libav.
# Enable with `cargo build -p moq-cli --features capture`, adding `pipewire` for
# display capture on Linux.
capture = ["dep:moq-video", "dep:moq-audio", "moq-video/capture", "moq-audio/capture"]
# Just-in-time transcoding (`moq ... transcode`). Off by default because it pulls
# in moq-video and its codec dependencies. Enable with
# `cargo build -p moq-cli --features transcode`.
transcode = ["dep:moq-transcode", "dep:moq-video"]
# Native playback (`moq ... play`): decode into a wgpu window and a cpal
# speaker. Off by default because it pulls both graphics and audio device stacks
# into a binary that may only be routing containers or serving gateways.
play = ["dep:moq-video", "moq-video/render", "dep:moq-audio", "moq-audio/playback", "dep:pollster", "dep:winit"]
# NVIDIA hardware codecs (NVENC + NVDEC) on Linux, on by default. Just turns on
# the matching moq-video feature, so it only bites when something else pulls in
# moq-video: `capture`, `transcode`, or `play`. For a build with no CUDA
# dependencies, drop it:
#   cargo build -p moq-cli --no-default-features --features "iroh,noq,websocket,capture"
nvidia = ["moq-video?/nvidia", "moq-transcode?/nvidia"]
# Compatibility aliases for the pre-consolidation names, kept so a manifest that
# already asks for the old split still resolves. Undocumented on purpose: the
# feature tables name only `nvidia`.
nvenc = ["nvidia"]
nvdec = ["nvidia"]
# Intel/AMD VAAPI hardware encoding (Linux), opt-in like the moq-video feature
# it turns on: libva is dlopen'd at runtime, but moq-vaapi's bindgen needs
# libclang on the build host. Only bites when `capture`, `transcode`, or `play`
# pulls in moq-video.
vaapi = ["moq-video?/vaapi", "moq-transcode?/vaapi"]
# The V4L2 M2M codecs of an ARM SoC (a Raspberry Pi's VideoCore and the like),
# opt-in like the moq-video feature it turns on. Costs the build nothing: moq-v4l
# checks its bindings in. Only applies when `capture`, `transcode`, or `play`
# pulls in moq-video.
v4l2 = ["moq-video?/v4l2", "moq-transcode?/v4l2"]
# Screen capture for `capture --display` on Linux (xdg-desktop-portal + PipeWire)
# and PipeWire cameras for `capture --camera pipewire:<node>`, opt-in like moq-video's own `pipewire` because it links libpipewire-0.3 at
# build time. Only bites when `capture` pulls in moq-video and moq-audio.
# Also reaches audio, so `devices`, microphone capture and playback go through
# the sound server rather than its ALSA plugin on a machine running one.
pipewire = ["moq-video?/pipewire", "moq-audio?/pipewire"]
# The other Linux sound server. Off by default, unlike `pipewire`: PulseAudio is
# what a machine runs when it is not running PipeWire, so enabling both by
# default would link a client library most builds never reach for.
pulseaudio = ["moq-audio?/pulseaudio"]

[dependencies]
anyhow = { workspace = true, features = ["backtrace"] }
axum = { workspace = true }
axum-server = { workspace = true }
base64 = { workspace = true }
bytes = { workspace = true }
hang = { workspace = true }
humantime = { workspace = true }
moq-audio = { workspace = true, optional = true, features = ["aac"] }
moq-auth = { workspace = true, features = ["serve"] }
# `server` enables the HTTP egress server for `moq export hls`; the importer is always available.
moq-hls = { workspace = true, features = ["server"] }
moq-mux = { workspace = true }
# Cluster, LAN mesh, and inbound `/.cluster` auth. default-features off so the
# CLI's own feature set (iroh, noq, cluster-lan) is what selects them.
moq-relay = { workspace = true }
moq-rtc = { workspace = true }
moq-rtmp = { workspace = true }
moq-srt = { workspace = true }
# Raw qmux listeners are part of the CLI surface. `uds` compiles only on Unix.
moq-tokio = { workspace = true, default-features = false, features = ["aws-lc-rs", "tcp", "uds"] }
moq-transcode = { workspace = true, optional = true, features = ["openh264"] }
moq-video = { workspace = true, optional = true, features = ["openh264"] }
pollster = { workspace = true, optional = true }
reqwest = { workspace = true, features = ["rustls", "json"] }
rustls = { version = "0.23", features = ["aws-lc-rs"], default-features = false }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tower-http = { workspace = true }
tracing = { workspace = true }
url = { workspace = true }
usage = { workspace = true, features = ["completions", "config"] }
winit = { version = "0.30.13", optional = true }

[target.'cfg(unix)'.dependencies]
sd-notify = { workspace = true }

[dev-dependencies]
# Authors an MSF-only catalog, which is the one shape that tells a completer reading
# the wrong catalog track apart from one reading the right one: `moq-mux`'s producer
# publishes hang and MSF from the same source, so both answer for an ordinary broadcast.
moq-msf = { path = "../moq-msf" }
# `test_relay` stands up a real relay for the `fetch` tests to read through.
moq-relay = { path = "../moq-relay", default-features = false, features = ["test-support"] }
tempfile = { workspace = true }
# `test-util` enables `tokio::time::pause` so the TS round-trip test simulates the
# exporter drain timeouts instantly instead of waiting on the wall clock.
tokio = { workspace = true, features = ["test-util"] }

[[bench]]
name = "play_buffer"
harness = false