pub struct ServeConfig {Show 35 fields
pub relay_addr: SocketAddr,
pub rtmp_addr: SocketAddr,
pub admin_addr: SocketAddr,
pub hls_addr: Option<SocketAddr>,
pub hls_dvr_window_secs: u32,
pub hls_target_duration_secs: u32,
pub hls_part_target_ms: u32,
pub whep_addr: Option<SocketAddr>,
pub whip_addr: Option<SocketAddr>,
pub dash_addr: Option<SocketAddr>,
pub rtsp_addr: Option<SocketAddr>,
pub srt_addr: Option<SocketAddr>,
pub mesh_enabled: bool,
pub max_peers: usize,
pub auth: Option<SharedAuth>,
pub record_dir: Option<PathBuf>,
pub archive_dir: Option<PathBuf>,
pub hmac_playback_secret: Option<String>,
pub wasm_filter: Vec<PathBuf>,
pub install_prometheus: bool,
pub otel_metrics_recorder: Option<OtelMetricsRecorder>,
pub tls_cert: Option<PathBuf>,
pub tls_key: Option<PathBuf>,
pub cluster_listen: Option<SocketAddr>,
pub cluster_seeds: Vec<String>,
pub cluster_node_id: Option<String>,
pub cluster_id: Option<String>,
pub cluster_advertise_hls: Option<String>,
pub cluster_advertise_dash: Option<String>,
pub cluster_advertise_rtsp: Option<String>,
pub federation_links: Vec<FederationLink>,
pub no_auth_live_playback: bool,
pub no_auth_signal: bool,
pub mesh_root_peer_count: Option<usize>,
pub mesh_ice_servers: Vec<IceServer>,
}Expand description
Configuration passed to [start] to bring up a full-stack LVQR server.
Every *_addr field accepts port 0 for ephemeral port binding; the
real bound address is reported back through [ServerHandle].
Fields§
§relay_addr: SocketAddrQUIC/MoQ relay bind address.
rtmp_addr: SocketAddrRTMP ingest bind address.
admin_addr: SocketAddrAdmin HTTP (and WS relay/ingest) bind address.
hls_addr: Option<SocketAddr>Optional LL-HLS HTTP bind address. When Some, start() spins up a
dedicated HlsServer axum router on this address that observes the
RTMP bridge’s fragment output and serves /playlist.m3u8,
/init.mp4, and the per-chunk media URIs the playlist references.
When None, no HLS surface is exposed.
hls_dvr_window_secs: u32DVR window depth in seconds for the LL-HLS sliding-window
eviction. Translated to max_segments = dvr_secs / target_duration_secs at server construction. 0 means
unbounded (no eviction). Default: 120 (60 segments at 2 s).
hls_target_duration_secs: u32LL-HLS target segment duration in seconds. Controls both the
EXT-X-TARGETDURATION declaration and the CMAF segmenter’s
segment-close policy. Default: 2.
hls_part_target_ms: u32LL-HLS target partial (chunk) duration in milliseconds.
Controls both EXT-X-PART-INF:PART-TARGET and the CMAF
segmenter’s partial-close policy. Default: 200.
whep_addr: Option<SocketAddr>Optional WHEP (WebRTC HTTP Egress Protocol) HTTP bind address.
When Some, start() constructs a Str0mAnswerer and a
WhepServer, attaches the server as a RawSampleObserver on
the RTMP bridge, and spins up an axum router on this address
that accepts POST /whep/{broadcast} SDP offers, answers
them via str0m, and fans each ingest sample into every
subscribed session. When None, no WHEP surface is exposed
and no str0m state is constructed.
whip_addr: Option<SocketAddr>Optional WHIP (WebRTC HTTP Ingest Protocol) HTTP bind
address. When Some, start() constructs a
Str0mIngestAnswerer and a WhipMoqBridge, attaches it
as an ingest sink, and spins up an axum router on this
address that accepts POST /whip/{broadcast} SDP offers.
When None, no WHIP surface is exposed.
dash_addr: Option<SocketAddr>Optional MPEG-DASH HTTP bind address. When Some, start()
spins up a MultiDashServer axum router on this address
that observes the same fragment stream the LL-HLS bridge
observes and serves /dash/{broadcast}/manifest.mpd plus
numbered segment URIs. RTMP and WHIP publishers both feed
the DASH egress without any per-protocol wiring.
rtsp_addr: Option<SocketAddr>Optional RTSP ingest bind address. When Some, start()
spins up an RtspServer on this TCP address that accepts
RTSP ANNOUNCE/RECORD sessions with interleaved RTP and fans
depacketized H.264/HEVC through the fragment observer chain.
srt_addr: Option<SocketAddr>Optional SRT ingest bind address. When Some, start()
spins up an SrtIngestServer on this UDP address that
accepts MPEG-TS streams and fans them through the fragment
observer chain.
mesh_enabled: boolEnable the peer mesh coordinator and /signal endpoint.
max_peers: usizeMax children per mesh parent when mesh_enabled.
auth: Option<SharedAuth>Pre-built auth provider. None means open access (NoopAuthProvider).
record_dir: Option<PathBuf>Recording directory. None disables recording.
archive_dir: Option<PathBuf>DVR archive directory. When Some, start() opens a
RedbSegmentIndex under <archive_dir>/archive.redb and
attaches an archiving fragment observer to the RTMP bridge
that writes every emitted fragment to
<archive_dir>/<broadcast>/<track>/<seq>.m4s and records a
SegmentRef against the index. The index + segment files
back the DVR scrub / time-range playback surface (Tier 2.4).
hmac_playback_secret: Option<String>Optional HMAC signing secret for short-lived playback URLs
(PLAN v1.1 row 121). When set, every /playback/* handler
accepts an alternative auth path: a ?exp=<unix_ts>&sig= <base64url> pair where sig = HMAC-SHA256(secret, "<path> ?exp=<ts>"). A valid signature short-circuits the normal
subscribe-token check so an operator can mint a one-off
share link for a third party who cannot authenticate. An
expired or tampered signature returns 403 (NOT 401) so the
client can distinguish missing auth from wrong auth. When
unset, all playback routes fall back to their existing
SubscribeAuth gate.
wasm_filter: Vec<PathBuf>Ordered list of WASM fragment filter modules. When
non-empty, start() loads + compiles each module via
lvqr_wasm::WasmFilter::load and installs a single
lvqr_wasm::ChainFilter tap on the shared
FragmentBroadcasterRegistry before any ingest listener
starts accepting traffic. Chain order is preserved; the
first filter that drops a fragment short-circuits the rest
of the chain for that fragment. Each path is watched
independently via its own WasmFilterReloader so
hot-swapping one slot does not disturb the others.
The tap observes every fragment flowing through every
broadcaster and drives
lvqr_wasm_fragments_total{outcome=keep|drop} counters; in
v1 it does NOT modify what downstream subscribers receive
(session-86 scope narrowing). Leave empty to disable.
install_prometheus: boolInstall the global Prometheus recorder. Must be false in tests
because metrics-exporter-prometheus panics on the second install
in a process. main.rs sets this to true.
otel_metrics_recorder: Option<OtelMetricsRecorder>Pre-built OTLP metrics recorder handed off by
lvqr_observability::init when LVQR_OTLP_ENDPOINT is
set. When Some, start() installs it as the global
metrics-crate recorder – either on its own or composed
with the Prometheus recorder via
metrics_util::layers::FanoutBuilder when
install_prometheus is also true. When None, only the
Prometheus path runs (legacy behavior).
tls_cert: Option<PathBuf>Path to TLS certificate (PEM). Reserved; not consumed yet. The relay auto-generates self-signed certs when unset.
tls_key: Option<PathBuf>Path to TLS private key (PEM). Reserved; not consumed yet.
cluster_listen: Option<SocketAddr>Optional cluster gossip bind address. When Some, start()
bootstraps an lvqr_cluster::Cluster on this address, wires
it into the admin router so /api/v1/cluster/* answers, and
installs an OwnerResolver on the HLS server so subscribers
hitting this node for a peer-owned broadcast receive a 302
pointing at the owner. None (default) disables clustering
and the node behaves as a standalone single-process server.
Feature-gated on cluster; the field is present regardless
so ServeConfig stays ABI-stable across feature flips.
cluster_seeds: Vec<String>Cluster peer seed addresses. Each entry is an ip:port
string the new node gossips to on boot. Ignored when
cluster_listen is None.
cluster_node_id: Option<String>Cluster-node identifier. None auto-generates a random
lvqr-<16 alphanumeric> id at bootstrap.
cluster_id: Option<String>Cluster tag gossipped in every SYN. Chitchat rejects
cross-cluster gossip so two LVQR deployments on the same
subnet stay isolated. Empty string falls back to the
crate-default ("lvqr").
cluster_advertise_hls: Option<String>Externally-reachable HLS base URL this node advertises
(e.g. "http://a.local:8888"). When clustering is enabled,
start() writes this URL into the per-node endpoints KV
so peers redirecting subscribers know where to send them.
None skips the publish; peers will then 404 rather than
redirect for this node’s broadcasts.
cluster_advertise_dash: Option<String>Externally-reachable DASH base URL this node advertises
(e.g. "http://a.local:8888"). Shape matches
cluster_advertise_hls;
peers use this when composing a 302 Location for
/dash/... requests.
cluster_advertise_rtsp: Option<String>Externally-reachable RTSP base URL this node advertises
(e.g. "rtsp://a.local:8554"). Used by the RTSP 302
redirect-to-owner path on DESCRIBE / PLAY for peer-owned
broadcasts.
federation_links: Vec<FederationLink>Cross-cluster federation links. Each link opens a single
outbound MoQ session to a peer cluster’s relay and
re-publishes matching broadcasts into the local origin.
Empty list disables federation. Feature-gated on cluster
since FederationLink lives in lvqr-cluster. Tier 4 item
4.4.
no_auth_live_playback: boolEscape hatch for deployments that want open live HLS +
DASH playback with auth scoped to ingest, admin, and
DVR only. When false (default), the composition root
wraps the HLS and DASH routers with the same
SubscribeAuth gate that already protects /ws/*,
/playback/*, and WHEP. When true, the live HLS and
DASH routers are exposed without an auth layer – the
pre-session-112 v0.4.0 behavior. Unauthed deployments
(Noop provider) see no behavior change either way
because the provider always allows. Session 112.
no_auth_signal: boolEscape hatch for deployments that want an unauthenticated
mesh /signal WebSocket. When false (default), the
composition root wraps /signal with the same
SubscribeAuth gate pattern that protects other
subscribe-side surfaces: Sec-WebSocket-Protocol: lvqr.bearer.<token> preferred, ?token=<token> query
fallback. Noop provider deployments see no behavior
change because the provider always allows. Configured
deployments (static token, JWT) now require a bearer
on every /signal upgrade. Only meaningful when
mesh_enabled is true. Session 111-B1.
mesh_root_peer_count: Option<usize>Override the mesh root_peer_count (number of peers
that connect directly to the origin before the tree
starts assigning parents). None uses the
lvqr_mesh::MeshConfig::default() value of 30. Tests
that want to exercise the AssignParent path with a
small number of peers set this to 1 so the second peer
becomes a child of the first. Only meaningful when
mesh_enabled is true. Session 111-B1.
mesh_ice_servers: Vec<IceServer>STUN/TURN servers to push to browser peers via the
AssignParent server-push message. Empty vec (default)
means “no opinion – client picks”: JS MeshPeer falls
back to whatever was passed to its constructor (or its
hardcoded Google STUN default). Non-empty vec is
authoritative: clients rebuild their RTCPeerConnection
iceServers list from this snapshot when AssignParent
lands. Operator-facing CLI flag is
--mesh-ice-servers <JSON> with LVQR_MESH_ICE_SERVERS
env fallback. Only meaningful when mesh_enabled is
true. Session 143 – TURN deployment recipe.
Implementations§
Source§impl ServeConfig
impl ServeConfig
Sourcepub fn loopback_ephemeral() -> Self
pub fn loopback_ephemeral() -> Self
Minimal loopback config for tests: every listener on 127.0.0.1:0,
open access, no recording, no Prometheus install.
Trait Implementations§
Source§impl Clone for ServeConfig
impl Clone for ServeConfig
Source§fn clone(&self) -> ServeConfig
fn clone(&self) -> ServeConfig
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for ServeConfig
impl !RefUnwindSafe for ServeConfig
impl Send for ServeConfig
impl Sync for ServeConfig
impl Unpin for ServeConfig
impl UnsafeUnpin for ServeConfig
impl !UnwindSafe for ServeConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request