Skip to main content

Media over QUIC: real-time pub/sub with built-in caching, fan-out, and prioritization, with a Pythonic API. Import as `moq`.

Project description

moq

Python bindings for Media over QUIC: real-time pub/sub with built-in caching, fan-out, and prioritization, on top of QUIC.

moq wraps the auto-generated moq-ffi UniFFI bindings with a Pythonic API: no Moq prefixes, async iterators, context managers, and simplified connection setup. At session setup it negotiates either the moq-lite or moq-transport wire protocol.

Installation

pip install moq

This pulls in the moq-ffi native bindings automatically. moq is pure Python and is versioned independently of moq-ffi; it floats to the latest compatible moq-ffi patch.

Quick Start

Subscribe to a stream

import asyncio
import moq

async def main():
    async with moq.Client("https://relay.quic.video") as client:
        async for announcement in client.announced():
            catalog = await announcement.broadcast.catalog()

            for name in catalog.audio:
                async for frame in announcement.broadcast.subscribe_media(name):
                    print(f"Got frame: {len(frame.payload)} bytes, ts={frame.timestamp_us}")

asyncio.run(main())

Publish a stream

import asyncio
import moq

async def main():
    async with moq.Client("https://relay.quic.video") as client:
        broadcast = moq.BroadcastProducer()

        # Publish an Opus audio track (init bytes from your encoder)
        audio = broadcast.publish_media("opus", opus_init_bytes)
        client.publish("my-stream", broadcast)

        # Write frames
        audio.write_frame(payload, timestamp_us=0)
        audio.write_frame(payload, timestamp_us=20000)

        # Clean up
        audio.finish()
        broadcast.finish()

asyncio.run(main())

Host a server

import asyncio
import moq

async def main():
    async with moq.Server("127.0.0.1:4443", tls_generate=["localhost"]) as server:
        broadcast = moq.BroadcastProducer()
        track = broadcast.publish_track("events")
        server.publish("hello", broadcast)
        print(f"listening on https://{server.local_addr}")

        sessions = []
        async for request in server:
            print(f"  + {request.transport} from {request.url}")
            sessions.append(await request.ok())

asyncio.run(main())

Reject a request instead of accepting it with await request.close(403).

Advanced: Manual origin wiring

For full control over the origin topology:

import moq

origin = moq.OriginProducer()
client = moq.Client(
    "https://relay.quic.video",
    publish=origin,
    subscribe=origin,
)

API

Connection

  • Client(url, *, tls_verify=True, bind=None, publish=None, subscribe=None). Async context manager for connecting to a relay.
  • Server(bind="[::]:443", *, tls_cert=(), tls_key=(), tls_generate=(), publish=None, subscribe=None). Async context manager + async iterator of incoming Requests.
    • .local_addr. The bound address (useful when binding to port 0).
    • .cert_fingerprints(). SHA-256 fingerprints of the configured TLS certificates, for serverCertificateHashes browser cert pinning.
    • .publish(path, broadcast). Publish a broadcast to be served.
  • Request. An incoming session, yielded by async for request in server.
    • .url, .transport. Properties.
    • .set_publish(origin), .set_consume(origin). Per-request overrides.
    • await .ok(). Complete the handshake, returns a session (hold it to keep the connection alive).
    • await .close(code). Reject with an HTTP status code.
    • .cancel(). Cancel an in-flight ok()/close() call.

Publishing

  • BroadcastProducer(). Create a broadcast to publish tracks into.
    • .publish_media(format, init) → MediaProducer
    • .finish()
  • MediaProducer. Write frames to a track.
    • .write_frame(payload, timestamp_us)
    • .finish()

Subscribing

  • BroadcastConsumer. Subscribe to tracks within a broadcast.
    • .subscribe_catalog() → CatalogConsumer
    • .subscribe_media(name, max_latency_ms=10000) → MediaConsumer
    • await .catalog() → Catalog (convenience)
  • CatalogConsumer. Async iterator of Catalog.
  • MediaConsumer. Async iterator of Frame.

Origin (advanced)

  • OriginProducer(). Manage broadcast announcements.
    • .consume() → OriginConsumer
    • .publish(path, broadcast)
  • OriginConsumer. Discover broadcasts.
    • .announced(prefix) → Announced (async iterator)
    • .announced_broadcast(path) → AnnouncedBroadcast (awaitable)

Types

  • Catalog. .audio: dict[str, Audio], .video: dict[str, Video], .display, .rotation, .flip.
  • Frame. .payload: bytes, .timestamp_us: int, .keyframe: bool.
  • Audio. .codec, .sample_rate, .channel_count, .bitrate, .description.
  • Video. .codec, .coded: Dimensions, .display_ratio, .bitrate, .framerate, .description.
  • Dimensions. .width: int, .height: int.

See Also

  • moq-ffi. The raw UniFFI bindings this package wraps. Use it directly only if you need the unwrapped Moq-prefixed API.
  • MoQ project. Full monorepo with Rust server, TypeScript browser lib, and more.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

moq_rs-0.3.0.tar.gz (16.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

moq_rs-0.3.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file moq_rs-0.3.0.tar.gz.

File metadata

  • Download URL: moq_rs-0.3.0.tar.gz
  • Upload date:
  • Size: 16.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for moq_rs-0.3.0.tar.gz
Algorithm Hash digest
SHA256 49d3d384a94d0c5fae11d2d8def86bcc643c2a2f2300d6e534307025dbde5b31
MD5 82509a0b25e3904f5099b1026e7bed9b
BLAKE2b-256 530cda54242fd61058474ab6f052cd87e52361edd9c41772a274bc4042c37ab4

See more details on using hashes here.

Provenance

The following attestation bundles were made for moq_rs-0.3.0.tar.gz:

Publisher: release-py.yml on moq-dev/moq

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file moq_rs-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: moq_rs-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for moq_rs-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0ed5eaa2bab517cb75fb90c044b35d4b8e6724fd41777b0d81cf056f46919669
MD5 cbb18dfa9ca20b89ff94882631e7d221
BLAKE2b-256 9d9ea92d9d4a5ef4f98befe15093d059f4ea258f5e714ba05a29aae7144acec3

See more details on using hashes here.

Provenance

The following attestation bundles were made for moq_rs-0.3.0-py3-none-any.whl:

Publisher: release-py.yml on moq-dev/moq

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page