195 lines
11 KiB
Markdown
195 lines
11 KiB
Markdown
# WAI Extension: Capability Constraints
|
||
|
||
> Status: Draft. Makes capability dispatch (WAI SPEC.md §4) a **precondition
|
||
> check** rather than a binary claim, by ingesting the constraint-set grammar and
|
||
> register pattern the broadcast-IP world already ratified. No transport, no
|
||
> registry service, no negotiation protocol — it evaluates values WAI already
|
||
> carries. A sink also declares what its display presents — resolution, refresh
|
||
> rate, bit depth, dynamic range and physical size — and no rendition above that is
|
||
> sent to it (§4); the receipt of each segment records how its rendition matched.
|
||
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
||
|
||
## 1. The problem: support is not binary
|
||
|
||
WAI dispatch treats a capability as present or absent: a sink either claims
|
||
`cap` or does not. Real sinks are not like that. A decoder supports a codec *to
|
||
a level* — up to a resolution, a frame rate, a bit depth, a profile. "This
|
||
capability, but only to 4K60 10-bit, this profile" is the normal case and is
|
||
currently unexpressible.
|
||
|
||
The consequence is that partial support fails at **decode time** rather than at
|
||
**selection time**. A sink advertises the capability, receives an object it
|
||
cannot actually handle, and fails after committing to the bytes. Worse, WAI's
|
||
rendition selection has nothing to evaluate, so it defers to a deployer policy
|
||
the specification never states.
|
||
|
||
## 2. Constraint sets
|
||
|
||
A **constraint set** is an ORed set of constraints over named parameters, each
|
||
constraint being an enumeration, a minimum, a maximum, or a combination. A sink
|
||
satisfies a capability when it advertises `cap` **and** the object's declared
|
||
parameters satisfy at least one of the registered constraint sets for `cap`.
|
||
|
||
This grammar is deliberately not invented here. It is the shape AMWA's Receiver
|
||
and Sender Capabilities specifications (BCP-004-01 and BCP-004-02, both v1.0.0)
|
||
use, with parameters drawn from a public register rather than a bespoke schema
|
||
per implementation. WAI ingests the **grammar and the register pattern**, not the
|
||
transport or the discovery model those specifications sit in.
|
||
|
||
- A capability registration **MAY** publish one or more constraint sets. A
|
||
capability with none is unconstrained, which is the current behaviour and
|
||
remains valid.
|
||
- A sink **MUST** evaluate constraint sets **before** dispatch, not during it.
|
||
The point is to move the failure earlier; a check performed at decode has
|
||
bought nothing.
|
||
- A sink **MUST NOT** advertise a capability whose constraint sets it cannot
|
||
evaluate. Advertising a capability while ignoring its constraints is the
|
||
binary behaviour this extension exists to replace.
|
||
- Where an object's declared parameters satisfy no set, the sink **MUST** treat
|
||
the capability as unsupported for that object — not as a decode error, and not
|
||
as a reason to attempt it anyway.
|
||
|
||
## 3. Parameters and the register
|
||
|
||
Parameters are named in a register, so two implementations constrain the same
|
||
property under the same name. WAI adopts the pattern; it does not adopt the
|
||
existing register wholesale, for a reason worth stating plainly:
|
||
|
||
**The ratified registers are broadcast-essence-shaped.** They cover media type,
|
||
frame rate, colour sampling, bit depth, codec profile — which serves WAI's
|
||
conventional media capabilities and nothing else. There are no entries for the
|
||
neural, quantum, world or haptic families. Those register entries **WAI must
|
||
author itself**, and until it does, those capabilities remain unconstrained under
|
||
§2, which is the honest state rather than a pretended one.
|
||
|
||
- A parameter name **MUST** resolve in a register. An implementation-local name
|
||
is not a constraint anyone else can evaluate.
|
||
- WAI-authored parameters **MUST** be namespaced so they cannot collide with
|
||
entries authored elsewhere.
|
||
|
||
### 3.1 The register this revision holds
|
||
|
||
WAI's parameters are named under the prefix `wai:`. Each value is an integer or a
|
||
string, so every evaluation is exact; a rate that would be a rational elsewhere is an
|
||
integer in a stated unit here.
|
||
|
||
| parameter | value | what it is |
|
||
|---|---|---|
|
||
| `wai:codec` | string | the codec string a decoder is configured with |
|
||
| `wai:frame_width` | integer | the coded width, in samples |
|
||
| `wai:frame_height` | integer | the coded height, in samples |
|
||
| `wai:frame_rate_milli` | integer | frames per 1000 seconds |
|
||
| `wai:bit_depth` | integer | bits per sample |
|
||
| `wai:chroma` | string | the chroma sampling: `4:2:0`, `4:2:2`, `4:4:4` or `4:0:0` |
|
||
| `wai:sample_rate` | integer | audio samples per second, per channel |
|
||
| `wai:channel_count` | integer | audio channels |
|
||
| `wai:bitrate` | integer | bits per second |
|
||
| `wai:transfer` | integer | the video's transfer characteristics, as a `TransferCharacteristics` code point of the coding-independent code points (ISO/IEC 23001-8, as `draft-pantos-hls-rfc8216bis-22` §4.4.6.2 cites it): 1, 6, 13, 14 and 15 are standard dynamic range, 16 is PQ and 18 is HLG |
|
||
|
||
The families §3 names (neural, quantum, world, haptic) have no entries yet, and stay
|
||
unconstrained until they do. The form a page evaluates constraint sets in, and their
|
||
evaluation, are [browser-sink](browser-sink.md) §5; its reference implementation is
|
||
the `browser_sink` module of `wai-rs`.
|
||
|
||
## 4. Display capability
|
||
|
||
Bits a panel cannot present are spent and never seen: pixels above its resolution, pictures
|
||
above its refresh rate, bits per sample above its depth, a dynamic range above its own. A
|
||
sink states what its panel presents in a **display declaration**, and a rendition above it is
|
||
not sent. The declaration is a statement the sink makes once to whatever chooses its
|
||
renditions, and makes again when its panel changes; nothing is exchanged beyond it.
|
||
|
||
### 4.1 The declaration
|
||
|
||
| member | value | what it is |
|
||
|---|---|---|
|
||
| `long` | integer, at least 1 | the panel's longer side, in its own pixels |
|
||
| `short` | integer, from 1 to `long` | its shorter side |
|
||
| `refresh_milli` | integer, at least 1 | the most pictures it presents per 1000 seconds; for a panel whose rate varies, its highest |
|
||
| `bit_depth` | integer, 1 to 16 | the bits per colour component it presents |
|
||
| `hdr` | boolean | whether it presents the range of the high-dynamic-range transfers, PQ and HLG, above standard dynamic range's |
|
||
| `long_mm`, `short_mm` | integer, 0 or more | its physical size along its longer and shorter sides, in millimetres; 0 where the sink does not know it |
|
||
|
||
The sides are stated without orientation, so a sink that turns its panel declares nothing
|
||
new. A native host reads every member from its platform's description of the display the
|
||
stream is presented on. A page reads them through the interfaces it has:
|
||
|
||
- `long` and `short`: CSSOM View's `screen.width` and `screen.height`, which are in CSS
|
||
pixels, each times `devicePixelRatio`, rounded to the nearest integer;
|
||
- `bit_depth`: ⌊`screen.colorDepth` / 3⌋, which is 8 where the user agent does not say
|
||
(CSSOM View has `colorDepth` return 24 when it does not know the depth or withholds it);
|
||
- `hdr`: true when the media query `(video-dynamic-range: high)` or `(dynamic-range: high)`
|
||
matches (Media Queries Level 5 §6.5, §8.2);
|
||
- `refresh_milli`: no interface states it, so a page measures it: 1000 times the whole
|
||
number of pictures per second nearest to 10⁶ divided by the median of at least 60 intervals,
|
||
in microseconds, between consecutive animation frames (of an even count, the upper of the
|
||
two middle ones);
|
||
- `long_mm` and `short_mm`: 0, since a page has no interface for them.
|
||
|
||
Texts read for this section: CSSOM View Module, W3C Working Draft 16 September 2025, §2.1
|
||
and §4.3 (`Screen`, `devicePixelRatio`); Media Queries Level 5, W3C Working Draft
|
||
19 February 2026, §6.5 and §8.2; `draft-pantos-hls-rfc8216bis-22` §4.4.6.2 (`RESOLUTION`,
|
||
`FRAME-RATE`, `VIDEO-RANGE`).
|
||
|
||
### 4.2 The match
|
||
|
||
A rendition is read through the parameters of §3.1: `w` = `wai:frame_width`, `h` =
|
||
`wai:frame_height`, `r` = `wai:frame_rate_milli`, `d` = `wai:bit_depth` and `x` =
|
||
`wai:transfer`, with `x` = 1 where the rendition declares none (an HLS variant stream without
|
||
`VIDEO-RANGE` is standard dynamic range, rfc8216bis-22 §4.4.6.2). Its **exceedances** against
|
||
a declaration are the bits:
|
||
|
||
| bit | name | set when |
|
||
|---|---|---|
|
||
| 0 | `resolution` | max(`w`, `h`) > `long`, or min(`w`, `h`) > `short` |
|
||
| 1 | `refresh` | `r` > `refresh_milli` |
|
||
| 2 | `bit_depth` | `d` > `bit_depth` |
|
||
| 3 | `dynamic_range` | `x` is 16 or 18, and `hdr` is false |
|
||
|
||
A rendition is **within** the declaration when its exceedances are 0. Of the renditions a
|
||
sender offers a sink (its **ladder**), the **admissible** ones are those within the
|
||
declaration; where none is, the least rendition alone is admissible. The **least** is the
|
||
first in the order of (`w` × `h`, `r`, `d`, 1 where `x` is 16 or 18 and 0 otherwise),
|
||
ascending, and of two equal there, the one the ladder lists first. A panel smaller than every
|
||
rendition is still served, by the least of them.
|
||
|
||
The **match** of a rendition is its exceedances, with bit 4, `none_within`, set when no
|
||
rendition of the ladder is within the declaration. It is what a receipt records
|
||
([stream-termination](stream-termination.md) §3.4).
|
||
|
||
- A sender that holds a sink's declaration **MUST NOT** send it a rendition that is not
|
||
admissible. A sink that chooses its own renditions — an HLS or DASH player's selection, a
|
||
MoQ subscriber's choice of track — **MUST NOT** request one that is not admissible.
|
||
- A sink **SHOULD** declare its panel to whatever chooses its renditions, before the first
|
||
is chosen, by a means this revision does not fix, and **MUST** declare it again when the
|
||
panel changes (a window moved to another display, its dynamic range switched).
|
||
- The physical size bounds nothing in this revision: how much of a resolution a viewer
|
||
resolves depends on how far away the viewer is, which a sink does not know. It is
|
||
declared and recorded.
|
||
- A receipt of a segment records the match of its rendition against the declaration in
|
||
effect when it was received, and a verifier refuses a segment of a rendition that was
|
||
not admissible (stream-termination §6.1, `rendition_above_panel`).
|
||
|
||
The check is made before dispatch, as §2's is, and like §2's an unmet declaration is not a
|
||
decode error: the rendition is not chosen.
|
||
|
||
## 5. What this is not
|
||
|
||
- It is **not** a negotiation protocol. There is no pre-flight exchange, no
|
||
controller, and no registry service. The display declaration of §4 is a statement
|
||
the sink makes, which a sender evaluates; nothing answers it. Capability-plus-budget binding before
|
||
execution is already owned by JCP, and duplicating it here would put two
|
||
mechanisms in the tree for one job.
|
||
- It is **not** a transport concern. Constraint evaluation reads values the
|
||
object already declares.
|
||
- It is **not** an energy mechanism. A constraint set says what a sink can
|
||
decode, and a display declaration what it can present; neither says what it
|
||
should spend. What a rendition above the panel would have cost is not claimed
|
||
as saved by this text.
|
||
|
||
## 6. Framing
|
||
|
||
The grammar is thin — close to a JSON-Schema subset — and that is fine. The value
|
||
is not expressiveness; it is that a ratified, register-backed way of saying
|
||
"supported, to here" already exists, and WAI's dispatch, which has only
|
||
"supported", gains a range by adopting it.
|