n0-computer/iroh-live

media livestreaming over iroh

Rust

128

565 commits

updated Sep 22, 2026

See the code

README

iroh-live

Early tech preview. Several parts are unfinished. Windows builds in CI but has never been run, on-device testing has been limited, rooms are being redesigned, and the relay has no authentication. Expect frequent API changes.

This repo currently depends on a Git dependency on the moq crates. We upstreamed all necessary changes and can move to a regular dependency after the next moq release.

Real-time audio and video over iroh, written in Rust. Connections are peer-to-peer by default, with no media server in the middle, and an optional relay bridges to browsers over WebTransport. The wire protocol is Media over QUIC, where every video rendition and audio track travels as its own set of QUIC streams, so a dropped video packet never delays audio.

Capture, encoding, decoding, and GPU rendering come from moq-video and moq-audio upstream. What this repository adds is an iroh transport, simulcast and adaptive rendition switching, a shared playout clock, and the application layer over all of it.

Quick start

cargo install --path iroh-live-cli

# Terminal 1: publish camera and microphone, print a ticket and a QR code
irl publish

# Terminal 2, or another machine
irl watch <TICKET>

No camera? irl publish --test-source publishes a generated pattern and a tone.

To reach subscribers that cannot dial this node directly, connect to a relay. Everything the node publishes is announced over that session:

irl publish --relay <RELAY_ENDPOINT_ID>

Full flag reference: docs/cli.md.

Using iroh-live in Rust

The workspace patches the moq crates to Frando/moq@iroh-live, which carries the changes behind eleven open pull requests to moq and one to moq-vaapi. Until they land in releases, a downstream user needs to copy the [patch.crates-io] block from Cargo.toml.

Publish a camera and a microphone:

use iroh_live::{Live, media::{audio, video}, ticket::LiveTicket};

let live = Live::from_env().await?.with_router().spawn();
let broadcast = live.publish("hello")?;

broadcast.video().set(video::capture::Config::default())?;
broadcast.audio().set(audio::capture::Config::default());

println!("{}", LiveTicket::new(live.endpoint().id(), "hello"));

Subscribe and read decoded frames:

let live = Live::from_env().await?.spawn();
let sub = live.subscribe(ticket.endpoint, &ticket.broadcast_name).await?;
let tracks = sub.media().await;

if let Some(video) = tracks.video {
    while let Some(frame) = video.recv().await {
        // hand `frame` to a renderer
    }
}

iroh-live/examples/publish.rs is the compilable version of the first, including a simulcast ladder. More in docs/guide/index.md.

Workspace

CrateDescription
iroh-liveLive, Call, Subscription, and tickets
iroh-moqMoQ transport over iroh: the node origin, sessions, and ALPN negotiation
iroh-roomsGossip rooms. Media-free, and being redesigned onto moq's announce bus
moq-mediaPublish and subscribe plumbing over moq-video and moq-audio. No iroh dependency
moq-media-eguiAn egui widget over the texture moq_video::render returns, plus the debug overlay
moq-media-androidThe Camera2 push bridge and the EGL renderer for Android
iroh-live-cliThe irl binary
iroh-live-relayRelay server bridging iroh publishers to browsers. No authentication yet

Demos

Platform support

PlatformState
Linux, Intel and AMDPrimary target. VAAPI decode behind the vaapi feature, checked pixel-exact against a software decoder, handing its pictures to the renderer without a copy
Linux, NVIDIANVENC and NVDEC behind the nvidia feature. Untested here
macOSBuilds in CI. VideoToolbox and ScreenCaptureKit from upstream. Lightly tested
AndroidTested on device, two-way audio and video
Raspberry PiTested on a Pi Zero 2 W and a Pi 4. Publishes pre-encoded H.264 through rpicam-vid, or raw pictures with --video rpicam:raw. The V4L2 hardware encoder and decoder behind v4l2 both run on a Pi 4
WindowsBuilds in CI, and the release workflow ships an x86-64 binary. Never run here
iOSUpstream has the backends. Never built here

Details, including what was lost when the in-house media stack was replaced: docs/platforms.md.

Building

cargo build --workspace

Codecs need no system libraries. Device access and graphics do:

# Debian and Ubuntu
sudo apt install libasound2-dev libpipewire-0.3-dev libclang-dev \
                 libegl-dev libgbm-dev libdrm-dev libfontconfig-dev libva-dev nasm

# Arch
sudo pacman -S alsa-lib pipewire clang mesa fontconfig libva nasm

macOS needs brew install libtool automake.

Feature flags

Every codec compiles unconditionally upstream, so there are no per-codec flags. What is left gates a build dependency or a graphics stack. moq-media defines them and the other crates pass them through.

FlagDefault in iroh-liveWhat it adds
captureyesCamera, screen, and microphone devices
renderyesThe wgpu renderer
playbacknoSpeaker output
aecnoEcho cancellation. Implies capture and playback
pipewirenoLinux screen capture. Links libpipewire-0.3
sound-serveryesReaches audio devices through PipeWire or PulseAudio
vaapinoIntel and AMD hardware H.264 encode and decode, the decoder handing its pictures over without a copy
nvidianoNVIDIA hardware encode and decode
v4l2noThe V4L2 hardware H.264 codecs on ARM SoCs. Encoder and decoder both exercised on a Raspberry Pi 4
rpicamnoThe Raspberry Pi camera, through rpicam-vid. Linux only

moq-media adds one of its own, test-source, for generated video and audio. iroh-live-cli turns on playback as well.

Cross-compiling for aarch64

cargo make cross-sysroot-aarch64                              # once
cargo make cross-build-aarch64 -- -p iroh-live-cli --release

This uses cargo-zigbuild against a Debian Bookworm sysroot assembled without sudo. A Docker path exists for hosts that cannot install zig. See cross/README.md.

Contributing

DEVELOPMENT.md covers the workspace layout, the build and test workflow, and the conventions. Issues live in the tracker.

cargo make check-all   # check and clippy across three feature sets, then fmt
cargo make test        # cargo nextest across the workspace

License

Copyright 2025 N0, INC.

This project is licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

iroh
livestreaming
media-over-quic
moq
p2p

Contributors

Frando

483 commits

dignifiedquire

80 commits

Arqu

2 commits

n0-computer/iroh-live

media livestreaming over iroh

Rust

128

565 commits

updated Sep 22, 2026

See the code

README

iroh-live

Early tech preview. Several parts are unfinished. Windows builds in CI but has never been run, on-device testing has been limited, rooms are being redesigned, and the relay has no authentication. Expect frequent API changes.

This repo currently depends on a Git dependency on the moq crates. We upstreamed all necessary changes and can move to a regular dependency after the next moq release.

Real-time audio and video over iroh, written in Rust. Connections are peer-to-peer by default, with no media server in the middle, and an optional relay bridges to browsers over WebTransport. The wire protocol is Media over QUIC, where every video rendition and audio track travels as its own set of QUIC streams, so a dropped video packet never delays audio.

Capture, encoding, decoding, and GPU rendering come from moq-video and moq-audio upstream. What this repository adds is an iroh transport, simulcast and adaptive rendition switching, a shared playout clock, and the application layer over all of it.

Quick start

cargo install --path iroh-live-cli

# Terminal 1: publish camera and microphone, print a ticket and a QR code
irl publish

# Terminal 2, or another machine
irl watch <TICKET>

No camera? irl publish --test-source publishes a generated pattern and a tone.

To reach subscribers that cannot dial this node directly, connect to a relay. Everything the node publishes is announced over that session:

irl publish --relay <RELAY_ENDPOINT_ID>

Full flag reference: docs/cli.md.

Using iroh-live in Rust

The workspace patches the moq crates to Frando/moq@iroh-live, which carries the changes behind eleven open pull requests to moq and one to moq-vaapi. Until they land in releases, a downstream user needs to copy the [patch.crates-io] block from Cargo.toml.

Publish a camera and a microphone:

use iroh_live::{Live, media::{audio, video}, ticket::LiveTicket};

let live = Live::from_env().await?.with_router().spawn();
let broadcast = live.publish("hello")?;

broadcast.video().set(video::capture::Config::default())?;
broadcast.audio().set(audio::capture::Config::default());

println!("{}", LiveTicket::new(live.endpoint().id(), "hello"));

Subscribe and read decoded frames:

let live = Live::from_env().await?.spawn();
let sub = live.subscribe(ticket.endpoint, &ticket.broadcast_name).await?;
let tracks = sub.media().await;

if let Some(video) = tracks.video {
    while let Some(frame) = video.recv().await {
        // hand `frame` to a renderer
    }
}

iroh-live/examples/publish.rs is the compilable version of the first, including a simulcast ladder. More in docs/guide/index.md.

Workspace

CrateDescription
iroh-liveLive, Call, Subscription, and tickets
iroh-moqMoQ transport over iroh: the node origin, sessions, and ALPN negotiation
iroh-roomsGossip rooms. Media-free, and being redesigned onto moq's announce bus
moq-mediaPublish and subscribe plumbing over moq-video and moq-audio. No iroh dependency
moq-media-eguiAn egui widget over the texture moq_video::render returns, plus the debug overlay
moq-media-androidThe Camera2 push bridge and the EGL renderer for Android
iroh-live-cliThe irl binary
iroh-live-relayRelay server bridging iroh publishers to browsers. No authentication yet

Demos

Platform support

PlatformState
Linux, Intel and AMDPrimary target. VAAPI decode behind the vaapi feature, checked pixel-exact against a software decoder, handing its pictures to the renderer without a copy
Linux, NVIDIANVENC and NVDEC behind the nvidia feature. Untested here
macOSBuilds in CI. VideoToolbox and ScreenCaptureKit from upstream. Lightly tested
AndroidTested on device, two-way audio and video
Raspberry PiTested on a Pi Zero 2 W and a Pi 4. Publishes pre-encoded H.264 through rpicam-vid, or raw pictures with --video rpicam:raw. The V4L2 hardware encoder and decoder behind v4l2 both run on a Pi 4
WindowsBuilds in CI, and the release workflow ships an x86-64 binary. Never run here
iOSUpstream has the backends. Never built here

Details, including what was lost when the in-house media stack was replaced: docs/platforms.md.

Building

cargo build --workspace

Codecs need no system libraries. Device access and graphics do:

# Debian and Ubuntu
sudo apt install libasound2-dev libpipewire-0.3-dev libclang-dev \
                 libegl-dev libgbm-dev libdrm-dev libfontconfig-dev libva-dev nasm

# Arch
sudo pacman -S alsa-lib pipewire clang mesa fontconfig libva nasm

macOS needs brew install libtool automake.

Feature flags

Every codec compiles unconditionally upstream, so there are no per-codec flags. What is left gates a build dependency or a graphics stack. moq-media defines them and the other crates pass them through.

FlagDefault in iroh-liveWhat it adds
captureyesCamera, screen, and microphone devices
renderyesThe wgpu renderer
playbacknoSpeaker output
aecnoEcho cancellation. Implies capture and playback
pipewirenoLinux screen capture. Links libpipewire-0.3
sound-serveryesReaches audio devices through PipeWire or PulseAudio
vaapinoIntel and AMD hardware H.264 encode and decode, the decoder handing its pictures over without a copy
nvidianoNVIDIA hardware encode and decode
v4l2noThe V4L2 hardware H.264 codecs on ARM SoCs. Encoder and decoder both exercised on a Raspberry Pi 4
rpicamnoThe Raspberry Pi camera, through rpicam-vid. Linux only

moq-media adds one of its own, test-source, for generated video and audio. iroh-live-cli turns on playback as well.

Cross-compiling for aarch64

cargo make cross-sysroot-aarch64                              # once
cargo make cross-build-aarch64 -- -p iroh-live-cli --release

This uses cargo-zigbuild against a Debian Bookworm sysroot assembled without sudo. A Docker path exists for hosts that cannot install zig. See cross/README.md.

Contributing

DEVELOPMENT.md covers the workspace layout, the build and test workflow, and the conventions. Issues live in the tracker.

cargo make check-all   # check and clippy across three feature sets, then fmt
cargo make test        # cargo nextest across the workspace

License

Copyright 2025 N0, INC.

This project is licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

iroh
livestreaming
media-over-quic
moq
p2p

Contributors

Frando

483 commits

dignifiedquire

80 commits

Arqu

2 commits

Languages

Rust

96.1%

TypeScript

2.2%

Shell

1.3%