Elixir Media over QUIC library.
Protocol code is built on top of a small transport adapter boundary so that native QUIC and deterministic support transports can share the same contract.
Summary
Types
Object delivery selected for a published track.
Protocol-neutral reason for publisher-initiated subscription completion.
Option accepted by add_track/4.
Option accepted by subscribe/3.
Relative object boundary requested when a subscription begins.
Option accepted by update_subscription/3.
Error returned by withdraw_track/3.
Functions
Accepts one pending inbound publisher subscription.
Registers a retained catalog track under a ready publication.
Registers a track under an active publication.
Cancels one discovery, withdrawing its reported broadcasts before DiscoveryDone.
Gracefully closes the selected protocol connection.
Connects to an endpoint using one explicitly selected protocol implementation.
Discovers matching Lite05 broadcasts using a literal path prefix.
Finishes every active delivery and withdraws a namespace publication.
Finishes one accepted publisher subscription without withdrawing its track or namespace publication.
Advertises a namespace through the selected protocol implementation.
Publishes a complete catalog snapshot on a handle returned by add_catalog/3.
Publishes a complete group containing zero objects on a registered Lite track.
Publishes one object on a registered track.
Rejects one pending inbound publisher subscription.
Rejects one pending track metadata request, without affecting sibling requests
or subscription authorization. Lite05 sends only the rejection code on wire;
textual reasons stay local. Decided, cancelled and foreign requests return
:stale_track_request.
Subscribes to a protocol-neutral track address.
Returns the default native QUIC transport implementation.
Ends an active subscription and sends the selected protocol's unsubscribe message.
Updates an active subscription's draft-neutral filter and delivery parameters.
Withdraws one registered track while keeping its publication and siblings active.
Types
@type publication_delivery() :: :subgroup | :datagram
Object delivery selected for a published track.
@type published_subscription_status() ::
:internal_error
| :unauthorized
| :track_ended
| :subscription_ended
| :going_away
| :expired
| :too_far_behind
| :malformed_track
| :update_failed
Protocol-neutral reason for publisher-initiated subscription completion.
@type published_track_option() :: {:retention, :live | :latest | :all} | {:delivery, publication_delivery()} | {:timescale, pos_integer()} | {:publisher_priority, 0..255} | {:publisher_max_latency, non_neg_integer()}
Option accepted by add_track/4.
@type subscription_option() :: {:profile, MOQX.Profile.t()} | {:max_catalog_bytes, pos_integer()} | {:max_catalog_encoded_bytes, pos_integer()} | {:start, subscription_start()} | {:filter, MOQX.SubscriptionFilter.t()} | {:priority, 0..255} | {:group_order, :ascending | :descending} | {:delivery_timeout, pos_integer()} | {:parameters, [MOQX.SubscriptionParameter.t()]}
Option accepted by subscribe/3.
@type subscription_start() :: :next_object | :next_group
Relative object boundary requested when a subscription begins.
:next_object starts after the publisher's current largest object and is the
compatibility default. :next_group waits for the first object in a later
group. A selected protocol returns an error when it cannot represent the
requested policy.
@type subscription_update_option() :: {:start, subscription_start()} | {:filter, MOQX.SubscriptionFilter.t()} | {:priority, 0..255} | {:delivery_timeout, pos_integer()} | {:forward, boolean()} | {:new_group, non_neg_integer()} | {:parameters, [MOQX.SubscriptionParameter.t()]}
Option accepted by update_subscription/3.
@type withdraw_track_error() :: :unknown_published_track | :wrong_client_published_track | :unsupported_completion_status | :invalid_track_completion | :timeout | {:connection_closed, term()} | {:transport_action_failed, term()}
Error returned by withdraw_track/3.
Functions
@spec accept_subscription( MOQX.Client.t(), MOQX.PublicationSubscriptionRequest.t(), MOQX.PublishedTrack.t(), keyword() ) :: {:ok, MOQX.PublishedSubscription.t()} | {:error, term()}
Accepts one pending inbound publisher subscription.
Pass an existing PublishedTrack to attach another subscriber to a
registered track; the result contains its PublishedSubscription handle.
Pass track options instead to register the requested track reactively and
accept its first subscription without sending a separate publisher-initiated
PUBLISH; that result contains both the new track and subscription handles.
@spec add_catalog(MOQX.Client.t(), MOQX.Publication.t(), keyword()) :: {:ok, MOQX.PublishedTrack.t()} | {:error, term()}
Registers a retained catalog track under a ready publication.
Requires an explicit :profile. HANG supports compression: :none (default,
catalog.json) and :deflate (catalog.json.z). Register both to serve both
forms. Each handle has independent update numbering and retains its latest
snapshot for late subscribers. CMSF uses its profile's conventional name.
@spec add_track(MOQX.Client.t(), MOQX.Publication.t(), binary(), [ published_track_option() ]) :: {:ok, MOQX.PublishedTrack.t()} | {:error, term()}
Registers a track under an active publication.
:delivery defaults to :subgroup. The selected protocol rejects a delivery
mode it cannot represent. MoQ Lite draft-05 additionally requires a positive
:timescale and accepts :publisher_priority and
:publisher_max_latency for its immutable TRACK_INFO.
Lite registration commits locally and returns a usable track even if one of
its pending metadata replies fails. Each reply is attempted independently:
PublicationTrackRequestDone reports :registered only after transport
admission, or :reply_failed with its error. Neither outcome proves peer
delivery or authorizes a subscription. Reactive accept_subscription/3 uses
the same isolated metadata-reply behavior without skipping admission actions.
@spec cancel_discovery(MOQX.Client.t(), MOQX.Discovery.t()) :: :ok | {:error, term()}
Cancels one discovery, withdrawing its reported broadcasts before DiscoveryDone.
@spec close(MOQX.Client.t(), keyword()) :: :ok | {:error, term()}
Gracefully closes the selected protocol connection.
@spec connect(binary() | URI.t(), keyword()) :: {:ok, MOQX.Client.t()} | {:error, term()}
Connects to an endpoint using one explicitly selected protocol implementation.
@spec discover(MOQX.Client.t(), binary(), keyword()) :: {:ok, MOQX.Discovery.t()} | {:error, term()}
Discovers matching Lite05 broadcasts using a literal path prefix.
BroadcastAvailable events enumerate initial matches, followed by
DiscoveryReady; additions and withdrawals then continue live. This does not
subscribe to track catalogs. max_broadcasts defaults to 1024; exceeding it
ends only that discovery. Replacement advertisements emit withdrawal with
reason :replaced followed by availability. An unknown withdrawal terminates
the discovery with :invalid_announcement, clearing all its broadcasts.
Other protocols return :unsupported_operation.
@spec finish_publication(MOQX.Client.t(), MOQX.Publication.t(), keyword()) :: :ok | {:error, term()}
Finishes every active delivery and withdraws a namespace publication.
Pending controlled subscription requests are cancelled before established subscriptions and published tracks complete. The selected protocol withdraws the namespace only after those per-request completion boundaries.
@spec finish_subscription( MOQX.Client.t(), MOQX.PublishedSubscription.t(), status: published_subscription_status(), reason: binary() ) :: :ok | {:error, term()}
Finishes one accepted publisher subscription without withdrawing its track or namespace publication.
The selected implementation maps the protocol-neutral :status atom to its
native PUBLISH_DONE code. The default is :subscription_ended.
@spec publish(MOQX.Client.t(), [binary()], keyword()) :: {:ok, MOQX.Publication.t()} | {:error, term()}
Advertises a namespace through the selected protocol implementation.
Lite05 supports missing_track_metadata: :reject | :controlled (default
:reject). Controlled metadata demand emits PublicationTrackRequested when
a peer asks for an absent track under this publication. track_metadata_timeout
defaults to 5,000 milliseconds (integer, 0..4_294_967_295);
max_pending_track_metadata defaults to 128 (positive integer, per publication).
The decision window begins on request receipt. Invalid bounds return
:invalid_track_metadata_options before advertising. Other protocols reject
these options with :unsupported_operation.
The connection's events_to recipient owns provisioning. Registering the
requested track through add_track/4 or reactive accept_subscription/3
resolves all its pending metadata requests; reject_track_request/3 rejects
only one. Terminal paths emit PublicationTrackRequestDone once, including
:reply_failed with the transport error when a metadata reply fails. Stream
cleanup is best-effort and cannot suppress the request's terminal outcome.
Unknown publications, default-rejected requests and capacity overflow reset
immediately without allocating application handles. Deadline, cancellation,
publication finish and connection close invalidate pending handles. Owner exit
closes the whole connection and its resources, not merely one publication.
Metadata demand does not change inbound_subscriptions: controlled media
subscriptions still need explicit acceptance. No implicit track factory,
application retry, or subscription approval is performed.
@spec publish_catalog(MOQX.Client.t(), MOQX.PublishedTrack.t(), MOQX.Catalog.t()) :: :ok | {:error, term()}
Publishes a complete catalog snapshot on a handle returned by add_catalog/3.
Groups increase from zero independently per handle. Every update is one
object, immediately finished, and retained for late subscribers. A failed
validation does not consume a group number. This is transport admission;
CatalogReceived at a receiver proves delivery.
@spec publish_empty_group(MOQX.Client.t(), MOQX.PublishedTrack.t(), non_neg_integer()) :: :ok | {:error, term()}
Publishes a complete group containing zero objects on a registered Lite track.
Unlike an object with an empty payload, this sends only a group header and FIN.
group_id must be in 0..4_611_686_018_427_387_902, leaving room for the
exclusive SUBSCRIBE_END bound. A new group must have a greater ID than the
previous published group, and an open non-empty group must first be finished
with an object whose end_of_group? is true. These publication-wide checks
also apply to publish_object/3, even with zero subscribers. Multiple objects
within an open group keep consecutive object IDs starting at zero.
An empty group has no timestamp. Subsequent groups may use earlier or later
timestamps; MOQX never interprets or rewrites codec epochs. HANG consumers own
decoder reset and any cross-group ordering. Receiver events preserve arrival
order, not global group order (see MOQX.Event.SubgroupEnded).
Only matching subscriber ranges receive the group; completion counts it in
the exclusive END bound. retention: :latest retains this header-only group
in place of the previous single-object snapshot, so late subscribers do not
receive stale pre-discontinuity media. This does not add an archive or
multi-object group cache; other retention modes retain their existing behavior.
Invalid IDs return :invalid_group_id, non-increasing IDs return
:invalid_group_sequence, and an open group returns :unfinished_group.
Foreign-client handles return :wrong_client_published_track; removed tracks
return :unknown_published_track (or :unknown_publication once the entire
publication has ended). A replacement track starts a fresh sequence.
Other protocol implementations return {:error, :unsupported_operation}.
Success means backend admission, not peer delivery or decoder reset.
@spec publish_object(MOQX.Client.t(), MOQX.PublishedTrack.t(), MOQX.Object.t()) :: :ok | {:error, term()}
Publishes one object on a registered track.
@spec reject_subscription( MOQX.Client.t(), MOQX.PublicationSubscriptionRequest.t(), MOQX.SubscriptionRejection.t() ) :: :ok | {:error, term()}
Rejects one pending inbound publisher subscription.
@spec reject_track_request( MOQX.Client.t(), MOQX.PublicationTrackRequest.t(), MOQX.SubscriptionRejection.t() ) :: :ok | {:error, term()}
Rejects one pending track metadata request, without affecting sibling requests
or subscription authorization. Lite05 sends only the rejection code on wire;
textual reasons stay local. Decided, cancelled and foreign requests return
:stale_track_request.
@spec subscribe(MOQX.Client.t(), MOQX.TrackRef.t(), [subscription_option()]) :: {:ok, MOQX.Subscription.t()} | {:error, term()}
Subscribes to a protocol-neutral track address.
:profile defaults to :none: even catalog-named tracks emit opaque
ObjectReceived events. Select :cloudflare_cmsf, :moqtail_cmsf, or :hang
explicitly for CatalogReceived snapshots. The byte-limit options default to
1 MiB each. HANG catalog.json.z selects raw DEFLATE; other HANG track names
select plain JSON. Malformed updates emit CatalogFailed on this handle and
preserve the last valid snapshot; a newer valid group can recover. HANG
snapshots replace the whole catalog, report added/removed/changed track refs,
and ignore older groups. Duplicate groups and nonzero object IDs are errors.
Profile selection is immutable for the subscription lifetime.
The :start option accepts :next_object or :next_group and defaults to
:next_object. Protocol implementations map that application policy to
their native subscription filter and reject unsupported policies explicitly.
@spec transport() :: module()
Returns the default native QUIC transport implementation.
@spec unsubscribe(MOQX.Client.t(), MOQX.Subscription.t()) :: :ok | {:error, term()}
Ends an active subscription and sends the selected protocol's unsubscribe message.
@spec update_subscription( MOQX.Client.t(), MOQX.Subscription.t(), [subscription_update_option()] ) :: :ok | {:error, term()}
Updates an active subscription's draft-neutral filter and delivery parameters.
@spec withdraw_track( MOQX.Client.t(), MOQX.PublishedTrack.t(), status: published_subscription_status(), reason: binary() ) :: :ok | {:error, withdraw_track_error()}
Withdraws one registered track while keeping its publication and siblings active.
The track is unavailable to new subscribers before this call returns. The
selected protocol maps :status to its native terminal code. The default
status is :track_ended.