Skip to main content

Overview

MOQTransport carries a session over Media over QUIC, moving audio and RTVI messages over QUIC instead of a WebRTC stack. It runs in two modes:
  • Serve mode (the default) — the bot binds its own UDP socket and the browser dials it. No relay process to run, and a self-signed certificate is minted for local development.
  • Client mode — the bot and the browser both dial a relay and rendezvous there. Neither side needs a reachable address, so this works when the bot is behind NAT.

Example Implementation

Runnable bot covering both modes

Media over QUIC

The protocol and its reference relay

Installation

Serve mode vs client mode

Serve mode is the shorter path for local development: nothing to run besides the bot.
The bot listens on [::]:4080, mints a self-signed certificate for localhost, and publishes its SHA-256 fingerprint so the browser can pin it. Client mode is selected by naming a relay:
Both peers dial the relay, so neither needs to be reachable from the other.
Each client-mode session gets its own random namespace, and on an anonymous relay that namespace is the session’s only access control — anyone who knows it can subscribe. Pass --moq-namespace to pin a well-known room only when the relay itself restricts who may join.

Broadcast paths

Each side publishes on one path and subscribes to the other’s. By default they’re composed from the namespace and the two participant ids, which are named by direction:
Set response_path and request_path to bypass the namespace entirely and give the paths directly. That suits a deployment where the paths are assigned externally — a host running one bot per caller, naming both paths after an id the caller minted, with no namespace for the two sides to agree on beforehand. Either can be set alone; the other still derives from the namespace.

Configuration

MOQTransport

MOQParams
required
Transport configuration. See MOQParams below.
str
default:"localhost"
Host used to compose the relay URL when params.relay_url is unset.
int
default:"4080"
Port used to compose the relay URL, and the serve-mode listen port when params.bind is unset.
str
default:"/moq"
Path used to compose the relay URL.
str | None
default:"None"
Optional name for the input transport processor.
str | None
default:"None"
Optional name for the output transport processor.

MOQParams

Extends TransportParams, so the standard audio, VAD, and turn-analyzer options apply too. Connection Paths Client-side TLS (client mode only)
client_tls_roots and client_tls_fingerprints are alternatives to turning verify_ssl off, not companions to it. Reach for them when a relay uses a private CA or a self-signed certificate, and leave verification on.
Serve-side TLS (serve mode only) Audio
serve_bind is deprecated since v1.8.0 and will be removed in 2.0.0. Use bind, which sets the listen address in serve mode and the source address in client mode.

Properties

cert_fingerprints

SHA-256 fingerprints of the certificate the bot serves, as hex. In serve mode the browser pins one of these to accept a self-signed certificate.

Usage

With the development runner, create_transport builds this for you:

Runner options

The /start response carries a moq block — relayUrl, certHash, serve, namespace, clientId, botId, and transcriptTrack — which is what the browser needs to join. The prebuilt client UI shipped with the runner extra speaks MoQ, so http://localhost:7860 can connect without any client code of your own.

Event Handlers

Notes

  • RTVI over MoQ: the transcript_track is a lossless, ordered JSON stream carrying RTVI messages in both directions, so MoQ is a full RTVI transport on par with Daily or WebSocket rather than an audio-only path.
  • Audio: a single Opus track each way. The library resamples to the nearest Opus-supported rate before encoding, so audio_out_sample_rate doesn’t have to be one of them.
  • Latency: audio_in_max_latency_ms trades interactivity against resilience — lower waits less for a late frame, at the cost of more drops on a poor network.