moq-room 0.1.0

Headless multi-participant rooms over MoQ: announce-derived roster, token claims, and a chat track.
Documentation

moq-room

Headless multi-participant rooms over Media over QUIC. A room is a path prefix. There is no service and no storage: joining is minting a moq-token rooted at that prefix.

Participants are discovered from the announce stream. Identity is the path before camera.hang / screen.hang. Each participant publishes {identity}/camera.hang and {identity}/screen.hang.

This is the native counterpart of @moq/room. hang.live and iroh-live (iroh-rooms is being redesigned onto the announce bus) can depend on it for roster, path convention, token claims, and the chat track. Gossip, tickets, and 1:1 Call stay in iroh-live. Capture/encode stay in moq-video / moq-audio. Native Local/Remote media plumbing stays with those crates too; this crate is media-free.

use moq_net::{Origin, Path};
use moq_room::{Kind, Room, chat, claims};

let token = key.sign(&claims("meet/demo", "alice")?, None)?;
// Dial the relay at meet/demo?jwt=...

let origin = Origin::random().produce();
let mut room = Room::new(&origin.consume(), Some(Path::new("alice").to_owned()));
while let Some(event) = room.next().await {
    if event.kind == Kind::Camera {
        if let Some(broadcast) = &event.broadcast {
            if let Ok(mut chat) = chat::Subscriber::subscribe(broadcast).await {
                // ...
            }
        }
    }
}

Chat uses moq-json::window with ten seconds of history. Drive Publisher::expire() alongside incoming sends (or call poll_expire from a poll loop) so messages expire while idle. Subscriber::recv returns push/pop/skip events and propagates errors. The format differs from iroh-live's raw UTF-8 chat.