Skip to content

Experimental MoQ server input.#1998

Open
JBRS307 wants to merge 30 commits into
masterfrom
@jbrs/moq
Open

Experimental MoQ server input.#1998
JBRS307 wants to merge 30 commits into
masterfrom
@jbrs/moq

Conversation

@JBRS307
Copy link
Copy Markdown
Contributor

@JBRS307 JBRS307 commented May 18, 2026

Based on the moq-lite crate, however adds a few more dependencies for QUIC server and CMAF handling.

Currently supports only H264 video and AAC audio.


Yet to be done:

  • Properly close all sessions on /reset
  • Properly close session in input removal
  • Sequential catalog handling
  • Refactor for new moq-mux version

What will NOT be done in the experimental:

  • Handling of catalog changes (catalog currently read only once per session)
  • Handling other containers than CMAF

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an experimental MoQ (Media over QUIC) input path (based on moq-lite) by adding a WebTransport server to smelter-core, wiring it into pipeline initialization/config, exposing a new moq_server input type in the public API, and surfacing MoQ in status/stats and integration-test demos.

Changes:

  • Add MoQ server + pipeline integration (WebTransport accept loop, origin announce loop, input registration, and broadcast-to-queue decode path for H264/AAC).
  • Extend configuration + pipeline options to enable/disable MoQ server and configure port/TLS.
  • Add API models/conversions + status/stats reporting for MoQ inputs, plus integration-test/demo support.

Reviewed changes

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/state.rs Plumbs MoQ server options into PipelineOptions derived from config.
src/routes/status.rs Adds "moq" protocol label in status output.
src/routes/register_request.rs Adds moq_server input registration route handling via MoqInput.
src/config.rs Adds MoQ env-driven config (port/enable/TLS cert+key).
smelter-core/src/stats/input/moq.rs Implements MoQ input stats state/events (bitrate tracking).
smelter-core/src/stats/input/mod.rs Registers MoQ stats state/event wiring and report mapping.
smelter-core/src/stats/input_reports.rs Adds serializable MoQ stats report structs + enum variant.
smelter-core/src/protocols/moq.rs Defines MoQ input options and MoQ-specific error types.
smelter-core/src/protocols.rs Exposes the new protocols::moq module.
smelter-core/src/pipeline/moq/state.rs Tracks registered MoQ inputs and active broadcast connection handles.
smelter-core/src/pipeline/moq/server.rs Implements MoQ WebTransport server startup, accept loop, and announce loop.
smelter-core/src/pipeline/moq/moq_input.rs Implements MoQ server input registration and teardown hooks.
smelter-core/src/pipeline/moq/mod.rs Declares MoQ pipeline submodules and re-exports.
smelter-core/src/pipeline/moq/connection.rs Implements catalog parsing, track subscription, decoding, queue feeding, and stats events.
smelter-core/src/pipeline/instance.rs Instantiates MoQ pipeline state and starts/stores MoQ server handle.
smelter-core/src/pipeline/input.rs Adds MoQ as a pipeline input variant and external input constructor branch.
smelter-core/src/pipeline.rs Adds PipelineMoqServerOptions + threads MoQ state through PipelineCtx.
smelter-core/src/input.rs Adds MoQ to RegisterInputOptions and InputProtocolKind.
smelter-core/src/error.rs Adds MoQ server init error and MoQ input init error variants.
smelter-core/Cargo.toml Adds MoQ/WebTransport/CMAF-related dependencies to core crate.
smelter-api/src/input/moq.rs Adds public API schema for MoqInput.
smelter-api/src/input/moq_into.rs Adds conversion from API MoqInput into core RegisterInputOptions.
smelter-api/src/input.rs Re-exports the new MoQ input API types.
integration-tests/src/bin/benchmark/utils.rs Updates benchmark pipeline options to include MoQ server option.
integration-tests/examples/demo/smelter_state.rs Adds MoQ input flow to the interactive demo app.
integration-tests/examples/demo/inputs/moq.rs Adds a demo MoQ input builder + registration JSON + publish instructions.
integration-tests/examples/demo/inputs.rs Registers MoQ in demo input selection and handle enum.
Cargo.toml Adds workspace dependency versions for MoQ/WebTransport/TLS helpers.
Cargo.lock Locks newly introduced transitive dependencies.
Comments suppressed due to low confidence (1)

smelter-core/src/pipeline/moq/connection.rs:332

  • process_audio_config will panic if the catalog's AAC rendition has description: None (it calls .expect(...)). Since description is optional in the catalog, this should be handled as an error (e.g., return a dedicated MoqConnectionError or treat the track as unsupported/missing config) instead of crashing the broadcast task.
    let aac_decoder_options = {
        let asc = audio
            .description
            .as_ref()
            .expect("process_audio_config called with description present")
            .clone();
        AudioDecoderOptions::FdkAac(FdkAacDecoderOptions { asc: Some(asc) })
    };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

.description
.clone()
.ok_or(MoqConnectionError::UnsupportedVideoCodec)?;
let h264_config = H264AvcDecoderConfig::parse(avcc_bytes).unwrap();
Comment on lines +223 to +252
let video = match catalog.video.renditions.first_key_value() {
Some((name, config)) if let HangVideoCodec::H264(_) = config.codec => {
match Hang::try_from(&config.container) {
Ok(container) => Some(DiscoveredVideo {
name: name.clone(),
container,
description: config.description.clone(),
}),
Err(error) => {
warn!(track=%name, "Unsupported video container, skipping: {error}");
None
}
}
}
Some((name, config)) => {
warn!(track=%name, codec=%config.codec, "Unsupported video codec, skipping track");
None
}
None => None,
};

let audio = match catalog.audio.renditions.first_key_value() {
Some((name, config)) if let HangAudioCodec::AAC(_) = config.codec => {
match Hang::try_from(&config.container) {
Ok(container) => Some(DiscoveredAudio {
name: name.clone(),
container,
description: config.description.clone(),
}),
Err(error) => {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aware of that, this code is not meant to be production ready for now

Comment on lines +26 to +29
pub fn on_after_registration(&self) -> Result<()> {
println!("Publish to this input using moq-cli:");
println!(
" moq-cli publish https://localhost:4443/{}",
Comment on lines +325 to +346
let aac_decoder_options = {
let asc = audio
.description
.as_ref()
.expect("process_audio_config called with description present")
.clone();
AudioDecoderOptions::FdkAac(FdkAacDecoderOptions { asc: Some(asc) })
};

match aac_decoder_options {
AudioDecoderOptions::FdkAac(decoder_options) => {
let options = AudioDecoderThreadOptions {
ctx: ctx.clone(),
decoder_options,
samples_sender,
input_buffer_size: MOQ_MAX_BUFFER,
};
AudioDecoderThread::<FdkAacDecoder>::spawn(input_ref.clone(), options)
.map_err(MoqConnectionError::InitAudioDecoder)
}
_ => Err(MoqConnectionError::UnsupportedAudioCodec),
}
Comment thread Cargo.toml Outdated
Comment thread smelter-core/src/pipeline.rs Outdated
Comment on lines +91 to +93
// XXX: I am not sure if this is the best solution from semantic POV, using `rtmp::TlsConfig` in
// MoQ
tls_config: Option<TlsConfig>,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good question

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, create separate type

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All stats related code should be put to another PR, remove it from here.

@JBRS307 JBRS307 requested a review from wkozyra95 May 18, 2026 14:35
Comment thread smelter-api/src/input/moq.rs Outdated
Comment thread smelter-core/src/pipeline.rs Outdated
Comment on lines +91 to +93
// XXX: I am not sure if this is the best solution from semantic POV, using `rtmp::TlsConfig` in
// MoQ
tls_config: Option<TlsConfig>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, create separate type

Comment thread smelter-core/src/pipeline/moq/server.rs Outdated
Comment thread src/config.rs Outdated
Err(_) => true,
};

let moq_tls_cert_file = match env::var("SMELTER_MOQ_TLS_CERT_FILE") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the moq server even make sense without certs? If no then you can skip enable option, by default do not enable it unless certs are provided

Comment thread smelter-core/src/pipeline/moq/server.rs Outdated
Comment on lines +147 to +148
// HACK: This is needed because even though `.with_certificate()` is sync it runs async code
// underneath and requires a runtime
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's worth preserving the comment that with_certificate requires runtime, but instead of hack, I would just make this function async

Comment thread smelter-core/src/pipeline/moq/server.rs Outdated
}
}

fn start_wt_server(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what wt is

Comment thread smelter-core/src/pipeline/moq/server.rs Outdated
tokio::spawn(async move {
let session = match request.ok().await {
Ok(session) => {
info!("WebTransport session created.");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct to refer to web transport? My understanding is that WebTransport is a browser API for QUICK, but if you run outside of browser it does not have anything to do with it, you just use quick then.

Comment thread smelter-core/src/pipeline/moq/server.rs Outdated
Comment thread smelter-core/src/pipeline/moq/server.rs Outdated
Comment thread smelter-core/src/pipeline/moq/connection.rs
@JBRS307 JBRS307 force-pushed the @jbrs/moq branch 13 times, most recently from f30de37 to 33d1397 Compare May 20, 2026 12:07
@JBRS307 JBRS307 requested a review from Copilot May 20, 2026 12:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated 4 comments.

Comment thread smelter-core/src/stats/input/mod.rs
Comment thread smelter-core/src/pipeline/moq/state.rs Outdated
Comment thread smelter-core/src/pipeline/moq/connection.rs
Comment thread smelter-core/src/pipeline/moq/connection.rs Outdated
@JBRS307 JBRS307 force-pushed the @jbrs/moq branch 2 times, most recently from 3730c61 to f641055 Compare May 20, 2026 15:12
@JBRS307 JBRS307 mentioned this pull request May 21, 2026
3 tasks
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.

3 participants