Some checks failed
WAI conformance / does this change touch it (pull_request) Successful in 5s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 5s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 6s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 8s
WAI energy receipts / does this change touch it (pull_request) Successful in 5s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 5s
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Successful in 6s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 5s
wai-web wasm32 / does this change touch it (pull_request) Successful in 5s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 6s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 27s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m0s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 12s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 25s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m10s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 28s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m17s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m34s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 5m38s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 9m11s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 3m15s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Failing after 18m23s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 18m40s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m48s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 1m46s
wai-pack / wai-pack · linux (pull_request) Successful in 1m41s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 4m14s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 3m18s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m39s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 14m26s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 2m43s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 8m48s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 3m57s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 42m36s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 17m14s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 26s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m6s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 8m1s
wai-quantum studio and desktop / desktop app · macos (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 5.5 <[email protected]>
859 lines
51 KiB
Markdown
859 lines
51 KiB
Markdown
# WAI Extension: Access Services
|
||
|
||
> Status: Draft. Registers the record `wai.access.services`: the access services of a room
|
||
> session, and figures about them that any verifier recomputes from signed records. Captions
|
||
> are [timed-text](timed-text.md)'s, unchanged. This extension adds a **quality figure** for a
|
||
> caption track: its **latency**, the room-clock instant a cue was first shown less the
|
||
> capture instant of the speech it carries; its **stability**, the revisions after first
|
||
> display and the words they changed; and its **accuracy**, the word errors of the first
|
||
> revision shown against a reviewed final revision or a signed reference transcript. Each is
|
||
> defined in integer arithmetic over the signed revisions, so two verifiers reach the same
|
||
> numbers, and a figure a vendor states is checked by recomputing it. **Audio description** is
|
||
> a signed description track, a script of timed descriptions with their mixing instructions
|
||
> (the programme audio ducked under each) and their voicing, a separate audio track or a voice
|
||
> the sink synthesizes, each labelled human or machine; it maps onto a document of the Dubbing
|
||
> and Audio description Profiles of TTML2. **Sign language** is a signing track, a
|
||
> `wai.avatar.pose` stream or the video of a person signing, whose objects are bound by digest
|
||
> to the caption revisions they translate, with a reviewer's optional sign-off. A
|
||
> **completeness claim** states, for a room session, that each access track it declares was
|
||
> delivered complete and in sync, measured from signed times against the tolerances the texts
|
||
> below state; a verifier checks it against the records. No new transport. The reference
|
||
> implementation is the `access_services` module of `wai-rs` (feature `access_services`); the
|
||
> corpus is [`live-conformance/access/`](../live-conformance/access/), and its second
|
||
> implementation is `live-conformance/access_services_verify.py`.
|
||
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
||
>
|
||
> Texts read for this revision, each pinned to the version named: Directive (EU) 2019/882,
|
||
> Annex I, Section IV, point (b)(ii), and Article 31(2), from a reproduction of the text as
|
||
> adopted (the Official Journal could not be fetched for this revision); EN 301 549 V4.1.1
|
||
> (2026-09), clauses 4.2.4, 6.5.2, 6.5.3, 7.1.2, 7.1.5, 7.2.1 to 7.2.3, 7.3, 12.4 and 12.5;
|
||
> Web Content Accessibility Guidelines (WCAG) 2.2, Success Criteria 1.2.2 to 1.2.7; 47 CFR
|
||
> 79.1(j)(2), (j)(3) and (k)(2), and 47 CFR 79.3(a)(3), as in force on 2026-10-01; Dubbing and
|
||
> Audio description Profiles of TTML2 (DAPT), W3C Candidate Recommendation Draft of
|
||
> 2026-06-26 (`CRD-dapt-20260626`), §4.1 to §4.10, §5.2, §5.3, §5.5 to §5.7 and Appendix
|
||
> H.2.2; EBU Tech 3370, EBU-TT Part 3, version 1.0 (May 2017), §2.3.2 and §2.3.3; and two
|
||
> statements of the United Kingdom's communications regulator, *Measuring the quality of live
|
||
> subtitling* (16 October 2013), §1.3, §3.65 to §3.67 and footnote 21, and *Ensuring the
|
||
> quality of TV and on-demand services* (15 April 2024), §3.3, §5.17, §5.23, §5.25, §5.29,
|
||
> §6.2 and §6.14. A section number of one of those texts in this extension is that version's,
|
||
> and is written with the text's name; a bare section number is this extension's. DAPT is a
|
||
> Candidate Recommendation Draft, whose features may change before it is a Recommendation,
|
||
> and one that §5.5 uses is at risk there.
|
||
|
||
## 1. Scope
|
||
|
||
In scope: the records and their encoding (§2); words, and the alignment of two lists of words
|
||
(§3); the quality figure of a caption track: the sources that place its words on the room
|
||
clock, a reference transcript, latency, stability, accuracy, and the figure record (§4);
|
||
audio description: the description record, its script, mixing and voicing, its
|
||
synchronisation, its DAPT document, and what a player owes its listeners (§5); sign language:
|
||
the signing record, its binding to caption revisions, and a review (§6); the completeness
|
||
claim (§7); verification (§8); and what each figure measures in the texts above (§9).
|
||
|
||
Out of scope: a transport; recognising speech, writing descriptions, translating into a sign
|
||
language and synthesizing speech, which produce the content; grading the severity of an
|
||
error, which needs a person (§9); decoding a voicing track or a signing track, whose objects
|
||
this extension names by digest; spoken subtitles and extended audio description, which pause
|
||
or lengthen the programme; how a sink renders a description or a signer; and what any law
|
||
requires.
|
||
|
||
Relationship to the core spec: `wai.access.services` is a **record** ([SPEC](../SPEC.md)
|
||
§5): a signed record a WAI tool emits and verifies. It names no payload format and is not
|
||
dispatchable.
|
||
|
||
Relationship to [timed-text](timed-text.md): captions are its live captions, verified as its
|
||
§4.3 verifies them, and this extension changes nothing in them. The audio description that
|
||
timed-text §1 leaves out of its scope is this extension's §5.
|
||
|
||
Relationship to [avatars](avatars.md) and [capture-binding](capture-binding.md): a signing
|
||
track in pose form is a `wai.avatar.pose` world, whose op batches are its objects (avatars
|
||
§5); a source on a take is placed on the room clock by the take's clock mapping
|
||
(capture-binding §9.3).
|
||
|
||
Relationship to [synthesis](synthesis.md): the origins this extension's records state are a
|
||
caption's, which synthesis §1 maps onto its classes. A description voiced or written by a
|
||
model, and a signing a model generates, is synthesized media in its sense: class
|
||
`synthesized`, step `generate`, with the operation `speech-synthesis` for a voice, and
|
||
oversight `fully_autonomous` for origin `machine` or `human_validated` for origin
|
||
`machine-reviewed` (synthesis §3.1, §3.2). The publisher of such a track signs its origin
|
||
claim there; this extension's label is the same statement, carried where a description or a
|
||
signing is read. A review of §6.4 reviews a translation against caption revisions; a review
|
||
of one exact reconstruction of a generated track, which every exact sink then shows, is
|
||
synthesis §9.1's.
|
||
|
||
Duties this extension supports: the access services of Directive (EU) 2019/882, Annex I,
|
||
Section IV(b)(ii) ("subtitles for the deaf and hard of hearing, audio description, spoken
|
||
subtitles and sign language interpretation … fully transmitted with adequate quality for
|
||
accurate display, and synchronised with sound and video, while allowing for user control of
|
||
their display and use"); EN 301 549 V4.1.1 clauses 7.2.1 to 7.2.3, 7.3 and 12.4, beside the
|
||
caption clauses timed-text §11 answers; WCAG 2.2 Success Criteria 1.2.3, 1.2.5 and 1.2.6,
|
||
beside the caption criteria 1.2.2 and 1.2.4; and the caption quality standards of 47 CFR
|
||
79.1(j). WAI states what its records carry and what a verifier checks. It makes no statement
|
||
about any regime, and a deployment confirms what a regime asks of it against that regime's
|
||
text.
|
||
|
||
## 2. Records
|
||
|
||
Every record of this extension is a JSON object (RFC 8259), read as
|
||
[jwp-receipts](jwp-receipts.md) §3.1 step 1 reads a claim: RFC 8259's grammar, no byte-order
|
||
mark, no member named twice in one object, no `\u` escape that leaves a surrogate unpaired,
|
||
and at most 32 levels of nesting. Its values use the encodings of jwp-receipts §2.4.3: byte
|
||
strings in lowercase hexadecimal; integers unsigned, at most 2^53 − 1, in plain decimal; no
|
||
other number and no boolean. The types in this extension's tables are:
|
||
|
||
- `hex32`, `hex64`: 64 or 128 lowercase hexadecimal digits;
|
||
- `int`: such an integer;
|
||
- `sint`: a **signed integer**, written as a JSON string: `0`, or an optional `-` then a
|
||
digit 1 to 9 then any digits, whose value lies in −2^63 to 2^63 − 1;
|
||
- `string`: a JSON string; `tag`: a string that live-events §4.10 reads as a language tag
|
||
(checked by the rules of the record's section);
|
||
- a list of quoted values: a string equal to one of them;
|
||
- `object`, `array`: as the table under it says; `null`, written where a member may be null.
|
||
|
||
A record has exactly the members its table lists, at every level, none missing and none
|
||
added, each of its type, and a `kind` that names it. One that is not JSON, or does not have
|
||
that shape, is `record_malformed`.
|
||
|
||
Every record carries `signer_pubkey` (`hex32`, the Ed25519 key of RFC 8032 that signs it) and
|
||
`sig` (`hex64`):
|
||
|
||
```
|
||
sig = Ed25519(signer_key, "wai:access\x01" || JCS(record without "sig"))
|
||
record id = SHA-256(JCS(record))
|
||
```
|
||
|
||
JCS is RFC 8785, which on these values reduces to what jwp-receipts §2.4.3 states. The
|
||
signature is verified strictly ([SPEC](../SPEC.md) §7 *Signatures*): a key that fails step 1
|
||
or 2 is `bad_key`, and a signature that fails a later step `bad_signature`. A record is named
|
||
by its record id wherever another names it. A member `room` names the room by its id
|
||
(live-events §2); a record whose `room` is not the verifier's room is `wrong_room`.
|
||
|
||
Which signers a verifier trusts for each kind of record is its policy. This extension checks
|
||
what each record states against the events and the other records; a figure's weight comes
|
||
from its recomputation (§4.7), not from its signer.
|
||
|
||
## 3. Words and their alignment
|
||
|
||
### 3.1 Words
|
||
|
||
The **words** of a text are found in two steps:
|
||
|
||
1. The text is split at every U+0020 and U+000A, and empty pieces are dropped.
|
||
2. In each piece, every code point from U+0041 to U+005A is replaced by the one 0x20 above
|
||
it (ASCII letters to lower case), and code points of the set *P* are removed from its
|
||
start and its end, repeatedly, until it neither starts nor ends with one. A piece left
|
||
empty is dropped; the rest are the words, in order.
|
||
|
||
*P* is U+0021 `!`, U+0022 `"`, U+0027 `'`, U+0028 `(`, U+0029 `)`, U+002C `,`, U+002D `-`,
|
||
U+002E `.`, U+003A `:`, U+003B `;`, U+003F `?`, U+005B `[`, U+005D `]`, U+00A1 `¡`, U+00AB
|
||
`«`, U+00BB `»`, U+00BF `¿`, U+2013 `–`, U+2014 `—`, U+2018 `‘`, U+2019 `’`, U+201C `“`,
|
||
U+201D `”` and U+2026 `…`.
|
||
|
||
No other normalisation is made: letters outside ASCII keep their case, and two words are
|
||
equal when their code points are. The words so found ignore the case of ASCII letters and
|
||
the punctuation at a word's edges, so an error of capitalisation or of such punctuation is
|
||
not a word error here (§9).
|
||
|
||
### 3.2 Alignment
|
||
|
||
The alignment of a **hypothesis** *H* (words *h*₁ … *h*ₘ) to a **reference** *R* (words
|
||
*r*₁ … *r*ₙ) is the table *D* of integers, for 0 ≤ *i* ≤ *m* and 0 ≤ *j* ≤ *n*:
|
||
|
||
- *D*[0][*j*] = *j*, and *D*[*i*][0] = *i*;
|
||
- *D*[*i*][*j*] = the least of *D*[*i* − 1][*j* − 1] + *c*, *D*[*i* − 1][*j*] + 1 and
|
||
*D*[*i*][*j* − 1] + 1, where *c* is 0 when *h*ᵢ = *r*ⱼ and 1 otherwise.
|
||
|
||
Its **end** is a column *j*\*:
|
||
|
||
- a **full** alignment ends at *j*\* = *n*;
|
||
- a **prefix** alignment ends at the greatest *j* for which *D*[*m*][*j*] is the least
|
||
value in row *m*: the reference is read as far as the hypothesis reaches, and no further.
|
||
|
||
Its **errors** are *E* = *D*[*m*][*j*\*] and its **reference words** *N* = *j*\*. They are
|
||
split into substitutions, deletions and insertions by walking back from (*m*, *j*\*) to
|
||
(0, 0), taking at each step the first of these that holds:
|
||
|
||
1. *i* > 0, *j* > 0 and *D*[*i*][*j*] = *D*[*i* − 1][*j* − 1] + *c*: to (*i* − 1, *j* − 1),
|
||
a **substitution** when *c* is 1;
|
||
2. *i* > 0 and *D*[*i*][*j*] = *D*[*i* − 1][*j*] + 1: to (*i* − 1, *j*), an **insertion**
|
||
(a hypothesis word the reference does not have);
|
||
3. otherwise: to (*i*, *j* − 1), a **deletion** (a reference word the hypothesis does not
|
||
have).
|
||
|
||
The substitutions, deletions and insertions add up to *E*.
|
||
|
||
## 4. Caption quality
|
||
|
||
### 4.1 The caption track and its cues
|
||
|
||
A **caption track** is the caption events of one principal *P* in a room's stream, verified
|
||
as [timed-text](timed-text.md) §4.3 verifies them. Its **cues** are the chains of its
|
||
revisions (timed-text §2): each from its first revision *r*₀ to its last *r*ₖ. A cue is named
|
||
by the digest of *r*₀'s `caption` event (live-events §3.2).
|
||
|
||
*P*'s captions are **whole** when *P* has at least one cue, the verifier holds every `seq` of
|
||
*P* from 0 to the last it holds (no delivery gap of *P*, live-events §6.2), and, for every
|
||
cue, *r*ₖ is final and its annotation is not unknown (timed-text §4.3). They are
|
||
**resolved** when they are whole and every *r*ₖ has a `duration_ms` above 0, so that each cue
|
||
resolves (timed-text §4.5). A figure is computed only over whole captions.
|
||
|
||
The **events digest** of *P* is SHA-256 over the digests of *P*'s `caption` events the
|
||
verifier holds, 32 bytes each, in `seq` order.
|
||
|
||
### 4.2 Sources
|
||
|
||
A **sources** record places the words of each cue on the room clock: where the speech the cue
|
||
carries was captured.
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | `"wai-caption-sources"` | |
|
||
| `room` | `hex32` | the room |
|
||
| `principal` | `hex32` | *P*, whose cues it places |
|
||
| `sources` | array | one entry per cue it places, each an object below |
|
||
| `signer_pubkey`, `sig` | | §2 |
|
||
|
||
| member of an entry | type | meaning |
|
||
|---|---|---|
|
||
| `cue` | `hex32` | the cue, by the digest of its first revision |
|
||
| `basis` | `"take"`, `"room"` | what `start` and `end` are measured on |
|
||
| `take` | `hex32` or `null` | for `take`, the take id (capture-binding §3.2); `null` for `room` |
|
||
| `start`, `end` | `int` | the capture of the cue's first word and of its last: device-clock microseconds of the take, or room-clock microseconds |
|
||
|
||
Its signer is whoever aligned the words to the media: the captioner, or anyone holding the
|
||
media afterwards. The alignment of a word to the media is the signer's statement; the
|
||
media's own time is not. On the basis `take`, the instants are positions in the master of a
|
||
take, and the take's clock mapping places them on the room clock: the offset *o* of the
|
||
take's opening commitment (capture-binding §9.3), which the capturing device signed while it
|
||
captured. A **source instant** *d* maps to the room-clock instant *d* + *o*. On the basis
|
||
`room`, the instants are on the room clock as stated.
|
||
|
||
Rules, in order:
|
||
|
||
1. `room` is the verifier's: otherwise `wrong_room`.
|
||
2. No sources record of *P* comes before it in the order given: otherwise
|
||
`record_conflict`.
|
||
3. Each entry: `take` is a `hex32` exactly when `basis` is `take`, and `start` ≤ `end`;
|
||
no cue is named twice: otherwise `record_malformed`.
|
||
4. *P*'s captions are whole (§4.1): otherwise `stream_incomplete`.
|
||
5. Each entry's `cue` names a cue of *P*'s captions: otherwise `source_unknown`.
|
||
6. Each entry on the basis `take`: among the events the verifier accepted there is a
|
||
`take_commit` event whose payload capture-binding §5.2 reads, whose `take` is the entry's
|
||
take, and which is an opening commitment (`n` 0, `phase` 1, capture-binding §5.3); the
|
||
first such in stream order is the take's opening commitment, its author *A* and its
|
||
offset *o*. The take is **derived**: an accepted `control` event whose command is
|
||
`record_start` and whose `target` is *A* has a digest *s* for which SHA-256 of
|
||
`wai:capture-take`, 0x01, the room id, *A* and *s* is the take (capture-binding §3.2).
|
||
And `start` + *o* is not below 0. Otherwise `source_take_unknown`.
|
||
|
||
*P*'s **sources record** is the first sources record of *P* in the order given, and its
|
||
**reference record** the first reference record (§4.3); a later one of either is
|
||
`record_conflict`. Who may start a take, and which device captures for which principal, are
|
||
live-rooms' and capture-binding's checks; this extension uses the take's mapping as
|
||
capture-binding §9.3 defines it, and its bound, *J*, holds where a take verifier gives the
|
||
take `single-take` and `aligned` (capture-binding §9.4, §10).
|
||
|
||
### 4.3 The reference transcript
|
||
|
||
A **reference** record gives, for each cue of *P*, the text a reviewer holds correct.
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | `"wai-caption-reference"` | |
|
||
| `room` | `hex32` | the room |
|
||
| `principal` | `hex32` | *P* |
|
||
| `entries` | array | one per cue, each `{"cue": hex32, "text": string}` |
|
||
| `signer_pubkey`, `sig` | | §2 |
|
||
|
||
Rules, in order: `room` is the verifier's (`wrong_room`); no reference record of *P* comes
|
||
before it in the order given (`record_conflict`); no cue is named twice (`record_malformed`);
|
||
each text meets timed-text §3.2 rules 1 to 3 (`text_not_in_subset`); *P*'s captions are whole
|
||
(`stream_incomplete`); each entry names a cue of *P* (`reference_unknown`); and every cue of
|
||
*P* has an entry (`reference_incomplete`).
|
||
|
||
### 4.4 Latency
|
||
|
||
The latency of a cue that a sources entry places is *L* = `t`(*r*₀) − *S*, in microseconds,
|
||
where `t`(*r*₀) is the room-clock instant its first revision was shown from (timed-text
|
||
§4.1) and *S* is its entry's `start` on the room clock (§4.2). *L* is negative when the
|
||
caption was shown before the speech began.
|
||
|
||
Over the cues of *P* that the sources record places, *n* of them, with their latencies in
|
||
ascending order *L*₁ ≤ … ≤ *L*ₙ:
|
||
|
||
- `min` = *L*₁, `max` = *L*ₙ;
|
||
- `mean` = ⌊(*L*₁ + … + *L*ₙ) / *n*⌋, rounded toward negative infinity;
|
||
- `p50` and `p95`: the latency at rank ⌈50 × *n* / 100⌉ and ⌈95 × *n* / 100⌉, counting
|
||
from 1.
|
||
|
||
Each is `null` when *n* is 0. The **class** of the latency is `none` when *n* is 0;
|
||
otherwise `capture` when every entry is on the basis `take`, and `stated` when any is on the
|
||
basis `room`.
|
||
|
||
### 4.5 Stability
|
||
|
||
For one cue, its **revisions** are *k*, the revisions after the first, and its **words
|
||
changed** the sum, over each revision *r*ᵢ and the one that supersedes it *r*ᵢ₊₁, of the
|
||
substitutions and insertions of the full alignment of the words of *r*ᵢ (the hypothesis) to
|
||
the words of *r*ᵢ₊₁ (the reference): the words a viewer saw that the next revision did not
|
||
keep. A word added at the end, as a partial grows, is a deletion there and is not counted.
|
||
|
||
The track's figures are the sums over its cues of revisions and of words changed, and
|
||
`cues_corrected`, the number of cues whose words changed is above 0.
|
||
|
||
### 4.6 Accuracy
|
||
|
||
The reference of a cue is its entry's text in *P*'s reference record, when *P* has one;
|
||
otherwise the text of *r*ₖ, the cue's final revision. The **class** of the accuracy is:
|
||
|
||
- `transcript` when *P* has a reference record;
|
||
- `reviewed` when it has none and every cue's *r*ₖ has origin 1 (human) or 3
|
||
(machine-reviewed): a person wrote or reviewed the reference;
|
||
- `self` otherwise: the reference is the machine's own final text, and the figure measures
|
||
how far its first display was from its own last.
|
||
|
||
Two figures, each the sums over the cues of the counts of §3.2:
|
||
|
||
- `first`: the prefix alignment of the words of *r*₀ to the words of the reference. It counts
|
||
the errors in what the viewer first saw, against as much of the reference as that revision
|
||
reaches, so the words a partial has not reached yet are not errors.
|
||
- `final`: the full alignment of the words of *r*ₖ to the words of the reference, when the
|
||
class is `transcript`; `null` otherwise.
|
||
|
||
Each is `{"words", "errors", "substitutions", "deletions", "insertions"}`: *N*, *E* and its
|
||
three parts.
|
||
|
||
### 4.7 The figure
|
||
|
||
A **quality** record states the figures of *P*'s track.
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | `"wai-caption-quality"` | |
|
||
| `room` | `hex32` | the room |
|
||
| `principal` | `hex32` | *P* |
|
||
| `events` | `hex32` | *P*'s events digest (§4.1) |
|
||
| `sources` | `hex32` or `null` | the record id of *P*'s sources record, or `null` when there is none |
|
||
| `reference` | `hex32` or `null` | likewise, of its reference record |
|
||
| `cues` | `int` | the number of *P*'s cues |
|
||
| `latency` | object | `{"class", "n", "min", "max", "mean", "p50", "p95"}`: a string of §4.4, an `int`, and five `sint` or `null` |
|
||
| `stability` | object | `{"revisions", "words_changed", "cues_corrected"}`, each an `int` |
|
||
| `accuracy` | object | `{"class", "first", "final"}`: a string of §4.6, an object of §4.6, and one or `null` |
|
||
| `signer_pubkey`, `sig` | | §2 |
|
||
|
||
Rules, in order:
|
||
|
||
1. `room` is the verifier's: otherwise `wrong_room`.
|
||
2. *P*'s captions are whole (§4.1): otherwise `stream_incomplete`.
|
||
3. `events`, `sources` and `reference` are as the table says: otherwise
|
||
`figure_inputs_mismatch`.
|
||
4. Every other member but `kind`, `signer_pubkey` and `sig` equals the figure the verifier
|
||
computes from §4.4 to §4.6: otherwise `figure_mismatch`.
|
||
|
||
A figure that passes is the figure of exactly those revisions, placed by exactly those
|
||
sources and measured against exactly that reference. A verifier needs no record of its own to
|
||
compute a figure: the **figure** of a whole track is the object a quality record would carry,
|
||
without `kind`, `signer_pubkey` and `sig`.
|
||
|
||
## 5. Audio description
|
||
|
||
### 5.1 The description record
|
||
|
||
A **description** record is an audio description track: a script of timed descriptions of
|
||
what is seen, the mixing of each into the programme audio, and its voicing. Times are media
|
||
time in milliseconds, on the timeline of the media the descriptions accompany, as
|
||
timed-text §2 defines it.
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | `"wai-description"` | |
|
||
| `lang` | `tag` | the language of the descriptions |
|
||
| `script` | object | `{"origin", "model"}`: who wrote the descriptions |
|
||
| `voicing` | object | `{"form", "origin", "model", "track"}`: who or what speaks them |
|
||
| `events` | array | the descriptions, each an object below |
|
||
| `signer_pubkey`, `sig` | | §2 |
|
||
|
||
`origin` is `"human"`, `"machine"` or `"machine-reviewed"`, the names timed-text §10.5 gives
|
||
the origins of a caption, and `model` is a `hex32` naming the model that wrote or spoke the
|
||
text, or `null`. `form` is `"track"`, the voicing is a separate audio track named by `track`
|
||
(a `hex32`, the track's digest, live-rooms §6.2), or `"sink"`, the sink synthesizes the
|
||
voice from the text with the model `model`, and `track` is `null`.
|
||
|
||
| member of an event | type | meaning |
|
||
|---|---|---|
|
||
| `id` | `string` | its identifier |
|
||
| `begin`, `end` | `int` | the interval it describes, the description's time slot |
|
||
| `represents` | `"visual"`, `"visual.nonText"`, `"visual.text"`, `"visual.text.title"`, `"visual.text.credit"`, `"visual.text.location"`, `"visual.dialogue"` | what of the image it describes: DAPT's content descriptors of the visual image (DAPT §4.7 and Appendix H.2.2) |
|
||
| `text` | `string` | the description |
|
||
| `duck` | object | `{"gain", "ramp"}`, each an `int`: the programme audio's gain under the description in thousandths, and the milliseconds it takes to fall to it and to rise back |
|
||
| `voice` | object or `null` | `{"begin", "end"}`, each an `int`: where the voicing track speaks it; `null` when the form is `sink`, or when the track has not voiced it |
|
||
|
||
### 5.2 Rules
|
||
|
||
In order; the first that fails names the refusal:
|
||
|
||
1. `lang` reads as live-events §4.10 reads a tag: otherwise `description_malformed`.
|
||
2. `script.model` is a `hex32` exactly when `script.origin` is `machine` or
|
||
`machine-reviewed`; likewise `voicing.model` for `voicing.origin`; `voicing.track` is a
|
||
`hex32` exactly when `form` is `track`; and when `form` is `sink`, `voicing.origin` is not
|
||
`human`: otherwise `description_malformed`.
|
||
3. There is at least one event; each `id` is one of `A`–`Z`, `a`–`z` or `_`, then up to 63
|
||
of those, `0`–`9`, `.` and `-`; no `id` twice; each `begin` < `end` ≤ 359 999 999; each
|
||
event's `begin` is at or after the `end` of the event before it (one voice describes one
|
||
thing at a time): otherwise `description_malformed`.
|
||
4. Each `text` meets timed-text §3.2 rules 1 to 3: otherwise `text_not_in_subset`.
|
||
5. Each `duck`: `gain` ≤ 1000; `ramp` is 0 when `gain` is 1000 and above 0 otherwise; and
|
||
2 × `ramp` ≤ `end` − `begin`. Each `voice`: `null` when the form is `sink`, and otherwise
|
||
`null` or within its event, the event's `begin` ≤ `voice.begin` < `voice.end` ≤ the
|
||
event's `end`, since a Script Event's audio is truncated at its end (DAPT §4.9.1):
|
||
otherwise `description_malformed`.
|
||
6. The synchronisation of §5.3: otherwise `description_out_of_sync`.
|
||
|
||
### 5.3 Synchronisation
|
||
|
||
The programme audio falls to the event's gain from `begin` to `begin` + `ramp`, and rises
|
||
back from `end` − `ramp` to `end`. The description is **spoken** over the interval between,
|
||
from *a* = `begin` + `ramp` to *z* = `end` − `ramp`. Of a voiced event (its `voice` not `null`):
|
||
|
||
- `voice.begin` ≥ *a* − 35 and `voice.begin` ≤ *a* + 45;
|
||
- `voice.end` ≤ *z* + 45.
|
||
|
||
These are DAPT §5.5's bounds on a presentation processor: audio presentation changes no more
|
||
than 35 ms before the time a document specifies and no more than 45 ms after it, which DAPT
|
||
derives from EBU R 37's bounds on audio relative to image. A voice that starts before the
|
||
programme audio has fallen, or runs on after it has risen, is out of those bounds. EN 301 549
|
||
V4.1.1 clause 7.2.2 requires the synchronisation to be preserved and states no figure.
|
||
|
||
The **offset** of a voiced event is `voice.begin` − *a*, a signed number of milliseconds;
|
||
an unvoiced event has none.
|
||
|
||
### 5.4 Description over dialogue
|
||
|
||
A description is spoken in the pauses of the dialogue (47 CFR 79.3(a)(3): "into natural
|
||
pauses between the program's dialogue"), though the regulator's 2024 statement accepts
|
||
describing over dialogue where what is seen matters more (§6.14 there). So this is a figure,
|
||
not a refusal. Against the dialogue of one or more caption tracks, whose resolved cues
|
||
(timed-text §4.5) cover the union *U* of their intervals, each from its `start` up to, not
|
||
including, its `end`, an event's **overlap** is the milliseconds of its spoken interval that lie
|
||
in *U*: from `voice.begin` up to `voice.end` when it is voiced, and from *a* up to *z*
|
||
otherwise. The figure is the sum of the overlaps and the
|
||
number of events whose overlap is above 0.
|
||
|
||
### 5.5 The DAPT document
|
||
|
||
A description record maps onto one DAPT document, given, for the form `track`, the voicing
|
||
track's URI `U` and media type `T`, each one to 2048 of the ASCII characters `!` to `~`
|
||
other than `"`, `&`, `<` and `>` (otherwise `parameter_malformed`). It is written as UTF-8
|
||
with U+000A line ends:
|
||
|
||
```
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<tt xmlns="http://www.w3.org/ns/ttml" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:tta="http://www.w3.org/ns/ttml#audio" xmlns:daptm="http://www.w3.org/ns/ttml/profile/dapt#metadata" xmlns:wai="tag:transaction.science,2026:wai/access" xml:lang="LANG" ttp:contentProfiles="http://www.w3.org/ns/ttml/profile/dapt1.0/content" daptm:langSrc="zxx" daptm:scriptRepresents="REPS" daptm:scriptType="TYPE" wai:script="SO" wai:voice="VO">
|
||
<body>
|
||
EVENTS
|
||
</body>
|
||
</tt>
|
||
```
|
||
|
||
- `LANG` is `lang`. `REPS` is each `represents` value of the events once, in the order each
|
||
first appears, joined by U+0020: every event's value is then one of them (DAPT §4.1.1).
|
||
`TYPE` is `asRecorded` for the form `track` and `preRecording` for the form `sink`.
|
||
- `SO` and `VO` are the script's and the voicing's origins. After `wai:script="SO"` comes
|
||
` wai:script-model="M"` when the script has a model, and after `wai:voice="VO"`,
|
||
` wai:voice-model="M"` when the voicing has one, `M` the digest in lowercase hexadecimal.
|
||
- `EVENTS` is, for each event in order:
|
||
|
||
```
|
||
<div xml:id="ID" begin="B" end="E" daptm:represents="R">
|
||
<animate begin="00:00:00.000" end="RAMP" tta:gain="1;G" fill="freeze"/>
|
||
<animate begin="FALL" end="DUR" tta:gain="G;1"/>
|
||
<p>CONTENT</p>
|
||
</div>
|
||
```
|
||
|
||
`B` and `E` are `begin` and `end` written `HH:MM:SS.mmm` (timed-text §5.1); `RAMP`, `FALL`
|
||
and `DUR` are `ramp`, `end` − `begin` − `ramp` and `end` − `begin`, written the same way;
|
||
`G` is the gain: `0` for 0, and otherwise `0.` and its three decimal digits with trailing
|
||
zeros removed. The two `animate` lines are written only when the gain is below 1000.
|
||
- `CONTENT` is the text, its lines separated by `<br/>` and `&`, `<` and `>` written `&`,
|
||
`<` and `>`:
|
||
- for the form `track` and a voiced event,
|
||
`<span begin="VB" end="VE"><audio src="U" type="T" clipBegin="CB" clipEnd="CE"/>TEXT</span>`,
|
||
with `VB` = `voice.begin` − `begin`, `VE` = `voice.end` − `begin`, `CB` = `voice.begin`
|
||
and `CE` = `voice.end`, each written `HH:MM:SS.mmm`. The voicing track is on the
|
||
programme's timeline (an audio description stem), so the event's audio is the interval
|
||
of it that the event's voice states;
|
||
- for the form `track` and an event not yet voiced, the text alone;
|
||
- for the form `sink`, `<span tta:speak="normal">TEXT</span>`.
|
||
|
||
The document's features are DAPT's: a Script Event per description, a `div` with `xml:id`,
|
||
`begin`, `end` and `daptm:represents` (DAPT §4.3); its Mixing Instructions as `animate`
|
||
children of the Script Event, which adjust the programme audio during it (DAPT §4.3, §4.10);
|
||
an Audio Recording by `src` and `type` with `clipBegin` and `clipEnd` (DAPT §4.9.1); and
|
||
Synthesized Audio by `tta:speak` (DAPT §4.9.2). `ttp:contentProfiles` names the DAPT content
|
||
profile, and no `ttp:profile` is written (DAPT §5.6). The document's time base is media time,
|
||
times are clock times without frames (DAPT §5.7), and `daptm:langSrc` is `zxx`, content
|
||
without an inherent language (DAPT §4.5). Two choices are this extension's:
|
||
|
||
- `src` on `audio`, for an external resource, is at risk in the Candidate Recommendation
|
||
(its Issue 218). If it does not stay, a later revision of this mapping names the voicing
|
||
track another way DAPT §4.9.1 keeps.
|
||
- For the form `sink`, DAPT says a pre-recording script SHOULD NOT contain Audio objects, and
|
||
an as-recorded script SHOULD NOT contain Synthesized Audio. There is no recording: the
|
||
sink's voice is the recording. The document is the script it speaks, marked as one, with
|
||
`tta:speak` saying that it is to be spoken.
|
||
|
||
The attributes in the namespace `tag:transaction.science,2026:wai/access` are foreign
|
||
vocabulary, which DAPT §5.2 has a processor keep or prune. They carry the origin labels of
|
||
§5.6, which DAPT has no field for.
|
||
|
||
### 5.6 Obligations of a WAI player
|
||
|
||
These are requirements on a WAI player that plays audio description or shows sign language.
|
||
Each cites the provision it answers by identifier; they are engineering requirements, and
|
||
meeting them is not a statement about any law.
|
||
|
||
1. **Description can be played.** A player of video with synchronised audio MUST let the
|
||
listener select an available description track and play it to the default audio output
|
||
(EN 301 549 V4.1.1 clause 7.2.1; WCAG 2.2 Success Criteria 1.2.3 and 1.2.5, which ask
|
||
content to provide it).
|
||
2. **In sync.** A player that mixes a description MUST apply its mixing instructions and play
|
||
each voice at the times its event states, within §5.3's bounds (EN 301 549 V4.1.1 clause
|
||
7.2.2).
|
||
3. **Preserved.** A player or converter that transmits, converts or records a description MUST
|
||
keep every event's timing, text, mixing instructions, voicing and labels (EN 301 549 V4.1.1
|
||
clause 7.2.3): §5.5's document keeps them all.
|
||
4. **One operation.** A player whose purpose is video MUST offer turning description on and
|
||
off as a single operation, at the same level as the volume control (EN 301 549 V4.1.1
|
||
clause 7.3), as timed-text §11 item 5 has it for captions.
|
||
5. **Labelled.** A player MUST show, with a description whose voicing is `machine` or
|
||
`machine-reviewed`, that the voice is synthesized, in a way the listener perceives without
|
||
turning on another feature, as timed-text §11 item 7 has it for a machine caption, and
|
||
SHOULD let the listener learn whether the script was machine-written. The script's origin
|
||
and the voicing's are the description's labels, as a caption's origin is its label
|
||
(timed-text §10.1); a synthesized voice's origin, with the model's digest, is the statement
|
||
its origin claim makes of it (synthesis §3.1), and a player shows its label as synthesis
|
||
§10 has it show a synthesized object's.
|
||
6. **Signing under the viewer's control.** A player that shows a signing track MUST let the
|
||
viewer choose to show it, and SHOULD let the viewer choose its size and position (Directive
|
||
(EU) 2019/882 Annex I Section IV(b)(ii), "user control of their display"); a pose stream
|
||
leaves both to the sink (§6.1). It MUST show, with a signing track whose origin is
|
||
`machine` or `machine-reviewed`, that the signing is generated.
|
||
|
||
## 6. Sign language
|
||
|
||
### 6.1 The signing record
|
||
|
||
A **signing** record is a sign language track: a `wai.avatar.pose` stream (avatars §1), or a
|
||
video track of a person signing. Its objects are bound, by digest, to the caption revisions
|
||
they translate.
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | `"wai-signing"` | |
|
||
| `room` | `hex32` | the room |
|
||
| `lang` | `tag` | the sign language |
|
||
| `source` | `hex32` | the principal of the caption track it translates |
|
||
| `form` | `"pose"`, `"video"` | an avatar pose stream, or a video of a signer |
|
||
| `track` | `hex32` | the track's digest (live-rooms §6.2) |
|
||
| `origin`, `model` | | as §5.1: `human` for a person signing (filmed, or motion-captured into the pose stream), `machine` for signing a model generated |
|
||
| `video` | object or `null` | for `video`, `{"width", "height", "rate_num", "rate_den"}`, each an `int`: its picture size and frame rate; `null` for `pose` |
|
||
| `segments` | array | each an object below |
|
||
| `signer_pubkey`, `sig` | | §2 |
|
||
|
||
| member of a segment | type | meaning |
|
||
|---|---|---|
|
||
| `object` | `hex32` | the content hash of an object of the track (jwp-receipts §2.1): an op batch of the pose world, or a video object |
|
||
| `start`, `end` | `int` | room-clock microseconds the signing of the object spans |
|
||
| `revisions` | array of `hex32` | the caption revisions it translates, by the digest of each `caption` event |
|
||
|
||
Pose-equivalence (avatars §4) makes the motion every sink shows the motion in the bound
|
||
objects, while the appearance is the sink's: a viewer may choose the signer's size, place
|
||
and appearance, which Directive (EU) 2019/882 Annex I Section IV(b)(ii) calls user control of
|
||
display, and the binding still holds.
|
||
|
||
### 6.2 Rules
|
||
|
||
In order:
|
||
|
||
1. `room` is the verifier's: otherwise `wrong_room`.
|
||
2. `lang` reads as a tag; `model` is a `hex32` exactly when `origin` is `machine` or
|
||
`machine-reviewed`; `video` is `null` exactly for `pose`, and its four numbers are above 0;
|
||
there is at least one segment, each with `start` < `end` and at least one revision, each
|
||
segment's `start` at or after the `end` of the segment before it; and no revision is
|
||
named twice in the record: otherwise `signing_malformed`.
|
||
3. `source`'s captions are whole (§4.1): otherwise `stream_incomplete`.
|
||
4. Each named revision is a `caption` event of `source` that the verifier holds: otherwise
|
||
`sign_revision_unknown`.
|
||
5. Each named revision is the last of its cue and final, its annotation not unknown: otherwise
|
||
`sign_revision_not_final`. Signing translates the text a cue resolves to; a partial that a
|
||
later revision changed is not what the captions say.
|
||
|
||
### 6.3 Figures
|
||
|
||
- The **offset** of a segment is its `start` less *S* (§4.4) of the earliest cue, by its
|
||
first revision's `t`, among those whose final revisions it names, when `source`'s sources
|
||
record places that cue; it has none otherwise. It is a signed number of microseconds: the
|
||
delay of the signing behind the speech it interprets.
|
||
- For the form `video`, the **video floor** is `meets` when the picture is at least 320 by 240
|
||
in either orientation (the smaller side at least 240 and the larger at least 320) and the
|
||
frame rate at least 20 a second (`rate_num` ≥ 20 × `rate_den`), and `below` otherwise: the
|
||
resolution and frame rate EN 301 549 V4.1.1 clauses 6.5.2 and 6.5.3 require of real-time
|
||
video communication, which its clause 4.2.4 NOTE 3 names for sign language that accompanies
|
||
audiovisual content. For the form `pose` it is `null`: the sink renders the signer at the
|
||
size it chooses.
|
||
|
||
### 6.4 Review
|
||
|
||
A person who reviews the translation signs a **review**:
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | `"wai-signing-review"` | |
|
||
| `signing` | `hex32` | the record id of the signing record it reviews |
|
||
| `scope` | `"translation"` | what was reviewed: the signing against the caption revisions it is bound to |
|
||
| `verdict` | `"approved"`, `"approved-with-notes"`, `"rejected"` | |
|
||
| `notes` | `hex32` or `null` | the digest of the reviewer's notes; `null` exactly for `approved` |
|
||
| `signer_pubkey`, `sig` | | §2 |
|
||
|
||
Rules: `notes` is `null` exactly when the verdict is `approved` (`record_malformed`), and
|
||
`signing` is the record id of a signing record the verifier holds (`review_subject_unknown`).
|
||
The review binds the objects by their digests, so, for a pose stream, every viewer whose sink
|
||
is pose-equivalent sees the motion the reviewer approved. Its vocabulary is synthesis §9.1's
|
||
review with the scope `translation`; that review binds one reconstruction of a synthesized
|
||
object, and this one binds a signing record to the caption revisions it translates.
|
||
|
||
## 7. The completeness claim
|
||
|
||
### 7.1 The record
|
||
|
||
A **completeness** claim states, for a room session, which access tracks it carried, and that
|
||
each was delivered complete and in sync.
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `kind` | `"wai-access-completeness"` | |
|
||
| `room` | `hex32` | the room |
|
||
| `from`, `to` | `int` | the session, from `from` up to, not including, `to`, in room-clock microseconds |
|
||
| `pt0` | `int` | the media time of the room's `t0`, in milliseconds (timed-text §2) |
|
||
| `tracks` | array | the access tracks it declares, each an object below |
|
||
| `signer_pubkey`, `sig` | | §2 |
|
||
|
||
| service | its members besides `service` |
|
||
|---|---|
|
||
| `"captions"` | `principal` (`hex32`), `lang` (`tag`), `latency_mean_max` and `latency_max` (each `int` or `null`, microseconds) |
|
||
| `"audio-description"` | `record` (`hex32`, a description record's id), `lang` (`tag`) |
|
||
| `"sign-language"` | `record` (`hex32`, a signing record's id), `lang` (`tag`), `review` (`hex32` or `null`, a review's id), `offset_max` (`int` or `null`, microseconds) |
|
||
|
||
The tracks a claim declares are the availability of access services an electronic programme
|
||
guide states (EN 301 549 V4.1.1 clauses 12.4 and 12.5), made checkable.
|
||
|
||
A cue of *P* is **in the session** when its first revision's `t` is at or after `from` and
|
||
before `to`. The
|
||
session's media interval is from `pt0` + ⌊`from` / 1000⌋ to `pt0` + ⌊`to` / 1000⌋.
|
||
|
||
### 7.2 Checking the claim
|
||
|
||
1. `room` is the verifier's: otherwise `wrong_room`.
|
||
2. `from` < `to`; at least one track; each track's `lang` reads; no principal is named by two
|
||
caption tracks, and no record by two tracks: otherwise `claim_malformed`.
|
||
|
||
Then each track in order, the first failure naming the refusal:
|
||
|
||
**Captions**, of principal *P*:
|
||
|
||
1. *P* has a cue in the session: otherwise `track_missing`.
|
||
2. *P*'s captions are resolved (§4.1): otherwise `track_incomplete`. A delivery gap is an
|
||
event not delivered, and a cue that does not resolve was not finished.
|
||
3. Every revision of every cue of *P* in the session has the track's `lang`: otherwise
|
||
`track_mismatch`.
|
||
4. When `latency_mean_max` or `latency_max` is not `null`: *P*'s sources record places every
|
||
cue of *P* in the session, otherwise `sync_unmeasured`; and over those cues the mean
|
||
latency (§4.4) is at most `latency_mean_max`, and each latency at most `latency_max`, where
|
||
each is given: otherwise `out_of_sync`.
|
||
|
||
**Audio description**, of record *D*:
|
||
|
||
1. *D* is a description record the verifier holds: otherwise `track_missing`.
|
||
2. Its `lang` is the track's, and each of its events lies in the session's media interval:
|
||
otherwise `track_mismatch`.
|
||
3. For the form `track`, every event is voiced: otherwise `track_incomplete`. (Each voice is
|
||
already in sync, §5.3.)
|
||
|
||
**Sign language**, of record *G*:
|
||
|
||
1. *G* is a signing record the verifier holds: otherwise `track_missing`.
|
||
2. Its `lang` is the track's, and its `source` is the principal of a caption track of this
|
||
claim: otherwise `track_mismatch`.
|
||
3. Every cue of `source` in the session has its final revision named by a segment of *G*:
|
||
otherwise `track_incomplete`.
|
||
4. When `review` is not `null`: it is the id of a review the verifier holds (otherwise
|
||
`review_missing`), which names *G* (otherwise `review_mismatch`) and whose verdict is not
|
||
`rejected` (otherwise `review_rejected`).
|
||
5. When `offset_max` is not `null`: every segment of *G* has an offset (§6.3), otherwise
|
||
`sync_unmeasured`; and each offset's absolute value is at most `offset_max`, otherwise
|
||
`out_of_sync`.
|
||
|
||
A claim that passes is **held**. Its **dialogue overlap** is, for each audio description
|
||
track, §5.4's figure against the resolved cues of the claim's caption tracks, their media
|
||
times as timed-text §4.5 gives them with the claim's `pt0`.
|
||
|
||
### 7.3 The tolerances
|
||
|
||
| track | measured from | tolerance | stated by |
|
||
|---|---|---|---|
|
||
| captions, live | each cue's first display and its source (§4.4) | a mean of at most 4.5 s across live programming: a recommendation, not a limit per programme | the regulator's 2024 statement, §5.17 and §5.25; its 2013 statement (§3.65 to §3.67) recorded the earlier guidance of at most 3 s |
|
||
| captions, shown by a player | a cue's time | within 100 ms of it, 20 ms as good practice | EN 301 549 V4.1.1 clause 7.1.2: the player's, timed-text §11 item 2 |
|
||
| audio description | each voice and its event (§5.3) | 35 ms early to 45 ms late | DAPT §5.5, from EBU R 37 |
|
||
| sign language | each segment and its source (§6.3) | none stated | no text read for this revision gives a figure; EN 301 549 V4.1.1 clause 4.2.4 NOTE 3 asks only that it be "well synchronized with the spoken content" |
|
||
|
||
A claim states the caption and sign tolerances it is held to (`latency_mean_max`,
|
||
`latency_max`, `offset_max`); the description tolerance is fixed by §5.3. The captions'
|
||
mean is computed over the session, while the 2024 statement's is over a provider's live
|
||
programming taken together; a claim that states 4 500 000 holds one session to it.
|
||
|
||
## 8. Verification
|
||
|
||
### 8.1 Inputs
|
||
|
||
A verifier is given the room id; the records of the room's event stream, in stream order
|
||
(live-events §6); and the records of this extension, as JSON texts, in the order given.
|
||
|
||
### 8.2 Steps
|
||
|
||
1. **Events.** Each event record is offered, in stream order, to a verifier of captions
|
||
([timed-text](timed-text.md) §4.3), which verifies it as live-events §6 does and the
|
||
captions in it as timed-text §4.3 does. A refusal is the outcome, at `events` and the
|
||
record's index, with that extension's reason. At the end of the stream the captions are
|
||
finished (timed-text §4.3), and the gaps, which are not refusals, are noted.
|
||
2. **Reading.** Each record is read (§2), its signature verified and its record id computed,
|
||
in the order given: a failure is the outcome, at `record` and the record's index.
|
||
3. **Rules.** Then each record is checked by its section's rules, kind by kind in this
|
||
order, and the records of one kind in the order given: sources (§4.2), references
|
||
(§4.3), descriptions (§5.2), signings (§6.2), reviews (§6.4), quality records (§4.7) and
|
||
claims (§7.2). So a record that another names has been checked before it. The first
|
||
failure is the outcome, at `record` and the failing record's index.
|
||
4. **Figures.** With no refusal, the outcome is **accept**, with: the figure (§4.7) of every
|
||
principal whose captions are whole, in the order of each one's first `caption` event in
|
||
the stream; for
|
||
each description record, its number of events, the number voiced and each event's offset
|
||
(§5.3); for each signing record, its number of segments and of revisions named, each
|
||
segment's offset and its video floor (§6.3); and for each claim, its dialogue overlap
|
||
(§7.2).
|
||
|
||
## 9. What the figures measure
|
||
|
||
| figure | what it measures | in the texts read |
|
||
|---|---|---|
|
||
| latency: per cue, its mean, its range (`min`, `max`) and two ranks | first display on the room clock, less the capture of the first word the cue carries | the 2013 statement's "average latency of the subtitling (the delay between speech and live subtitling), and the range of latencies" (§1.3(b)); the 2024 statement's mean (§5.17, §5.25); 47 CFR 79.1(k)(2)(vi), "lag between the spoken word supplied by the program origination point and when captions are received at the same program origination point", which the room clock's `t`, stamped as the caption leaves its author, measures; 79.1(j)(2)(ii) and (j)(3)(ii); EBU Tech 3370 §2.3.2's authoring delay, from the subtitler hearing the audio to the tool's output, and its §2.3.3 `ebuttm:authoringDelay`, which a producer may state and this figure measures |
|
||
| stability: revisions after first display, words changed, cues corrected | what the viewer saw that a later revision changed | the 2024 statement's research finding that subtitles corrected live on air distract (§5.23) |
|
||
| accuracy: words, errors, and their kinds | word errors against a reference a person wrote or reviewed | 47 CFR 79.1(k)(2)(iv): accuracy is the total words less the errors, over the total words, which is (*N* − *E*) / *N* here, and (k)(2)(v)'s kinds of error, of which this figure counts incorrect and missing words; 79.1(j)(2)(i); the 2013 statement's "number and type of errors" (§1.3(c)); the 2024 statement sets no minimum accuracy (§5.29) |
|
||
| dialogue overlap | description spoken over captioned dialogue | 47 CFR 79.3(a)(3); the 2024 statement §6.2 and §6.14 |
|
||
| completeness | every declared track present, every cue finished, every event voiced and every cue signed | Directive (EU) 2019/882 Annex I Section IV(b)(ii), "fully transmitted … synchronised"; 47 CFR 79.1(j)(2)(iii), captioning "from the beginning to the end of the program", which this claim checks over the cues the session holds, not over the speech it does not hold |
|
||
|
||
Not computed here:
|
||
|
||
- the severity of an error, which the error-classification model the 2013 statement's
|
||
measurement used (its footnote 21) grades minor, standard or serious: that grading needs a
|
||
person. The alignment gives the errors and the reference words a grader starts from;
|
||
- errors of capitalisation and of punctuation at a word's edge, which §3.1 removes, and which
|
||
47 CFR 79.1(j)(2)(i) counts;
|
||
- the speed of the captions, and their placement (79.1(j)(2)(iv));
|
||
- the quality of a description, of a voice or of a signing, which a person judges, and
|
||
whose judgement a review records.
|
||
|
||
## 10. Reasons
|
||
|
||
| reason | raised at |
|
||
|---|---|
|
||
| `record_malformed` | §2, §4.2, §4.3, §6.4 |
|
||
| `bad_key` | §2 |
|
||
| `bad_signature` | §2 |
|
||
| `wrong_room` | §2, §4.2, §4.3, §4.7, §6.2, §7.2 |
|
||
| `record_conflict` | §4.2, §4.3 |
|
||
| `source_unknown` | §4.2 |
|
||
| `source_take_unknown` | §4.2 |
|
||
| `text_not_in_subset` | §4.3, §5.2 |
|
||
| `reference_unknown` | §4.3 |
|
||
| `reference_incomplete` | §4.3 |
|
||
| `stream_incomplete` | §4.2, §4.3, §4.7, §6.2 |
|
||
| `figure_inputs_mismatch` | §4.7 |
|
||
| `figure_mismatch` | §4.7 |
|
||
| `description_malformed` | §5.2 |
|
||
| `description_out_of_sync` | §5.2, §5.3 |
|
||
| `parameter_malformed` | §5.5 |
|
||
| `signing_malformed` | §6.2 |
|
||
| `sign_revision_unknown` | §6.2 |
|
||
| `sign_revision_not_final` | §6.2 |
|
||
| `review_subject_unknown` | §6.4 |
|
||
| `claim_malformed` | §7.2 |
|
||
| `track_missing` | §7.2 |
|
||
| `track_incomplete` | §7.2 |
|
||
| `track_mismatch` | §7.2 |
|
||
| `sync_unmeasured` | §7.2 |
|
||
| `out_of_sync` | §7.2 |
|
||
| `review_missing` | §7.2 |
|
||
| `review_mismatch` | §7.2 |
|
||
| `review_rejected` | §7.2 |
|
||
|
||
An event record that [live-events](live-events.md) or [timed-text](timed-text.md) refuses
|
||
keeps that extension's reason.
|
||
|
||
## 11. Conformance
|
||
|
||
[`live-conformance/access/`](../live-conformance/access/) holds the corpus, written from fixed
|
||
seeds by `wai_access_services_vectors gen`: `vectors.json`, and each description record's DAPT
|
||
document as a file of its own, `NAME.dapt.ttml`. Each vector is a room's event stream and the
|
||
records of this extension, with the outcome §8 gives them and, when accepted, every figure. It
|
||
has:
|
||
|
||
- **accepted sessions**: a lesson with a human captioner, a machine captioner whose partials
|
||
are revised to final, a capture take placing the machine captions' words, a reference
|
||
transcript, a quality record for each track, a description voiced on a separate track, a
|
||
motion-captured signer bound to the human captions with an approved review, and a claim over
|
||
all of them held to the 2024 statement's mean; a session whose machine captions a person
|
||
reviews, with a description the sink voices by a pinned model, the video of a signer, and a
|
||
claim without latency bounds; and a session with no sources, whose latency class is `none`;
|
||
- **negative controls**, each a copy of an accepted session with one defect, and each refused
|
||
with its reason: a latency figure misstated, a broken revision chain, a sign track bound to a
|
||
revision a later one superseded and to a revision the stream does not hold, a description
|
||
spoken late and one spoken early, a claim over a track the verifier does not hold, and one
|
||
for every other reason of §10.
|
||
|
||
A conforming verifier gives every vector the outcome, the reason, the place and every figure
|
||
the corpus states, and writes every DAPT document byte for byte. `wai_access_services_vectors
|
||
verify` and the test `tests/access_services.rs` check that every file regenerates byte for
|
||
byte, that no other file is there, that `wai-rs` gives every vector its outcome, that every
|
||
reason of §10 refuses a vector, and that §10 lists exactly the reference's codes.
|
||
`live-conformance/access_services_verify.py` is the second implementation, written from this
|
||
text: it shares no code with `wai-rs`; it verifies events and captions with the timed-text
|
||
corpus's second implementation (`timed_text_verify.py`) and signatures with WAI's strict rule
|
||
(`claim-conformance/_ed25519.py`); it computes every figure, writes every DAPT document and
|
||
parses each with an XML parser; and it requires every mutated copy of the corpus to fail.
|
||
|
||
## 12. Security and privacy considerations
|
||
|
||
- Every figure is recomputed from signed records. A figure states nothing a verifier takes on
|
||
trust; a quality record's signer vouches only that it computed the figure, and a verifier
|
||
that recomputes it needs no trust in the signer.
|
||
- A source places words on the room clock as its signer states. On a take, the media's time is
|
||
the device's signed commitment and cannot be moved; where a word lies in the media is the
|
||
aligner's statement, attributable to it by its signature, and checkable by anyone holding the
|
||
master. A source on the basis `room` places the words by the signer's word alone, and the
|
||
latency's class says so (`stated`).
|
||
- A take's opening commitment is the device's, but a principal that is not a capturing device
|
||
can sign one too. This extension requires the take to be derived from a `record_start`
|
||
addressed to the commitment's author; that the author was permitted to capture, and for
|
||
whom, is what a take verifier and a room verifier check (capture-binding §9, live-rooms §9).
|
||
- `t` is its author's statement of the room clock (live-events §11). A captioner who stamps
|
||
its captions early lowers its latency, and the stamp is signed: the room's relays see when
|
||
each event arrived, and a later extension's per-hop receipts witness it.
|
||
- A reference transcript is its reviewer's. The accuracy's class names what the reference is;
|
||
a verifier's policy decides whose transcripts it accepts.
|
||
- Labels are their producers' statements, as timed-text §14 says of captions. A description
|
||
or a signing labelled human that a model produced misleads its audience, and the signature
|
||
makes that attributable.
|
||
- A signing track's binding names caption revisions by digest. It shows what the signing
|
||
translates; it does not show that the translation is correct, which a review states.
|
||
- A sources record ties a cue to a position in a recording, and a signing record ties a track
|
||
to a person who signs. Both persist with the session's records, as the events do.
|