web/room/binding.js: the side table a page carries contentBinding in until a registry lists the member (decoder and timestamp, clone, transfer, reset, a bound; ambiguity refused), the capability report built in two passes so that only codec strings the WebCodecs Codec Registry lists are put to the user agent, and the state of the frame on screen. The room routes each track before it decodes it, binds every frame its video decoders output to the verified object and group receipt, and shows the state of each tile's frame with ?debug=binding. web/binding/ runs live-conformance/browser in the page, the wasm route's verified decode, the binding through clone, transfer, copyTo and re-encode, the metadata probe and a capability report from the user agent's answers. e2e: scenario binding, energy.py for the host's per-process counter, and the decode wasm built by run.sh. Co-Authored-By: Claude Opus 5.5 <[email protected]>
42 lines
2 KiB
JavaScript
42 lines
2 KiB
JavaScript
// The side table a page keeps its frames' bindings in (WAI browser-sink §9.2), held to the
|
|
// sequences of live-conformance/browser (`node --test web/room/binding.test.mjs`). The page runs
|
|
// the same sequences in the browser; here the frames and decoders are stand-in objects.
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import { runSequence, SideTable, chainToken } from "./binding.js";
|
|
|
|
const corpus = JSON.parse(fs.readFileSync(fileURLToPath(new URL("../../../../../../wai/live-conformance/browser/vectors.json", import.meta.url)), "utf8"));
|
|
// The bindings in the sequences are valid: their canonical form is their members in §7.1's order.
|
|
const canonicalOf = (b) => JSON.stringify({ alg: b.alg, digest: b.digest, ...(b.receipt ? { receipt: b.receipt } : {}), tier: b.tier });
|
|
|
|
for (const c of corpus.tables) {
|
|
test(`side table: ${c.name}`, () => {
|
|
const got = runSequence(c.bound, c.ops, canonicalOf);
|
|
assert.deepEqual(got, c.result);
|
|
});
|
|
}
|
|
|
|
test("a frame object is unbound until a decoder's output attaches an entry, and a struck entry binds nothing", () => {
|
|
const t = new SideTable(4);
|
|
const d = {};
|
|
const f = { timestamp: 5 };
|
|
assert.equal(SideTable.of(f), null);
|
|
t.chunk(d, 5, { binding: "b" });
|
|
t.chunk(d, 5, { binding: "c" });
|
|
assert.equal(t.output(d, f), null);
|
|
assert.deepEqual(t.refusals, [{ at: 1, reason: "binding_ambiguous" }]);
|
|
// A binding that depends on the frame is computed when the frame is output.
|
|
t.chunk(d, 6, { binding: (fr) => `tier-of-${fr.timestamp}` });
|
|
assert.equal(t.output(d, { timestamp: 6 }).binding, "tier-of-6");
|
|
});
|
|
|
|
test("chain admissions read as §10's tokens", () => {
|
|
assert.equal(chainToken("linked"), "linked");
|
|
assert.equal(chainToken("already"), "linked");
|
|
assert.equal(chainToken("anchor"), "anchor");
|
|
assert.equal(chainToken("held:parent_not_held"), "held");
|
|
assert.equal(chainToken("refused:chain_break"), "refused");
|
|
assert.equal(chainToken(undefined), "held");
|
|
});
|