Skip to main content

WAI Extension: HTTP Delivery

Mirrored from the canonical text at commit 626d9db2 ().

Status: Draft. Binds WAI envelopes to HTTP: a proposed media type, a codecs grammar, content-addressed immutable objects, verified byte-range fetch of one component of a WAI2, receipt, key and playlist sidecars, cache rules, delivery order and deadlines, and HLS / DASH adjacency for on-demand, live and low-latency live. No envelope byte and no manifest member changes. The reference implementation is in wai-rs: http_binding (feature http) for §3–§7 and the origin side of §5 and §9, and the wai http commands of the wai tool. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119 / RFC 8174.

1. Scope

This extension says how a WAI envelope is named, served, cached and fetched over HTTP (RFC 9110, RFC 9111), and how WAI objects sit beside a classical HLS or DASH presentation without changing it. It is the HTTP sibling of moq-streaming-format; Appendix C maps the two. It defines no codec, no player and no re-packing: a node that serves bytes other than those it received is a producer under jwp-receipts §2.6 and §3.2, not a cache under §9. What a refinement does to its base is staged-delivery’s and SPEC §7.1’s; §10 defines only how one is carried over HTTP and when a client gives up on it.

2. Terms

3. Media type application/wai (proposed; not registered)

An object is served with media type application/wai. The name is proposed: RFC 6838 §3.1 admits a standards-tree registration only through an IETF document or a recognized standards organization, and none has been made. Until one is, the name identifies WAI objects between parties that implement this extension, and an implementation MUST NOT present it as registered.

The type’s properties, in the fields of RFC 6838 §5.6:

fieldvalue
Type name / Subtype nameapplication / wai
Required parametersnone
Optional parameterscodecs (§4)
Encoding considerationsbinary
Security considerations§15
Interoperability considerationsWAI1 and WAI2 containers; a reader refuses an unknown MAJOR (SPEC §8)
Published specificationWAI SPEC.md; this extension
Fragment identifier considerations§3.1
Magic number(s)57 41 49 31 (“WAI1”) or 57 41 49 32 (“WAI2”) at offset 0
File extension(s).wai

3.1 Fragment identifiers

A fragment on an object’s URI is a &-separated list of key=value pairs. It is never sent to a server and never changes the object. Unknown keys are ignored.

n and h are hints, never checks: every length that matters is checked against the head proof (§6.3) or, for an object fetched whole, the cid. A wrong h costs a request. A wrong n below 1009 costs the whole object: the client fetches it whole (§5.4), whatever its real length.

4. The codecs parameter

4.1 Grammar

The codecs parameter of application/wai, the HLS CODECS attribute and the DASH @codecs attribute carry WAI elements in this grammar (ABNF, RFC 5234):

wai-element = wai-prefix "." alt *( "|" alt )
wai-prefix  = "wai1" / "wai2"
alt         = cap *( "+" cap )
cap         = 1*lcalnum 1*( "." 1*( lcalnum / "_" ) )
lcalnum     = %x61-7A / %x30-39

4.2 Meaning: the union and the floor

4.3 Not a question for the browser’s decoders

An interface that answers for the user agent’s own decoders (Media Capabilities, MediaSource.isTypeSupported, WebCodecs isConfigSupported) cannot answer for a WAI element. A sink MUST NOT pass a WAI element to such an interface, and MUST NOT read its answer about a classical codec string as support for a WAI capability, except for a capability whose payload the sink hands to that user-agent decoder (§12).

5. Objects

5.1 One envelope, nothing after it

An object MUST be exactly one envelope: for WAI1, envelope_len = 12 + man_len + payload_len; for WAI2, envelope_len = head_len + Σ lengths. A reader that finds another length refuses the object (object_length_mismatch). This rule binds HTTP objects; it does not change which envelopes conform to SPEC.

5.2 Names and aliases

An object SHOULD be published at a URI whose last path segment is <cid>.wai. Such a URI names those bytes forever: a publisher MUST NOT serve other bytes under it.

An object MAY also be served under an alias. An alias MUST serve exactly the object’s bytes with its ETag, and MUST NOT serve other bytes at any time. A client learns no content hash from a response, so before it presents anything fetched by alias it MUST verify the bytes against a cid it holds from a listing (a cid fragment or a <cid>.wai URI in a playlist) or from a verified receipt.

5.3 Response headers

For a GET or HEAD of an object an origin MUST send:

Content-Type: application/wai          (MAY carry ; codecs="…" of §4 for that object)
Cache-Control: public, max-age=31536000, immutable, no-transform
ETag: "<cid>"
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Range, Content-Length, ETag
Timing-Allow-Origin: *

It MUST NOT send Content-Encoding other than none, MUST NOT send Vary, and MUST NOT select bytes by any request header. An object listed only at a live edge (§11.4) MAY carry a smaller max-age, not less than the time it stays listed. An origin MAY send Repr-Digest: sha-256=:<base64>: (RFC 9530 §3) over the whole envelope.

An origin MUST answer a preflight for an object with Access-Control-Allow-Headers: Range, Priority and Access-Control-Max-Age.

A server MUST answer a single byte-range request on an object with 206 and a Content-Range whose complete length is envelope_len (RFC 9110 §14.4, §15.3.7), or with 200 and the whole object. It MAY answer a multi-range request with 200.

5.4 Sizes

A publisher SHOULD give each listed object’s n and, for a WAI2, its h (§3.1). A client that holds n below 1009 fetches the object whole: no head proof can cover less than one chunk.

5.5 Every media class (informative)

The binding is the same for every capability. What a range fetch saves, and where a refinement sits, depend on the media class.

registry mediatypical objectrange fetch savesrefinement, carried as
imageWAI2: a pinned integer learned rendition beside standard image renditionsevery rendition but the picka refinement component, or layer objects
audioa WAI1 per segment; or a WAI2 with an integer or learned codec beside a standard onethe renditions not pickeda refinement component, or layer objects
videoone object per segment or part, aligned with a classical ladder (§11)the same, per segmentan enhancement companion such as wai.video.lcevc (§10.3), a refinement component, or layer objects
metadata (companions)bound to a rendition in a WAI2fetched only with its rendition—
interactive (worlds, feeds, avatars)snapshot and op-delta objectshead first: decide, then fetchlater op-deltas are separate objects
volumetricWAI2: an integer splat codec beside a standard mesh, splat or point-cloud payloadthe rendition not pickeda refinement component, or layer objects
haptic, textsmall objectsnothing: below 1009 bytes they are fetched whole (§5.4)—
binary (parameter sets, circuits, ternary)a parameter set served as an immutable resource, verified by its pin (§8.5)——
records and derivationscarried as objects, never named in codecs (codecs_not_media)——

6. The head proof

6.1 What it proves

A head proof lets a client verify the first covered_len envelope bytes against the cid without the rest of the object. The content hash is a BLAKE3 root over 1024-byte chunks of X = "moq-jwp:object\x01" ‖ envelope; the proof is the chaining values of the subtrees of X that lie wholly at or after offset c = 15 + covered_len. It is a pure function of the object: anyone holding the object can produce it, and a wrong one fails verification.

6.2 Format (<cid>.wai.hp)

All integers are little-endian (SPEC §2).

offsetsizefield
04magic 57 48 50 31 (“WHP1”)
432cid, raw bytes
368envelope_len (u64)
448covered_len (u64), equal to §2’s formula
521n_cv (u8), at most 64
5332·n_cvchaining values, in verification order

The file is exactly 53 + 32·n_cv bytes. When covered_len = envelope_len, n_cv is 0 and the client verifies the whole object: its content hash is computed over the bytes it holds. A head proof is served under §5.3’s cache headers with Content-Type: application/octet-stream.

6.3 Verification

With L = 15 + envelope_len, c = 15 + covered_len, and left(n) = 1024 · 2^⌊log₂((n−1)/1024)⌋, when covered_len < envelope_len:

cv(start, len):
  if start ≥ c:            take the next chaining value from the proof
  elif start + len ≤ c:    the non-root chaining value of the len bytes of X at start,
                           a subtree whose first chunk has counter start/1024
  else:                    parent_cv(cv(start, left(len)), cv(start+left(len), len−left(len)))
root = parent_root(cv(0, left(L)), cv(left(L), L − left(L)))

parent_cv and parent_root are BLAKE3’s parent node in hash mode, without and with the ROOT flag. c is a multiple of 1024 whenever covered_len < envelope_len, so every subtree the procedure meets lies wholly before c or wholly at or after it once it is split far enough. A client checks, in order:

  1. the file has the format above; its cid is the object’s; its envelope_len equals the complete length of every Content-Range and the length of every 200 body it received; and its covered_len is envelope_len, with n_cv 0, or is less than it with 15 + covered_len a multiple of 1024 (head_proof_malformed);
  2. the chaining values are consumed exactly, and root equals the cid (head_proof_mismatch);
  3. envelope_len is the length the verified head gives (§5.1), and covered_len is §2’s formula for that head (head_proof_malformed). The root does not encode the object’s length, so a wrong envelope_len that leaves the tree’s shape unchanged passes check 2 and is refused here.

No covered byte is read as a head before check 2 passes. A producer writes the chaining values in the order the procedure consumes them.

7. Byte-range fetch of a WAI2 component

A client that fetches part of an object MUST verify, before it presents or decodes anything, every byte it uses: the head against the cid (§6), and each component it uses against the sha256 of its entry in that verified head (SPEC §7.1). The procedure:

  1. In parallel, request Range: bytes=0-(E−1), with E the h fragment if given and 16369 otherwise, and request <cid>.wai.hp.
  2. Check each response (§7.1). If covered_len exceeds the bytes received, request the rest of the first covered_len bytes.
  3. Verify the head (§6.3). Parse it (head_malformed); apply §5.1; refuse a capability the variant’s union does not list (codecs_undeclared).
  4. Select from the head exactly as SPEC §7.1 selects, deferring only the component-digest test to the bytes. A deployer policy MAY reorder and restrict the entries considered, as SPEC §7.1 allows. The result is the picked entry, the companions SPEC §7.1 binds to it, and the refinement components whose refines.base is its id.
  5. If the picked entry, or a bound companion the sink will apply that is not a refinement (§2), states no sha256, go to step 7 (component_digest_absent). A refinement that states none is dropped: the client does not request it, and the base’s path does not change.
  6. Request the ranges of the picked component and of the companions and refinements it will apply that the client does not already hold: one request per range, merging ranges that touch only when they are in the same priority class (§10.1), so a refinement is always requested on its own. Verify each against its entry’s sha256. On a mismatch of the picked component or of a companion that is not a refinement (component_digest_mismatch), discard every byte held past covered_len and go to step 7. A refinement that mismatches is dropped alone.
  7. Request the rest, bytes=covered_len- (or GET the whole object), verify the whole envelope against the cid (object_digest_mismatch), and select as SPEC §7.1 selects on the whole envelope.

A client SHOULD also go to step 7 when the base-class bytes step 6 would request — the picked component’s and those of the companions that are not refinements — are at least 90 % of the bytes after covered_len. A refinement’s bytes never count, so a refinement never moves its base to step 7; when the base goes there, the rest of the object carries the refinement’s bytes with it. A client MUST NOT send a multi-range request and rely on a multipart answer. A WAI1 has one component, its payload: a client decides from its verified head whether it can dispatch it (SPEC §4), and only then fetches the rest after the head. A layer object (§10.4) is never dispatched: the client fetches it whole, at refinement urgency, verifies it against its cid, and hands it to staged-delivery §4.

7.1 Response checks

For each request a client checks, in order:

A refused response’s bytes are discarded and never presented. A refused base-class response ends the fetch; a refused refinement-class response abandons that refinement (§10.2), and the base goes on. A client MAY retry once with Cache-Control: no-cache.

7.2 One pick on every path

On bytes that verify, §7 picks the same entry that SPEC §7.1 picks on the whole envelope: the digest test runs on the bytes either way, and every case in which a range client cannot run it (no sha256, a mismatch) is decided on the whole envelope. A range client never picks an entry the whole-envelope selection would skip, and never skips one it would pick. When the head alone shows that no entry can be picked, the client stops there and reports the reasons the head gives; an entry whose pin was refused may also fail its digest, which only its bytes would show.

8. Receipts, keys, grants and parameter sets over HTTP

8.1 Receipt files

rcpt/<h>.json, resolved against the object’s URI, holds exactly one receipt: a group receipt whose link hash (jwp-receipts §3 step 3) is h, in its canonical form, or a claim whose link_hash (§2.4.3) is h, in its JCS form. It is immutable and served under §5.3’s cache headers with Content-Type: application/json. A client refuses a receipt file whose computed hash is not its name (receipt_name_mismatch). A group receipt’s parent_receipt_hash is the name of its parent’s file, so a client resolves jwp-receipts §3 step 3 by fetching rcpt/<parent_receipt_hash>.json, and reports parent_not_held when it cannot, never skipping the step.

8.2 Receipt index

<cid>.wai.receipts is the sidecar carriage of the WAI_RECEIPT property (moq-streaming-format §5):

{ "kind": "wai-receipt-index", "object": "<cid>",
  "delivery": [ { "property": { …WAI_RECEIPT… }, "object_receipt": { …jwp-receipts §2.4.2… } } ],
  "claims":   [ "<link hash>" ] }

It is mutable and is served with Cache-Control: no-cache, no-transform and an ETag of its own. It is a locator, never evidence. A client checks each item on its own and ignores, item by item, one that fails:

8.3 A range-fetched object

A client that holds only the head and some components cannot recompute the content hash over the envelope. Under jwp-receipts §3 step 4 it takes the cid its head proof verified, and the receipt then attests the object the cid names; the components it holds are attested through the verified head’s sha256 values.

A component’s exploded envelope (SPEC §7.1, Exploding a component) is a function of the verified head and the component’s bytes, so a client that holds them builds it. A receipt about that exploded envelope is checked under step 4 over the envelope the client built, as for any object: this is how a refinement component fetched by range meets staged-delivery §10.1, which applies a layer only on a receipt checked over its envelope bytes.

8.4 Keys, statuses and grants

resourcelocationCache-Control
key log (jwp-receipts §7.2)/.well-known/wai-keysmax-age=300, no-transform
key status (§7.9 there)/.well-known/wai-key-statusmax-age at most a quarter of the head’s status_max_age_s, no-transform
module grants (§7.9 there)/.well-known/wai-grants/<module digest>.json: {"kind":"wai-module-grants","module":"<digest>","grants":[…]}max-age=300, no-transform

All are application/json. A verifier that anchors an origin fetches its key log from the origin over HTTPS without following a redirect, as jwp-receipts §7.3 states, and with Cache-Control: no-cache. Later revisions MAY come through any cache: each is checked against its parent, and a rolled-back copy is reported (key_log_rolled_back). The grants file is a locator: each grant is checked on its own.

8.5 Parameter sets

A parameter set MAY be served as an immutable resource named by its pin’s digest (<base>/<sha256>), under §5.3’s cache headers with application/octet-stream. A sink verifies it by its pin (SPEC §3.1) and decodes against it only if the checks of jwp-receipts §7.9 pass. A set they refuse is not held, and dispatch continues as SPEC §4 and §7.1 state.

8.6 Playlist receipts

A WAI playlist (§11) is authenticated by a manifest receipt (wai.video.manifest, SPEC §5) whose manifest_hash is the BLAKE3 of the playlist bytes, served immutable at mr/<manifest_hash>.json resolved against the playlist URI. Each revision of a live playlist has its own receipt, whose parent_receipt_hash names the previous one. A playlist receipt MAY carry render, the rendering parameters of the playlist it signs (version, media sequence, discontinuity sequence, part target, whether it ends), and extras, the per-segment lines that rendering adds (discontinuities, program date-time, parts, layer lines). When both are absent, the playlist is rendered as before. manifest_hash covers the rendered bytes, so both are bound by the signature through it.

9. Cache rules

An HTTP cache that stores and serves objects under this extension is a transparent byte store, not a relay under jwp-receipts §4.1 (see §4.5 there). It is bound by §4.3 there, and it MUST:

  1. store and serve an object byte for byte, and not transform it (RFC 9111 §5.2.2.6) or apply a content coding to it;
  2. answer a single byte-range request from a stored complete object with 206 and the exact bytes (RFC 9110 §14), and with 416 and Content-Range: bytes */<len> for an unsatisfiable range. On a miss it MAY forward the range, or fetch the whole object and answer from it;
  3. keep ETag, Content-Type, Cache-Control and, on a 200, Content-Length as the origin sent them;
  4. not vary a stored object by any request header;
  5. evaluate If-Range with a strong comparison (RFC 9110 §13.1.5, §8.8.3.2);
  6. store head proofs, receipt files, playlist receipts and parameter sets under the same rules, and revalidate receipt indexes on every use and the other §8.4 resources per their Cache-Control;
  7. where a configuration cannot meet 1–6 for a request, pass the request through uncached and relay the origin’s bytes unchanged.

A cache SHOULD NOT revalidate an object while it is fresh (RFC 8246 §2). A node that serves other bytes than an object’s — recompressed, re-packed or split — derives a new object: it publishes the new bytes under their own cid, with its own receipts and a soft-binding claim to the ancestor (jwp-receipts §2.6.2), listed in the new object’s index, and MUST NOT serve them under the original name or an alias of it. Over HTTP an edge selects only by serving such derived objects; a client selects by range.

10. Delivery order, deadlines and refinements

10.1 Priority

A base and each refinement are separate requests. A client MUST NOT let a request whose bytes it needs for a base wait on a refinement’s bytes, and a cache MUST NOT hold a base response for a refinement request. A client presents a base as soon as it has verified it (§7), and applies each refinement when that refinement arrives and verifies; it never holds a verified base back for its refinements. A base, once verified, is decided: no later response changes its bytes or its outcome. Of a response to a refinement request, a client keeps only the bytes of the range it requested, even from a 200 that carries the whole object (§7.1), so a refinement’s response never reaches its base’s bytes, before or after the base verified. A client SHOULD signal urgency 2 for a base and urgency 5 with incremental for a refinement (RFC 9218 §4.1, §4.2): by the Priority header (§5 there), or in a browser by the fetch priority option. A deadline never applies to a base: a base request that is never answered ends the fetch (base_unanswered).

10.2 Deadlines

A client presenting live sets a deadline on every refinement request: the latest time at which the refinement, once received and verified, can still be applied, which for a layer is its lead_ms before the presentation time of the first unit it covers (staged-delivery §8). When the deadline passes, the client abandons the request and presents what it has. This is the HTTP counterpart of the delivery timeout after which a MoQ relay drops an object; on either binding a refinement never stalls its base, and a layer that arrives late is not applied to the units that are already due (deadline-missed, staged-delivery §8).

A deadline runs on the client’s clock from the moment the base verified, the moment §10.1 presents it: the time the response that completed the base was received. A refinement that has not arrived and verified within it is abandoned, and the base, already presented, is unaffected. What the clock read before the base verified never moves that start. A clock that steps back has not passed a deadline until it again reaches it, and a deadline past the clock’s range is at its end. The reference client’s session reads no clock of its own: every response it is given carries the caller’s time, and the caller tells it the time between responses.

10.3 Enhancement companions and refinement components

A companion whose registered role is enhancement (for example wai.video.lcevc, SPEC §5) and a component with role: "refinement" are refinements inside the object: each range is requested in its own request, at refinement priority, after or beside the base component’s. A client that abandons an enhancement companion presents the base, as SPEC §7.1 lets a sink that does not apply a companion present the rendition; one that abandons a refinement component presents the stage it has (staged-delivery §7). A refinement that states no sha256, or does not match it, is dropped (§7 steps 5 and 6), and its base is unaffected.

10.4 Layer objects

A layer object is a WAI1 whose capability is refinement-only (SPEC §5, staged-delivery §3). Whether an object is one is decided by its capability alone: a WAI1 whose capability is a payload is an ordinary object even when it carries refines (which staged delivery §3 forbids its producer to write), so a client dispatches it under SPEC §4 and does not read refines. A client never dispatches a layer object under SPEC §4: it fetches it whole, at refinement urgency (§10.1) and under a deadline (§10.2), verifies it against its cid, and hands it to staged-delivery §4, which decides what it does to its base. A client that finds one by its head (§7) does the same with the rest of it. Against a declared union (§4.2), a layer is declared only in the alt of its own base’s capability. An object a playlist lists as a layer that is not one, a payload carrying refines among them, is refused (not_a_layer); a layer’s request abandoned at its deadline, or whose response §7.1 refuses, leaves the layer not delivered (§10.5).

A WAI media playlist lists the layer objects of a segment or part after its EXTINF or EXT-X-PART line, in the order a sink applies them:

#WAI-LAYER:N=<1..255>,URI="<cid>.wai#n=…"

Its attributes are an HLS attribute list (RFC 8216 §4.2): N a decimal integer from 1 to 255, URI a quoted string, neither named twice; an attribute this revision does not define is ignored. A line that breaks these is layer_tag_malformed.

N is a locator: it lets a client choose the depth it fetches before it fetches any layer. The layer an envelope brings its units to is its refines.layer, inside the envelope and so inside its content hash; a sink reads it from there and ignores N, as staged-delivery §13 reads a MoQ layer header. The base is layer 0, the segment or part URI. A client fetches to the depth its policy chooses, each layer under §10.1 and §10.2.

10.5 Objects not delivered

A refinement a client abandoned is not delivered to it. Its receipts stay listed in the index; the client neither presents it nor reports its delivery, and the group receipt stays valid for the objects it did receive (jwp-receipts §4.4). A client that checks the abandoned refinement’s object receipt from the index without its bytes finds it inclusion-verified (jwp-receipts §3, Verified by inclusion): signed and not delivered, never applied (staged-delivery §10.1). A stage claim the client signs lists it as dropped with that evidence, or as late if it arrived after its units were due (staged-delivery §10.2).

11. HLS and DASH adjacency

11.1 Mode N (native objects) — the default

11.2 Alignment

A WAI media playlist is adjacent to a classical media playlist when, segment for segment, they have the same EXT-X-MEDIA-SEQUENCE, EXT-X-DISCONTINUITY-SEQUENCE, EXTINF durations to the millisecond, discontinuities and EXT-X-PROGRAM-DATE-TIME values, and, where both carry parts, the same EXT-X-PART-INF:PART-TARGET and the same part durations to the millisecond in each segment. In DASH: the same Period@ids and @starts, and a SegmentTimeline with the same timescale, t and d. The WAI segment (or part) with a sequence number covers exactly the presentation interval of the classical one, so a sink can move between them at any boundary. A packager MUST NOT publish a WAI playlist that breaks this (adjacency_misaligned). #WAI-LAYER lines do not affect alignment.

11.3 Live at segment granularity (Live-S)

Each segment is one object, listed as <cid>.wai#n=…&h=… once it is complete. A client presents an object only after its bytes verify against the listed cid. The latency from the end of a segment’s media interval to presentation is at least

S_floor = e + p + r_pl + r_obj + v

where e is encode and packaging time, p the time to publish and list, r_pl the wait for a playlist that lists the object (with blocking reload, one request time), r_obj the object request time (one round trip and transfer), and v the verification time.

11.4 Low-latency live (Live-P)

Each part is its own object, served under an alias, and listed with its cid:

#EXT-X-PART-INF:PART-TARGET=0.333
#EXT-X-PART:DURATION=0.333,INDEPENDENT=YES,URI="live/720/1200.3.wai#cid=<hex>&n=…"
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="live/720/1200.4.wai"

11.5 Live to on demand

Every object is immutable from the moment it is listed, so a live playlist becomes on-demand by appending EXT-X-ENDLIST; no object is rewritten.

11.6 Playlist authentication

A WAI playlist SHOULD be authenticated by its receipt (§8.6). A client that verifies it holds the cids, durations and order its signer published. Without it, which objects a playlist names is only as trustworthy as the connection to the origin that served it; each object is still bound to the cid the playlist names. A client reports which held: listed (bytes match a cid in a playlist fetched over HTTPS from the origin the multivariant playlist names), signed (that playlist’s receipt, or the object’s receipt, verified), and the confirmation level of jwp-receipts §7.4. In Live-P a client MAY present at listed and verify the playlist receipt after presenting; it MUST NOT report the part as signed until it has.

A WAI segment whose payload is a classical segment’s media relates to the classical package’s segment map (wai.video.package) by sequence number: the package’s content_hash identifies the media and the cid identifies the envelope that carries it. They are hashes of different bytes, and neither replaces the other.

11.7 Mode F (fragmented MP4) — provisional

Appendix B defines ISOBMFF sample entries that carry one WAI envelope per sample. Such segments are fragmented MP4 (RFC 8216 §3.3), so a WAI track could be a variant of the classical multivariant playlist. The 4CCs are not registered: until they are, Mode F MUST NOT be published outside test material.

11.8 CTA-5005-B

In Mode N the classical presentation’s conformance to CTA-5005-B is preserved by byte equality of its manifests. The EXT-X-SESSION-DATA option and Mode F are to be checked against CTA-5005-B’s clauses before use.

12. Capability probe

12.1 The Sink Capability Descriptor

{ "wai_sink": 1,
  "containers": ["WAI1", "WAI2"],
  "caps": { "<capability>": { "via": "wasm" | "ua" | "host",
                              "asked": { "<ua codec string>": true | false },
                              "provisional": true | false } },
  "held_sets": { "<capability>": [ "<pin sha256>" ] } }

12.2 Asking the user agent

A capability is ua only if the sink asked the user-agent decoder it will hand the payload to, under that decoder’s own name, and the answer was supported: WebCodecs isConfigSupported for a video or audio elementary stream, or an image decode of a known sample. Media Capabilities is asked only as a further question about a decoder already found. Before decoding a payload through a ua capability, a sink MUST ask again with the configuration that payload’s own header gives; a refusal makes the capability unsupported for that object, and selection continues.

12.3 Support

supports(codecs, descriptor) is §4.2’s rule with “reads the container” read as “is in containers” and “supports cap” read as “wai.<cap> is in caps”.

12.4 Capable share (informative)

For a WAI variant V and a set C of sessions observed in a stated window:

capable_share(V, C) = |{ s ∈ C : supports(codecs(V), descriptor(s)) ∧ probe_ok(V, s) }| / |C|

probe_ok(V, s) holds when the session decoded V’s published probe object and its output had the published digest (an exact tier), or decoded without error (any other tier). A report states |C|, the window, how C was sampled and the descriptor version. It is a share of sessions, not of devices or people.

13. Reasons

reasonraised at
object_length_mismatch§5.1
head_malformed§7 step 3
head_proof_malformed, head_proof_mismatch§6.3
http_status_unexpected, content_coding_present, content_range_mismatch, complete_length_mismatch§7.1
component_digest_absent§7 step 5 (a reason to fetch whole, never a skip)
component_digest_mismatch§7 step 6 (SPEC §7.1’s reason)
object_digest_mismatch§7 step 7, or any whole fetch
receipt_name_mismatch, receipt_not_about_object§8.1, §8.2
codecs_malformed, codecs_not_media, codecs_candidate, codecs_no_common_capability, codecs_undeclared, codecs_layer_unbound§4
base_unanswered§10.1
not_a_layer, layer_tag_malformed§10.4
adjacency_misaligned§11.2

Selection, pin, receipt, key and module reasons are those of SPEC §3.1 and §7.1 and jwp-receipts §3, §7.7 and §7.9, and the layer reasons those of staged-delivery §4.2, unchanged. An object at which selection picks nothing is inert at the sink, with each entry’s reason, as SPEC §7.1 step 5 states.

14. Conformance

15. Security and privacy considerations

Appendix A — CDNI configuration

Path patterns /objects/*.wai, *.wai.hp, rcpt/* and mr/* take the RFC 8006 metadata MI.Cache with include-query-strings: [], and MI.SourceMetadata; a receipt index (*.wai.receipts) takes the cache rule with no storage beyond revalidation. RFC 8006 has no metadata for range handling, transformation or a time-to- live override: a configuration interface that has them states, for these paths, the behaviour §9 requires.

Appendix B — ISOBMFF sample entries (provisional; 4CCs not registered)

aligned(8) class WAIConfigurationBox extends FullBox('waiC', 0, 0) {
    unsigned int(8)  wai_major;                 // 1
    unsigned int(8)  max_minor;                 // highest manifest MINOR in the track
    unsigned int(16) element_len;
    unsigned int(8)  element[element_len];      // the track's union element, UTF-8
    unsigned int(16) floor_len;
    unsigned int(8)  floor[floor_len];          // the track's floor element, UTF-8
}
class WAIVisualSampleEntry(type) extends VisualSampleEntry(type)    { WAIConfigurationBox config; } // 'vide'
class WAIAudioSampleEntry(type)  extends AudioSampleEntry(type)     { WAIConfigurationBox config; } // 'soun'
class WAIMetaSampleEntry(type)   extends MetaDataSampleEntry(type)  { WAIConfigurationBox config; } // 'meta'
// type = 'wai1' when every sample is a WAI1 envelope, else 'wai2'

Appendix C — Mapping to moq-streaming-format

MoQ (moq-streaming-format)HTTP (this extension)
object = one envelope (§3 there)object <cid>.wai (§5.1)
packaging: "wai"media type application/wai
catalog wai_capabilities, exhaustive (§4 there)codecs union (§4.2); codecs_undeclared is the same protocol error
(no floor)X-WAI-FLOOR / DASH SupplementalProperty
WAI_RECEIPT property (§5 there)index item property (§8.2)
group receipt per grouprcpt/<link hash>.json; a group per segment (on demand) or per segment with its parts (Live-P)
a layer object on its own tracka layer object listed by #WAI-LAYER (§10.4); its layer is its refines.layer either way
a subscriber’s layer capthe client’s depth policy; nothing is sent to the edge
a relay drops layers above the cap, receipts intactthe client does not request them; caches never drop; receipts stay listed (§10.5)
the delivery timeout after which a relay drops an objectthe client’s refinement deadline (§10.2)
publisher priorityRFC 9218 urgency (§10.1)

Appendix D — Worked example

The envelope. A WAI2 with a 560-byte manifest:

{"wai":"1.1","media":"video","intent":"replicate","renditions":[{"capability":"wai.video.av1","kind":"av1","id":"low","sha256":"f541874101876255b4baf3a739778d04cb9cba25ffa38b30bc1fb8b0701f2a45"},{"capability":"wai.video.av1","kind":"av1","id":"high","sha256":"b76bf31be170d9df8eafbd020941b5fd4b7ab017af6a1e5c1c03e909aa8f9fb7"},{"capability":"wai.meta.hdr10plus","kind":"descriptor","id":"hdr","sha256":"74739b7242c81aa5ec2a1601fd04a5f81bed0302970e6a51f3a7dc9e92ea8520","role":"companion","companion_of":"wai.video.av1","companion_of_id":"high"}],"target":null}

Payloads, synthetic (they show the layout, and decode to nothing):

Layout.

The plans below assume the object is listed with #h=1009 (and n), so the first request ends at covered_len. Without h, the first request is 16,369 bytes.

Plan 1: the sink picks low (the table’s order, or a policy under low throughput).

Plan 2: a policy reorders to high, which binds hdr.

Appendix E — References and their verification status

referencestatus
RFC 9110 §7.7, §8.4, §8.8.3, §13.1.5, §14.1–§14.6, §15.3.7, §15.5.17read
RFC 9111 §5.2.2.6 · RFC 8246 §2 · RFC 6381 §3.2 · RFC 6838 §3.1, §3.2, §5.6read
RFC 9530 §2, §3 · RFC 9218 §4.1, §4.2, §5read
RFC 8216 §3.1, §3.3, §4.3.4.2, §4.3.4.4 · the HLS second-edition draft (its date only)read
RFC 8006 MI.* objectsread
The HLS second-edition draft’s EXT-X-PART, EXT-X-PRELOAD-HINT and blocking-reload clausesnot re-read here: §11.4 is to be checked against them
CTA-5005-Btitle and date only
The BLAKE3 specificationthe tree rule is checked by the reference implementation against whole-input hashing
RFC 8615, RFC 8785, RFC 4151, RFC 5234, ISO/IEC 14496-12 and -15, ISO/IEC 23000-19, ISO/IEC 23009-1, the Fetch Standard (CORS-safelisted Range, priority), WebCodecs, Media Capabilitiesnot re-read here

Every row not read is read before this extension leaves Draft.