diff --git a/.github/workflows/wai-conformance.yml b/.github/workflows/wai-conformance.yml index 2c7c9ef1e..e0fea12c0 100644 --- a/.github/workflows/wai-conformance.yml +++ b/.github/workflows/wai-conformance.yml @@ -75,6 +75,9 @@ on: # tests/capture_take.rs requires this extension's §12 to list the codes the reference # reports, and the registry's wire identifiers test reads its sections. - 'wai/extensions/capture-binding.md' + # tests/live_compose.rs requires this extension's §10 to list the codes the reference + # reports, and the registry's wire identifiers test reads its sections. + - 'wai/extensions/live-compose.md' - 'wai/wai-web/**' # The audio provenance check below reads the corpora above with this tool. - 'wai/tools/wai_audio_provenance_check.py' @@ -121,6 +124,9 @@ on: # tests/capture_take.rs requires this extension's §12 to list the codes the reference # reports, and the registry's wire identifiers test reads its sections. - 'wai/extensions/capture-binding.md' + # tests/live_compose.rs requires this extension's §10 to list the codes the reference + # reports, and the registry's wire identifiers test reads its sections. + - 'wai/extensions/live-compose.md' - 'wai/wai-web/**' # The audio provenance check below reads the corpora above with this tool. - 'wai/tools/wai_audio_provenance_check.py' @@ -773,7 +779,8 @@ jobs: # staged_verify.py (the staged-delivery corpus), and http_verify.py (the HTTP delivery # corpus), and quantum-conformance/tools/referee.py (both quantum-sim capabilities), and # live_events_verify.py (the live-events corpus), and live_rooms_verify.py (the - # live-rooms corpus), and capture_take_verify.py (the capture-binding corpus). + # live-rooms corpus), and capture_take_verify.py (the capture-binding corpus), and + # live_compose_verify.py (the live-compose corpus). # Each exits non-zero on any failure or any difference, and the step fails with it. # One platform: what they check is the reading of the text, not the architecture. independent-verifiers: @@ -944,6 +951,26 @@ jobs: (cd wai-rs && cargo test --no-default-features --features capture_take --lib -- capture_take:: output_tree::) (cd wai-rs && cargo test --no-default-features --features capture_take --test capture_take) python3 -I live-conformance/capture_take_verify.py live-conformance/takes + # wai.live.compose (extensions/live-compose.md): the reference module's unit tests (the + # layout over every grid of 1 to 64 tiles stays on its canvas with no tile overlapping + # another, the fill modes, the attributes, the mixer) and tests/live_compose.rs (the + # committed corpus regenerates byte for byte from its fixed seeds, wai-rs gives every + # case its stated outcome, every reason of §10 refuses a case, and §10 lists exactly + # the reference's codes); then the corpus's second implementation, + # live_compose_verify.py, written from the extension's text and sharing no code with + # wai-rs, which verifies each room with live_rooms_verify.py, steps through its + # lifecycle replay to each instant itself, gives every layout, mix, descriptor, + # composition and receipt the same outcome rectangle for rectangle and sample for + # sample, and requires every mutated copy of the corpus to fail; standard library + # only, run isolated (-I). + - name: live compose · wai-rs and live_compose_verify.py + working-directory: wai + shell: bash + run: | + set -euo pipefail + (cd wai-rs && cargo test --no-default-features --features live_compose --lib live_compose::) + (cd wai-rs && cargo test --no-default-features --features live_compose --test live_compose) + python3 -I live-conformance/live_compose_verify.py live-conformance/compose # The quantum corpus's second implementation (quantum-sim extension), integers only: # it derives the circuit/1 phase table by its recurrence and the circuit2 table by an # interval-certified procedure, and requires both literal tables and their digests, diff --git a/wai/CHANGELOG.md b/wai/CHANGELOG.md index 953adf182..878f66d47 100644 --- a/wai/CHANGELOG.md +++ b/wai/CHANGELOG.md @@ -6,6 +6,45 @@ wire format may change and such changes are recorded here. ## v0.4.0 — current +### `wai.live.compose`: a room's composition as an integer function + +- **The extension** ([live-compose](extensions/live-compose.md)) registers the record + `wai.live.compose`. A `WCD1` composition descriptor, signed by the room authority or by a + principal whose grant has the compose power, fixes a canvas (each edge even, 16 to 1920 + pixels, at most 1920 × 1080 pixels, 1 to 60 frames a second), an sRGB background, the + highest layer composed, a layout, the grant attributes it reads, and its limits on tiles + and voices. +- **The participant set** at a room-clock instant is the room's lifecycle replay up to it: + every present publisher but the compositor, its video source (own video, own screen, or + its live place in a slot) and audio source, each with the dimensions of the composed + layer, the attributes of its grant in effect, and its join order. A gap in a room key's + chain is `lifecycle_incomplete`; a gap elsewhere changes nothing. The set has a digest. +- **The layout** (§5) is integer arithmetic throughout, with every rounding stated: a grid + chosen by the largest tile of the reference aspect among every column count, its rows + centred; tile aspects auto, 16:9, 1:1 and 3:4; a featured participant above the others; + fill, cover and contain, by default cover for grid tiles and contain for the featured + one; stopped video shown or omitted; order by attribute, then join order, then key; and + picture in picture, the PiP participant's window over the grid in any corner, of a set or + derived size, static or dynamic (alone, it is laid out as though it had no PiP + attribute). The layout is computed again at every lifecycle event and grant exchange. +- **The mix** (§6): per-voice gain and pan as integers in units of 1/4096, over signed + 16-bit PCM, summed exactly in 64 bits and saturated once, so it is byte-exact over the + decoded PCM; a decode and a lossy re-encode are not, and the receipt binds objects. +- **Where it runs** (§7): on each sink by default, with no server encode; a server + compositor must be the descriptor's compositor, hold the compose power and sign a `WCR1` + receipt for each object of a composed track, naming the descriptor, the set's digest at + `t`, the output object and the input objects of exactly the tracks the layout reads. +- **Live rooms.** §1, §3.3 and §4.4 point at the extension for the compose power and the + attributes `featured`, `order` and `pip` (and `gain` and `pan`, which it adds). +- **Reference and corpus.** `wai-rs` feature `live_compose` (`src/live_compose.rs`; the + layout and the mixer in `src/live_compose/layout.rs` use nothing beyond `core`, `Vec` and + `String`); `live-conformance/compose/`, written from fixed seeds by + `wai_live_compose_vectors`, and checked by `tests/live_compose.rs` and by + `live-conformance/live_compose_verify.py`, a second implementation that shares no code + with `wai-rs`, steps through the room's lifecycle replay itself and requires every + mutated copy of the corpus to fail. The registry lists the record and its magics (`WCD1`, + `WCR1`). + ### `wai.capture.take`: a device's master recording bound to a live room - **The extension** ([capture-binding](extensions/capture-binding.md)) registers the diff --git a/wai/REGISTRY.md b/wai/REGISTRY.md index 28d1b1f30..17545832d 100644 --- a/wai/REGISTRY.md +++ b/wai/REGISTRY.md @@ -40,7 +40,7 @@ Every registered string has one kind. - **record** — a signed record a WAI tool emits and verifies (a receipt kind: `wai.asset.provenance`, the quantum-operations receipts, the delivery records `wai.video.manifest` and its siblings; the live records `wai.live.events`, - `wai.live.room` and `wai.capture.take`). + `wai.live.room`, `wai.capture.take` and `wai.live.compose`). It names no payload format. A derivation or record string is not a payload capability, so it is not @@ -62,8 +62,8 @@ bindings ([http-delivery](extensions/http-delivery.md), [moq-streaming-format](extensions/moq-streaming-format.md)), the key discovery they serve ([jwp-receipts](extensions/jwp-receipts.md) §7), [packaging](extensions/packaging.md), [live-events](extensions/live-events.md), -[live-rooms](extensions/live-rooms.md) and [capture-binding](extensions/capture-binding.md) -put on the wire outside a +[live-rooms](extensions/live-rooms.md), [capture-binding](extensions/capture-binding.md) +and [live-compose](extensions/live-compose.md) put on the wire outside a manifest — magic numbers, a media type, `codecs` prefixes, paths, playlist tags and attributes, document kinds and catalog fields — each with its kind, the section that defines it, and whether it is defined, provisional (test material only until @@ -192,6 +192,7 @@ and a role are fixed once registered. | `wai.image.jpegai` | payload | registered | image | standalone | royalty-free | neural-entropy-exact | — | §5 Neural capabilities | | `wai.image.jxl` | payload | registered | image | standalone | royalty-free | standard-tolerance | recommended | §5 Recommended modern set | | `wai.image.png` | payload | registered | image | standalone | royalty-free | standard-defined | floor | §5 Mandatory floor | +| `wai.live.compose` | record | registered | — | — | — | — | — | §5 Interactive, temporal & computed content | | `wai.live.events` | record | registered | — | — | — | — | — | §5 Interactive, temporal & computed content | | `wai.live.room` | record | registered | — | — | — | — | — | §5 Interactive, temporal & computed content | | `wai.mesh.draco` | payload | registered | volumetric | standalone | royalty-free | standard-unclassified | — | §5 Immersive audio, cinema, volumetric, haptics, HDR | @@ -288,7 +289,9 @@ and a role are fixed once registered. | `WAI1` | magic | defined | SPEC §2 | | `WAI2` | magic | defined | SPEC §7.1 | | `WAI_RECEIPT` | catalog | defined | moq-streaming-format §5 | +| `WCD1` | magic | defined | live-compose §3.1 | | `WCN1` | magic | defined | capture-binding §8.1 | +| `WCR1` | magic | defined | live-compose §8.1 | | `WEP1` | magic | defined | live-events §5 | | `WEV1` | magic | defined | live-events §3.1 | | `WHP1` | magic | defined | http-delivery §6.2 | diff --git a/wai/SPEC.md b/wai/SPEC.md index 52d76145d..1bbd0ba41 100644 --- a/wai/SPEC.md +++ b/wai/SPEC.md @@ -592,7 +592,8 @@ kind: `wai.asset.provenance`, `wai.quantum.calibration`, `wai.quantum.job`, and the delivery records `wai.video.manifest`, `wai.video.ssai`, `wai.video.keys`, `wai.video.package` and `wai.video.channel`; and the live records `wai.live.events`, - `wai.live.room` and `wai.capture.take`), which names no payload format. + `wai.live.room`, `wai.capture.take` and `wai.live.compose`), which names no payload + format. Only payload, companion and refinement capabilities have a media class, a fidelity tier, a replicate class and a role. A derivation or record string is not a payload @@ -894,6 +895,22 @@ at its index), `aligned` (capture began at the count-in's instant), `complete`, `publishable` for each purpose. The take maps onto C2PA live video output: [`extensions/capture-binding.md`](extensions/capture-binding.md). +And for the **composition** of a room — `wai.live.compose`: a signed composition +descriptor, by the room authority or a principal whose grant has the compose power, that +fixes a canvas (at most 1920 pixels an edge and 1920 × 1080 pixels, at 1 to 60 frames a +second), a background, and a layout: a grid, with a featured participant above the +others, a gap, a tile aspect, a fill mode (fill, cover or contain), an order by +attribute and stopped video shown or omitted; or the same grid under a picture-in-picture +window in a corner, of a set or derived size, static or dynamic. The participant set at +each instant follows from the room's lifecycle replay: who publishes, each one's source +and its dimensions, the attributes of its grant in effect and its join order. The layout +is a pure integer function of the descriptor and the set, laid out again at every +lifecycle event and grant exchange, and the mix a saturating integer function of decoded +PCM, so every sink composes the same rectangles locally; a server compositor under the +compose power signs a receipt naming the descriptor, the set and the input and output +objects, which anyone checks against the same function: +[`extensions/live-compose.md`](extensions/live-compose.md). + ### Payloads of the WAI-native integer codecs This revision pins a payload format to each WAI-native integer codec whose row named diff --git a/wai/extensions/live-compose.md b/wai/extensions/live-compose.md new file mode 100644 index 000000000..4ddd17086 --- /dev/null +++ b/wai/extensions/live-compose.md @@ -0,0 +1,592 @@ +# WAI Extension: Live Composition + +> Status: Draft. Registers the record `wai.live.compose`: the deterministic composition +> of a live room's participants. A signed **composition descriptor** fixes a canvas, a +> background, a layout (a grid, with a featured tile, or a grid under a +> picture-in-picture window), the grant attributes it reads and its limits. The +> **participant set** at a room-clock instant is derived from the room's lifecycle +> replay ([live-rooms](live-rooms.md) §9): who publishes, each one's video and audio +> source and its dimensions, the attributes of its grant in effect, and its join order. +> The layout is then a pure integer function of the descriptor and the set, and the mix +> a pure integer function of decoded PCM, so every sink composes the same rectangles +> locally, with no server encode, and a server compositor that publishes a composed track +> signs a **composition receipt** that anyone can check against the same function. No new +> transport: a composed track is a track of the room, and the receipt names the objects it +> was made from. The reference implementation is the `live_compose` module of `wai-rs` +> (feature `live_compose`); the corpus is +> [`live-conformance/compose/`](../live-conformance/compose/), and its second +> implementation is `live-conformance/live_compose_verify.py`. +> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174. +> +> Texts read for this revision: `draft-ietf-moq-transport-22` (MOQT), an Internet-Draft +> not past Working Group Last Call, for the Full Track Name (§2.4.1) and the Location +> (§8.2); RFC 6716 §6; RFC 8032; FIPS 180-4; and IEC 61966-2-1 (sRGB). A section number of +> that draft in this text is that revision's. + +## 1. Scope + +In scope: the composition descriptor, its digest and signature, its limits and who may +sign it (§3); the participant set at an instant, the attributes the descriptor reads, the +order, and the set's digest (§4); the layout function (§5); the audio mix (§6); where +composition runs (§7); the composition receipt and its verification (§8, §9). + +Out of scope: a transport; how a renderer scales and filters a source into its rectangle, +and how it converts the background's colour into its output's (the layout fixes +rectangles, not pixels); decoding, resampling and encoding; and the browser compositor +that renders a layout in a page, which a later slice builds from this function. + +Relationship to the core spec: `wai.live.compose` 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. + +## 2. Terms + +- **Room**, **room clock**, **principal**, **event**, **chain**, **grant**, **grant in + effect**, **room key**, **merged order**, **slot**, **publish profile**: as in + live-events §2 and live-rooms §2, §8, §9.2. +- **Room authority**: the key that signs the room's descriptor (live-rooms §2). +- **Compose power**: bit 2 of a capability set's `powers` (live-rooms §3.3). +- **Canvas**: the picture a composition makes, `width` × `height` pixels. +- **Source**: the track a participant is composed from (§4.2). +- **Compositor**: the principal that publishes a composed track (§7). +- **Rectangle**: (`x`, `y`, `w`, `h`): its left edge and top edge, in pixels from the top + left of the canvas (or of a source), and its width and height. +- A **short** field is a u8 length and that many bytes. Integers are little-endian. A + digest is SHA-256 (FIPS 180-4), 32 bytes. + +## 3. The composition descriptor + +### 3.1 Layout + +| field | size | meaning | +|---|---|---| +| `magic` | 4 | `WCD1` (ASCII) | +| `version` | 1 | 1 in this revision | +| `room` | 32 | the room id (live-rooms §3.2) | +| `signer` | 32 | the Ed25519 key that signs the descriptor (§3.5) | +| `effective` | 8 | u64: the room-clock instant from which the descriptor applies | +| `compositor` | 32 | the principal that may publish the composed tracks (§7); 32 zero bytes for none | +| `width`, `height` | 2 each | u16: the canvas, in pixels (§3.4) | +| `fps` | 1 | the canvas's frame rate, in frames per second (§3.4) | +| `background` | 3 | the canvas's colour: red, green and blue, 8 bits each, in sRGB (IEC 61966-2-1) | +| `layer` | 1 | the highest layer of a source composed (§4.2) | +| `layout` | 1 | 1 grid, 2 picture in picture (§5) | +| `gap` | 2 | u16: the pixels between two grid tiles | +| `aspect` | 1 | the grid tiles' aspect: 0 auto, 1 video (16:9), 2 square (1:1), 3 portrait (3:4) (§5.3) | +| `fill` | 1 | 0 default, 1 fill, 2 cover, 3 contain (§5.6) | +| `featured_attr` | short | the attribute key that marks the featured participant; empty for none (§4.3) | +| `order_attr` | short | the attribute key that orders participants; empty for none | +| `omit_stopped` | 1 | 1: a participant whose video is stopped has no tile; 0: it has one (§5.2) | +| `pip_attr` | short | the attribute key that marks the PiP participant; empty for none | +| `corner` | 1 | the PiP window's corner: 1 top left, 2 top right, 3 bottom left, 4 bottom right | +| `pip_width`, `pip_height` | 2 each | u16: the PiP window's size; 0 derives it (§5.5) | +| `offset` | 2 | u16: the window's distance, in pixels, from both edges of its corner | +| `behaviour` | 1 | what the PiP participant does when it is the only one composed: 1 static, 2 dynamic (§5.5) | +| `channels` | 1 | the mix's channels: 1 mono, 2 stereo (§6) | +| `sample_rate` | 4 | u32: the rate, in Hz, every voice is decoded to before it is mixed | +| `gain_attr` | short | the attribute key of a participant's gain; empty for none (§6) | +| `pan_attr` | short | the attribute key of a participant's pan; empty for none | +| `max_tiles` | 1 | the most tiles (§5.2) | +| `max_voices` | 1 | the most voices of the mix (§6) | +| `sig` | 64 | §3.2 | + +A grid's `pip_attr` is empty and its `corner`, `pip_width`, `pip_height`, `offset` and +`behaviour` are 0 (§3.3). + +### 3.2 Digest and signature + +The **digest** of a descriptor is SHA-256 over its record from `magic` through +`max_voices`: every byte but `sig`. The **signature** is Ed25519 (RFC 8032) by `signer` +over the 17 bytes `wai:live-compose` (ASCII) and 0x01, followed by the bytes the digest +covers. It is verified strictly, as [SPEC](../SPEC.md) §7 *Signatures* requires: a key +that fails step 1 or 2 is `bad_key`, and a signature that fails a later step is +`bad_signature`. + +### 3.3 Reading and field rules + +A reader reads exactly the bytes it is given as one descriptor, in the order of §3.1, and +refuses at the first of these that holds: + +1. Fewer than 4 bytes: `truncated`. A magic other than `WCD1`: `malformed`. No byte after + the magic: `truncated`. A version other than 1: `unknown_version`. +2. The bytes end before a field the layout requires: `truncated`. +3. Bytes after `sig`: `malformed`. + +It then holds the canvas to §3.4, and refuses one beyond its limits as +`canvas_out_of_range`. It then refuses, as `compose_invalid`, a descriptor that breaks any +of these rules: + +- `layout` is 1 or 2, `aspect` at most 3, `fill` at most 3, and `omit_stopped` 0 or 1. +- Each attribute key is empty or a slot name of live-rooms §2 (1 to 32 bytes of `a`–`z`, + `0`–`9` and `_`), which is what a grant attribute's key is (live-rooms §4.4). +- A grid has an empty `pip_attr`, and `corner`, `pip_width`, `pip_height`, `offset` and + `behaviour` 0. A picture in picture has a `corner` of 1 to 4 and a `behaviour` of 1 or 2, + an `offset` below both `width` and `height`, `pip_width` + `offset` at most `width`, + and `pip_height` + `offset` at most `height`. +- `channels` is 1 or 2, and `sample_rate` 8 000 to 192 000. +- `max_tiles` and `max_voices` are each 1 to 64. +- With *k* the least integer whose square is at least `max_tiles`: `gap` is below + `height`; `width` is at least *k* + (*k* − 1) × `gap`; and the band under a featured + tile (§5.4), `height` − `gap` − ⌊(`height` − `gap`) × 3 / 4⌋, is at least *k* + + (*k* − 1) × `gap`. Every grid the layout makes then has a candidate whose cells are at + least a pixel each way (§5.3). + +Then the signature (§3.2): `bad_key` or `bad_signature`. + +### 3.4 The canvas + +`width` and `height` are each even, and each 16 to 1920; `width` × `height` is at most +2 073 600, the pixels of 1920 × 1080; and `fps` is 1 to 60. The edges are even so that a +picture subsampled 4:2:0 has whole chroma samples. A portrait 1080 × 1920 and a square +1440 × 1440 canvas are within these limits. + +### 3.5 Who may sign + +Against a room, a descriptor that reads (§3.3) is refused as `wrong_room` when its `room` +is not the room id; and as `compose_not_permitted` unless its `signer` is the room +authority, or a principal present at `effective` whose grant in effect then (§4.1) has the +compose power. + +The power is checked at `effective`, when the descriptor takes effect: a descriptor does +not lapse when its signer leaves or later loses the power. A composition has one +descriptor; a room that changes its layout signs another, and each composed track and +each receipt names the one it follows (§8). + +## 4. The participant set + +### 4.1 The room at an instant + +A composition reads a room that verifies (live-rooms §9): one refused is refused here +with the room's reason, at `room`. A room whose outcome is a gap is composed only when no +gap is in a room key's chain: the lifecycle is then whole, and a gap in another +principal's chain (a chat not delivered) changes no room state. A gap in a room key's +chain is `lifecycle_incomplete`, at `room`: the state at no instant after it is known. + +The **room at** *t* is the room state (live-rooms §9.3) replayed from the lifecycle events +whose `t` is at most *t*, in the merged order: equally, the room each chain gives when it +is cut before its first record whose `t` is above *t*. Events at *t* itself are applied, +so a principal that joins at *t* is in the set at *t*. + +The **join order** of a principal present at *t* is the number of the `join` that made it +present (its last), where the room's accepted `join` events up to *t* are numbered from 0 +in the merged order, a duplicate (live-events §6.2 step 1) counted once. + +### 4.2 Participants and their sources + +The **participants** at *t* are the principals present at *t*, other than the +descriptor's `compositor`, that publish at *t*: each has an own track of any media kind +published, or is the live publisher of a slot (live-rooms §7.1). A standby is not +composed for its place in a slot, since its media is not delivered. + +Each participant has: + +- its **video source**: the first of its own `video` track; its own `screen` track; and + its live place in a slot of media kind `video` or `screen`, the first such slot in the + room descriptor's order. With none, its video is **stopped**. +- its **audio source**: its own `audio` track; or else its live place in the first slot of + media kind `audio`. With none, it has no voice. +- the attributes of its grant in effect at *t* (live-rooms §4.4). + +A source's **profile** is the profile its track was published under (the `publish` or +`takeover` that made it, live-rooms §7.2), and its **layers** the number of layers +published. Its **composed layer** *L* is the lower of `layers` − 1 and the descriptor's +`layer`, and its width and height are those of layer *L* of the profile (live-rooms §8.1); +an audio source's are 0. A descriptor whose `layer` is below a publisher's top layer +composes from a layer the compositor's grant can subscribe to, and every sink lays the +room out in that layer's pixels. + +### 4.3 Attributes + +For each participant, each attribute key the descriptor names (not empty) is looked up +among the attributes of its grant in effect, and read: + +| key | value | when absent | +|---|---|---| +| `featured_attr`, `pip_attr` | `true` or `false` | `false` | +| `order_attr` | a decimal integer from −2 147 483 648 to 2 147 483 647 | no order | +| `gain_attr` | a decimal integer from 0 to 16 384 | 4096 | +| `pan_attr` | a decimal integer from −4096 to 4096 | 0 | + +A **decimal integer** is `0`, or an optional `-` followed by 1 to 10 of the digits `0`–`9` +of which the first is not `0`: no `+`, no space, no `-0`. Every attribute the descriptor +names is read for every participant, whether or not it has the source the attribute is +about; one whose value is not of its row is `attr_malformed`, and the composition at *t* +is refused, at `set`. The keys `featured`, `order` and `pip` that live-rooms §4.4 names +are these attributes under the keys a descriptor gives them; `gain` and `pan` are the +mix's. + +### 4.4 Order + +The participants are ordered: those with an order first, by order ascending, then those +with none; between two of one order (or none), by join order ascending; and between two +of one join order, by key, as unsigned bytes. This order is **S**. + +### 4.5 The set's digest + +The digest of the participant set at *t* is SHA-256 over the 21 bytes +`wai:live-compose-set` (ASCII) and 0x01, the room id, *t* (u64), the number of +participants (u32), and then, for each participant in ascending order of key: + +| field | size | meaning | +|---|---|---| +| `principal` | 32 | its key | +| `grant` | 32 | the digest of its grant in effect | +| `join` | 4 | u32: its join order | +| `video`, `audio` | 1 or 9 + *s* each | its source: one byte 0 for none; otherwise `media` (u8, the media kind of live-rooms §6.1), `slot` (short: empty for an own track), `profile` (u8, the profile's index in the room descriptor), `layers` (u8), the composed layer *L* (u8), `width` and `height` (u16 each) | + +The grant's digest fixes its attributes, so the set's digest fixes everything §5 and §6 +read of the room at *t*. + +## 5. The layout + +### 5.1 Integers + +Every quantity of this section is an integer, and none is negative. ⌊*a* / *b*⌋, for *b* +above 0, rounds down. **fit**(*bw*, *bh*, *a*, *b*), the largest rectangle of aspect +*a*:*b* within *bw* × *bh*, is (*bw*, max(1, ⌊*bw* × *b* / *a*⌋)) when *bw* × *b* ≤ *bh* +× *a*, and (max(1, ⌊*bh* × *a* / *b*⌋), *bh*) otherwise. A rectangle of *w* × *h* +**centred** in (*x*, *y*, *W*, *H*) is (*x* + ⌊(*W* − *w*) / 2⌋, *y* + ⌊(*H* − *h*) / 2⌋, +*w*, *h*). No product here exceeds 2^63. + +### 5.2 Which participants have tiles + +From S (§4.4): + +1. **V** is S, less every participant whose video is stopped when `omit_stopped` is 1. +2. For a picture in picture, the **PiP participant** P is the first of V whose `pip_attr` + attribute is `true`; with none there is no PiP window. For a grid there is none. +3. **G** is V without P, in order. The **featured participant** F is the first of G whose + `featured_attr` attribute is `true`; it is moved to the front of G. +4. G is cut to its first `max_tiles` members, less one when there is a P. F, being first, + is kept; when G is then empty there is no F. + +### 5.3 The grid + +A grid of *n* ≥ 1 tiles over a region (*X*, *Y*, *W*, *H*) is chosen by its **reference +aspect** *a*:*b*: 16:9 for auto and video, 1:1 for square, 3:4 for portrait. + +- **Candidates.** For each number of columns *c* from 1 to *n*, with *r* = ⌈*n* / *c*⌉ + rows: *c* is a candidate when (*c* − 1) × `gap` is below *W*, (*r* − 1) × `gap` below + *H*, and the cells, *cw* = ⌊(*W* − (*c* − 1) × `gap`) / *c*⌋ wide and *ch* = ⌊(*H* − + (*r* − 1) × `gap`) / *r*⌋ high, are each at least 1. Its **area** is *tw* × *th*, where + (*tw*, *th*) = fit(*cw*, *ch*, *a*, *b*). +- **The choice.** The candidate of the largest area; of several, the one with the most + columns. §3.3's rule on `gap` makes *c* = ⌈√*n*⌉ a candidate for every *n* a + descriptor allows. +- **Placement.** The rows are centred: the first row's top is *y*0 = *Y* + ⌊(*H* − (*r* × + *ch* + (*r* − 1) × `gap`)) / 2⌋. Tile *k*, from 0, is in row *i* = ⌊*k* / *c*⌋ and column + *j* = *k* mod *c*. Every row holds *c* tiles but the last, which holds *n* − (*r* − 1) × + *c*; a row of *m* tiles is centred, beginning at *x*0 = *X* + ⌊(*W* − (*m* × *cw* + (*m* − + 1) × `gap`)) / 2⌋. Cell *k* is (*x*0 + *j* × (*cw* + `gap`), *y*0 + *i* × (*ch* + `gap`), + *cw*, *ch*). +- **The tile.** Under auto, tile *k* is its cell; otherwise it is fit(*cw*, *ch*, *a*, *b*) + centred in its cell. + +With no tile the canvas is its background. + +### 5.4 The featured tile + +With F and *n* ≥ 2 members of G, the **featured tile** is (0, 0, `width`, *mh*), with *mh* += ⌊(`height` − `gap`) × 3 / 4⌋, and the other *n* − 1 members are a grid (§5.3) over the +band below it, (0, *mh* + `gap`, `width`, `height` − *mh* − `gap`). The featured tile is its +whole region: `aspect` is the grid tiles'. With F alone the featured tile is the whole +canvas. With no F, the members of G are a grid over the whole canvas. + +### 5.5 Picture in picture + +With P and a G that is not empty, G is laid out over the canvas as §5.3 and §5.4 lay it out, +and P's **window** is drawn over it. With P and an empty G: + +- **static**: P's window, and the background; +- **dynamic**: P is laid out as though it had no `pip_attr` attribute: a grid of P alone, + or, when P is featured, the featured tile, the whole canvas. + +The window is `pip_width` × `pip_height` when both are above 0. Otherwise, with *a*:*b* the +width and height of P's video source, or the canvas's when P's video is stopped, it is +fit(*bw*, *bh*, *a*, *b*), where *bw* is `pip_width` when that is above 0, `width` − +`offset` when only `pip_height` is, and the lower of ⌊`width` / 4⌋ and `width` − `offset` +when neither is; and *bh* is `pip_height` when that is above 0 and `height` − `offset` +otherwise. With *o* the `offset` and *pw* × *ph* the window, it is at (*o*, *o*) in the top +left corner, (`width` − *o* − *pw*, *o*) in the top right, (*o*, `height` − *o* − *ph*) in +the bottom left, and (`width` − *o* − *pw*, `height` − *o* − *ph*) in the bottom right. + +### 5.6 Fill + +A tile (*tx*, *ty*, *tw*, *th*) shows a source of *sw* × *sh* by its fill mode. The source +is **wider** when *sw* × *th* ≥ *sh* × *tw*. + +- **Fill**: the whole source, (0, 0, *sw*, *sh*), stretched over the whole tile. +- **Cover**: the source cropped to the tile's aspect, over the whole tile. A wider source's + crop is *cw* = max(1, ⌊*sh* × *tw* / *th*⌋) wide, at (⌊(*sw* − *cw*) / 2⌋, 0, *cw*, *sh*); + any other's is *ch* = max(1, ⌊*sw* × *th* / *tw*⌋) high, at (0, ⌊(*sh* − *ch*) / 2⌋, *sw*, + *ch*). +- **Contain**: the whole source, letterboxed in the tile. A wider source is drawn into + (*tx*, *ty* + ⌊(*th* − *dh*) / 2⌋, *tw*, *dh*) with *dh* = max(1, ⌊*tw* × *sh* / *sw*⌋); + any other into (*tx* + ⌊(*tw* − *dw*) / 2⌋, *ty*, *dw*, *th*) with *dw* = max(1, ⌊*th* × + *sw* / *sh*⌋). +- **Default**: cover for a grid tile and the PiP window, contain for the featured tile. + +Each mode gives a **source rectangle** and a **destination rectangle**: the part of the +source drawn, and where on the canvas it is drawn. A tile of stopped video has neither, and +shows the background, as does the part of a tile outside its destination. How the source +rectangle is scaled into the destination is the renderer's; a sink that holds a source at a +layer below its composed one scales it to the composed layer's width and height first. + +### 5.7 What the layout gives + +The layout of a descriptor and a participant set gives: + +- **the order**: S, every participant, by key; +- **the tiles**, in drawing order: the featured tile, then the grid's in G's order, then + the PiP window. Each has its participant, its **place** (`grid`, `featured` or `pip`), + its **z** (0, or 1 for the PiP window, drawn over the others), the tile, and, unless its + video is stopped, its source and destination rectangles; +- **the voices** (§6). + +A renderer paints the background over the canvas, then the tiles in order. No two tiles +of z 0 overlap. + +### 5.8 Re-layout + +The participant set changes only at the `t` of a lifecycle event: a `join`, `leave`, +`publish`, `unpublish`, `grant_exchange`, `takeover` or `failover` (an exchange always +changes it, since the set names each participant's grant). At every such instant at or +after `effective` the layout is computed again, and it changes when the sources, the +attributes or the order do; between two such instants it does not change. The layout at *t* +is the function of this section over the descriptor and the set at *t*, and of nothing a +sink sees otherwise, so a sink that joins late lays the room out as one that was there +throughout, and a grant exchange that changes an attribute re-lays the room out at the +exchange's tick, with no participant leaving. + +## 6. The audio mix + +The **voices** are the members of S (before any is omitted for its video) that have an +audio source, in S's order, the first `max_voices` of them. Each has its **gain** *g*, +from 0 to 16 384 in units of 1/4096 (4096 is unity), and its **pan** *p*, from −4096 +(left) to 4096 (right) (§4.3). + +The mixer mixes one block of *N* frames. Each voice's input is its decoded audio for the +block: *N* frames of signed 16-bit samples, of 1 or 2 channels (interleaved, left first), +at the descriptor's `sample_rate`. Each output sample is a sum over the voices in signed +64-bit integers, one term per voice: + +- **mono output** (`channels` 1): *x* × 4096 × *g* for a mono voice's sample *x*; (*x*L + + *x*R) × 2048 × *g* for a stereo voice's samples *x*L and *x*R. +- **stereo output** (`channels` 2), with *a*L = 4096 − max(*p*, 0) and *a*R = 4096 + + min(*p*, 0): to the left channel *x* × *g* × *a*L and to the right *x* × *g* × *a*R for + a mono voice; *x*L × *g* × *a*L and *x*R × *g* × *a*R for a stereo one. + +The output sample is ⌊(*s* + 2^23) / 2^24⌋ of the sum *s*, the arithmetic shift right by +24 bits of *s* + 2^23, which rounds half up; then saturated once to −32 768 … 32 767. A +term is at most 2^41 in magnitude and a mix has at most 64 voices, so the sum is exact, +the order of its terms changes nothing, and saturation applies to the whole once. The pan +is a balance: at the centre both channels are at the voice's gain, and panning attenuates +one channel only. A single voice at unity gain and the centre is passed through +unchanged. A mixer that holds no decoded block of a voice for the output mixes it as +silence. + +A mixer is refused as `mix_input_malformed` when an output has other than 1 or 2 +channels, or an input has other than 1 or 2 channels, has other than *N* frames, or a +gain or pan out of range. + +The mix is byte-exact over the decoded PCM: two mixers given the same blocks give the +same samples. It is not byte-exact over what precedes and follows it. A decoder of a lossy +codec need not reproduce another decoder's PCM bit for bit (RFC 6716 §6 holds a decoder to +a quality measure, not to equality), and a lossy encode of the mix is not +byte-reproducible: two encoders, or one encoder under two settings, give different bytes. +The receipt (§8) therefore binds the input objects and the output object, not samples. + +## 7. Where composition runs + +**On each sink, by default.** A sink composes the room locally from the tracks it +subscribes to, by §5 and §6, with no server decode or encode. It needs no power: the +descriptor states how the room is laid out, and laying it out is reading it. + +**On a server, under the compose power.** A principal that publishes a composed track (its +own `video` track for a layout, its own `audio` track for a mix, live-rooms §6.1) **MUST** +be the descriptor's `compositor`, **MUST** hold the compose power in its grant in effect, +and **MUST** sign a receipt (§8) for each object of a composed track it publishes. It is +not a participant of its own composition (§4.2), so a composed track is never composed +again. A subscriber subscribes to a composed track as to any other; the descriptor and the +receipts let it check that the track is the room's composition. + +## 8. The composition receipt + +### 8.1 Layout + +| field | size | meaning | +|---|---|---| +| `magic` | 4 | `WCR1` (ASCII) | +| `version` | 1 | 1 in this revision | +| `room` | 32 | the room id | +| `compositor` | 32 | the compositor's key, which signs the receipt | +| `descriptor` | 32 | the digest of the descriptor it follows (§3.2) | +| `t` | 8 | u64: the room-clock instant of the output object | +| `state` | 32 | the digest of the participant set at `t` (§4.5) | +| `media` | 1 | 1 audio (a mix), 2 video (a layout) | +| `output` | 80 | the output object | +| `inputs` | 1 + 112 × *n* | a u8 count *n*, then each input: `principal` (32), the participant it is read from, and an object (80) | +| `sig` | 64 | Ed25519 by `compositor` | + +An **object** is 80 bytes: `track` (32), the digest live-events §3.1 gives an anchor's +`track`, over the track's namespace as live-rooms §6.2 renders it, one zero byte, and its +name; `group` and `object` (u64 each), its MOQT Location (MOQT §8.2); and `digest` (32), +the SHA-256 of the object's payload. An input whose `digest` is 32 zero bytes states that +the compositor held no object of that track for the output: it drew the tile with no +video, or mixed the voice as silence. + +The **digest** of a receipt is SHA-256 over its bytes before `sig`; its **signature** is +Ed25519 by `compositor` over the 25 bytes `wai:live-compose-receipt` (ASCII) and 0x01, +followed by the bytes the digest covers, verified strictly (SPEC §7 *Signatures*). A +reader reads exactly the bytes it is given, as §3.3 steps 1 to 3 read a descriptor with +`WCR1` for `WCD1` (`truncated`, `malformed`, `unknown_version`); refuses as +`receipt_invalid` a receipt whose `media` is not 1 or 2, or that names two inputs of one +participant and one track; and then verifies the signature (`bad_key`, `bad_signature`). + +### 8.2 The inputs + +The inputs of an output at *t* are, in this order: + +- **video** (`media` 2): for each tile of the layout at *t* that shows video, in drawing + order (§5.7), the tracks of its participant's video source; +- **audio** (`media` 1): for each voice, in order (§6), the tracks of its audio source. + +The **tracks** of a source are named as live-rooms §6.1 names them: the namespace is the +room, the owner (the participant's key, or `_` and the slot's name for a slot) and the +media kind; the names follow the profile's `layering` (live-rooms §6.3) at the composed +layer *L*: track `0` for `single` and `svc` (an `svc` track carries every layer), track +*L* for `simulcast`, and tracks `0` to *L* for `staged`, since a refinement is applied to +the layers below it ([staged-delivery](staged-delivery.md)). The receipt names, for each, +the object it read. + +### 8.3 Verifying a receipt + +A receipt verifier is given a room (as live-rooms §9.1), a descriptor and a receipt. In +this order, the first that fails names the refusal and where: + +1. **The room** (§4.1): its refusal, at `room`. +2. **The descriptor** (§3.3, §3.5): at `descriptor`. +3. **The receipt** reads (§8.1), at `receipt`; and its `room` is the room id, otherwise + `wrong_room`. +4. Its `descriptor` is the descriptor's digest: otherwise `descriptor_mismatch`. +5. Its `t` is at or after the descriptor's `effective`: otherwise `not_yet_effective`. +6. The descriptor names a compositor, the receipt's `compositor` is it, and that principal + is present at `t` with a grant in effect that has the compose power: otherwise + `compositor_not_permitted`. +7. Its `output`'s `track` is a track of the compositor's own track of the receipt's media + kind, published at `t`, at a layer from 0 to its `layers` − 1: otherwise + `output_not_published`. +8. **The set and the layout** at `t` (§4, §5): their refusal, at `set`. +9. Its `state` is the set's digest: otherwise `state_mismatch`. +10. Its inputs, each its `principal` and its object's `track`, are §8.2's, in order: + otherwise `inputs_mismatch`. + +A receipt that passes is **accepted**: its output object was composed under this +descriptor, from this set, out of objects of exactly the tracks the layout reads. Anyone +holding the room's events and the descriptor recomputes the layout and checks that the +inputs were the right ones; a party holding the objects checks their digests. The receipt +does not fix the output's pixels or samples (§6). + +## 9. Verification + +A **composition verifier** is given a room, a descriptor and a list of instants. It runs +these steps and stops at the first refusal, which it reports with the reason and where: + +1. **The room** (§4.1): at `room`, with the room's own place (live-rooms §9.1) when the + room is refused. +2. **The descriptor** (§3.3, §3.5): at `descriptor`. +3. **Each instant**, in the list's order: the instant is at or after `effective` + (otherwise `not_yet_effective`), and the participants' attributes read (§4.3, + otherwise `attr_malformed`): at `set`, with the instant. + +Its outcome is **refuse**, with the reason and the place; or the **composition**: the +descriptor's digest and, for each instant, the participants with their sources and +tracks, the set's digest, the order, the tiles and the voices. A receipt verifier (§8.3) +reports its refusals at the same places, and at `receipt`. + +## 10. Reasons + +The codes this extension adds, each with where it is raised: + +| reason | raised at | +|---|---| +| `canvas_out_of_range` | §3.3, §3.4 | +| `compose_invalid` | §3.3 | +| `compose_not_permitted` | §3.5 | +| `not_yet_effective` | §8.3 step 5, §9 step 3 | +| `lifecycle_incomplete` | §4.1 | +| `attr_malformed` | §4.3 | +| `mix_input_malformed` | §6 | +| `receipt_invalid` | §8.1 | +| `descriptor_mismatch` | §8.3 step 4 | +| `compositor_not_permitted` | §7, §8.3 step 6 | +| `output_not_published` | §8.3 step 7 | +| `state_mismatch` | §8.3 step 9 | +| `inputs_mismatch` | §8.3 step 10 | + +A verifier of this extension also raises `truncated`, `malformed` and `unknown_version` +for a descriptor or a receipt that does not read; `bad_key` and `bad_signature` for their +signatures; `wrong_room` for one of another room (§3.5, §8.3); and every code a room +verifier raises (live-rooms §11 and the live-events codes it lists), at `room`. + +## 11. Conformance + +[`live-conformance/compose/`](../live-conformance/compose/) holds the corpus, in one file, +`vectors.json`, written from fixed seeds by `wai_live_compose_vectors gen`. It has: + +- **layouts**: the layout function alone (§5, §6's voices), each case its parameters and + its participants with their join orders, video sizes, audio and attributes, and the + order, tiles and voices it gives, or its refusal. Grids of 0 to 12 tiles on a 16:9 + canvas, and on portrait, square and auto ones; every fill mode over sources of four + shapes and of extreme aspects; a featured participant present, absent, kept past the + tile limit, and first in order of two; ties in order broken by join order and by key; + stopped video shown and omitted; picture in picture in every corner under both + behaviours, alone static and alone dynamic, with derived sizes and stopped video; and + attributes that do not read. +- **mixes**: blocks of PCM and the mix of them (§6): passing through, both widths into + both, saturation high and low and only at the end, pans and gains at their limits, + rounding at ties, silence, and inputs refused. +- **descriptors**: records read (§3), with their digest and fields, or refused with each + reason a descriptor alone can have. +- **rooms**: a studio room under the live-rooms descriptor, grants and chains that its + vectors name, and four variants of it: a grant whose order does not read, a lifecycle + record not delivered, a viewer's chat not delivered, and a viewer's record refused. +- **compositions**: a room, a descriptor and instants (§9), with the composition or the + refusal. The grid over the whole session re-lays the room out at each lifecycle + instant, among them a grant exchange that reorders it; the picture in picture composes + a lower layer. +- **receipts**: a room, a descriptor and a receipt (§8.3), accepted with its digest and + the set's, or refused with each reason a receipt can have. + +A conforming verifier gives every case the outcome, the reason, the place and the data the +corpus states. `wai_live_compose_vectors verify` and the test `tests/live_compose.rs` +check that the file regenerates byte for byte, that `wai-rs` gives every case its +outcome, that every reason of §10 refuses a case, and that §10 lists exactly the +reference's codes. `live-conformance/live_compose_verify.py` is the second implementation, +written from this text: it shares no code with `wai-rs`, verifies signatures with WAI's +strict rule written from RFC 8032 (`claim-conformance/_ed25519.py`), verifies each room +with the live-rooms corpus's own second implementation (`live_rooms_verify.py`) and +replays its lifecycle to each instant itself, and gives every case the same outcome, +rectangle for rectangle and sample for sample; it also mutates copies of the corpus and +requires every copy to fail. + +## 12. Security and privacy considerations + +- The layout is computed from what the room authority signed: the descriptor, or a + principal's under the power the authority granted, and the attributes of grants the + authority signed. A participant cannot place itself; a relay that drops or reorders + lifecycle events is seen as a gap in a room key's chain (§4.1), not as another layout. +- A server compositor's receipt fixes which objects it composed and under which set. A + compositor that left a participant out, read a layer other than the composed one, or + composed a stale set is refused by §8.3. The receipt does not fix the output's pixels + or samples, which a lossy encode does not reproduce (§6); a party that needs them + composes locally from the inputs. +- Composition on each sink needs no server to decode the room's media, so a room whose + tracks are end-to-end encrypted ([confidentiality](confidentiality.md)) can still be + laid out: the layout reads the room's events and the grants, never media. +- The participant set names every publisher, its grant and its join order. Composing a + room reveals nothing a member of it does not already hold, but a set digest published + outside the room links the participants it names; a room that needs participation + unlinkable across rooms gives principals a key per room (live-events §11). +- Attributes are read as the descriptor's keys name them and nothing else is read of a + grant's attributes, so an attribute a descriptor does not name changes nothing. diff --git a/wai/extensions/live-rooms.md b/wai/extensions/live-rooms.md index b4e6d4edf..b52eea8d3 100644 --- a/wai/extensions/live-rooms.md +++ b/wai/extensions/live-rooms.md @@ -32,7 +32,7 @@ slots, and the `detail` of every lifecycle kind of live-events §4.13 (§7); the profiles (§8); room verification (§9); and the bindings onto token formats (§10). Out of scope: a transport; how a principal obtains a grant; composition, which reads the -grant's attributes (a later extension); the review workflow, of which this extension +grant's attributes ([live-compose](live-compose.md)); the review workflow, of which this extension fixes only the policy's fields and their meaning (§3.6); and what a recording holds, which the recording policy constrains (§3.7) and later extensions define: a device's master recording is [capture-binding](capture-binding.md)'s take. @@ -108,7 +108,8 @@ A **role** maps a name to a **capability set**: - `events`: the event kinds it may send, a kinds bitmap within the ceiling's `kinds`. - `powers`: bit 0 **moderate** (its `decision` events, live-events §4.11, are a moderator's), bit 1 **direct** (it may send `control` commands other than recording), - bit 2 **compose** (it may author the room's composition, a later extension), bit 3 + bit 2 **compose** (it may sign the room's composition descriptor and publish a composed +track, [live-compose](live-compose.md) §3.5, §7), bit 3 **record** (it may send `record_start` and `record_stop`). A role whose `events` permit `decision` has the moderate power; one whose `events` permit @@ -260,9 +261,11 @@ value (a long field holding UTF-8, RFC 3629). Keys are in strictly ascending byt and the entries take at most 1024 bytes, not counting the field's own length. An entry that runs past the field's end breaks the rule. -Attributes are for composition: a later extension lays a room out from them. It reads -`featured` (`true` or `false`), `order` (a decimal integer) and `pip` (`true` or -`false`); this revision reads their syntax alone. Capture binding +Attributes are for composition: [live-compose](live-compose.md) lays a room out from +them. It reads `featured` (`true` or `false`), `order` (a decimal integer) and `pip` +(`true` or `false`), and `gain` and `pan` (decimal integers) for the mix, under the keys a +composition descriptor names, and gives each its syntax and its meaning (live-compose +§4.3); this revision checks only the form of the entries. Capture binding ([capture-binding](capture-binding.md) §3) reads two more: `subject`, the principal a device captures for, as 64 lowercase hexadecimal digits of its key; and `minor` (`true` or `false`), whether the authority marks that principal a minor. Attributes are signed with the grant, diff --git a/wai/live-conformance/README.md b/wai/live-conformance/README.md index 491e1eb68..7baefba92 100644 --- a/wai/live-conformance/README.md +++ b/wai/live-conformance/README.md @@ -8,11 +8,13 @@ and the independent verifier of each, beside it. | [`events/`](events/) | [live-events](../extensions/live-events.md) (`wai.live.events`) | `live_events_verify.py` | | [`rooms/`](rooms/) | [live-rooms](../extensions/live-rooms.md) (`wai.live.room`) | `live_rooms_verify.py` | | [`takes/`](takes/) | [capture-binding](../extensions/capture-binding.md) (`wai.capture.take`) | `capture_take_verify.py` | +| [`compose/`](compose/) | [live-compose](../extensions/live-compose.md) (`wai.live.compose`) | `live_compose_verify.py` | **Provenance.** Generated here: `wai_live_events_vectors gen` writes `events/`, -`wai_live_room_vectors gen` writes `rooms/` and `wai_capture_take_vectors gen` writes -`takes/`, each from records authored in code, from fixed seeds (`events/README.md`, -`rooms/README.md`, `takes/README.md`). No recorded data. +`wai_live_room_vectors gen` writes `rooms/`, `wai_capture_take_vectors gen` writes +`takes/` and `wai_live_compose_vectors gen` writes `compose/`, each from records authored in +code, from fixed seeds (`events/README.md`, `rooms/README.md`, `takes/README.md`, +`compose/README.md`). No recorded data. Each verifier is written from its extension's text, shares no code with `wai-rs`, and is run by `.github/workflows/wai-conformance.yml` beside the reference's own check: @@ -21,4 +23,5 @@ run by `.github/workflows/wai-conformance.yml` beside the reference's own check: python3 live_events_verify.py events python3 live_rooms_verify.py rooms python3 capture_take_verify.py takes +python3 live_compose_verify.py compose ``` diff --git a/wai/live-conformance/compose/README.md b/wai/live-conformance/compose/README.md new file mode 100644 index 000000000..6f48d37a2 --- /dev/null +++ b/wai/live-conformance/compose/README.md @@ -0,0 +1,111 @@ +# live-conformance/compose — live composition + +The corpus of [`extensions/live-compose.md`](../../extensions/live-compose.md) §11: the +layout function and the mixer on their own, `WCD1` composition descriptors, and rooms (a +signed `WRD1` descriptor, its `WRG1` grants and its principals' `WEV1` chains) composed at +a list of instants, with `WCR1` composition receipts checked against them. + +**Composition equivalence.** A conforming implementation reaches, for every case, the +outcome the case states, rectangle for rectangle and sample for sample: + +- a **layout** case's `params` (the descriptor's fields, §3.1) and `entrants` (each a + `principal`, its `join` order, its `video` as `[width, height]` or `null`, whether it has + `audio`, and its `attrs` as `[key, value]` pairs) give the `order`, the `tiles` and the + `voices` of §5 and §6, or the refusal `reason`. A tile is its `principal`, its `place` + (`grid`, `featured` or `pip`), its `z`, its `tile` rectangle and its `dst` and `src` + rectangles (`null` when its video is stopped), each `[x, y, w, h]`; a voice its + `principal`, `gain` and `pan`; +- a **mix** case's `channels`, `frames` and `inputs` (each its `channels`, `gain`, `pan` and + `pcm`, signed 16-bit little-endian samples in hexadecimal) give the mixed `pcm` (§6), or + the refusal; +- a **descriptor** case's `bytes` read (§3.3) to its `digest` and `fields`, or are refused; +- a **composition** case's `room`, `descriptor` and `instants` give the descriptor's + `digest` and a frame per instant (§9): its `participants` (each its `principal`, its + `grant`, its `join` order, its `attrs`, and its `video` and `audio` sources with their + slot, media kind, profile, layers, composed layer, layering, dimensions and `tracks`), + its `set_digest` (§4.5), and its `order`, `tiles` and `voices`; or a refusal and where, + `at`: `["room"]`, `["room", …]` with the room verifier's own place (live-rooms §9.1), + `["descriptor"]` or `["set", t]`; +- a **receipt** case's `room`, `descriptor` and `receipt` are accepted (§8.3) with the + receipt's `digest` and the `set_digest` it names, or refused, `at` as above or + `["receipt"]`. + +A verifier that reaches another outcome, reason, place, rectangle, sample or digest does +not conform. + +**Provenance.** Generated here: `wai_live_compose_vectors gen` writes every case, room, +descriptor, record and receipt from scenes authored in code, from fixed seeds. Each key is +SHA-256 of a fixed label and the principal's index, each pure layout case's participant a +SHA-256 of a fixed label and an index (a name, not a key), each block of PCM SHA-256 output +under a fixed label (it stands for decoded audio and is no recording), each object digest +of a receipt SHA-256 of a fixed label (it stands for an object and hashes none), every time +is a constant (the room's `t0` is 2026-10-17T00:00:00Z), and Ed25519 signing is +deterministic (RFC 8032), so the file is the same bytes on every machine. The generator +asserts that each case reaches the outcome it was written to have before it writes it. No +recorded data. + +## Layout + +One file, `vectors.json`: + +- `principals`: the room's keys, by name (informative). +- `layouts`, `mixes`, `descriptors`: the cases above, each with `name` and `about`. +- `rooms`: by name, each a `descriptor` and `grants` (hexadecimal), `key_log_head` (`null`: + the room names no origin) and `chains` (lists of records in hexadecimal). +- `compositions`, `receipts`: the cases above, each naming its room. + +The **studio** room has a director (its role has the direct and compose powers), a +performer (camera and music, featured, order 1, gain 5120), a guest (speech only at first, +order 3, then exchanged at 5 s for a grant of order 0, gain 2048 and pan −2048, then video +at 7 s), a screen-sharing device, an encoder live in the slot `main` under a staged +profile of the room's own, a mixer (the compose power; it publishes the composed tracks), +and a viewer. The director's video stops at 6 s and the performer leaves at 8 s. Its +variants: `studio_bad_order` (the guest's order is `third`), `studio_lifecycle_gap` (the +relay's record at 6 s not delivered), `studio_viewer_gap` (the viewer's first chat not +delivered) and `studio_refused` (the viewer sends a `control` it may not). + +Cases: + +- layouts: `grid_0` to `grid_12`; portrait, square and auto canvases; `fill_fill`, + `fill_cover`, `fill_contain`, `fill_default` and extreme aspects; the featured + participant alone, of four, on a portrait canvas, kept past the tile limit, first of two, + absent, and unread; order by attribute and ties broken by key; stopped video shown and + omitted; the tile limit and the voice limit; picture in picture in each corner, static + and dynamic, alone, with derived sizes, with stopped video, first of two, and over a + featured tile; and attributes that do not read; +- mixes: passing through, both widths into both, saturation, pans, gains, ties, silence and + five refusals; +- descriptors: the room's three and canvases at their limits, and each refusal a descriptor + alone can have; +- compositions: `grid_session` (every second from 1 s to 9 s), `pip_session`, + `participant_gap`, `signer_with_power`, and a refusal for a signer without the power, one + not in the room, another room, a bad signature, an instant before `effective`, an + attribute that does not read, a lifecycle gap and a refused room; +- receipts: `video`, `audio` and `pip_video` accepted, and one refused for each reason a + receipt can have. + +## Running + +``` +cd ../../wai-rs +cargo run --no-default-features --features live_compose --bin wai_live_compose_vectors -- verify ../live-conformance/compose +cargo run --no-default-features --features live_compose --bin wai_live_compose_vectors -- gen ../live-conformance/compose # regenerate +cargo test --no-default-features --features live_compose --test live_compose +cd ../live-conformance +python3 live_compose_verify.py compose +``` + +`wai_live_compose_vectors verify` and `tests/live_compose.rs` require the file to regenerate +byte for byte and `wai-rs` to give every case its outcome; the test also requires every +reason of §10 to refuse a case, the cases above to be there, the grid session to change its +order at the guest's exchange, and §10 to list exactly the reasons the reference reports. +`live_compose_verify.py` is the second implementation, written from the extension's text +and sharing no code with `wai-rs`: it verifies each room with `live_rooms_verify.py` and +steps through its lifecycle replay to take the room at each instant, gives every case the +same outcome, requires the same coverage of reasons, and then mutates copies of the corpus, +one defect each (a tile moved, tiles swapped, the PiP window's z, a source or destination +rectangle, the order, an entrant's attribute, a parameter, a stated reason, a voice, a mixed +or input sample, a pan, a descriptor's byte or digest, a frame's tile, set digest, join +order or tracks, an instant, a lifecycle record not delivered, a grant's byte, a receipt's +byte or digest, and a stated outcome), each of which must fail. Pass = an exit status of 0 +from each. diff --git a/wai/live-conformance/compose/vectors.json b/wai/live-conformance/compose/vectors.json new file mode 100644 index 000000000..fcbafe516 --- /dev/null +++ b/wai/live-conformance/compose/vectors.json @@ -0,0 +1,19209 @@ +{ + "corpus": "wai.live.compose", + "extension": "extensions/live-compose.md", + "principals": { + "authority": "5307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4", + "relay": "823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b", + "director": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "performer": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "guest": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "screen": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "encoder": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "mixer": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "viewer": "f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b5", + "impostor": "1806fc2de983e5f70a0b10e791ec06743adef5f2ef21d729e2ff6a8ab6e63c7f" + }, + "layouts": [ + { + "name": "grid_0", + "about": "0 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [], + "outcome": "layout", + "order": [], + "tiles": [], + "voices": [] + }, + { + "name": "grid_1", + "about": "1 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 1080 + ], + "dst": [ + 0, + 0, + 1920, + 1080 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_2", + "about": "2 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 964, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_3", + "about": "3 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_4", + "about": "4 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_5", + "about": "5 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 90, + 634, + 356 + ], + "dst": [ + 1, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 643, + 90, + 634, + 356 + ], + "dst": [ + 643, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1285, + 90, + 634, + 356 + ], + "dst": [ + 1285, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 322, + 634, + 634, + 356 + ], + "dst": [ + 322, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 964, + 634, + 634, + 356 + ], + "dst": [ + 964, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_6", + "about": "6 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 90, + 634, + 356 + ], + "dst": [ + 1, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 643, + 90, + 634, + 356 + ], + "dst": [ + 643, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1285, + 90, + 634, + 356 + ], + "dst": [ + 1285, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1, + 634, + 634, + 356 + ], + "dst": [ + 1, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 643, + 634, + 634, + 356 + ], + "dst": [ + 643, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 1285, + 634, + 634, + 356 + ], + "dst": [ + 1285, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_7", + "about": "7 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 3, + 1, + 629, + 354 + ], + "dst": [ + 3, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 645, + 1, + 629, + 354 + ], + "dst": [ + 645, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1287, + 1, + 629, + 354 + ], + "dst": [ + 1287, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 3, + 363, + 629, + 354 + ], + "dst": [ + 3, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 645, + 363, + 629, + 354 + ], + "dst": [ + 645, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 1287, + 363, + 629, + 354 + ], + "dst": [ + 1287, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 645, + 725, + 629, + 354 + ], + "dst": [ + 645, + 725, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_8", + "about": "8 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 3, + 1, + 629, + 354 + ], + "dst": [ + 3, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 645, + 1, + 629, + 354 + ], + "dst": [ + 645, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1287, + 1, + 629, + 354 + ], + "dst": [ + 1287, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 3, + 363, + 629, + 354 + ], + "dst": [ + 3, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 645, + 363, + 629, + 354 + ], + "dst": [ + 645, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 1287, + 363, + 629, + 354 + ], + "dst": [ + 1287, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 324, + 725, + 629, + 354 + ], + "dst": [ + 324, + 725, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "place": "grid", + "z": 0, + "tile": [ + 966, + 725, + 629, + 354 + ], + "dst": [ + 966, + 725, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_9", + "about": "9 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "join": 8, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 3, + 1, + 629, + 354 + ], + "dst": [ + 3, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 645, + 1, + 629, + 354 + ], + "dst": [ + 645, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1287, + 1, + 629, + 354 + ], + "dst": [ + 1287, + 1, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 3, + 363, + 629, + 354 + ], + "dst": [ + 3, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 645, + 363, + 629, + 354 + ], + "dst": [ + 645, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 1287, + 363, + 629, + 354 + ], + "dst": [ + 1287, + 363, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 3, + 725, + 629, + 354 + ], + "dst": [ + 3, + 725, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "place": "grid", + "z": 0, + "tile": [ + 645, + 725, + 629, + 354 + ], + "dst": [ + 645, + 725, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "place": "grid", + "z": 0, + "tile": [ + 1287, + 725, + 629, + 354 + ], + "dst": [ + 1287, + 725, + 629, + 354 + ], + "src": [ + 0, + 0, + 1279, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_10", + "about": "10 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "join": 8, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "join": 9, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 45, + 474, + 266 + ], + "dst": [ + 0, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 482, + 45, + 474, + 266 + ], + "dst": [ + 482, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 964, + 45, + 474, + 266 + ], + "dst": [ + 964, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 45, + 474, + 266 + ], + "dst": [ + 1446, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 0, + 407, + 474, + 266 + ], + "dst": [ + 0, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 482, + 407, + 474, + 266 + ], + "dst": [ + 482, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 964, + 407, + 474, + 266 + ], + "dst": [ + 964, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 407, + 474, + 266 + ], + "dst": [ + 1446, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "place": "grid", + "z": 0, + "tile": [ + 482, + 769, + 474, + 266 + ], + "dst": [ + 482, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "place": "grid", + "z": 0, + "tile": [ + 964, + 769, + 474, + 266 + ], + "dst": [ + 964, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "gain": 4096, + "pan": 0 + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_11", + "about": "11 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "join": 8, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "join": 9, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "join": 10, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 45, + 474, + 266 + ], + "dst": [ + 0, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 482, + 45, + 474, + 266 + ], + "dst": [ + 482, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 964, + 45, + 474, + 266 + ], + "dst": [ + 964, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 45, + 474, + 266 + ], + "dst": [ + 1446, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 0, + 407, + 474, + 266 + ], + "dst": [ + 0, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 482, + 407, + 474, + 266 + ], + "dst": [ + 482, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 964, + 407, + 474, + 266 + ], + "dst": [ + 964, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 407, + 474, + 266 + ], + "dst": [ + 1446, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "place": "grid", + "z": 0, + "tile": [ + 241, + 769, + 474, + 266 + ], + "dst": [ + 241, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "place": "grid", + "z": 0, + "tile": [ + 723, + 769, + 474, + 266 + ], + "dst": [ + 723, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "place": "grid", + "z": 0, + "tile": [ + 1205, + 769, + 474, + 266 + ], + "dst": [ + 1205, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "gain": 4096, + "pan": 0 + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "grid_12", + "about": "12 participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "join": 8, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "join": 9, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "join": 10, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "join": 11, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 45, + 474, + 266 + ], + "dst": [ + 0, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 482, + 45, + 474, + 266 + ], + "dst": [ + 482, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 964, + 45, + 474, + 266 + ], + "dst": [ + 964, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 45, + 474, + 266 + ], + "dst": [ + 1446, + 45, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 0, + 407, + 474, + 266 + ], + "dst": [ + 0, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 482, + 407, + 474, + 266 + ], + "dst": [ + 482, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 964, + 407, + 474, + 266 + ], + "dst": [ + 964, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 407, + 474, + 266 + ], + "dst": [ + 1446, + 407, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "place": "grid", + "z": 0, + "tile": [ + 0, + 769, + 474, + 266 + ], + "dst": [ + 0, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "place": "grid", + "z": 0, + "tile": [ + 482, + 769, + 474, + 266 + ], + "dst": [ + 482, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "place": "grid", + "z": 0, + "tile": [ + 964, + 769, + 474, + 266 + ], + "dst": [ + 964, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 769, + 474, + 266 + ], + "dst": [ + 1446, + 769, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "gain": 4096, + "pan": 0 + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "gain": 4096, + "pan": 0 + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "portrait_2", + "about": "2 participants on a 1080 × 1920 canvas with 3:4 tiles: rows before columns (§5.3)", + "params": { + "width": 1080, + "height": 1920, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 3, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 181, + 0, + 717, + 956 + ], + "dst": [ + 181, + 0, + 717, + 956 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 181, + 964, + 717, + 956 + ], + "dst": [ + 181, + 964, + 717, + 956 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "portrait_5", + "about": "5 participants on a 1080 × 1920 canvas with 3:4 tiles: rows before columns (§5.3)", + "params": { + "width": 1080, + "height": 1920, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 3, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 30, + 1, + 475, + 634 + ], + "dst": [ + 30, + 1, + 475, + 634 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 574, + 1, + 475, + 634 + ], + "dst": [ + 574, + 1, + 475, + 634 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 30, + 643, + 475, + 634 + ], + "dst": [ + 30, + 643, + 475, + 634 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 574, + 643, + 475, + 634 + ], + "dst": [ + 574, + 643, + 475, + 634 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 302, + 1285, + 475, + 634 + ], + "dst": [ + 302, + 1285, + 475, + 634 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "portrait_7", + "about": "7 participants on a 1080 × 1920 canvas with 3:4 tiles: rows before columns (§5.3)", + "params": { + "width": 1080, + "height": 1920, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 3, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 90, + 0, + 355, + 474 + ], + "dst": [ + 90, + 0, + 355, + 474 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 634, + 0, + 355, + 474 + ], + "dst": [ + 634, + 0, + 355, + 474 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 90, + 482, + 355, + 474 + ], + "dst": [ + 90, + 482, + 355, + 474 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 634, + 482, + 355, + 474 + ], + "dst": [ + 634, + 482, + 355, + 474 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 90, + 964, + 355, + 474 + ], + "dst": [ + 90, + 964, + 355, + 474 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 634, + 964, + 355, + 474 + ], + "dst": [ + 634, + 964, + 355, + 474 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 362, + 1446, + 355, + 474 + ], + "dst": [ + 362, + 1446, + 355, + 474 + ], + "src": [ + 370, + 0, + 539, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "portrait_12", + "about": "12 participants on a 1080 × 1920 canvas with 3:4 tiles: rows before columns (§5.3)", + "params": { + "width": 1080, + "height": 1920, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 3, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "join": 8, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "join": 9, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "join": 10, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "join": 11, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 1, + 354, + 472 + ], + "dst": [ + 1, + 1, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 363, + 1, + 354, + 472 + ], + "dst": [ + 363, + 1, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 725, + 1, + 354, + 472 + ], + "dst": [ + 725, + 1, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1, + 483, + 354, + 472 + ], + "dst": [ + 1, + 483, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 363, + 483, + 354, + 472 + ], + "dst": [ + 363, + 483, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 725, + 483, + 354, + 472 + ], + "dst": [ + 725, + 483, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 1, + 965, + 354, + 472 + ], + "dst": [ + 1, + 965, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "place": "grid", + "z": 0, + "tile": [ + 363, + 965, + 354, + 472 + ], + "dst": [ + 363, + 965, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "place": "grid", + "z": 0, + "tile": [ + 725, + 965, + 354, + 472 + ], + "dst": [ + 725, + 965, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "place": "grid", + "z": 0, + "tile": [ + 1, + 1447, + 354, + 472 + ], + "dst": [ + 1, + 1447, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "place": "grid", + "z": 0, + "tile": [ + 363, + 1447, + 354, + 472 + ], + "dst": [ + 363, + 1447, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "place": "grid", + "z": 0, + "tile": [ + 725, + 1447, + 354, + 472 + ], + "dst": [ + 725, + 1447, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "gain": 4096, + "pan": 0 + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "gain": 4096, + "pan": 0 + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "square_3", + "about": "3 participants on a 1080 × 1080 canvas with 1:1 tiles (§5.3)", + "params": { + "width": 1080, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 2, + "aspect": 2, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 539, + 539 + ], + "dst": [ + 0, + 0, + 539, + 539 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 541, + 0, + 539, + 539 + ], + "dst": [ + 541, + 0, + 539, + 539 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 270, + 541, + 539, + 539 + ], + "dst": [ + 270, + 541, + 539, + 539 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "square_6", + "about": "6 participants on a 1080 × 1080 canvas with 1:1 tiles (§5.3)", + "params": { + "width": 1080, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 2, + "aspect": 2, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 90, + 358, + 358 + ], + "dst": [ + 1, + 90, + 358, + 358 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 361, + 90, + 358, + 358 + ], + "dst": [ + 361, + 90, + 358, + 358 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 721, + 90, + 358, + 358 + ], + "dst": [ + 721, + 90, + 358, + 358 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1, + 631, + 358, + 358 + ], + "dst": [ + 1, + 631, + 358, + 358 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 361, + 631, + 358, + 358 + ], + "dst": [ + 361, + 631, + 358, + 358 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 721, + 631, + 358, + 358 + ], + "dst": [ + 721, + 631, + 358, + 358 + ], + "src": [ + 280, + 0, + 720, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "auto_4", + "about": "four participants on 1280 × 720 with auto tiles: the 16:9 grid, each tile its whole cell (§5.2, §5.3)", + "params": { + "width": 1280, + "height": 720, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 0, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 636, + 356 + ], + "dst": [ + 0, + 0, + 636, + 356 + ], + "src": [ + 0, + 2, + 1280, + 716 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 644, + 0, + 636, + 356 + ], + "dst": [ + 644, + 0, + 636, + 356 + ], + "src": [ + 0, + 2, + 1280, + 716 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 0, + 364, + 636, + 356 + ], + "dst": [ + 0, + 364, + 636, + 356 + ], + "src": [ + 0, + 2, + 1280, + 716 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 644, + 364, + 636, + 356 + ], + "dst": [ + 644, + 364, + 636, + 356 + ], + "src": [ + 0, + 2, + 1280, + 716 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "auto_9_no_gap", + "about": "nine participants on 1280 × 720, auto tiles, no gap: three by three cells that tile the canvas (§5.3)", + "params": { + "width": 1280, + "height": 720, + "fps": 30, + "layout": 1, + "gap": 0, + "aspect": 0, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "join": 8, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 0, + 426, + 240 + ], + "dst": [ + 1, + 0, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 427, + 0, + 426, + 240 + ], + "dst": [ + 427, + 0, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 853, + 0, + 426, + 240 + ], + "dst": [ + 853, + 0, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1, + 240, + 426, + 240 + ], + "dst": [ + 1, + 240, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 427, + 240, + 426, + 240 + ], + "dst": [ + 427, + 240, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 853, + 240, + 426, + 240 + ], + "dst": [ + 853, + 240, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 1, + 480, + 426, + 240 + ], + "dst": [ + 1, + 480, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "place": "grid", + "z": 0, + "tile": [ + 427, + 480, + 426, + 240 + ], + "dst": [ + 427, + 480, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "place": "grid", + "z": 0, + "tile": [ + 853, + 480, + 426, + 240 + ], + "dst": [ + 853, + 480, + 426, + 240 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "fill_fill", + "about": "a portrait, a square, a 4:3 and a 16:9 source in 16:9 tiles, fill mode fill (§5.6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 1, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 720, + 1280 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1080, + 1080 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 640, + 480 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1920, + 1080 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 0, + 0, + 720, + 1280 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 0, + 0, + 1080, + 1080 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 0, + 0, + 640, + 480 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "fill_cover", + "about": "a portrait, a square, a 4:3 and a 16:9 source in 16:9 tiles, fill mode cover (§5.6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 2, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 720, + 1280 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1080, + 1080 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 640, + 480 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1920, + 1080 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 0, + 437, + 720, + 405 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 0, + 236, + 1080, + 608 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 0, + 60, + 640, + 360 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1918, + 1080 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "fill_contain", + "about": "a portrait, a square, a 4:3 and a 16:9 source in 16:9 tiles, fill mode contain (§5.6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 3, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 720, + 1280 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1080, + 1080 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 640, + 480 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1920, + 1080 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 327, + 0, + 301, + 536 + ], + "src": [ + 0, + 0, + 720, + 1280 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 1174, + 0, + 536, + 536 + ], + "src": [ + 0, + 0, + 1080, + 1080 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 121, + 544, + 714, + 536 + ], + "src": [ + 0, + 0, + 640, + 480 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 535 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "fill_default", + "about": "a portrait, a square, a 4:3 and a 16:9 source in 16:9 tiles, fill mode default (§5.6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 720, + 1280 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1080, + 1080 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 640, + 480 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1920, + 1080 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 0, + 437, + 720, + 405 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 0, + 236, + 1080, + 608 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 0, + 60, + 640, + 360 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1918, + 1080 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "extreme_aspect", + "about": "a 1920 × 2 source and a 2 × 1080 one, cover and contain: every rectangle at least a pixel each way (§5.1, §5.6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 3, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1920, + 2 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 2, + 1080 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 539, + 956, + 1 + ], + "src": [ + 0, + 0, + 1920, + 2 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 1441, + 271, + 1, + 537 + ], + "src": [ + 0, + 0, + 2, + 1080 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "extreme_aspect_cover", + "about": "the same two sources under cover (§5.6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 2, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1920, + 2 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 2, + 1080 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 271, + 956, + 537 + ], + "src": [ + 958, + 0, + 3, + 2 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 964, + 271, + 956, + 537 + ], + "src": [ + 0, + 539, + 2, + 1 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "featured_alone", + "about": "one participant, featured: the featured tile is the whole canvas, contained by default (§5.4)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 1080 + ], + "dst": [ + 0, + 0, + 1920, + 1080 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "featured_4", + "about": "four participants, the third featured: it takes the region above, the other three a grid in the band below (§5.4)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 80, + 812, + 476, + 268 + ], + "dst": [ + 80, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 722, + 812, + 476, + 268 + ], + "dst": [ + 722, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1364, + 812, + 476, + 268 + ], + "dst": [ + 1364, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "featured_4_portrait", + "about": "the same on a portrait canvas (§5.4)", + "params": { + "width": 1080, + "height": 1920, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 3, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1080, + 1434 + ], + "dst": [ + 0, + 413, + 1080, + 607 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 1445, + 354, + 472 + ], + "dst": [ + 1, + 1445, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 363, + 1445, + 354, + 472 + ], + "dst": [ + 363, + 1445, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 725, + 1445, + 354, + 472 + ], + "dst": [ + 725, + 1445, + 354, + 472 + ], + "src": [ + 370, + 0, + 540, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "featured_kept_past_the_limit", + "about": "twelve participants and at most eight tiles, the tenth featured: it is moved first, so the cut keeps it (§5.2)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 8, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "join": 8, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "join": 9, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "join": 10, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "join": 11, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd" + ], + "tiles": [ + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 871, + 267, + 150 + ], + "dst": [ + 1, + 871, + 267, + 150 + ], + "src": [ + 0, + 0, + 1280, + 719 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 276, + 871, + 267, + 150 + ], + "dst": [ + 276, + 871, + 267, + 150 + ], + "src": [ + 0, + 0, + 1280, + 719 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 551, + 871, + 267, + 150 + ], + "dst": [ + 551, + 871, + 267, + 150 + ], + "src": [ + 0, + 0, + 1280, + 719 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 826, + 871, + 267, + 150 + ], + "dst": [ + 826, + 871, + 267, + 150 + ], + "src": [ + 0, + 0, + 1280, + 719 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 1101, + 871, + 267, + 150 + ], + "dst": [ + 1101, + 871, + 267, + 150 + ], + "src": [ + 0, + 0, + 1280, + 719 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "grid", + "z": 0, + "tile": [ + 1376, + 871, + 267, + 150 + ], + "dst": [ + 1376, + 871, + 267, + 150 + ], + "src": [ + 0, + 0, + 1280, + 719 + ] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "place": "grid", + "z": 0, + "tile": [ + 1651, + 871, + 267, + 150 + ], + "dst": [ + 1651, + 871, + 267, + 150 + ], + "src": [ + 0, + 0, + 1280, + 719 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + }, + { + "principal": "f56b5515b14d2adbb0076ad32787881ae8482ef5723332c277cf32ef394ba0d0", + "gain": 4096, + "pan": 0 + }, + { + "principal": "7ed05a511b07c93236eeec79f3e4c2e6d24c070a83641a14756235ebd86cf530", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ba5d7437f27ce816865d6e2ca3d80c947f20ecb37f98c1b9f8e047fdacc621a4", + "gain": 4096, + "pan": 0 + }, + { + "principal": "29aab9850edff9d2fb4f3fd0990a75193d7f18ef9ec963fb744841e11b7206dd", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "featured_first_in_order", + "about": "two participants featured: the first in order is featured, the other is a grid tile (§5.2)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 80, + 812, + 476, + 268 + ], + "dst": [ + 80, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 722, + 812, + 476, + 268 + ], + "dst": [ + 722, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1364, + 812, + 476, + 268 + ], + "dst": [ + 1364, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "featured_absent", + "about": "no participant featured (one says false): a plain grid (§5.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "false" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "featured_attr_unread", + "about": "a participant featured under a descriptor that names no featured attribute: a plain grid (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "order_attribute", + "about": "orders 5, none, -3, 5, none: -3 first, the two 5s by join order, then the two without one by join order (§4.4)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "5" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "-3" + ] + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "5" + ] + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df" + ], + "tiles": [ + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1, + 90, + 634, + 356 + ], + "dst": [ + 1, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 643, + 90, + 634, + 356 + ], + "dst": [ + 643, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 1285, + 90, + 634, + 356 + ], + "dst": [ + 1285, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 322, + 634, + 634, + 356 + ], + "dst": [ + 322, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 964, + 634, + 634, + 356 + ], + "dst": [ + 964, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "order_key_tie_break", + "about": "four participants with one order and one join order: ordered by key (§4.4)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "1" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "1" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "1" + ] + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "1" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c" + ], + "tiles": [ + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "stopped_shown", + "about": "five participants, two with stopped video, which keep their tiles with no video (§5.2)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": null, + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": null, + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 90, + 634, + 356 + ], + "dst": [ + 1, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 643, + 90, + 634, + 356 + ], + "dst": null, + "src": null + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1285, + 90, + 634, + 356 + ], + "dst": [ + 1285, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 322, + 634, + 634, + 356 + ], + "dst": null, + "src": null + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 964, + 634, + 634, + 356 + ], + "dst": [ + 964, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "stopped_omitted", + "about": "the same five with omit_stopped: three tiles; the mix keeps all five voices (§5.2, §6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": true, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": null, + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": null, + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "tile_limit", + "about": "eight participants and at most four tiles (§5.2)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 4, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "join": 6, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "join": 7, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + }, + { + "principal": "9764bf2c067b579903383e7abc4133c1fedd909877b1adcaedc69af7ef151ab3", + "gain": 4096, + "pan": 0 + }, + { + "principal": "ceab90a0754c5365f14f040b42d4263ea5e0e4257855d38756e4d8a92b7b37f6", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "voices", + "about": "five participants, one without audio, gains 0 and 16384 and pans at both ends, at most three voices (§6)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 3 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "gain", + "0" + ], + [ + "pan", + "-4096" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": false, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "gain", + "16384" + ], + [ + "pan", + "4096" + ] + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 1, + 90, + 634, + 356 + ], + "dst": [ + 1, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 643, + 90, + 634, + 356 + ], + "dst": [ + 643, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1285, + 90, + 634, + 356 + ], + "dst": [ + 1285, + 90, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 322, + 634, + 634, + 356 + ], + "dst": [ + 322, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "place": "grid", + "z": 0, + "tile": [ + 964, + 634, + 634, + 356 + ], + "dst": [ + 964, + 634, + 634, + 356 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 0, + "pan": -4096 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 16384, + "pan": 4096 + } + ] + }, + { + "name": "pip_top_left_static", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the top left corner, static: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 1, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 24, + 24, + 480, + 270 + ], + "dst": [ + 24, + 24, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_top_left_dynamic", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the top left corner, dynamic: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 1, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 2, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 24, + 24, + 480, + 270 + ], + "dst": [ + 24, + 24, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_top_right_static", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the top right corner, static: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 2, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 24, + 480, + 270 + ], + "dst": [ + 1416, + 24, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_top_right_dynamic", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the top right corner, dynamic: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 2, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 2, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 24, + 480, + 270 + ], + "dst": [ + 1416, + 24, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_bottom_left_static", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the bottom left corner, static: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 3, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 24, + 786, + 480, + 270 + ], + "dst": [ + 24, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_bottom_left_dynamic", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the bottom left corner, dynamic: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 3, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 2, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 24, + 786, + 480, + 270 + ], + "dst": [ + 24, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_bottom_right_static", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the bottom right corner, static: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_bottom_right_dynamic", + "about": "three participants and a PiP participant in a 480 × 270 window 24 pixels from the bottom right corner, dynamic: the others in a grid under it (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 2, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_alone_static", + "about": "the PiP participant alone, static: its window and the background (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_alone_dynamic", + "about": "the PiP participant alone, dynamic: laid out as if it had no pip attribute, a grid of one (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 2, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 1080 + ], + "dst": [ + 0, + 0, + 1920, + 1080 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_alone_dynamic_featured", + "about": "the PiP participant alone, dynamic, and featured: the featured tile, the whole canvas (§5.4, §5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 2, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ], + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 1080 + ], + "dst": [ + 0, + 0, + 1920, + 1080 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_size_derived", + "about": "pip_width and pip_height 0: a window of the PiP source's aspect, at most a quarter of the canvas wide (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 0, + "pip_height": 0, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 720, + 1280 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 964, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 203, + 480, + 853 + ], + "dst": [ + 1416, + 203, + 480, + 853 + ], + "src": [ + 0, + 0, + 720, + 1279 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_height_derived", + "about": "pip_width 360 and pip_height 0: the height from the source's aspect (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 360, + "pip_height": 0, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 720, + 1280 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 964, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "pip", + "z": 1, + "tile": [ + 1536, + 416, + 360, + 640 + ], + "dst": [ + 1536, + 416, + 360, + 640 + ], + "src": [ + 0, + 0, + 720, + 1280 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_width_derived", + "about": "pip_height 360 and pip_width 0: the width from the source's aspect (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 0, + "pip_height": 360, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 720, + 1280 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 964, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "pip", + "z": 1, + "tile": [ + 1694, + 696, + 202, + 360 + ], + "dst": [ + 1694, + 696, + 202, + 360 + ], + "src": [ + 1, + 0, + 718, + 1280 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_stopped_shown", + "about": "a PiP participant with stopped video and a derived size: a window of the canvas's aspect with no video (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 0, + "pip_height": 0, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": null, + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 964, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": null, + "src": null + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_stopped_omitted", + "about": "the same with omit_stopped: no PiP window, a grid of the others (§5.2, §5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": true, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": null, + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 0, + 271, + 956, + 537 + ], + "dst": [ + 0, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 964, + 271, + 956, + 537 + ], + "dst": [ + 964, + 271, + 956, + 537 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_first_in_order", + "about": "two PiP participants: the first in order takes the window, the other a grid tile (§5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "1" + ], + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_over_featured", + "about": "a PiP participant over a grid with a featured participant (§5.4, §5.5)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "true" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 240, + 812, + 476, + 268 + ], + "dst": [ + 240, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 1204, + 812, + 476, + 268 + ], + "dst": [ + 1204, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "pip_limit", + "about": "a PiP participant and five others, at most four tiles: the window and three grid tiles (§5.2)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 4, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "join": 3, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "join": 4, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "join": 5, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pip", + "true" + ] + ] + } + ], + "outcome": "layout", + "order": [ + "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411" + ], + "tiles": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": [ + 966, + 0, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "place": "grid", + "z": 0, + "tile": [ + 484, + 544, + 952, + 536 + ], + "dst": [ + 484, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "gain": 4096, + "pan": 0 + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "gain": 4096, + "pan": 0 + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "gain": 4096, + "pan": 0 + }, + { + "principal": "35cdbbf6ec5096f2e014fa1dadd2b36f825a9487a737a7bf97fd4b17f0e97386", + "gain": 4096, + "pan": 0 + }, + { + "principal": "cc40505c0f33b6bd1485ebf0fc046a4aaf309028dd9627d61c5a108ddbd235df", + "gain": 4096, + "pan": 0 + }, + { + "principal": "b9feb70372161bc9258cfa31617305e6b0587e7e7cdcc67772b549fbc77df411", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "name": "attr_order_leading_zero", + "about": "a participant whose order attribute is \"01\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "01" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_order_negative_zero", + "about": "a participant whose order attribute is \"-0\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "-0" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_order_too_large", + "about": "a participant whose order attribute is \"2147483648\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "2147483648" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_order_plus", + "about": "a participant whose order attribute is \"+1\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "order", + "+1" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_featured_capital", + "about": "a participant whose featured attribute is \"TRUE\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "featured", + "TRUE" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_gain_too_large", + "about": "a participant whose gain attribute is \"16385\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "gain", + "16385" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_gain_negative", + "about": "a participant whose gain attribute is \"-1\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "gain", + "-1" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_pan_too_far", + "about": "a participant whose pan attribute is \"-4097\" (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [ + [ + "pan", + "-4097" + ] + ] + }, + { + "principal": "d2eefc6518de0c92b4ce803ea00d4dbfb9fe8a883b37bf0039049a37e1750828", + "join": 2, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "attr_pip_yes", + "about": "a PiP attribute \"yes\", read though the participant's video is stopped and omitted (§4.3)", + "params": { + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": true, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 1, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": null, + "audio": true, + "attrs": [ + [ + "pip", + "yes" + ] + ] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "attr_malformed" + }, + { + "name": "params_canvas", + "about": "parameters a descriptor could not hold: a 1922-pixel canvas (§3.4)", + "params": { + "width": 1922, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + }, + "entrants": [ + { + "principal": "fd60bba9bcbf11525c8f5db827b49f80a59c4ccc0c01f30132777f83882d1d8c", + "join": 0, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + }, + { + "principal": "5b89dd49131a38fb5d4f386f43b2f9700f221913075f0d71c81a856f95a8eafa", + "join": 1, + "video": [ + 1280, + 720 + ], + "audio": true, + "attrs": [] + } + ], + "outcome": "refuse", + "reason": "canvas_out_of_range" + } + ], + "mixes": [ + { + "name": "unity_mono", + "about": "one mono voice at unity gain into mono: its samples unchanged, the extremes among them (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "0080ffff00000100ff7fc7cf39300200feff0300fdff64009cff007d00830700" + } + ], + "outcome": "mix", + "pcm": "0080ffff00000100ff7fc7cf39300200feff0300fdff64009cff007d00830700" + }, + { + "name": "unity_mono_to_stereo", + "about": "the same voice at the centre into stereo: both channels equal it (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "0080ffff00000100ff7fc7cf39300200feff0300fdff64009cff007d00830700" + } + ], + "outcome": "mix", + "pcm": "00800080ffffffff0000000001000100ff7fff7fc7cfc7cf3930393002000200fefffeff03000300fdfffdff640064009cff9cff007d007d0083008307000700" + }, + { + "name": "unity_stereo", + "about": "one stereo voice at unity gain and the centre into stereo: unchanged (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 2, + "gain": 4096, + "pan": 0, + "pcm": "fb5ffd0d87708b2de4592f801445ef23d59cd1a3120133d34879f5433336f6cd415b8eed70aac4e73bdff7ca78a76532981efdcdfad53f147bbe520a3a5bd80c" + } + ], + "outcome": "mix", + "pcm": "fb5ffd0d87708b2de4592f801445ef23d59cd1a3120133d34879f5433336f6cd415b8eed70aac4e73bdff7ca78a76532981efdcdfad53f147bbe520a3a5bd80c" + }, + { + "name": "stereo_to_mono", + "about": "a stereo voice into mono: half the sum of its channels, rounded half up (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 2, + "gain": 4096, + "pan": 0, + "pcm": "fb5ffd0d87708b2de4592f801445ef23d59cd1a3120133d34879f5433336f6cd415b8eed70aac4e73bdff7ca78a76532981efdcdfad53f147bbe520a3a5bd80c" + } + ], + "outcome": "mix", + "pcm": "fc36094f0aed823453a023ea9f5e150268241ac919d5efec4bf61df567e40934" + }, + { + "name": "sum_saturates_high", + "about": "two loud voices whose sum passes 32767: saturated once, at the end (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "3075307530753075307530753075307530753075307530753075307530753075" + }, + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "e02ee02ee02ee02ee02ee02ee02ee02ee02ee02ee02ee02ee02ee02ee02ee02e" + } + ], + "outcome": "mix", + "pcm": "ff7fff7fff7fff7fff7fff7fff7fff7fff7fff7fff7fff7fff7fff7fff7fff7f" + }, + { + "name": "sum_saturates_low", + "about": "two loud negative voices whose sum passes -32768 (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "d08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08a" + }, + { + "channels": 2, + "gain": 4096, + "pan": 0, + "pcm": "20d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d120d1" + } + ], + "outcome": "mix", + "pcm": "00800080008000800080008000800080008000800080008000800080008000800080008000800080008000800080008000800080008000800080008000800080" + }, + { + "name": "saturation_is_last", + "about": "+30000, +30000 and -30000: the exact sum 30000, with no saturation along the way (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "3075307530753075307530753075307530753075307530753075307530753075" + }, + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "3075307530753075307530753075307530753075307530753075307530753075" + }, + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "d08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08ad08a" + } + ], + "outcome": "mix", + "pcm": "3075307530753075307530753075307530753075307530753075307530753075" + }, + { + "name": "pan_hard_left", + "about": "a mono voice panned -4096: all in the left channel (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": -4096, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d355b51" + } + ], + "outcome": "mix", + "pcm": "a3060000a2b9000015040000bc9a00008d3600009f0d00008c7a0000a393000072c80000354f0000c9df00008ec500005207000080ab00006d3500005b510000" + }, + { + "name": "pan_hard_right", + "about": "a mono voice panned 4096: all in the right channel (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 4096, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d355b51" + } + ], + "outcome": "mix", + "pcm": "0000a3060000a2b9000015040000bc9a00008d3600009f0d00008c7a0000a393000072c80000354f0000c9df00008ec500005207000080ab00006d3500005b51" + }, + { + "name": "pan_part_right", + "about": "a mono voice panned 1365: the left channel attenuated, rounded half up (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 1365, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d355b51" + } + ], + "outcome": "mix", + "pcm": "6d04a30615d1a2b9b90215047bbcbc9a5f248d3615099f0db5518c7ac0b7a393f6da72c8d034354f85eac9df08d98ec5e1045207a9c780ab9f236d353e365b51" + }, + { + "name": "pan_stereo_balance", + "about": "a stereo voice panned -2048: its right channel at half (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 2, + "gain": 4096, + "pan": -2048, + "pcm": "effe6f8325a50071ded8029d41f46905e0e24acde2605c1e1858eef036ea17feea8afe6d2876a393ced2d8a3b01e7970c1440046fd6b133024f5994a6fd83ca6" + } + ], + "outcome": "mix", + "pcm": "effeb8c125a58038ded881ce41f4b502e0e2a5e6e2602e0f185877f836ea0cffea8aff362876d2c9ced2ecd1b01e3d38c1440023fd6b0a1824f54d256fd81ed3" + }, + { + "name": "gain_zero", + "about": "a voice at gain 0 beside one at unity: muted (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 0, + "pan": 0, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d355b51" + }, + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "49e806ee8c09c3fb6af9f0e7e8f8e1e8e1f2750c2d1a6f165ef01e1852ea000d" + } + ], + "outcome": "mix", + "pcm": "49e849e806ee06ee8c098c09c3fbc3fb6af96af9f0e7f0e7e8f8e8f8e1e8e1e8e1f2e1f2750c750c2d1a2d1a6f166f165ef05ef01e181e1852ea52ea000d000d" + }, + { + "name": "gain_four", + "about": "a quiet voice at gain 16384, four times, saturating where it passes the range (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 16384, + "pan": 0, + "pcm": "021a080cd9c5cbd534c940ca931ff3f87835f3f7f2fc021c34d751f6942d3431" + } + ], + "outcome": "mix", + "pcm": "0868203000800080008000804c7ecce3ff7fccdfc8f30870008044d9ff7fff7f" + }, + { + "name": "half_gain_ties", + "about": "odd samples at gain 2048: each half is a tie, rounded up (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 2048, + "pan": 0, + "pcm": "0100ffff0300fdff0500fbff0700f9ffff7f01800900f7ff0b00f5ff0d00f3ff" + } + ], + "outcome": "mix", + "pcm": "010000000200ffff0300feff0400fdff004001c00500fcff0600fbff0700faff" + }, + { + "name": "three_voices", + "about": "three voices of both widths, three gains and three pans (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 3000, + "pan": -1000, + "pcm": "a80168ee0501afe6a30d6703a31ee8e41cf2cd13f2f763f1d401e0ea5b0d5614" + }, + { + "channels": 2, + "gain": 5000, + "pan": 700, + "pcm": "bbffdbe049e9401c37f640e710fd5a01b8f852f33818970706163bfc8dfa85ffbae27f1b8a1de8e4b3f4f6e8ac071e1c30118011ff1a040c49fda6121bf68fe9" + }, + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "74e5fe1da7e42f1c061f5af6771efc12c20075168de965e8db007a080e0c7a0b" + } + ], + "outcome": "mix", + "pcm": "65e65ac01efabd367fdb01c7ab06d10fa42118175b118001324bd32aa0f96603f5d8a21adb42580037d8f8c875e5a10297133b175414730b1713362a5b1057fb" + }, + { + "name": "silence", + "about": "no voice: silence (§6)", + "channels": 2, + "frames": 16, + "inputs": [], + "outcome": "mix", + "pcm": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "name": "short_input", + "about": "a voice one sample short of its block (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d35" + } + ], + "outcome": "refuse", + "reason": "mix_input_malformed" + }, + { + "name": "output_channels", + "about": "a mix into three channels (§6)", + "channels": 3, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 0, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d355b51" + } + ], + "outcome": "refuse", + "reason": "mix_input_malformed" + }, + { + "name": "input_channels", + "about": "a voice of zero channels (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 0, + "gain": 4096, + "pan": 0, + "pcm": "" + } + ], + "outcome": "refuse", + "reason": "mix_input_malformed" + }, + { + "name": "gain_over", + "about": "a voice at gain 16385 (§6)", + "channels": 1, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 16385, + "pan": 0, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d355b51" + } + ], + "outcome": "refuse", + "reason": "mix_input_malformed" + }, + { + "name": "pan_over", + "about": "a voice panned 4097 (§6)", + "channels": 2, + "frames": 16, + "inputs": [ + { + "channels": 1, + "gain": 4096, + "pan": 4097, + "pcm": "a306a2b91504bc9a8d369f0d8c7aa39372c8354fc9df8ec5520780ab6d355b51" + } + ], + "outcome": "refuse", + "reason": "mix_input_malformed" + } + ], + "descriptors": [ + { + "name": "grid", + "about": "the room's grid descriptor (§3.1)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "outcome": "read", + "digest": "15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "effective": 1000000, + "compositor": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "background": "101018", + "layer": 2, + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + } + }, + { + "name": "pip", + "about": "the room's picture-in-picture descriptor (§3.1)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c15307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c400000000000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101801020400000200056f72646572010370697004e0010e011800020280bb0000046761696e0370616e060cc17a2acbb2cf4159ff17ae5aee793aa3bcd9eac6239c3dda678ee010de89cad1aae7e3f6b849b575d0cd43d25b69c8c90b479bc407ec85459e9f375805d4a309", + "outcome": "read", + "digest": "5ad64329fe0eb76d320922749a16c9358465444e542fc6c0ad6fbbe519408ad4", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "5307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4", + "effective": 0, + "compositor": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "background": "101018", + "layer": 1, + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 2, + "gap": 4, + "aspect": 0, + "fill": 2, + "featured_attr": "", + "order_attr": "order", + "omit_stopped": true, + "pip_attr": "pip", + "corner": 4, + "pip_width": 480, + "pip_height": 270, + "offset": 24, + "behaviour": 2, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 6, + "max_voices": 12 + } + }, + { + "name": "client_only", + "about": "a grid with no compositor: composed by each sink alone (§3.1, §7)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c15307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c400000000000000000000000000000000000000000000000000000000000000000000000000000000800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5b4f59f3e9e55b114603a51feeffbb03f7cc8e717ad48b0033734ed85af4f8e7327ad11f7478508bee5c9814eeb3024d53bda8e6b314b7f0c329014827652004", + "outcome": "read", + "digest": "61a1ca7d436ed458bab60685cabbcbbf3e8d1f3599e077f82bdc24a567934a1b", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "5307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4", + "effective": 0, + "compositor": "0000000000000000000000000000000000000000000000000000000000000000", + "background": "101018", + "layer": 2, + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + } + }, + { + "name": "largest_canvas", + "about": "1920 × 1080 at 60 fps, gap 0, 64 tiles: the canvas at its limits (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738043c101018020100000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e40406f79d3f185e111cec070b257169b7234d48e372b76f66ff4e0828a5eab61da70c80af053f5fb794e6591b593bf67c73cf8ba0946e3d3b0dd6bd1d40eda594806", + "outcome": "read", + "digest": "c3d3eac26e9dd863bcc6e448be6eef42d91d80f580d07af39e66b0f7df762db9", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "effective": 1000000, + "compositor": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "background": "101018", + "layer": 2, + "width": 1920, + "height": 1080, + "fps": 60, + "layout": 1, + "gap": 0, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 64, + "max_voices": 64 + } + }, + { + "name": "portrait_canvas", + "about": "1080 × 1920 and 1440 × 1440 hold as many pixels as 1920 × 1080 (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a380480071e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0cf52e22e32912bd11c13b09faeb7fe3e163905d2101d4bb32bb39b7f4eed3908790050182fc6f10bf074d6d55d672a19701fd33d571215e2cb737b3d7235bea06", + "outcome": "read", + "digest": "a914e9c9559941d1b922fa94051a69d6a45e5395a4fd6ca84a29c8ac1dd1291c", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "effective": 1000000, + "compositor": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "background": "101018", + "layer": 2, + "width": 1080, + "height": 1920, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + } + }, + { + "name": "square_canvas", + "about": "1440 × 1440 (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510aa005a0051e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0ca31ee20d22a041b97b0a640528a4c2ef0f5342a2c8d836178b90bea6ddcd49fb609215c627c69699acb66991aeaf9045a0e80c52d461b8c8017101bde2f3760c", + "outcome": "read", + "digest": "8e4e865bc9b6366d2d990d79d968d7f2897bdde8eedc03e5d3a73f75d9cf8540", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "effective": 1000000, + "compositor": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "background": "101018", + "layer": 2, + "width": 1440, + "height": 1440, + "fps": 30, + "layout": 1, + "gap": 8, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + } + }, + { + "name": "smallest_canvas", + "about": "16 × 16 at 1 fps with one tile (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a1000100001101018020100000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e010c88567b9c301b907fe2486d9edbb1af594ecbc85addde17869988f5b064764d966a1a8834cc9b921c07389b244554d5b9ca86831f8569aedaffedc4ee091ffe0e", + "outcome": "read", + "digest": "c4cce4a99633ddc0fb9c5fdd1558550d9aa2f883474f9e4af8eaee0523ea2fd5", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "effective": 1000000, + "compositor": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "background": "101018", + "layer": 2, + "width": 16, + "height": 16, + "fps": 1, + "layout": 1, + "gap": 0, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 1, + "max_voices": 12 + } + }, + { + "name": "canvas_too_wide", + "about": "a canvas 1922 pixels wide (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a8207d0021e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c030be133f873dd27e933744529d8bd8ab8ed83b48c3e2056421660b74d3806eef8b8e0c796aed91507dca42632c34ba5f727dcee1b91ac10103dc91f2d9df30b", + "outcome": "refuse", + "reason": "canvas_out_of_range" + }, + { + "name": "canvas_too_many_pixels", + "about": "1920 × 1082: each edge within 1920, more pixels than 1920 × 1080 (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a80073a041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c0e92d52f58fc439b1dc92a8e955d0ef05ea2959689d0c255538fb80fa4f0fbc95028eb8949f194e3e9e1ce622658d5e910950ef216762484dcf76f559f2cb80a", + "outcome": "refuse", + "reason": "canvas_out_of_range" + }, + { + "name": "canvas_odd", + "about": "a canvas 1279 pixels wide (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510aff04d0021e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0ce3909db0dffd403d78cffae8fb418228b2a2a2ac3c41f2a1957fd794ef29fcd5394f91fc5d494be4eed114b3276802d3b4004f2e27c38493c067e094dfc9130a", + "outcome": "refuse", + "reason": "canvas_out_of_range" + }, + { + "name": "canvas_too_small", + "about": "a canvas 14 pixels high (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a80070e001e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e010cb075027470fd0f966759420ee95963fd0d0d28f35d0dca0c6739a15bf0361b933851fe779ef6f432a55de44219f69b35115dadcd2c8b7ea841db5b7e63f5fb0e", + "outcome": "refuse", + "reason": "canvas_out_of_range" + }, + { + "name": "fps_zero", + "about": "a frame rate of 0 (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a8007380400101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c583d5b209c7c0469c6ad04d69c2b4d4a4877dca7403edeb390893995c69193eadd6821ed97c9e6b851e11d40f9d5b18bd7c411272f1fb86fa0871eb9e9263405", + "outcome": "refuse", + "reason": "canvas_out_of_range" + }, + { + "name": "fps_61", + "about": "a frame rate of 61 (§3.4)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738043d101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0cd766bfa8e1c46748ddd6597d0cffe69df7c140b3c41a52281097e92ef62b5a83c3739788df102e6953d2628bc454257579a89a77d6cc959bc34a651f6dc8aa0c", + "outcome": "refuse", + "reason": "canvas_out_of_range" + }, + { + "name": "canvas_before_fields", + "about": "a canvas 1922 wide and an aspect of 4: the canvas is checked first (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a8207d0021e101018020108000400086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c855b300f54cc1db22b9d5a8fc1448ab73bdddcc93c4e4d388a1ea1cedd487528fc159473b102108160c9b002fc905a2987ff74f7d2bf0c908cfbbca69a5c0e01", + "outcome": "refuse", + "reason": "canvas_out_of_range" + }, + { + "name": "layout_unknown", + "about": "a layout of 3 (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020308000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c3abb3484dd4c652968e58b5c66cc2555af325550db4077db99c875be1e7d4818aa53f826ac5b83e8599c038e6840a3b315f61494d3465efafdb66b23887e7f04", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "aspect_unknown", + "about": "an aspect of 4 (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000400086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c16cc743b30307eb3e9e7d9b3a7d4ea09af72ae503b2bf45cdee84716baa5761faefde0f1eaa44c1ccc069ef088f4b7657a45d1e4ad0fe97166c08f81d9e31704", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "fill_unknown", + "about": "a fill of 4 (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000104086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0ca1f8bf11eb0eac8304acb2c2eec1df90828d3d2dda4e7b88ffe2bae1c0a94c6cec39c5995eccbdd2a614996379cea819678f4b4fbc8275032b101e469d30f00a", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "omit_two", + "about": "omit_stopped 2 (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572020000000000000000000280bb0000046761696e0370616e0c0cc440179e15fad0c31ceca9f11b39e97652ab7f4302cf2cb58923c6bddff1b592feb37c22d8b6f20fac6db6226aee7dc4dbc3c3e2469c8c306d3d083b17553303", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "attr_key_capital", + "about": "a featured attribute key `Featured` (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100084665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c6106717a40f1b5df8e6d6ebdb0b55c524d16e0b2ed6dc244e9dc7c106f43ed60b1b3a8dd7c75b254eea4037df19048f5812c6a3fb7c30d6373b27df674795c06", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "attr_key_too_long", + "about": "an order attribute key of 33 bytes (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564216f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f000000000000000000000280bb0000046761696e0370616e0c0c09c2013ede3f99f0850cfd080f789215cbdef0b325148834d5c0429b49f11dc04dfedc22fabeb6d438116b9c9ef7ce0a978c4697be66774c75c608b89998550a", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "grid_with_corner", + "about": "a grid with a PiP corner (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000001000000000000000280bb0000046761696e0370616e0c0cce0e802680256d4e926b9a3f7d278378edcb68035783cda57c627d8526dfcb448237ef10b69092bac215364333f35f95e8f7473b009de70c913bc07a0497f404", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "pip_without_corner", + "about": "a PiP layout with corner 0 (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101802020400000200056f72646572010370697000e0010e011800020280bb0000046761696e0370616e060c4426409b2e85c39dff333d8a1c5934c772600212b0d50ad9cde1c25cf62ad8ad6c9cde7a61e1e67828fab4a20a16b6be7217da262c8880bfa364ab6918b7b10c", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "pip_without_behaviour", + "about": "a PiP layout with behaviour 3 (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101802020400000200056f72646572010370697004e0010e011800030280bb0000046761696e0370616e060cfd1f40d2d631065c9f0a0489f339559f4acf56b2c0147dfba1c6cc3be19e49035aec335bff9f74e7c0ec32833729f5a39b0fcabd34d2c7b6d95f8b5617f19b08", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "pip_too_wide", + "about": "a PiP window 1900 wide 24 pixels from the edge of a 1920 canvas (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101802020400000200056f726465720103706970046c070e011800020280bb0000046761696e0370616e060c0b2d172ab7ed2f3ee08049c59161ab58bdbbe0e73b0563fcf9b77eff611769df869f256e0c413c103287de9aa3b9b6dc3e6b7540130888e8744a994af572cd0a", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "pip_offset_too_large", + "about": "a PiP offset of 1080 on a 1080-high canvas (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101802020400000200056f72646572010370697004000000003804020280bb0000046761696e0370616e060ca130f572c3a24761e9fe52d1dda26dcd4b58590ef78f6b8dfd824e7bfac50af82e8487a6dcf57c05cea986f93f4f3f45996ea189a151dbe1c3e996b6eae1fb05", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "channels_three", + "about": "a mix of three channels (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000380bb0000046761696e0370616e0c0c30640ea47510617502b37767cb10e4485c26c09dd4a49afbfbb264d8f0ddf50cee97a7ef21fb36775e07f65dd1893f2d5ed930f4ca5512ab3100c56cd7e2cc01", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "sample_rate_low", + "about": "a sample rate of 4000 Hz (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f726465720000000000000000000002a00f0000046761696e0370616e0c0c53de220b9446b3f10ff4a07b9c2e8c9004cf3fd1c6756b59a2da7e99b8405da22a681a818a5e165914ae26bc7445cacddda0591ac7b2dd666da2db6999f57704", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "max_tiles_zero", + "about": "at most 0 tiles (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e000c04717abc11d42d273403ad915e872d33760205c15e90d46bef3bcb35821243a9e58edd586c61d1e728ed871cfa40fb8456a5ae73ba5fd646ad64f963854cbe01", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "max_voices_65", + "about": "at most 65 voices (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c41cf2ae7c51b88a4c1fc29cb29766e16b06c5756a4dedc7edf4b722579988abd3dbeac8c4fc5f55cfc44ba8bc815f7078f8e4725e4fa9068f8731e12d288cf390a", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "gap_too_large", + "about": "a 300-pixel gap with twelve tiles: the band under a featured tile cannot hold four rows (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101802012c010100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0ccd1d7c0ef383b4b8ae98015d716a5f12bf1831a967183f4d785a152acc28baac0aff0596589d5291f4fe19b87461189d3f45b6887e6347d41c08899b6bd98800", + "outcome": "refuse", + "reason": "compose_invalid" + }, + { + "name": "gap_fits", + "about": "a 60-pixel gap with twelve tiles: the band still holds four rows of a pixel (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101802013c000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c1210b781a0def4976eaf457d48c48c8983afbbc86f69cebf41095143bb3ae85a5aeb5b91dee7068141e0c0a422a5375ebeb090c6bbdb1b3d442f4c84fc21eb0d", + "outcome": "read", + "digest": "811f1bbfaf617c35acad89b6bb16749c5499364bd0a34b7af4473cb74462e63c", + "fields": { + "room": "fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1", + "signer": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "effective": 1000000, + "compositor": "4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a", + "background": "101018", + "layer": 2, + "width": 1920, + "height": 1080, + "fps": 30, + "layout": 1, + "gap": 60, + "aspect": 1, + "fill": 0, + "featured_attr": "featured", + "order_attr": "order", + "omit_stopped": false, + "pip_attr": "", + "corner": 0, + "pip_width": 0, + "pip_height": 0, + "offset": 0, + "behaviour": 0, + "channels": 2, + "sample_rate": 48000, + "gain_attr": "gain", + "pan_attr": "pan", + "max_tiles": 12, + "max_voices": 12 + } + }, + { + "name": "truncated", + "about": "the grid descriptor less its last byte (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d341", + "outcome": "refuse", + "reason": "truncated" + }, + { + "name": "magic", + "about": "magic WCD2 (§3.3)", + "bytes": "5743443201fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "outcome": "refuse", + "reason": "malformed" + }, + { + "name": "version", + "about": "version 2 (§3.3)", + "bytes": "5743443102fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "outcome": "refuse", + "reason": "unknown_version" + }, + { + "name": "trailing", + "about": "a byte after the signature (§3.3)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d3410100", + "outcome": "refuse", + "reason": "malformed" + }, + { + "name": "bad_signature", + "about": "one bit of the signature flipped (§3.2)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe63c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "outcome": "refuse", + "reason": "bad_signature" + }, + { + "name": "bad_key", + "about": "the identity point as the signer, a key of small order (§3.2)", + "bytes": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1010000000000000000000000000000000000000000000000000000000000000040420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "outcome": "refuse", + "reason": "bad_key" + } + ], + "rooms": { + "studio": { + "descriptor": "57524431015307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b00a043f6fd5d060040420f000000000000001000000008002c0100005745503101fe1f0000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f000000000007086469726563746f7203010206080200000000000000000000000000000000000000000000000000000000000009706572666f726d65720301020018000000000000000000000000000000000000000000000000000000000000000567756573740701010008000000000000000000000000000000000000000000000000000000000000000664657669636504000000000000000000000000000000000000000000000000000000000000000000000007656e636f646572020000000000000000000000000000000000000000000000000000000000000000000000056d697865720301020400000000000000000000000000000000000000000000000000000000000000000861756469656e636500010100080000000000000000000000000000000000000000000000000000000000000001046d61696e02010000000006067370656563680101046f707573000001000000000000100000004000000080bb0000010f056d757369630101046f70757300000100000000000080000000fe01000080bb000002000a63616d6572612d37323002020d617630312e302e30354d2e30380b617663312e363430303146010002800268011e0096000000f40100000005d0021e00f4010000dc0500000000000000000b63616d6572612d3130383002020d617630312e302e30384d2e30380b617663312e363430303238010003800268011e0096000000f40100000005d0021e00f4010000dc050000800738041e00dc050000a00f00000000000000000673637265656e03020d617630312e302e30384d2e30380b617663312e36343030323802044c31543301800738040f002c010000c409000000000000000005737461676502010d617630312e302e30384d2e3038030002c0031c021e00f4010000dc050000800738041e00dc050000a00f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fe7dbb536427c7878ce529c185205683673fb456b5f235030ff590ad9e8cf9cb5a8171427eaf0815b7cbd362e3e350947b292ba40229b57d15e2b5f9fc19703", + "grants": [ + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000003010206000000000000000000000000000000000000000000000000000000000000000000574550310108020000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020002001300056f726465720100320370697004007472756580450b030caaba83551ff5692a8c4c875850dc001857fd0cb1ab9006865c36d0d5d2e1644afc7cc9e8d44bfb305146af4dcfac3acb9d3123fbec567276b5eb06", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c16c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000103010200000000000000000000000000000000000000000000000000000000000000000000574550310118000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103002300086665617475726564040074727565046761696e040035313230056f726465720100318c2ca95cd77bbf90c51196e395b981c65aebcb619360d8cebc02ac022e1ef20a927483b76917a9899e8775f7498a79d8558b3d10558dd5d1353ce88ac394df0d", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204000900056f72646572010033baf89b30e2012f41d94859d9f68360f2a60cfa43deb66a2c85d5d228d012c04fbe87bb748a5ff3ce12947870158bd14b99dce91f4d9d7fee15279c057549670e", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb404b4c000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204001f00046761696e040032303438056f726465720100300370616e05002d3230343888b4b7b0f34c777ccf5e9f7b6d47f4754be94876a01fd380a3ccd3143f75ee4a15cab40dba93452d53ddfd42cd398a8aca2fa873a0c0cb9301eb034c48a8b00a", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b4670000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000304000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000104000900056f726465720100345d27b87859c990b56b36c3a9d9a4adb9d055604a44e2286b14f0f086e5516f0ce01ccbdce6f6c8d8ea8cec4767a0ff2d7e84873fba4b0d81ce8dc4524cef5008", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c171bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000402000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000105000900056f72646572010035cab27eed3e80e7d7d110a63bc1762cf0a9aa73f7cc23f063af1fa031cd2526cfeb96252b4ea55326de456237471cfb1c85493ab5a011af0ac7214ef436a89f00", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000503010204000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103000000cb0003729a42a412ef3360a9b6a5abfebc3614e92c6ba46446888d6570c11a251fedca06998f7f82a845c06b04cb646a879f250479731b993341b3a5e4c3b207", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b50000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000600010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000000000026a9b29ec093d694c84d8617902c3ad0988336eae0f8cc14d1ba2db3fc637ea9ba13a9ec752f4208e618ca6178fb3fff8940b842bfea80880e041168a3fcac0d" + ], + "key_log_head": null, + "chains": [ + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d195e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce40d7f46a9e65a915692a069d0cd9fdc6555b82f057ecf42bc46135baf46670d9631dd1bbaf83038386f70a83dc98339f660fe2da7efb0b60732c445acb0a8b04", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0100000000000000495f88e2124194ba930fbafe754f2a18bca5c75374b9aa15581262149e18edf10000000000000000001040006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4fcccbbf904396ff6b660581ad712641ef0fe16097a206cf4472c3b6a21713db2ad9353fe5a3e5472b6f3f1ed28495ff4ff4778dd265701fa02a302120d552108", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0200000000000000777b529a49995eab01a34504b02a0b7a54d608d39e96426a33e1358e22779cf40000000000000000001040004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a2a5c4620f83c620060e48f40dcf7df65c4bf32ba4e0f5e47b68e129e46f670408d5349f71bb059f76decefe20e043503b3cc47fc8f76f1c7e44b03230d313024436a95dfd2360078713b7de1b247a489dc4c0d5650e57171a211afc474329e0f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0300000000000000192c9e861bc16961b09fcef12766feeceec1f2401a2fe5f17805d637b12d585b000000000000000000104000f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b56e6be610872303d962695eea1d3f37ef67720fe624f92a5af6aaee85d103e4af2c7c238cff5670d1382ee2a12c54257424b409fed0f9622b907c3a84eda75a9c9cfbd18c5f6af307f99602af62c01a3d5824cd5b8e04dd5b9e4689d9ff455c0e", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b04000000000000003b62ab376b7acd57b3be5c53e4208050df69cc7377ea47b0c9e353f46f92908b40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0001010148c45d005c36ed3d5ded95b5864490c7d0687fc3a8abd7c4ada7b793386bc797ba9655c95b3057cce8b3c491a8be8e37a7706fdf596ea112649cae379717620f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0500000000000000c481fc3597ccd521d186950b299a18e46d07561ddddf61b3f530a8298d2a3fdd40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee00020303bc534a120d3beb1b91182b3d9efbd2f12499494349eee0ce186e0e64fd028aa3e295036af52833a8e419bf813ce93dfc9fbd7cb78fa60d0aab7e8ff754f5910a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0600000000000000f955c41c16c212fdef272f71455618ea2893358bbdaac69680e79f9d1064bb5340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900010001d04c2b1882c3473322e584c7dbb42c42d4d785e0ab4ad5385dfd87f58ed7e9a746e0e670ba2f21580e55b02732e90a655b93e4005390dc3c7a427809319c6e09", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0700000000000000e35f740d28abdc423147afd793f4c1a1c0495f6f5a42ce61047052696217047340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900020202ad6f7a51630985b19b7823c49a112515f8868618ef54d57fe9b06519e2c6157c9889d78ec20579c6e800dc40abbf17bf8ea84a242672314286b54cfd7c8cd400", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0800000000000000d070a74443ca8ec316c7ebe10adfc1e6e1b315f901cdeb3d9c093a189197939b80841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0002030391c03f8db98e739cc85ccdacade03fd3af84f56589f63dc4c818bec0d888be8f6bb8cf443a31bb7c9508dc8842c204308dd708d3580e59effd22d2452ab0930a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0900000000000000c3eaa5c50ef476b1db3a6917cdea3348b1bc586f5dff14f6a24bb59049b0220280841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a00010101efac7bdea673bf1a7835b65681123d6284d985bf18bef2c7d432deb3a23ed7373b619ab16de7b3ccc9a06456b6ab73bb817ee2745934aa84559bb880c15c9f08", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0a000000000000004db38667a64f130a431f196fe13e7823bac346d8e0e0aab6accc0cd6c9f4efa0c0c62d00000000000010400087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb043d0254c2c23705a7f999356bdcad35245d39aa7a3fb6d71f447f3111eef8ac728c205feda089e102c875d47ce46f6ea3b7a1100ef69cb86661f741b6d22309", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0b0000000000000060c5fb696e1c57d2c72b579325645491f82da96b92685fd479590205a0b64950c0c62d00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00010001f7733aeaeef3b5897ef3b347eb8f90ba3aa2d3502e34955234bef48f2ffab2ea539340c4fccd76a259c79319b928bd10d282fe1d907f66eee66279e1c021c701", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0c00000000000000c08bc94c25f46048e7700b65933b1a094ec41b95804e2ebf4981553f50c29d1000093d000000000000104000a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe26440d7e48b31b32b4411f13f4ea257af8fb6b7808fb1b4cacfbf382952f436557f3da1f5437cb2fcfe8383663516b0e16fd1f8b38b0ad14727b61f635ea060f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0d000000000000009a387fe90a62d0a2736a340c0abec8661e4f209541a79564e6e6684b335ffeb100093d000000000000122400a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467000304017216c32b856e553e4c953d95b717bdf1d6df1f17d4a860291881309d40cd3f324607b729ab13d9ae7987528b76088aee0403a6501aa567b550a4c2cd0da90902", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0e000000000000007d18182a07f55583e678af4b34ee88a8b80d6b98cb785603ef5fc6453d07dd9a00093d00000000000010400071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f4ce7d75774aa79578c785fc9db75f84ac8e0e53b82f23b1aa8d4efa3d623052f460202bd27efb074b7e889355a04680d4df9bf81f682ad012244ebcb9bcf4602", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0f00000000000000c1ee68a25be97b76521cede8f5ff14ded91028b92c6b8d282b798bdcdcb43af800093d00000000000012280071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d046d61696e020502277072b2e7cdc671dfe85d22b25a90ec33a85443d92c8d4d55054f5edf3a354bb78a9d414665e955ad6577b4981352abbd9af2d042c9d04e5aa556ae03aeed03", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b100000000000000054cc92986fe5f8e34f5c945820f4fcec9e01a6648ff95fe45242a6652af9ca19404b4c00000000000014600087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d36b48698d7f70a5584576a80843f364aa00af48148146bcd2362e90f9dc49ae530ee0ced88fb573c738d5dbca9900522cb768c7e7ca4ff1997fd899e8d721104", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1100000000000000a592b2446f22475e2404ac22417cd90f9e184f38875a9f23a48cb1d1f3c509cf808d5b0000000000001322009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190002b171f1b7a684a7b69644c3f8d97cb98ba8310d371d31b41c2e7370c595b70fc22a140f583b847ad8ace041592570825e8eb5eee51118bafa6661d6f369dfff07", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b120000000000000032c069fce1fd0761d0a2264e777c1aa07d918908c3c85f2cdab638e9be41bdebc0cf6a00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00020201b73925e86757df2cb97dff95f062bfda5e5dbdecb8c74a2052d41acd02cb089214ea19c6c0b4ca69d920de95eba32c36e63ae248dbf018e45043df4f149da409", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1300000000000000a8bf5ae6643b41380949b4a5e61732c8d0b0a6505c8f2a1926745e24e09be5dd00127a0000000000001121006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0188bd61cf143dbd8dbb09c511deb1629bb3b2c8cd935c0385ecb0cca1d736042b7fac8e51eb77dc774720741e54493258857ee63443a752a4b6f48fe6c322470a" + ], + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b500000000000000000000000000000000000000000000000000000000000000000000000000000000a02526000000000000030700050068656c6c6fc2236d2ae9a34e5a1f2e9d7183cb6bcd9f2ee42bfa4d6b75e0daf9b903c9ecaddaea040d91daea50da4ba4ff29e593c793370f111d60f19a25326ded11983100", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b501000000000000009cfb474f8db2525a038f2cdc07ed84c60c5a9dfc0f7c2790c9cde824a9c06bc9e06735000000000000030900070077656c636f6d657a76ca1b05f90a1376ccf6139c1684728e097ee45d8b66aabd8a37ec0331cc174185780d7e5d0c48a0c597b4daa4b5adb5ad63f11b8e2a08990ba8fa3e717709" + ] + ] + }, + "studio_bad_order": { + "descriptor": "57524431015307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b00a043f6fd5d060040420f000000000000001000000008002c0100005745503101fe1f0000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f000000000007086469726563746f7203010206080200000000000000000000000000000000000000000000000000000000000009706572666f726d65720301020018000000000000000000000000000000000000000000000000000000000000000567756573740701010008000000000000000000000000000000000000000000000000000000000000000664657669636504000000000000000000000000000000000000000000000000000000000000000000000007656e636f646572020000000000000000000000000000000000000000000000000000000000000000000000056d697865720301020400000000000000000000000000000000000000000000000000000000000000000861756469656e636500010100080000000000000000000000000000000000000000000000000000000000000001046d61696e02010000000006067370656563680101046f707573000001000000000000100000004000000080bb0000010f056d757369630101046f70757300000100000000000080000000fe01000080bb000002000a63616d6572612d37323002020d617630312e302e30354d2e30380b617663312e363430303146010002800268011e0096000000f40100000005d0021e00f4010000dc0500000000000000000b63616d6572612d3130383002020d617630312e302e30384d2e30380b617663312e363430303238010003800268011e0096000000f40100000005d0021e00f4010000dc050000800738041e00dc050000a00f00000000000000000673637265656e03020d617630312e302e30384d2e30380b617663312e36343030323802044c31543301800738040f002c010000c409000000000000000005737461676502010d617630312e302e30384d2e3038030002c0031c021e00f4010000dc050000800738041e00dc050000a00f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fe7dbb536427c7878ce529c185205683673fb456b5f235030ff590ad9e8cf9cb5a8171427eaf0815b7cbd362e3e350947b292ba40229b57d15e2b5f9fc19703", + "grants": [ + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000003010206000000000000000000000000000000000000000000000000000000000000000000574550310108020000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020002001300056f726465720100320370697004007472756580450b030caaba83551ff5692a8c4c875850dc001857fd0cb1ab9006865c36d0d5d2e1644afc7cc9e8d44bfb305146af4dcfac3acb9d3123fbec567276b5eb06", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c16c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000103010200000000000000000000000000000000000000000000000000000000000000000000574550310118000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103002300086665617475726564040074727565046761696e040035313230056f726465720100318c2ca95cd77bbf90c51196e395b981c65aebcb619360d8cebc02ac022e1ef20a927483b76917a9899e8775f7498a79d8558b3d10558dd5d1353ce88ac394df0d", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204000d00056f72646572050074686972645cec8630d08652006719f3954ac9c8c0958c4c765ba52d2cde079169d725262cbd1f815fabc5412e05bf1874f9919d3eb14e66427769f99f7943768eacebfd0f", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a06ec65b2a6f15d033b10d6b40d4e8d7db4bb41a1db2a2e889d75462f7877b388404b4c000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204001f00046761696e040032303438056f726465720100300370616e05002d32303438ec80bcda7505ca451e77cafea604585980439f6bdeb3fa2537e05533ca2f31de5d911c27248d004d570204a913a4caa934d8a3c5827509965b49184ac3ef9f0d", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b4670000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000304000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000104000900056f726465720100345d27b87859c990b56b36c3a9d9a4adb9d055604a44e2286b14f0f086e5516f0ce01ccbdce6f6c8d8ea8cec4767a0ff2d7e84873fba4b0d81ce8dc4524cef5008", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c171bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000402000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000105000900056f72646572010035cab27eed3e80e7d7d110a63bc1762cf0a9aa73f7cc23f063af1fa031cd2526cfeb96252b4ea55326de456237471cfb1c85493ab5a011af0ac7214ef436a89f00", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000503010204000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103000000cb0003729a42a412ef3360a9b6a5abfebc3614e92c6ba46446888d6570c11a251fedca06998f7f82a845c06b04cb646a879f250479731b993341b3a5e4c3b207", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b50000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000600010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000000000026a9b29ec093d694c84d8617902c3ad0988336eae0f8cc14d1ba2db3fc637ea9ba13a9ec752f4208e618ca6178fb3fff8940b842bfea80880e041168a3fcac0d" + ], + "key_log_head": null, + "chains": [ + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d195e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce40d7f46a9e65a915692a069d0cd9fdc6555b82f057ecf42bc46135baf46670d9631dd1bbaf83038386f70a83dc98339f660fe2da7efb0b60732c445acb0a8b04", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0100000000000000495f88e2124194ba930fbafe754f2a18bca5c75374b9aa15581262149e18edf10000000000000000001040006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4fcccbbf904396ff6b660581ad712641ef0fe16097a206cf4472c3b6a21713db2ad9353fe5a3e5472b6f3f1ed28495ff4ff4778dd265701fa02a302120d552108", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0200000000000000777b529a49995eab01a34504b02a0b7a54d608d39e96426a33e1358e22779cf40000000000000000001040004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a2a5c4620f83c620060e48f40dcf7df65c4bf32ba4e0f5e47b68e129e46f670408d5349f71bb059f76decefe20e043503b3cc47fc8f76f1c7e44b03230d313024436a95dfd2360078713b7de1b247a489dc4c0d5650e57171a211afc474329e0f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0300000000000000192c9e861bc16961b09fcef12766feeceec1f2401a2fe5f17805d637b12d585b000000000000000000104000f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b56e6be610872303d962695eea1d3f37ef67720fe624f92a5af6aaee85d103e4af2c7c238cff5670d1382ee2a12c54257424b409fed0f9622b907c3a84eda75a9c9cfbd18c5f6af307f99602af62c01a3d5824cd5b8e04dd5b9e4689d9ff455c0e", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b04000000000000003b62ab376b7acd57b3be5c53e4208050df69cc7377ea47b0c9e353f46f92908b40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0001010148c45d005c36ed3d5ded95b5864490c7d0687fc3a8abd7c4ada7b793386bc797ba9655c95b3057cce8b3c491a8be8e37a7706fdf596ea112649cae379717620f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0500000000000000c481fc3597ccd521d186950b299a18e46d07561ddddf61b3f530a8298d2a3fdd40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee00020303bc534a120d3beb1b91182b3d9efbd2f12499494349eee0ce186e0e64fd028aa3e295036af52833a8e419bf813ce93dfc9fbd7cb78fa60d0aab7e8ff754f5910a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0600000000000000f955c41c16c212fdef272f71455618ea2893358bbdaac69680e79f9d1064bb5340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900010001d04c2b1882c3473322e584c7dbb42c42d4d785e0ab4ad5385dfd87f58ed7e9a746e0e670ba2f21580e55b02732e90a655b93e4005390dc3c7a427809319c6e09", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0700000000000000e35f740d28abdc423147afd793f4c1a1c0495f6f5a42ce61047052696217047340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900020202ad6f7a51630985b19b7823c49a112515f8868618ef54d57fe9b06519e2c6157c9889d78ec20579c6e800dc40abbf17bf8ea84a242672314286b54cfd7c8cd400", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0800000000000000d070a74443ca8ec316c7ebe10adfc1e6e1b315f901cdeb3d9c093a189197939b80841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0002030391c03f8db98e739cc85ccdacade03fd3af84f56589f63dc4c818bec0d888be8f6bb8cf443a31bb7c9508dc8842c204308dd708d3580e59effd22d2452ab0930a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0900000000000000c3eaa5c50ef476b1db3a6917cdea3348b1bc586f5dff14f6a24bb59049b0220280841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a00010101efac7bdea673bf1a7835b65681123d6284d985bf18bef2c7d432deb3a23ed7373b619ab16de7b3ccc9a06456b6ab73bb817ee2745934aa84559bb880c15c9f08", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0a000000000000004db38667a64f130a431f196fe13e7823bac346d8e0e0aab6accc0cd6c9f4efa0c0c62d00000000000010400087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a06ec65b2a6f15d033b10d6b40d4e8d7db4bb41a1db2a2e889d75462f7877b3883cc1b90b7e80201bbaeed8092f504fa9009b60b1c8ba966f7224f1659a07a8f555168de509667ac0d673bc231e4cb01d0a6f22510d68b6f7e73e4256f4db7407", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0b00000000000000a2e771fcfb046ad7f1cc5587a309944a9fcda1a2b6f4337169b73e1af083f684c0c62d00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00010001e090471aa1794ec9019afc1eb1e72b3337a06047eeb0304ebf3f86e8855f646c771bf642e634f47431fa104b28db7675397b21c43fbfb51b8e0c706c70079507", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0c00000000000000a5349ebc24b5683cb2d5a47bdfe88f3ba0879194ae242532772769143f7d2e8f00093d000000000000104000a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe7090d58843999af2a55a20918a4381e8ec349b2a4507e1cc951acb012fc30d66f1cda96abb49b07afbc3d913b249126d7715631284641ca2c4092e5dd9102c08", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0d00000000000000390cc368086881195d7d575b1d845832c52b363dd6299ecb49a920d8c49a0f8a00093d000000000000122400a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467000304018be6a0fd5a11f495897335b8087bb560ba879aa3f05192d7d121e86810d7b2afc2368a33c5152dd7d3e9651497f74f6edd88c1ab904d9b823d816242159b2708", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0e000000000000005a7a9352cf5889f939c73cd1a82184dbbcaa32928a038f7e76c5bbbe281cfe6e00093d00000000000010400071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0fab135f21be0b3c3f4e499ac0a160c678d09ddb18dd893f4e5fe64b1a350c492369c581373310c987e838d3a813862e8b38cbb54b447e5224b26d9280b9aba006", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0f00000000000000960b8c413807b93881cfbc39fb31995bef1df6469355f5ed32449fee0e8f65d600093d00000000000012280071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d046d61696e02050241b28f8301ea5c2e369056e2c772bae79eb6d62a14dd710754f706e42119915ac2e8d669ea064406127435111803f10982cfe622f8aff7faba4955737128150a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b10000000000000001729d524bee8c5d4a06a1863ddbf812b295917fe9cd406478737770df276c176404b4c00000000000014600087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a06ec65b2a6f15d033b10d6b40d4e8d7db4bb41a1db2a2e889d75462f7877b38841d2140d8ee4a8612a1f5991ad94e3830e08446bb6d5d65fdec396a738abbfda4bc8bd4f5d56a88b9eba48625bd8fce95b1b6a53d1ae663ae2f445c4c900a2ab9ac354015ae9b5411fb379975f8f3f7fd37f01a40f5ca2f35c9d723976711000", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1100000000000000adf27f2fac26fad1a28885c3b9e8c9e5ed29c3c8a352be1e9e026daae321f679808d5b0000000000001322009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900027d8f1307110fc14ffe864f6fe989baf90dc018765a99d54f3650d40553eadb19f34dce38ecc880562448e845d5ad22bde56c5adf66f3dc0f0ff2cab6a34eb500", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1200000000000000803a229cca8e1fede6a550204d5ea7317e34cf6e78b8a5bc31d3652a7c74ffa2c0cf6a00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a000202015bb5484c6c0de670113e512cbb8e26e94297e2a830d3044bd423e38d562c1895daab2dba8597f5083af1473485b988e8a94aaedd50b5441e349f99b01c990403", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b13000000000000003f5509b977b0244f5fb545c253ff40b092c6c6052b072288be0f7000e66e397d00127a0000000000001121006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0122719b62dd27e4bb6e2e6de1c58d0c7de4da99c42a988ae3ce7b282ec2735320f3c27a4166c75bf337e9b43a0c1b9ebe8d4a1f96af755917f4828fe53f069a0e" + ], + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b500000000000000000000000000000000000000000000000000000000000000000000000000000000a02526000000000000030700050068656c6c6fc2236d2ae9a34e5a1f2e9d7183cb6bcd9f2ee42bfa4d6b75e0daf9b903c9ecaddaea040d91daea50da4ba4ff29e593c793370f111d60f19a25326ded11983100", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b501000000000000009cfb474f8db2525a038f2cdc07ed84c60c5a9dfc0f7c2790c9cde824a9c06bc9e06735000000000000030900070077656c636f6d657a76ca1b05f90a1376ccf6139c1684728e097ee45d8b66aabd8a37ec0331cc174185780d7e5d0c48a0c597b4daa4b5adb5ad63f11b8e2a08990ba8fa3e717709" + ] + ] + }, + "studio_lifecycle_gap": { + "descriptor": "57524431015307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b00a043f6fd5d060040420f000000000000001000000008002c0100005745503101fe1f0000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f000000000007086469726563746f7203010206080200000000000000000000000000000000000000000000000000000000000009706572666f726d65720301020018000000000000000000000000000000000000000000000000000000000000000567756573740701010008000000000000000000000000000000000000000000000000000000000000000664657669636504000000000000000000000000000000000000000000000000000000000000000000000007656e636f646572020000000000000000000000000000000000000000000000000000000000000000000000056d697865720301020400000000000000000000000000000000000000000000000000000000000000000861756469656e636500010100080000000000000000000000000000000000000000000000000000000000000001046d61696e02010000000006067370656563680101046f707573000001000000000000100000004000000080bb0000010f056d757369630101046f70757300000100000000000080000000fe01000080bb000002000a63616d6572612d37323002020d617630312e302e30354d2e30380b617663312e363430303146010002800268011e0096000000f40100000005d0021e00f4010000dc0500000000000000000b63616d6572612d3130383002020d617630312e302e30384d2e30380b617663312e363430303238010003800268011e0096000000f40100000005d0021e00f4010000dc050000800738041e00dc050000a00f00000000000000000673637265656e03020d617630312e302e30384d2e30380b617663312e36343030323802044c31543301800738040f002c010000c409000000000000000005737461676502010d617630312e302e30384d2e3038030002c0031c021e00f4010000dc050000800738041e00dc050000a00f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fe7dbb536427c7878ce529c185205683673fb456b5f235030ff590ad9e8cf9cb5a8171427eaf0815b7cbd362e3e350947b292ba40229b57d15e2b5f9fc19703", + "grants": [ + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000003010206000000000000000000000000000000000000000000000000000000000000000000574550310108020000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020002001300056f726465720100320370697004007472756580450b030caaba83551ff5692a8c4c875850dc001857fd0cb1ab9006865c36d0d5d2e1644afc7cc9e8d44bfb305146af4dcfac3acb9d3123fbec567276b5eb06", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c16c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000103010200000000000000000000000000000000000000000000000000000000000000000000574550310118000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103002300086665617475726564040074727565046761696e040035313230056f726465720100318c2ca95cd77bbf90c51196e395b981c65aebcb619360d8cebc02ac022e1ef20a927483b76917a9899e8775f7498a79d8558b3d10558dd5d1353ce88ac394df0d", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204000900056f72646572010033baf89b30e2012f41d94859d9f68360f2a60cfa43deb66a2c85d5d228d012c04fbe87bb748a5ff3ce12947870158bd14b99dce91f4d9d7fee15279c057549670e", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb404b4c000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204001f00046761696e040032303438056f726465720100300370616e05002d3230343888b4b7b0f34c777ccf5e9f7b6d47f4754be94876a01fd380a3ccd3143f75ee4a15cab40dba93452d53ddfd42cd398a8aca2fa873a0c0cb9301eb034c48a8b00a", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b4670000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000304000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000104000900056f726465720100345d27b87859c990b56b36c3a9d9a4adb9d055604a44e2286b14f0f086e5516f0ce01ccbdce6f6c8d8ea8cec4767a0ff2d7e84873fba4b0d81ce8dc4524cef5008", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c171bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000402000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000105000900056f72646572010035cab27eed3e80e7d7d110a63bc1762cf0a9aa73f7cc23f063af1fa031cd2526cfeb96252b4ea55326de456237471cfb1c85493ab5a011af0ac7214ef436a89f00", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000503010204000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103000000cb0003729a42a412ef3360a9b6a5abfebc3614e92c6ba46446888d6570c11a251fedca06998f7f82a845c06b04cb646a879f250479731b993341b3a5e4c3b207", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b50000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000600010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000000000026a9b29ec093d694c84d8617902c3ad0988336eae0f8cc14d1ba2db3fc637ea9ba13a9ec752f4208e618ca6178fb3fff8940b842bfea80880e041168a3fcac0d" + ], + "key_log_head": null, + "chains": [ + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d195e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce40d7f46a9e65a915692a069d0cd9fdc6555b82f057ecf42bc46135baf46670d9631dd1bbaf83038386f70a83dc98339f660fe2da7efb0b60732c445acb0a8b04", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0100000000000000495f88e2124194ba930fbafe754f2a18bca5c75374b9aa15581262149e18edf10000000000000000001040006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4fcccbbf904396ff6b660581ad712641ef0fe16097a206cf4472c3b6a21713db2ad9353fe5a3e5472b6f3f1ed28495ff4ff4778dd265701fa02a302120d552108", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0200000000000000777b529a49995eab01a34504b02a0b7a54d608d39e96426a33e1358e22779cf40000000000000000001040004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a2a5c4620f83c620060e48f40dcf7df65c4bf32ba4e0f5e47b68e129e46f670408d5349f71bb059f76decefe20e043503b3cc47fc8f76f1c7e44b03230d313024436a95dfd2360078713b7de1b247a489dc4c0d5650e57171a211afc474329e0f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0300000000000000192c9e861bc16961b09fcef12766feeceec1f2401a2fe5f17805d637b12d585b000000000000000000104000f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b56e6be610872303d962695eea1d3f37ef67720fe624f92a5af6aaee85d103e4af2c7c238cff5670d1382ee2a12c54257424b409fed0f9622b907c3a84eda75a9c9cfbd18c5f6af307f99602af62c01a3d5824cd5b8e04dd5b9e4689d9ff455c0e", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b04000000000000003b62ab376b7acd57b3be5c53e4208050df69cc7377ea47b0c9e353f46f92908b40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0001010148c45d005c36ed3d5ded95b5864490c7d0687fc3a8abd7c4ada7b793386bc797ba9655c95b3057cce8b3c491a8be8e37a7706fdf596ea112649cae379717620f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0500000000000000c481fc3597ccd521d186950b299a18e46d07561ddddf61b3f530a8298d2a3fdd40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee00020303bc534a120d3beb1b91182b3d9efbd2f12499494349eee0ce186e0e64fd028aa3e295036af52833a8e419bf813ce93dfc9fbd7cb78fa60d0aab7e8ff754f5910a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0600000000000000f955c41c16c212fdef272f71455618ea2893358bbdaac69680e79f9d1064bb5340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900010001d04c2b1882c3473322e584c7dbb42c42d4d785e0ab4ad5385dfd87f58ed7e9a746e0e670ba2f21580e55b02732e90a655b93e4005390dc3c7a427809319c6e09", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0700000000000000e35f740d28abdc423147afd793f4c1a1c0495f6f5a42ce61047052696217047340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900020202ad6f7a51630985b19b7823c49a112515f8868618ef54d57fe9b06519e2c6157c9889d78ec20579c6e800dc40abbf17bf8ea84a242672314286b54cfd7c8cd400", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0800000000000000d070a74443ca8ec316c7ebe10adfc1e6e1b315f901cdeb3d9c093a189197939b80841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0002030391c03f8db98e739cc85ccdacade03fd3af84f56589f63dc4c818bec0d888be8f6bb8cf443a31bb7c9508dc8842c204308dd708d3580e59effd22d2452ab0930a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0900000000000000c3eaa5c50ef476b1db3a6917cdea3348b1bc586f5dff14f6a24bb59049b0220280841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a00010101efac7bdea673bf1a7835b65681123d6284d985bf18bef2c7d432deb3a23ed7373b619ab16de7b3ccc9a06456b6ab73bb817ee2745934aa84559bb880c15c9f08", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0a000000000000004db38667a64f130a431f196fe13e7823bac346d8e0e0aab6accc0cd6c9f4efa0c0c62d00000000000010400087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb043d0254c2c23705a7f999356bdcad35245d39aa7a3fb6d71f447f3111eef8ac728c205feda089e102c875d47ce46f6ea3b7a1100ef69cb86661f741b6d22309", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0b0000000000000060c5fb696e1c57d2c72b579325645491f82da96b92685fd479590205a0b64950c0c62d00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00010001f7733aeaeef3b5897ef3b347eb8f90ba3aa2d3502e34955234bef48f2ffab2ea539340c4fccd76a259c79319b928bd10d282fe1d907f66eee66279e1c021c701", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0c00000000000000c08bc94c25f46048e7700b65933b1a094ec41b95804e2ebf4981553f50c29d1000093d000000000000104000a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe26440d7e48b31b32b4411f13f4ea257af8fb6b7808fb1b4cacfbf382952f436557f3da1f5437cb2fcfe8383663516b0e16fd1f8b38b0ad14727b61f635ea060f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0d000000000000009a387fe90a62d0a2736a340c0abec8661e4f209541a79564e6e6684b335ffeb100093d000000000000122400a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467000304017216c32b856e553e4c953d95b717bdf1d6df1f17d4a860291881309d40cd3f324607b729ab13d9ae7987528b76088aee0403a6501aa567b550a4c2cd0da90902", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0e000000000000007d18182a07f55583e678af4b34ee88a8b80d6b98cb785603ef5fc6453d07dd9a00093d00000000000010400071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f4ce7d75774aa79578c785fc9db75f84ac8e0e53b82f23b1aa8d4efa3d623052f460202bd27efb074b7e889355a04680d4df9bf81f682ad012244ebcb9bcf4602", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0f00000000000000c1ee68a25be97b76521cede8f5ff14ded91028b92c6b8d282b798bdcdcb43af800093d00000000000012280071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d046d61696e020502277072b2e7cdc671dfe85d22b25a90ec33a85443d92c8d4d55054f5edf3a354bb78a9d414665e955ad6577b4981352abbd9af2d042c9d04e5aa556ae03aeed03", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b100000000000000054cc92986fe5f8e34f5c945820f4fcec9e01a6648ff95fe45242a6652af9ca19404b4c00000000000014600087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d36b48698d7f70a5584576a80843f364aa00af48148146bcd2362e90f9dc49ae530ee0ced88fb573c738d5dbca9900522cb768c7e7ca4ff1997fd899e8d721104", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b120000000000000032c069fce1fd0761d0a2264e777c1aa07d918908c3c85f2cdab638e9be41bdebc0cf6a00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00020201b73925e86757df2cb97dff95f062bfda5e5dbdecb8c74a2052d41acd02cb089214ea19c6c0b4ca69d920de95eba32c36e63ae248dbf018e45043df4f149da409", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1300000000000000a8bf5ae6643b41380949b4a5e61732c8d0b0a6505c8f2a1926745e24e09be5dd00127a0000000000001121006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0188bd61cf143dbd8dbb09c511deb1629bb3b2c8cd935c0385ecb0cca1d736042b7fac8e51eb77dc774720741e54493258857ee63443a752a4b6f48fe6c322470a" + ], + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b500000000000000000000000000000000000000000000000000000000000000000000000000000000a02526000000000000030700050068656c6c6fc2236d2ae9a34e5a1f2e9d7183cb6bcd9f2ee42bfa4d6b75e0daf9b903c9ecaddaea040d91daea50da4ba4ff29e593c793370f111d60f19a25326ded11983100", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b501000000000000009cfb474f8db2525a038f2cdc07ed84c60c5a9dfc0f7c2790c9cde824a9c06bc9e06735000000000000030900070077656c636f6d657a76ca1b05f90a1376ccf6139c1684728e097ee45d8b66aabd8a37ec0331cc174185780d7e5d0c48a0c597b4daa4b5adb5ad63f11b8e2a08990ba8fa3e717709" + ] + ] + }, + "studio_viewer_gap": { + "descriptor": "57524431015307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b00a043f6fd5d060040420f000000000000001000000008002c0100005745503101fe1f0000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f000000000007086469726563746f7203010206080200000000000000000000000000000000000000000000000000000000000009706572666f726d65720301020018000000000000000000000000000000000000000000000000000000000000000567756573740701010008000000000000000000000000000000000000000000000000000000000000000664657669636504000000000000000000000000000000000000000000000000000000000000000000000007656e636f646572020000000000000000000000000000000000000000000000000000000000000000000000056d697865720301020400000000000000000000000000000000000000000000000000000000000000000861756469656e636500010100080000000000000000000000000000000000000000000000000000000000000001046d61696e02010000000006067370656563680101046f707573000001000000000000100000004000000080bb0000010f056d757369630101046f70757300000100000000000080000000fe01000080bb000002000a63616d6572612d37323002020d617630312e302e30354d2e30380b617663312e363430303146010002800268011e0096000000f40100000005d0021e00f4010000dc0500000000000000000b63616d6572612d3130383002020d617630312e302e30384d2e30380b617663312e363430303238010003800268011e0096000000f40100000005d0021e00f4010000dc050000800738041e00dc050000a00f00000000000000000673637265656e03020d617630312e302e30384d2e30380b617663312e36343030323802044c31543301800738040f002c010000c409000000000000000005737461676502010d617630312e302e30384d2e3038030002c0031c021e00f4010000dc050000800738041e00dc050000a00f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fe7dbb536427c7878ce529c185205683673fb456b5f235030ff590ad9e8cf9cb5a8171427eaf0815b7cbd362e3e350947b292ba40229b57d15e2b5f9fc19703", + "grants": [ + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000003010206000000000000000000000000000000000000000000000000000000000000000000574550310108020000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020002001300056f726465720100320370697004007472756580450b030caaba83551ff5692a8c4c875850dc001857fd0cb1ab9006865c36d0d5d2e1644afc7cc9e8d44bfb305146af4dcfac3acb9d3123fbec567276b5eb06", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c16c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000103010200000000000000000000000000000000000000000000000000000000000000000000574550310118000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103002300086665617475726564040074727565046761696e040035313230056f726465720100318c2ca95cd77bbf90c51196e395b981c65aebcb619360d8cebc02ac022e1ef20a927483b76917a9899e8775f7498a79d8558b3d10558dd5d1353ce88ac394df0d", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204000900056f72646572010033baf89b30e2012f41d94859d9f68360f2a60cfa43deb66a2c85d5d228d012c04fbe87bb748a5ff3ce12947870158bd14b99dce91f4d9d7fee15279c057549670e", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb404b4c000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204001f00046761696e040032303438056f726465720100300370616e05002d3230343888b4b7b0f34c777ccf5e9f7b6d47f4754be94876a01fd380a3ccd3143f75ee4a15cab40dba93452d53ddfd42cd398a8aca2fa873a0c0cb9301eb034c48a8b00a", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b4670000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000304000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000104000900056f726465720100345d27b87859c990b56b36c3a9d9a4adb9d055604a44e2286b14f0f086e5516f0ce01ccbdce6f6c8d8ea8cec4767a0ff2d7e84873fba4b0d81ce8dc4524cef5008", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c171bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000402000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000105000900056f72646572010035cab27eed3e80e7d7d110a63bc1762cf0a9aa73f7cc23f063af1fa031cd2526cfeb96252b4ea55326de456237471cfb1c85493ab5a011af0ac7214ef436a89f00", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000503010204000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103000000cb0003729a42a412ef3360a9b6a5abfebc3614e92c6ba46446888d6570c11a251fedca06998f7f82a845c06b04cb646a879f250479731b993341b3a5e4c3b207", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b50000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000600010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000000000026a9b29ec093d694c84d8617902c3ad0988336eae0f8cc14d1ba2db3fc637ea9ba13a9ec752f4208e618ca6178fb3fff8940b842bfea80880e041168a3fcac0d" + ], + "key_log_head": null, + "chains": [ + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d195e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce40d7f46a9e65a915692a069d0cd9fdc6555b82f057ecf42bc46135baf46670d9631dd1bbaf83038386f70a83dc98339f660fe2da7efb0b60732c445acb0a8b04", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0100000000000000495f88e2124194ba930fbafe754f2a18bca5c75374b9aa15581262149e18edf10000000000000000001040006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4fcccbbf904396ff6b660581ad712641ef0fe16097a206cf4472c3b6a21713db2ad9353fe5a3e5472b6f3f1ed28495ff4ff4778dd265701fa02a302120d552108", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0200000000000000777b529a49995eab01a34504b02a0b7a54d608d39e96426a33e1358e22779cf40000000000000000001040004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a2a5c4620f83c620060e48f40dcf7df65c4bf32ba4e0f5e47b68e129e46f670408d5349f71bb059f76decefe20e043503b3cc47fc8f76f1c7e44b03230d313024436a95dfd2360078713b7de1b247a489dc4c0d5650e57171a211afc474329e0f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0300000000000000192c9e861bc16961b09fcef12766feeceec1f2401a2fe5f17805d637b12d585b000000000000000000104000f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b56e6be610872303d962695eea1d3f37ef67720fe624f92a5af6aaee85d103e4af2c7c238cff5670d1382ee2a12c54257424b409fed0f9622b907c3a84eda75a9c9cfbd18c5f6af307f99602af62c01a3d5824cd5b8e04dd5b9e4689d9ff455c0e", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b04000000000000003b62ab376b7acd57b3be5c53e4208050df69cc7377ea47b0c9e353f46f92908b40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0001010148c45d005c36ed3d5ded95b5864490c7d0687fc3a8abd7c4ada7b793386bc797ba9655c95b3057cce8b3c491a8be8e37a7706fdf596ea112649cae379717620f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0500000000000000c481fc3597ccd521d186950b299a18e46d07561ddddf61b3f530a8298d2a3fdd40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee00020303bc534a120d3beb1b91182b3d9efbd2f12499494349eee0ce186e0e64fd028aa3e295036af52833a8e419bf813ce93dfc9fbd7cb78fa60d0aab7e8ff754f5910a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0600000000000000f955c41c16c212fdef272f71455618ea2893358bbdaac69680e79f9d1064bb5340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900010001d04c2b1882c3473322e584c7dbb42c42d4d785e0ab4ad5385dfd87f58ed7e9a746e0e670ba2f21580e55b02732e90a655b93e4005390dc3c7a427809319c6e09", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0700000000000000e35f740d28abdc423147afd793f4c1a1c0495f6f5a42ce61047052696217047340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900020202ad6f7a51630985b19b7823c49a112515f8868618ef54d57fe9b06519e2c6157c9889d78ec20579c6e800dc40abbf17bf8ea84a242672314286b54cfd7c8cd400", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0800000000000000d070a74443ca8ec316c7ebe10adfc1e6e1b315f901cdeb3d9c093a189197939b80841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0002030391c03f8db98e739cc85ccdacade03fd3af84f56589f63dc4c818bec0d888be8f6bb8cf443a31bb7c9508dc8842c204308dd708d3580e59effd22d2452ab0930a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0900000000000000c3eaa5c50ef476b1db3a6917cdea3348b1bc586f5dff14f6a24bb59049b0220280841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a00010101efac7bdea673bf1a7835b65681123d6284d985bf18bef2c7d432deb3a23ed7373b619ab16de7b3ccc9a06456b6ab73bb817ee2745934aa84559bb880c15c9f08", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0a000000000000004db38667a64f130a431f196fe13e7823bac346d8e0e0aab6accc0cd6c9f4efa0c0c62d00000000000010400087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb043d0254c2c23705a7f999356bdcad35245d39aa7a3fb6d71f447f3111eef8ac728c205feda089e102c875d47ce46f6ea3b7a1100ef69cb86661f741b6d22309", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0b0000000000000060c5fb696e1c57d2c72b579325645491f82da96b92685fd479590205a0b64950c0c62d00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00010001f7733aeaeef3b5897ef3b347eb8f90ba3aa2d3502e34955234bef48f2ffab2ea539340c4fccd76a259c79319b928bd10d282fe1d907f66eee66279e1c021c701", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0c00000000000000c08bc94c25f46048e7700b65933b1a094ec41b95804e2ebf4981553f50c29d1000093d000000000000104000a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe26440d7e48b31b32b4411f13f4ea257af8fb6b7808fb1b4cacfbf382952f436557f3da1f5437cb2fcfe8383663516b0e16fd1f8b38b0ad14727b61f635ea060f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0d000000000000009a387fe90a62d0a2736a340c0abec8661e4f209541a79564e6e6684b335ffeb100093d000000000000122400a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467000304017216c32b856e553e4c953d95b717bdf1d6df1f17d4a860291881309d40cd3f324607b729ab13d9ae7987528b76088aee0403a6501aa567b550a4c2cd0da90902", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0e000000000000007d18182a07f55583e678af4b34ee88a8b80d6b98cb785603ef5fc6453d07dd9a00093d00000000000010400071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f4ce7d75774aa79578c785fc9db75f84ac8e0e53b82f23b1aa8d4efa3d623052f460202bd27efb074b7e889355a04680d4df9bf81f682ad012244ebcb9bcf4602", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0f00000000000000c1ee68a25be97b76521cede8f5ff14ded91028b92c6b8d282b798bdcdcb43af800093d00000000000012280071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d046d61696e020502277072b2e7cdc671dfe85d22b25a90ec33a85443d92c8d4d55054f5edf3a354bb78a9d414665e955ad6577b4981352abbd9af2d042c9d04e5aa556ae03aeed03", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b100000000000000054cc92986fe5f8e34f5c945820f4fcec9e01a6648ff95fe45242a6652af9ca19404b4c00000000000014600087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d36b48698d7f70a5584576a80843f364aa00af48148146bcd2362e90f9dc49ae530ee0ced88fb573c738d5dbca9900522cb768c7e7ca4ff1997fd899e8d721104", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1100000000000000a592b2446f22475e2404ac22417cd90f9e184f38875a9f23a48cb1d1f3c509cf808d5b0000000000001322009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190002b171f1b7a684a7b69644c3f8d97cb98ba8310d371d31b41c2e7370c595b70fc22a140f583b847ad8ace041592570825e8eb5eee51118bafa6661d6f369dfff07", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b120000000000000032c069fce1fd0761d0a2264e777c1aa07d918908c3c85f2cdab638e9be41bdebc0cf6a00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00020201b73925e86757df2cb97dff95f062bfda5e5dbdecb8c74a2052d41acd02cb089214ea19c6c0b4ca69d920de95eba32c36e63ae248dbf018e45043df4f149da409", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1300000000000000a8bf5ae6643b41380949b4a5e61732c8d0b0a6505c8f2a1926745e24e09be5dd00127a0000000000001121006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0188bd61cf143dbd8dbb09c511deb1629bb3b2c8cd935c0385ecb0cca1d736042b7fac8e51eb77dc774720741e54493258857ee63443a752a4b6f48fe6c322470a" + ], + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b501000000000000009cfb474f8db2525a038f2cdc07ed84c60c5a9dfc0f7c2790c9cde824a9c06bc9e06735000000000000030900070077656c636f6d657a76ca1b05f90a1376ccf6139c1684728e097ee45d8b66aabd8a37ec0331cc174185780d7e5d0c48a0c597b4daa4b5adb5ad63f11b8e2a08990ba8fa3e717709" + ] + ] + }, + "studio_refused": { + "descriptor": "57524431015307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c4823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b00a043f6fd5d060040420f000000000000001000000008002c0100005745503101fe1f0000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f000000000007086469726563746f7203010206080200000000000000000000000000000000000000000000000000000000000009706572666f726d65720301020018000000000000000000000000000000000000000000000000000000000000000567756573740701010008000000000000000000000000000000000000000000000000000000000000000664657669636504000000000000000000000000000000000000000000000000000000000000000000000007656e636f646572020000000000000000000000000000000000000000000000000000000000000000000000056d697865720301020400000000000000000000000000000000000000000000000000000000000000000861756469656e636500010100080000000000000000000000000000000000000000000000000000000000000001046d61696e02010000000006067370656563680101046f707573000001000000000000100000004000000080bb0000010f056d757369630101046f70757300000100000000000080000000fe01000080bb000002000a63616d6572612d37323002020d617630312e302e30354d2e30380b617663312e363430303146010002800268011e0096000000f40100000005d0021e00f4010000dc0500000000000000000b63616d6572612d3130383002020d617630312e302e30384d2e30380b617663312e363430303238010003800268011e0096000000f40100000005d0021e00f4010000dc050000800738041e00dc050000a00f00000000000000000673637265656e03020d617630312e302e30384d2e30380b617663312e36343030323802044c31543301800738040f002c010000c409000000000000000005737461676502010d617630312e302e30384d2e3038030002c0031c021e00f4010000dc050000800738041e00dc050000a00f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fe7dbb536427c7878ce529c185205683673fb456b5f235030ff590ad9e8cf9cb5a8171427eaf0815b7cbd362e3e350947b292ba40229b57d15e2b5f9fc19703", + "grants": [ + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000003010206000000000000000000000000000000000000000000000000000000000000000000574550310108020000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020002001300056f726465720100320370697004007472756580450b030caaba83551ff5692a8c4c875850dc001857fd0cb1ab9006865c36d0d5d2e1644afc7cc9e8d44bfb305146af4dcfac3acb9d3123fbec567276b5eb06", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c16c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000103010200000000000000000000000000000000000000000000000000000000000000000000574550310118000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103002300086665617475726564040074727565046761696e040035313230056f726465720100318c2ca95cd77bbf90c51196e395b981c65aebcb619360d8cebc02ac022e1ef20a927483b76917a9899e8775f7498a79d8558b3d10558dd5d1353ce88ac394df0d", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204000900056f72646572010033baf89b30e2012f41d94859d9f68360f2a60cfa43deb66a2c85d5d228d012c04fbe87bb748a5ff3ce12947870158bd14b99dce91f4d9d7fee15279c057549670e", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb404b4c000000000070acd26a00000000000cd46a000000000207010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff00000003000204001f00046761696e040032303438056f726465720100300370616e05002d3230343888b4b7b0f34c777ccf5e9f7b6d47f4754be94876a01fd380a3ccd3143f75ee4a15cab40dba93452d53ddfd42cd398a8aca2fa873a0c0cb9301eb034c48a8b00a", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b4670000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000304000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000104000900056f726465720100345d27b87859c990b56b36c3a9d9a4adb9d055604a44e2286b14f0f086e5516f0ce01ccbdce6f6c8d8ea8cec4767a0ff2d7e84873fba4b0d81ce8dc4524cef5008", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c171bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000402000000000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000105000900056f72646572010035cab27eed3e80e7d7d110a63bc1762cf0a9aa73f7cc23f063af1fa031cd2526cfeb96252b4ea55326de456237471cfb1c85493ab5a011af0ac7214ef436a89f00", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000503010204000000000000000000000000000000000000000000000000000000000000000000574550310100000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff000000020103000000cb0003729a42a412ef3360a9b6a5abfebc3614e92c6ba46446888d6570c11a251fedca06998f7f82a845c06b04cb646a879f250479731b993341b3a5e4c3b207", + "5752473101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b50000000000000000000000000000000000000000000000000000000000000000000000000000000070acd26a00000000000cd46a000000000600010100000000000000000000000000000000000000000000000000000000000000000000574550310108000000000000000000000000000000000000000000000000000000000000000004f4013200000040420f00000000000100000040420f0000000000ffffffffffffffffffffffffffffffff0000000000000026a9b29ec093d694c84d8617902c3ad0988336eae0f8cc14d1ba2db3fc637ea9ba13a9ec752f4208e618ca6178fb3fff8940b842bfea80880e041168a3fcac0d" + ], + "key_log_head": null, + "chains": [ + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001040009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d195e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce40d7f46a9e65a915692a069d0cd9fdc6555b82f057ecf42bc46135baf46670d9631dd1bbaf83038386f70a83dc98339f660fe2da7efb0b60732c445acb0a8b04", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0100000000000000495f88e2124194ba930fbafe754f2a18bca5c75374b9aa15581262149e18edf10000000000000000001040006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4fcccbbf904396ff6b660581ad712641ef0fe16097a206cf4472c3b6a21713db2ad9353fe5a3e5472b6f3f1ed28495ff4ff4778dd265701fa02a302120d552108", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0200000000000000777b529a49995eab01a34504b02a0b7a54d608d39e96426a33e1358e22779cf40000000000000000001040004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a2a5c4620f83c620060e48f40dcf7df65c4bf32ba4e0f5e47b68e129e46f670408d5349f71bb059f76decefe20e043503b3cc47fc8f76f1c7e44b03230d313024436a95dfd2360078713b7de1b247a489dc4c0d5650e57171a211afc474329e0f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0300000000000000192c9e861bc16961b09fcef12766feeceec1f2401a2fe5f17805d637b12d585b000000000000000000104000f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b56e6be610872303d962695eea1d3f37ef67720fe624f92a5af6aaee85d103e4af2c7c238cff5670d1382ee2a12c54257424b409fed0f9622b907c3a84eda75a9c9cfbd18c5f6af307f99602af62c01a3d5824cd5b8e04dd5b9e4689d9ff455c0e", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b04000000000000003b62ab376b7acd57b3be5c53e4208050df69cc7377ea47b0c9e353f46f92908b40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0001010148c45d005c36ed3d5ded95b5864490c7d0687fc3a8abd7c4ada7b793386bc797ba9655c95b3057cce8b3c491a8be8e37a7706fdf596ea112649cae379717620f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0500000000000000c481fc3597ccd521d186950b299a18e46d07561ddddf61b3f530a8298d2a3fdd40420f0000000000001224006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee00020303bc534a120d3beb1b91182b3d9efbd2f12499494349eee0ce186e0e64fd028aa3e295036af52833a8e419bf813ce93dfc9fbd7cb78fa60d0aab7e8ff754f5910a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0600000000000000f955c41c16c212fdef272f71455618ea2893358bbdaac69680e79f9d1064bb5340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900010001d04c2b1882c3473322e584c7dbb42c42d4d785e0ab4ad5385dfd87f58ed7e9a746e0e670ba2f21580e55b02732e90a655b93e4005390dc3c7a427809319c6e09", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0700000000000000e35f740d28abdc423147afd793f4c1a1c0495f6f5a42ce61047052696217047340420f0000000000001224009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1900020202ad6f7a51630985b19b7823c49a112515f8868618ef54d57fe9b06519e2c6157c9889d78ec20579c6e800dc40abbf17bf8ea84a242672314286b54cfd7c8cd400", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0800000000000000d070a74443ca8ec316c7ebe10adfc1e6e1b315f901cdeb3d9c093a189197939b80841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a0002030391c03f8db98e739cc85ccdacade03fd3af84f56589f63dc4c818bec0d888be8f6bb8cf443a31bb7c9508dc8842c204308dd708d3580e59effd22d2452ab0930a", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0900000000000000c3eaa5c50ef476b1db3a6917cdea3348b1bc586f5dff14f6a24bb59049b0220280841e0000000000001224004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a00010101efac7bdea673bf1a7835b65681123d6284d985bf18bef2c7d432deb3a23ed7373b619ab16de7b3ccc9a06456b6ab73bb817ee2745934aa84559bb880c15c9f08", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0a000000000000004db38667a64f130a431f196fe13e7823bac346d8e0e0aab6accc0cd6c9f4efa0c0c62d00000000000010400087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb043d0254c2c23705a7f999356bdcad35245d39aa7a3fb6d71f447f3111eef8ac728c205feda089e102c875d47ce46f6ea3b7a1100ef69cb86661f741b6d22309", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0b0000000000000060c5fb696e1c57d2c72b579325645491f82da96b92685fd479590205a0b64950c0c62d00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00010001f7733aeaeef3b5897ef3b347eb8f90ba3aa2d3502e34955234bef48f2ffab2ea539340c4fccd76a259c79319b928bd10d282fe1d907f66eee66279e1c021c701", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0c00000000000000c08bc94c25f46048e7700b65933b1a094ec41b95804e2ebf4981553f50c29d1000093d000000000000104000a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe26440d7e48b31b32b4411f13f4ea257af8fb6b7808fb1b4cacfbf382952f436557f3da1f5437cb2fcfe8383663516b0e16fd1f8b38b0ad14727b61f635ea060f", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0d000000000000009a387fe90a62d0a2736a340c0abec8661e4f209541a79564e6e6684b335ffeb100093d000000000000122400a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467000304017216c32b856e553e4c953d95b717bdf1d6df1f17d4a860291881309d40cd3f324607b729ab13d9ae7987528b76088aee0403a6501aa567b550a4c2cd0da90902", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0e000000000000007d18182a07f55583e678af4b34ee88a8b80d6b98cb785603ef5fc6453d07dd9a00093d00000000000010400071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f4ce7d75774aa79578c785fc9db75f84ac8e0e53b82f23b1aa8d4efa3d623052f460202bd27efb074b7e889355a04680d4df9bf81f682ad012244ebcb9bcf4602", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b0f00000000000000c1ee68a25be97b76521cede8f5ff14ded91028b92c6b8d282b798bdcdcb43af800093d00000000000012280071bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d046d61696e020502277072b2e7cdc671dfe85d22b25a90ec33a85443d92c8d4d55054f5edf3a354bb78a9d414665e955ad6577b4981352abbd9af2d042c9d04e5aa556ae03aeed03", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b100000000000000054cc92986fe5f8e34f5c945820f4fcec9e01a6648ff95fe45242a6652af9ca19404b4c00000000000014600087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d36b48698d7f70a5584576a80843f364aa00af48148146bcd2362e90f9dc49ae530ee0ced88fb573c738d5dbca9900522cb768c7e7ca4ff1997fd899e8d721104", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1100000000000000a592b2446f22475e2404ac22417cd90f9e184f38875a9f23a48cb1d1f3c509cf808d5b0000000000001322009f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d190002b171f1b7a684a7b69644c3f8d97cb98ba8310d371d31b41c2e7370c595b70fc22a140f583b847ad8ace041592570825e8eb5eee51118bafa6661d6f369dfff07", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b120000000000000032c069fce1fd0761d0a2264e777c1aa07d918908c3c85f2cdab638e9be41bdebc0cf6a00000000000012240087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a00020201b73925e86757df2cb97dff95f062bfda5e5dbdecb8c74a2052d41acd02cb089214ea19c6c0b4ca69d920de95eba32c36e63ae248dbf018e45043df4f149da409", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1823db080c11bf96cba9deb1195e9b96428f78c03d87c1a425da1eefc9647998b1300000000000000a8bf5ae6643b41380949b4a5e61732c8d0b0a6505c8f2a1926745e24e09be5dd00127a0000000000001121006c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee0188bd61cf143dbd8dbb09c511deb1629bb3b2c8cd935c0385ecb0cca1d736042b7fac8e51eb77dc774720741e54493258857ee63443a752a4b6f48fe6c322470a" + ], + [ + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b500000000000000000000000000000000000000000000000000000000000000000000000000000000a02526000000000000030700050068656c6c6fc2236d2ae9a34e5a1f2e9d7183cb6bcd9f2ee42bfa4d6b75e0daf9b903c9ecaddaea040d91daea50da4ba4ff29e593c793370f111d60f19a25326ded11983100", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b501000000000000009cfb474f8db2525a038f2cdc07ed84c60c5a9dfc0f7c2790c9cde824a9c06bc9e06735000000000000030900070077656c636f6d657a76ca1b05f90a1376ccf6139c1684728e097ee45d8b66aabd8a37ec0331cc174185780d7e5d0c48a0c597b4daa4b5adb5ad63f11b8e2a08990ba8fa3e717709", + "5745563101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c1f44e67da0f6baff711fcc3c8de005501461bfd869c55c9cf79269a9547e848b5020000000000000003934c750a6ab0f651bffabfa76f1ec48ea222da8eecde92a31fab428bdcb6c4e0707200000000000009220087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a04019f7b580c18937a22c43a15c1b738dc1437b216226f6049073226f0d9e8299062dbf66cd3fd112a7b4899f2b678a354944b4ec6bc11edf2b71c7aae8f3dcc0f0c" + ] + ] + } + }, + "compositions": [ + { + "name": "grid_session", + "about": "the grid over the whole session, at every second from 1 s to 9 s: publishes, a stopped video, a screen, a slot, a grant exchange that reorders, a video stopped and one started, a leave (§4, §5, §5.8)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "instants": [ + 1000000, + 2000000, + 3000000, + 4000000, + 5000000, + 6000000, + 7000000, + 8000000, + 9000000 + ], + "outcome": "compose", + "digest": "15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527", + "frames": [ + { + "t": 1000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + } + ], + "set_digest": "e0396b92bf6438d0ee49c6dc40bd09f768b98227fc66003d7da53cc77059370b", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 722, + 812, + 476, + 268 + ], + "dst": [ + 722, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 2000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + } + ], + "set_digest": "eba850e9e4071e0ba6b37f9c86f1550a8bf9d8e97f9cfc1a41617206911fb205", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 722, + 812, + 476, + 268 + ], + "dst": [ + 722, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 3000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb", + "join": 4, + "attrs": [ + [ + "order", + "3" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + } + ], + "set_digest": "837786ecb2c658f9bec8bfbbd65908f0798e00b6739666693db26db0c14990c5", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 240, + 812, + 476, + 268 + ], + "dst": [ + 240, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 1204, + 812, + 476, + 268 + ], + "dst": null, + "src": null + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 4000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb", + "join": 4, + "attrs": [ + [ + "order", + "3" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "50e0241058fc1c9489fd8784f1285e41be3914c1a1c1d527cfa8290bd866c65e", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 0, + 813, + 474, + 266 + ], + "dst": [ + 0, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 482, + 813, + 474, + 266 + ], + "dst": null, + "src": null + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 964, + 813, + 474, + 266 + ], + "dst": [ + 964, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 813, + 474, + 266 + ], + "dst": [ + 1446, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 5000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 0, + 813, + 474, + 266 + ], + "dst": null, + "src": null + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 482, + 813, + 474, + 266 + ], + "dst": [ + 482, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 964, + 813, + 474, + 266 + ], + "dst": [ + 964, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 813, + 474, + 266 + ], + "dst": [ + 1446, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 6000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "c24ad360e916fea3bb7a8cd29c44d0bdba04d4703f5f91c500bda1bda96d43b4", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 0, + 813, + 474, + 266 + ], + "dst": null, + "src": null + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 482, + 813, + 474, + 266 + ], + "dst": null, + "src": null + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 964, + 813, + 474, + 266 + ], + "dst": [ + 964, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 813, + 474, + 266 + ], + "dst": [ + 1446, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 7000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 1, + "layer": 0, + "layering": 1, + "width": 640, + "height": 360, + "tracks": [ + "4aa47e3f75fa852b5b7011f10205b1375b0fbe59ecfc1aa44da7f61b75183a1c" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "8a0f5d016fd22ff00df19ad8236054f40829413eace259e3cc7771fb56eb4a4b", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 0, + 813, + 474, + 266 + ], + "dst": [ + 0, + 813, + 474, + 266 + ], + "src": [ + 0, + 0, + 640, + 359 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 482, + 813, + 474, + 266 + ], + "dst": null, + "src": null + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 964, + 813, + 474, + 266 + ], + "dst": [ + 964, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 813, + 474, + 266 + ], + "dst": [ + 1446, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 8000000, + "participants": [ + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 1, + "layer": 0, + "layering": 1, + "width": 640, + "height": 360, + "tracks": [ + "4aa47e3f75fa852b5b7011f10205b1375b0fbe59ecfc1aa44da7f61b75183a1c" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "2c8aa111ea37aa8115b84a2bd0df0d26b49e23218f6fa1f3df795ef4df40e1e3", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 0, + 0, + 639, + 360 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": null, + "src": null + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1918, + 1080 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1918, + 1080 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 9000000, + "participants": [ + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 1, + "layer": 0, + "layering": 1, + "width": 640, + "height": 360, + "tracks": [ + "4aa47e3f75fa852b5b7011f10205b1375b0fbe59ecfc1aa44da7f61b75183a1c" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "ba205a6f96d876ac93282762df6d48c96ddb5a1ca37f5e99d2a9006fa176e4a5", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 2, + 0, + 952, + 536 + ], + "dst": [ + 2, + 0, + 952, + 536 + ], + "src": [ + 0, + 0, + 639, + 360 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 966, + 0, + 952, + 536 + ], + "dst": null, + "src": null + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 2, + 544, + 952, + 536 + ], + "dst": [ + 2, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1918, + 1080 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 966, + 544, + 952, + 536 + ], + "dst": [ + 966, + 544, + 952, + 536 + ], + "src": [ + 1, + 0, + 1918, + 1080 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + } + ] + }, + { + "name": "pip_session", + "about": "picture in picture over the session, stopped video omitted, sources read at layer 1 (§4.2, §5.5)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c15307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c400000000000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101801020400000200056f72646572010370697004e0010e011800020280bb0000046761696e0370616e060cc17a2acbb2cf4159ff17ae5aee793aa3bcd9eac6239c3dda678ee010de89cad1aae7e3f6b849b575d0cd43d25b69c8c90b479bc407ec85459e9f375805d4a309", + "instants": [ + 0, + 1000000, + 3000000, + 6000000, + 7000000, + 8000000 + ], + "outcome": "compose", + "digest": "5ad64329fe0eb76d320922749a16c9358465444e542fc6c0ad6fbbe519408ad4", + "frames": [ + { + "t": 0, + "participants": [], + "set_digest": "207b8825ee651975c9b18ab0a1be41b6b451643bea83aca7dc3d20fd1fca9575", + "order": [], + "tiles": [], + "voices": [] + }, + { + "t": 1000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "316cceb04a36e10398601ff08bca686f789ef3de4e301bb7fd46fabeadfc57f4" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + } + ], + "set_digest": "65b09a1166040ca3741998413595db8d15f8c93718bf7b863f288cf325c65ba5", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 1080 + ], + "dst": [ + 0, + 0, + 1920, + 1080 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 3000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "316cceb04a36e10398601ff08bca686f789ef3de4e301bb7fd46fabeadfc57f4" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb", + "join": 4, + "attrs": [ + [ + "order", + "3" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + } + ], + "set_digest": "0eadf16db32a0981602310b7d786c3b83865765e50a510bf57d0f43eeac44fad", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 1080 + ], + "dst": [ + 0, + 0, + 1920, + 1080 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "pip", + "z": 1, + "tile": [ + 1416, + 786, + 480, + 270 + ], + "dst": [ + 1416, + 786, + 480, + 270 + ], + "src": [ + 0, + 0, + 1280, + 720 + ] + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 6000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "316cceb04a36e10398601ff08bca686f789ef3de4e301bb7fd46fabeadfc57f4" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "8bc1324ec4d9520e1f51a1477bc7270b17f0610ecc4c15b37e117cfdddd1dbfe", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 958, + 538 + ], + "dst": [ + 0, + 0, + 958, + 538 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 962, + 0, + 958, + 538 + ], + "dst": [ + 962, + 0, + 958, + 538 + ], + "src": [ + 0, + 1, + 1920, + 1078 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 481, + 542, + 958, + 538 + ], + "dst": [ + 481, + 542, + 958, + 538 + ], + "src": [ + 0, + 1, + 1920, + 1078 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 7000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "316cceb04a36e10398601ff08bca686f789ef3de4e301bb7fd46fabeadfc57f4" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 1, + "layer": 0, + "layering": 1, + "width": 640, + "height": 360, + "tracks": [ + "4aa47e3f75fa852b5b7011f10205b1375b0fbe59ecfc1aa44da7f61b75183a1c" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "0421439e2bbaa7f2d0de5edbd92769cd26729645f550ec2c10a5c326ae7be62d", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 958, + 538 + ], + "dst": [ + 0, + 0, + 958, + 538 + ], + "src": [ + 0, + 0, + 640, + 359 + ] + }, + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "grid", + "z": 0, + "tile": [ + 962, + 0, + 958, + 538 + ], + "dst": [ + 962, + 0, + 958, + 538 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 0, + 542, + 958, + 538 + ], + "dst": [ + 0, + 542, + 958, + 538 + ], + "src": [ + 0, + 1, + 1920, + 1078 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 962, + 542, + 958, + 538 + ], + "dst": [ + 962, + 542, + 958, + 538 + ], + "src": [ + 0, + 1, + 1920, + 1078 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 8000000, + "participants": [ + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 1, + "layer": 0, + "layering": 1, + "width": 640, + "height": 360, + "tracks": [ + "4aa47e3f75fa852b5b7011f10205b1375b0fbe59ecfc1aa44da7f61b75183a1c" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "2c8aa111ea37aa8115b84a2bd0df0d26b49e23218f6fa1f3df795ef4df40e1e3", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 0, + 0, + 958, + 538 + ], + "dst": [ + 0, + 0, + 958, + 538 + ], + "src": [ + 0, + 0, + 640, + 359 + ] + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 962, + 0, + 958, + 538 + ], + "dst": [ + 962, + 0, + 958, + 538 + ], + "src": [ + 0, + 1, + 1920, + 1078 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 481, + 542, + 958, + 538 + ], + "dst": [ + 481, + 542, + 958, + 538 + ], + "src": [ + 0, + 1, + 1920, + 1078 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + } + ] + }, + { + "name": "participant_gap", + "about": "a gap in the viewer's chat chain does not stop composition: the lifecycle is whole (§4.1)", + "room": "studio_viewer_gap", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "instants": [ + 3000000, + 5000000 + ], + "outcome": "compose", + "digest": "15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527", + "frames": [ + { + "t": 3000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb", + "join": 4, + "attrs": [ + [ + "order", + "3" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + } + ], + "set_digest": "837786ecb2c658f9bec8bfbbd65908f0798e00b6739666693db26db0c14990c5", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 240, + 812, + 476, + 268 + ], + "dst": [ + 240, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 1204, + 812, + 476, + 268 + ], + "dst": null, + "src": null + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 5000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "0218be2590a31b4ab015e9a29cc8a3e91fbbff406372e89e2cdd624593cd191d", + "join": 4, + "attrs": [ + [ + "gain", + "2048" + ], + [ + "order", + "0" + ], + [ + "pan", + "-2048" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b", + "order": [ + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 0, + 813, + 474, + 266 + ], + "dst": null, + "src": null + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 482, + 813, + 474, + 266 + ], + "dst": [ + 482, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 964, + 813, + 474, + 266 + ], + "dst": [ + 964, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 813, + 474, + 266 + ], + "dst": [ + 1446, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + } + ], + "voices": [ + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 2048, + "pan": -2048 + }, + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + } + ] + }, + { + "name": "signer_without_power", + "about": "a grid signed by the performer, whose grant has no compose power (§3.5)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c16c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee40420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c8f5a0209e9526a7fcd01bdbdbb7faced3ea7e2a07f5c3f70528d8717593e889219319c24ceed0bbf376209b280a1c5106b55045a955ccb01042526052e91f005", + "instants": [ + 1000000, + 2000000, + 3000000, + 4000000, + 5000000, + 6000000, + 7000000, + 8000000, + 9000000 + ], + "outcome": "refuse", + "reason": "compose_not_permitted", + "at": [ + "descriptor" + ] + }, + { + "name": "signer_not_present", + "about": "a grid signed by a key that is not in the room (§3.5)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c11806fc2de983e5f70a0b10e791ec06743adef5f2ef21d729e2ff6a8ab6e63c7f40420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c2df464c0feb573dd4a6dc5da81ca50d9e6fe7b8a9f64e01eb196129dc65e75dcfd5773b1f3bde94c8cb5e2331d4d2a19160ebc6c2a4d482dc552920d0745a70d", + "instants": [ + 1000000, + 2000000, + 3000000, + 4000000, + 5000000, + 6000000, + 7000000, + 8000000, + 9000000 + ], + "outcome": "refuse", + "reason": "compose_not_permitted", + "at": [ + "descriptor" + ] + }, + { + "name": "signer_with_power", + "about": "a grid signed by the mixer, effective at 0 s: a principal whose grant in effect has the compose power may sign, not only the authority (§3.5)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a00000000000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c14941dcc362a51e4a7feb6e3fbf7beb331f78b41f4a190ba5700a917779c3fc8709c019438d5eb69cf88aa8fa75cf76fd2f4a4ba415e3f44c2e8f691987b4902", + "instants": [ + 1000000, + 4000000 + ], + "outcome": "compose", + "digest": "30fec33168e45e0e1cf47eabe9f51850161bd806b26b7d36e3968ff32be89cac", + "frames": [ + { + "t": 1000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + } + ], + "set_digest": "e0396b92bf6438d0ee49c6dc40bd09f768b98227fc66003d7da53cc77059370b", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 722, + 812, + 476, + 268 + ], + "dst": [ + 722, + 812, + 476, + 268 + ], + "src": [ + 1, + 0, + 1278, + 720 + ] + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + } + ] + }, + { + "t": 4000000, + "participants": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "grant": "6202d91e7b9d2d1adceb654701176cc30880688d0f41e9fef58445525ff3d3c4", + "join": 1, + "attrs": [ + [ + "featured", + "true" + ], + [ + "gain", + "5120" + ], + [ + "order", + "1" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 3, + "layers": 3, + "layer": 2, + "layering": 1, + "width": 1920, + "height": 1080, + "tracks": [ + "cc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 1, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be" + ] + } + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "grant": "689d5ceb0f5c277afac0f8d24fc68e2c655f2af656290b686362f779d1dc4c0f", + "join": 6, + "attrs": [ + [ + "order", + "5" + ] + ], + "video": { + "slot": "main", + "media": 2, + "profile": 5, + "layers": 2, + "layer": 1, + "layering": 3, + "width": 1920, + "height": 1080, + "tracks": [ + "bb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6", + "5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91" + ] + }, + "audio": null + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "grant": "19e4a9970e5fad392dc65d53e045cf19069a360f679a416048a7c754a019d7fb", + "join": 4, + "attrs": [ + [ + "order", + "3" + ] + ], + "video": null, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "dc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a" + ] + } + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "grant": "5e153b4a977b1069920833823cc267865d67710d748456eeb1d3539b86acf1ce", + "join": 0, + "attrs": [ + [ + "order", + "2" + ], + [ + "pip", + "true" + ] + ], + "video": { + "slot": "", + "media": 2, + "profile": 2, + "layers": 2, + "layer": 1, + "layering": 1, + "width": 1280, + "height": 720, + "tracks": [ + "3986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e" + ] + }, + "audio": { + "slot": "", + "media": 1, + "profile": 0, + "layers": 1, + "layer": 0, + "layering": 0, + "width": 0, + "height": 0, + "tracks": [ + "ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a65" + ] + } + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "grant": "b2f92327aad00aa45f6632c18c709d0552ca9d7c9d6e3d1fce50df2261881ebe", + "join": 5, + "attrs": [ + [ + "order", + "4" + ] + ], + "video": { + "slot": "", + "media": 3, + "profile": 4, + "layers": 1, + "layer": 0, + "layering": 2, + "width": 1920, + "height": 1080, + "tracks": [ + "525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e" + ] + }, + "audio": null + } + ], + "set_digest": "50e0241058fc1c9489fd8784f1285e41be3914c1a1c1d527cfa8290bd866c65e", + "order": [ + "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d" + ], + "tiles": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "place": "featured", + "z": 0, + "tile": [ + 0, + 0, + 1920, + 804 + ], + "dst": [ + 245, + 0, + 1429, + 804 + ], + "src": [ + 0, + 0, + 1920, + 1080 + ] + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "place": "grid", + "z": 0, + "tile": [ + 0, + 813, + 474, + 266 + ], + "dst": [ + 0, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1280, + 718 + ] + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "place": "grid", + "z": 0, + "tile": [ + 482, + 813, + 474, + 266 + ], + "dst": null, + "src": null + }, + { + "principal": "a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467", + "place": "grid", + "z": 0, + "tile": [ + 964, + 813, + 474, + 266 + ], + "dst": [ + 964, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + }, + { + "principal": "71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d", + "place": "grid", + "z": 0, + "tile": [ + 1446, + 813, + 474, + 266 + ], + "dst": [ + 1446, + 813, + 474, + 266 + ], + "src": [ + 0, + 1, + 1920, + 1077 + ] + } + ], + "voices": [ + { + "principal": "6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee", + "gain": 5120, + "pan": 0 + }, + { + "principal": "9f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19", + "gain": 4096, + "pan": 0 + }, + { + "principal": "87c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a", + "gain": 4096, + "pan": 0 + } + ] + } + ] + }, + { + "name": "descriptor_wrong_room", + "about": "a grid of another room (§3.5)", + "room": "studio", + "descriptor": "574344310107070707070707070707070707070707070707070707070707070707070707079f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c8b4b118486af9fae8e047b4e8170f07d142c4d74badc20558398422705f2811046e599ada1a13e2789d9c307f11f0b3fcb1456642ca8d2f678a7b22dc0c8d400", + "instants": [ + 1000000, + 2000000, + 3000000, + 4000000, + 5000000, + 6000000, + 7000000, + 8000000, + 9000000 + ], + "outcome": "refuse", + "reason": "wrong_room", + "at": [ + "descriptor" + ] + }, + { + "name": "descriptor_bad_signature", + "about": "the grid with a bit of its signature flipped (§3.2)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34100", + "instants": [ + 1000000, + 2000000, + 3000000, + 4000000, + 5000000, + 6000000, + 7000000, + 8000000, + 9000000 + ], + "outcome": "refuse", + "reason": "bad_signature", + "at": [ + "descriptor" + ] + }, + { + "name": "before_effective", + "about": "the grid asked for at 0.5 s, before its effective instant of 1 s (§3.1, §4)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "instants": [ + 1000000, + 500000 + ], + "outcome": "refuse", + "reason": "not_yet_effective", + "at": [ + "set", + 500000 + ] + }, + { + "name": "attr_malformed", + "about": "the guest's grant states its order as `third`: the grid holds until the guest joins at 3 s (§4.3)", + "room": "studio_bad_order", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "instants": [ + 1000000, + 2000000, + 3000000 + ], + "outcome": "refuse", + "reason": "attr_malformed", + "at": [ + "set", + 3000000 + ] + }, + { + "name": "lifecycle_incomplete", + "about": "the relay's unpublish at 6 s not delivered: the room is a gap in a room key's chain (§4.1)", + "room": "studio_lifecycle_gap", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "instants": [ + 1000000 + ], + "outcome": "refuse", + "reason": "lifecycle_incomplete", + "at": [ + "room" + ] + }, + { + "name": "room_refused", + "about": "the viewer sends a control its grant does not permit: the room is refused, and with it the composition (§9 step 1)", + "room": "studio_refused", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "instants": [ + 1000000 + ], + "outcome": "refuse", + "reason": "kind_not_permitted", + "at": [ + "room", + "record", + 1, + 2 + ] + } + ], + "receipts": [ + { + "name": "video", + "about": "the mixer's receipt for its composed video at 5 s: every input the layout reads, in drawing order (§8)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692ee866c160c3850fb406937f18c3a38ab5a5f868b39995cd9c4bb2cd209a9993b9183028871ffe91886af962d75c3a484353e17ed6db4110ef94c521628af1901", + "outcome": "accept", + "digest": "1424243bb1e97d542a54a70021b1c7ab7bfbd47faf9fc375093271da2b74ee42", + "set_digest": "140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b" + }, + { + "name": "audio", + "about": "the mixer's receipt for its mix at 5 s: every voice's audio track (§8)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b010b4bbaec5774fe574146ac9a64caaa4707645925bcf753e118be2d2b229c27ed050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f0387c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6adc33e042094a4b1429dea952d08c2bbf00d4af65cf73eb15bd50d1e30338876a0500000000000000000000000000000094a8cf914f0b5e6135355f5f4cade692a1fe6794e73178d566d89586d6dee8646c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee4a5aededef781290a71492b76bd01c17b66d49f3e1859773812397c7568020be050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d19ead6e1928b3c8abb29bd67def2980ce3219610d0404a6244f37486daaac36a6505000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdc07bdd8301e44c402ce03ebc5bdd390550dd34f10a1050bdee5bce65dd3d6ca11b12d5282c0ae07a1dc640699af6f5418ec0400177f29e148587a5eed62c9a908", + "outcome": "accept", + "digest": "f43593bab8516979f664f41e571f519c8b73bfe4df37aa38ac92db8ce3990da5", + "set_digest": "140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b" + }, + { + "name": "pip_video", + "about": "the mixer's receipt for the picture in picture at 6 s, its sources read at layer 1 (§8)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c15307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c400000000000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101801020400000200056f72646572010370697004e0010e011800020280bb0000046761696e0370616e060cc17a2acbb2cf4159ff17ae5aee793aa3bcd9eac6239c3dda678ee010de89cad1aae7e3f6b849b575d0cd43d25b69c8c90b479bc407ec85459e9f375805d4a309", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a5ad64329fe0eb76d320922749a16c9358465444e542fc6c0ad6fbbe519408ad4808d5b00000000008bc1324ec4d9520e1f51a1477bc7270b17f0610ecc4c15b37e117cfdddd1dbfe029dd94c4076074e04d5d0795a14e34ecf96a2187fe21e660f465e9264e808924006000000000000000000000000000000a6fc01fbf785c5c8cd189f902ae1a9a7499e3505c5c2839bc73e7ffe5edec780046c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee316cceb04a36e10398601ff08bca686f789ef3de4e301bb7fd46fabeadfc57f406000000000000000000000000000000655a4d71c3b6f0bbeae06ede1b6d7229d7d4f8e153d899d5b69c3444caa8e780a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e0600000000000000000000000000000008a750cf7853caa49561f61a28881333a042acd86c97778c1938b32937957bc571bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6060000000000000000000000000000009c02e04a74325975e765e1acea7899515924e43fe3123834d57ac2fea7c2b4c571bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91060000000000000000000000000000009c02e04a74325975e765e1acea7899515924e43fe3123834d57ac2fea7c2b4c52421c43591ad16123517d95b1cb98ce555f9135a3a907519d5a3921467a116cb137f846e1e2af1820e9ebc9604f3e0352d8d56aab16d4e8721bdcfb34298fc00", + "outcome": "accept", + "digest": "31180ce0314bcac34666ee37648fee9eebacb4832c2292d380d9a653501a4767", + "set_digest": "8bc1324ec4d9520e1f51a1477bc7270b17f0610ecc4c15b37e117cfdddd1dbfe" + }, + { + "name": "inputs_missing", + "about": "the video receipt less its last input (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f046c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692f6d064a41da2a0297769657b66ad7e3cc5295bd01f92bd36d28ce388f9e1ee3bb4641f70d8267348a6fd68c617f910b0e72dc518425c456e9a3fd10eed5feb0b", + "outcome": "refuse", + "reason": "inputs_mismatch", + "at": [ + "receipt" + ] + }, + { + "name": "inputs_reordered", + "about": "the video receipt with its first two inputs swapped (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f059f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdc6c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f29a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692a4376cf04c266d4dd901364f9b615c4019b3e729b846448bf184f2b450fe2d7607b15915489671b416ad0e17c3f14b6a3cc584e79c6bf0781e44cdb54fe6f70e", + "outcome": "refuse", + "reason": "inputs_mismatch", + "at": [ + "receipt" + ] + }, + { + "name": "inputs_wrong_layer", + "about": "the performer's input read from layer 1, where the composition reads layer 2 (§8.2)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee316cceb04a36e10398601ff08bca686f789ef3de4e301bb7fd46fabeadfc57f4050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692306256610841f1500a5554eb06b50a7da30d20def1e6422d2b9ae444f66a2a0a111570dcc7bc1a0d7777fbd86eab468516f66a734a77d4296c7889d7f8348b00", + "outcome": "refuse", + "reason": "inputs_mismatch", + "at": [ + "receipt" + ] + }, + { + "name": "state_stale", + "about": "the video receipt at 5 s naming the set of 4 s, before the guest's exchange (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c000000000050e0241058fc1c9489fd8784f1285e41be3914c1a1c1d527cfa8290bd866c65e026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692549d50bf473fe0c87591da16c8b8715b4acf1fcf7a32a2d8ff450fe6c63da92df01cd4735f2fd496ad4954cedffe90c30721c37f7594cd593fee201579de9e0f", + "outcome": "refuse", + "reason": "state_mismatch", + "at": [ + "receipt" + ] + }, + { + "name": "descriptor_mismatch", + "about": "the video receipt naming the picture-in-picture descriptor while checked against the grid's (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a5ad64329fe0eb76d320922749a16c9358465444e542fc6c0ad6fbbe519408ad4404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692bd91c7abd649500bfa3eca8bd1cfd72f0791464bd477ed5afb3c3060cb34682d2109a9705d73136fef76bb8e89838280d199f71bbfa8dd28e310e7c6c54b1e01", + "outcome": "refuse", + "reason": "descriptor_mismatch", + "at": [ + "receipt" + ] + }, + { + "name": "compositor_not_named", + "about": "the video receipt signed by the director, which the descriptor does not name as its compositor (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1915fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692247afa688eac5ddaf3d39caec740148cd676a1e8bf01296818fa06d8337228df2f8aec6088332d09ad7c4ceee1cc0004666ec8c76da0864924b3bddb05c66f05", + "outcome": "refuse", + "reason": "compositor_not_permitted", + "at": [ + "receipt" + ] + }, + { + "name": "compositor_without_power", + "about": "a descriptor naming the guest as its compositor, and the guest's receipt at 7 s: its grant has no compose power (§7, §8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f000000000087c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c841b0dd77971aeaeaa69562a255356c28a97ca7a7cc773f2626b8c6b285281fc62ce71f46b89ff869a3a63eed3c5fc5fb1e5a31d74401fd9ef7c044f92016a08", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c187c984cef8181deafed7796500394739e11d96fe4e8d5b583d6d48aae3f95d6a8ccde96602879235baa71bae62a06841c1e27b8ff37da0c3f7acfce2fc4e3f60c0cf6a0000000000b4ac17e27870be2f2dbeebfeed1ca79a024c7ac3906e62ba0a13b2c04ea1cfe0024aa47e3f75fa852b5b7011f10205b1375b0fbe59ecfc1aa44da7f61b75183a1c07000000000000000000000000000000868e8735649b73cfa97b456305775e617b2cf5344aab31754c9196aa2943468c056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f0700000000000000000000000000000068126b00272a4c6ee654d77eb8f40750772ddfcbbcf65c89abd752988803d9fba5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e0700000000000000000000000000000061378b17ea8e9a3a55beb2519f4ac2c51c5765be75fdc9cc401c4c361b9dd9fe71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa60700000000000000000000000000000091a6e049646ecbd17869664a79047baf2931dfe9e7f4da9b256056b2bb7128ec71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a910700000000000000000000000000000091a6e049646ecbd17869664a79047baf2931dfe9e7f4da9b256056b2bb7128ec4ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a6bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc259107000000000000000000000000000000f0f524d622f3525430ed38cb53c0ae361c3830dc4f5b7645a7fe61efd6bd85230ff8f9a5b5400c6732f68bab956a123c582613a933547c296273f8ba3c4a17bc897cdd44bf3542a447f09887292ace496da1913d6b052e5e1240f5a162e3330a", + "outcome": "refuse", + "reason": "compositor_not_permitted", + "at": [ + "receipt" + ] + }, + { + "name": "client_only", + "about": "a receipt against a descriptor that names no compositor (§7)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c15307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c400000000000000000000000000000000000000000000000000000000000000000000000000000000800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5b4f59f3e9e55b114603a51feeffbb03f7cc8e717ad48b0033734ed85af4f8e7327ad11f7478508bee5c9814eeb3024d53bda8e6b314b7f0c329014827652004", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a61a1ca7d436ed458bab60685cabbcbbf3e8d1f3599e077f82bdc24a567934a1b404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692604bd38ca4ebdd0764b95068b034cf73218047c0a48587bd770b6f84ec9327b7503e09a2db5b7c06740e97c530f14ec9877f2d4103f83948e9985c62824d310c", + "outcome": "refuse", + "reason": "compositor_not_permitted", + "at": [ + "receipt" + ] + }, + { + "name": "output_not_yet_published", + "about": "the mixer's picture-in-picture receipt at 1 s: it publishes its video from 2 s (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c15307e7ddb9c808290f82a08e90f782343e26aea715bc78e53fdb7e839de325c400000000000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e10101801020400000200056f72646572010370697004e0010e011800020280bb0000046761696e0370616e060cc17a2acbb2cf4159ff17ae5aee793aa3bcd9eac6239c3dda678ee010de89cad1aae7e3f6b849b575d0cd43d25b69c8c90b479bc407ec85459e9f375805d4a309", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a5ad64329fe0eb76d320922749a16c9358465444e542fc6c0ad6fbbe519408ad440420f000000000065b09a1166040ca3741998413595db8d15f8c93718bf7b863f288cf325c65ba5026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc259101000000000000000000000000000000ef8dbb1f296de5ccdf0198c4b44be02579c672cdebf186b9956f9a762a070791026c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebee316cceb04a36e10398601ff08bca686f789ef3de4e301bb7fd46fabeadfc57f401000000000000000000000000000000a3fc6ccaf8cf10e4e9713a5c8d764bd3a7554b6f33575355cab331b781d443e29f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e01000000000000000000000000000000b7785f03568c0856bc7db7d08242555f834122ef5b94548563b964acf7a58334d30d08bb740b8422381383ebe21f020c7f308bc0c2a5e9d4984a1cca400d263b59cc62931e206cda3040eab7021fc54a69b6a82930c8c19942e7d27764867e01", + "outcome": "refuse", + "reason": "output_not_published", + "at": [ + "receipt" + ] + }, + { + "name": "output_wrong_layer", + "about": "an output on layer 3 of a video the mixer publishes in three layers, 0 to 2 (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b022fd77e9dc612eb90eff3ee3782a62193e2efc748d620bf66fe1f8bfb41045480050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169216d56e6d80259b0d084a1ac2298eba2b31d3b05d38c51d144cec7bd86d7ae61409ea6eaecce925f0ad4804bda6d7c1675c5aa09a1ec7184ce9c5440cf685dc0f", + "outcome": "refuse", + "reason": "output_not_published", + "at": [ + "receipt" + ] + }, + { + "name": "before_effective", + "about": "a receipt at 0.5 s, before the grid's effective instant (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e634221452720a1070000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692b8d5de45630b8bd4b5b8a73cbe0ca4c63424901ca7975a9d27a0c50dc305898e03f7b7a0f66955f0cbdb1d98e43932f3c488f5e8de33b493765e4ce746c99007", + "outcome": "refuse", + "reason": "not_yet_effective", + "at": [ + "receipt" + ] + }, + { + "name": "media_invalid", + "about": "a receipt of media 3 (§8.1)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b036bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692557ff62ad760f90c0bad5f4f8b55fb380c854592c72d371e9c623f3c4ab68321b183f4ec011e44dc1cd5da4b8002fe2094de40bdeb776ae20ee12711d4908c05", + "outcome": "refuse", + "reason": "receipt_invalid", + "at": [ + "receipt" + ] + }, + { + "name": "duplicate_input", + "about": "a receipt naming one input twice (§8.1)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f296c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f29a5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692af516d991e432ff2bf64acfd60b3e86098657011d4ded96b2ba516bdcb5e23224707634d52dc092e20db270d675a553d4cd26e15b1b581af97c639ae966a5c00", + "outcome": "refuse", + "reason": "receipt_invalid", + "at": [ + "receipt" + ] + }, + { + "name": "wrong_room", + "about": "a receipt of another room (§8.3)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "574352310107070707070707070707070707070707070707070707070707070707070707074ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692a0d7d632a72d845fcbf86d40f0864e36271f37a3e91183105f52a017199508edc4dabe992cde584b051a9460892f84c630183f1d08688e68022f3c80ae25c101", + "outcome": "refuse", + "reason": "wrong_room", + "at": [ + "receipt" + ] + }, + { + "name": "bad_signature", + "about": "one bit of the video receipt's signature flipped (§8.1)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692ee866c160c3850fb406937f18c3a38ab5a5f868b39995cd9c4bb2cd209a9992b9183028871ffe91886af962d75c3a484353e17ed6db4110ef94c521628af1901", + "outcome": "refuse", + "reason": "bad_signature", + "at": [ + "receipt" + ] + }, + { + "name": "truncated", + "about": "the video receipt less its last byte (§8.1)", + "room": "studio", + "descriptor": "5743443101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c19f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d1940420f00000000004ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a800738041e101018020108000100086665617475726564056f72646572000000000000000000000280bb0000046761696e0370616e0c0c5258ac1fc493382df9cd5ab331fd19582894be169156ce90c8f5c2bd74c7bd6f7d84893a6eff538b7a9c24fe67c43854ea50fe7c5cfd4b8e4a617d3af6d34101", + "receipt": "5743523101fd5f152a8ed2db3c3058d2f7b604cde7784b03b6612b7452adbfa486ac7a00c14ac355b9ab4fc8dddfa491a574f7e493dc85db04ad1152ed400a33864a4a510a15fdbad8ebfabd96d01a12e4c1193b465f1f9682f3eca4e4f1490e6342214527404b4c0000000000140204a294ea4873893713be4016e8f92827faa7564e3fdadd6366125313424b026bddaa11c07b6853d90600a3222709da24e1b132ff079c36664067d35bcc2591050000000000000000000000000000004b01fb1e27b8088d380592402ce895464804685f070065d46ef225b4f3f9d50f056c96412e6fcc3d4823454734f632fc808a44afeaf227429c8ad44e6040abebeecc493c9ae64ab358389ed6f5a91e11bd65c83d406686ef9fdad3e9feea92102f050000000000000000000000000000005017d0bc8191717f45798b7c91bf9691e8ae328b4a69056c87e6ec4adc124f299f8e662f24d3151862fd7a236781330489bb0476e94af22019c820554db05d193986272e5ceda2874f386430ede3f212dd039fd8e9d8bb3827effcd106265a4e05000000000000000000000000000000ed52f59a568c9b9f223a237c78bf9812fb432c8f1c87d68a44f2af757bd7bbdca5c21d1b2019a3ef63e7fac45ada16e1d09e6d3b2d5c182cf4b5d60a8973b467525921a019551db3ce28d5111a7697f75fed6173316d8eaf9a35890d0b4a576e05000000000000000000000000000000c8e444fbe9b0bca3ef7675f04061777c6ebb10fc1c50ebb4c07742126077123b71bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1dbb03838daa0e460babe3c9af88357dc67bdf09e0af52dec38ce653171394efa6050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab169271bb089c4a2c7dee8aa7f0be1f5e8b00cc1a6ee8776b9247c08821396cd99b1d5c354cc263989fb40d81958f70eb439463a6f8e7d82a1e9bcb534ca4dfe19a91050000000000000000000000000000005a4071d8e660c359c7de101a00a75f33196dadb7131036818eeaf29557ab1692ee866c160c3850fb406937f18c3a38ab5a5f868b39995cd9c4bb2cd209a9993b9183028871ffe91886af962d75c3a484353e17ed6db4110ef94c521628af19", + "outcome": "refuse", + "reason": "truncated", + "at": [ + "receipt" + ] + } + ] +} diff --git a/wai/live-conformance/live_compose_verify.py b/wai/live-conformance/live_compose_verify.py new file mode 100644 index 000000000..a991fdd95 --- /dev/null +++ b/wai/live-conformance/live_compose_verify.py @@ -0,0 +1,886 @@ +#!/usr/bin/env python3 +"""Independent verifier of the live-composition corpus (extensions/live-compose.md). + +Written from the extension's text. It shares no code with wai-rs, which generates the +corpus, and never runs it. It checks Ed25519 signatures with +../claim-conformance/_ed25519.py, WAI's strict rule (SPEC §7 *Signatures*) written from +RFC 8032 with the standard library. Each room is verified by the live-rooms corpus's own +second implementation, live_rooms_verify.py (live-rooms §9), whose lifecycle replay this +verifier steps through itself, record by record, to take the room at each instant (§4.1). +Everything else is here, from the text: + +- the descriptor (§3): read, its canvas, its field rules, its signature and who may sign; +- the participant set (§4): sources, attributes, order, and the set's digest; +- the layout function (§5): the grid and its candidates, the featured tile, picture in + picture, the fill modes; and the mixer (§6), over the corpus's PCM; +- the receipt (§8): read, its inputs, and its verification. + +For every case it requires the outcome, reason and place, and the order, tiles, voices, +samples, digests, participants and sources the corpus states; of the corpus, that every +reason of §10 refuses a case. Then it mutates copies of the corpus, one defect each, and +requires every copy to fail. + + python3 live_compose_verify.py + +Exit status 0 only if every case verifies and every mutated copy fails. Python 3.8 or +later; standard library only. +""" +import copy +import hashlib +import json +import os +import struct +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "..", "claim-conformance")) +import live_events_verify as LEV # noqa: E402 +import live_rooms_verify as LRV # noqa: E402 +import _ed25519 as ED # noqa: E402 + +Refuse = LEV.Refuse + +DESCRIPTOR_DOMAIN = b"wai:live-compose\x01" +RECEIPT_DOMAIN = b"wai:live-compose-receipt\x01" +SET_DOMAIN = b"wai:live-compose-set\x01" +ZERO = bytes(32) +AUDIO, VIDEO, SCREEN = 1, 2, 3 +MEDIA_NAME = {1: "audio", 2: "video", 3: "screen"} +COMPOSE_POWER = 4 +JOIN = 0x10 +GRID, PIP = 1, 2 +AUTO, VIDEO_ASPECT, SQUARE, PORTRAIT = 0, 1, 2, 3 +DEFAULT, FILL, COVER, CONTAIN = 0, 1, 2, 3 +STATIC, DYNAMIC = 1, 2 +SINGLE, SIMULCAST, SVC, STAGED = 0, 1, 2, 3 + +# §10, in its order. +REASONS = [ + "canvas_out_of_range", "compose_invalid", "compose_not_permitted", "not_yet_effective", + "lifecycle_incomplete", "attr_malformed", "mix_input_malformed", "receipt_invalid", + "descriptor_mismatch", "compositor_not_permitted", "output_not_published", "state_mismatch", + "inputs_mismatch", +] + +PARAM_KEYS = ["width", "height", "fps", "layout", "gap", "aspect", "fill", "featured_attr", "order_attr", + "omit_stopped", "pip_attr", "corner", "pip_width", "pip_height", "offset", "behaviour", + "channels", "sample_rate", "gain_attr", "pan_attr", "max_tiles", "max_voices"] + + +def sha(*parts): + h = hashlib.sha256() + for p in parts: + h.update(p) + return h.digest() + + +class Reader: + """Fields in order; running out is `truncated`.""" + + def __init__(self, b, p=0): + self.b, self.p = b, p + + def take(self, n): + if self.p + n > len(self.b): + raise Refuse("truncated") + s = self.b[self.p:self.p + n] + self.p += n + return s + + def u8(self): + return self.take(1)[0] + + def u16(self): + return struct.unpack(" 3 or p["fill"] > 3: + return False + for k in ("featured_attr", "order_attr", "pip_attr", "gain_attr", "pan_attr"): + if p[k] != "" and not is_key(p[k].encode()): + return False + if p["layout"] == GRID: + if p["pip_attr"] != "" or p["corner"] or p["pip_width"] or p["pip_height"] or p["offset"] or p["behaviour"]: + return False + else: + o = p["offset"] + if not (1 <= p["corner"] <= 4 and p["behaviour"] in (STATIC, DYNAMIC) and o < w and o < h + and p["pip_width"] + o <= w and p["pip_height"] + o <= h): + return False + if p["channels"] not in (1, 2) or not 8000 <= p["sample_rate"] <= 192000: + return False + if not (1 <= p["max_tiles"] <= 64 and 1 <= p["max_voices"] <= 64): + return False + k = least_root(p["max_tiles"]) + need = k + (k - 1) * g + return g < h and w >= need and h - g - (h - g) * 3 // 4 >= need + + +def check_params(p): + if not canvas_ok(p): + raise Refuse("canvas_out_of_range") + if not fields_ok(p): + raise Refuse("compose_invalid") + + +def read_descriptor(b): + """§3.3: the descriptor, or Refuse.""" + read_head(b, b"WCD1") + r = Reader(b, 5) + c = {"room": r.take(32), "signer": r.take(32), "effective": r.u64(), "compositor": r.take(32)} + p = {"width": r.u16(), "height": r.u16(), "fps": r.u8()} + c["background"], c["layer"] = r.take(3), r.u8() + p["layout"], p["gap"], p["aspect"], p["fill"] = r.u8(), r.u16(), r.u8(), r.u8() + raw = {"featured_attr": r.short(), "order_attr": r.short()} + omit = r.u8() + raw["pip_attr"] = r.short() + p["corner"], p["pip_width"], p["pip_height"], p["offset"], p["behaviour"] = r.u8(), r.u16(), r.u16(), r.u16(), r.u8() + p["channels"], p["sample_rate"] = r.u8(), r.u32() + raw["gain_attr"], raw["pan_attr"] = r.short(), r.short() + p["max_tiles"], p["max_voices"] = r.u8(), r.u8() + body = b[:r.p] + c["sig"] = r.take(64) + if r.p != len(b): + raise Refuse("malformed") + keys_ok = all(v == b"" or is_key(v) for v in raw.values()) + for k, v in raw.items(): + p[k] = v.decode("latin-1") + p["omit_stopped"] = omit == 1 + if not canvas_ok(p): + raise Refuse("canvas_out_of_range") + if not keys_ok or omit > 1 or not fields_ok(p): + raise Refuse("compose_invalid") + bad = ED.verify(c["signer"], DESCRIPTOR_DOMAIN + body, c["sig"]) + if bad: + raise Refuse(bad) + c["params"] = p + c["digest"] = sha(body) + return c + + +def fields_of(c): + out = {"room": c["room"].hex(), "signer": c["signer"].hex(), "effective": c["effective"], + "compositor": c["compositor"].hex(), "background": c["background"].hex(), "layer": c["layer"]} + for k in PARAM_KEYS: + out[k] = c["params"][k] + return out + + +# ---------------------------------------------------------------- §4.3 attributes + +def decimal(v): + """A decimal integer of §4.3, or None.""" + neg = v.startswith("-") + digits = v[1:] if neg else v + if not 1 <= len(digits) <= 10 or any(ch not in "0123456789" for ch in digits): + return None + if digits[0] == "0" and (len(digits) > 1 or neg): + return None + n = int(digits) + return -n if neg else n + + +def read_attributes(p, attrs): + """§4.3 for one participant: (featured, order, pip, gain, pan), or Refuse.""" + def look(key): + if key == "": + return None + return next((v for k, v in attrs if k == key), None) + + def boolean(key): + v = look(key) + if v is None or v == "false": + return False + if v == "true": + return True + raise Refuse("attr_malformed") + + def ranged(key, lo, hi, absent): + v = look(key) + if v is None: + return absent + n = decimal(v) + if n is None or not lo <= n <= hi: + raise Refuse("attr_malformed") + return n + + featured = boolean(p["featured_attr"]) + order = ranged(p["order_attr"], -2 ** 31, 2 ** 31 - 1, None) + pip = boolean(p["pip_attr"]) + gain = ranged(p["gain_attr"], 0, 16384, 4096) + pan = ranged(p["pan_attr"], -4096, 4096, 0) + return featured, order, pip, gain, pan + + +# ---------------------------------------------------------------- §5 the layout + +def fit(bw, bh, a, b): + """§5.1.""" + if bw * b <= bh * a: + return bw, max(1, bw * b // a) + return max(1, bh * a // b), bh + + +def centred(outer, w, h): + x, y, ow, oh = outer + return (x + (ow - w) // 2, y + (oh - h) // 2, w, h) + + +def reference(aspect): + return {SQUARE: (1, 1), PORTRAIT: (3, 4)}.get(aspect, (16, 9)) + + +def grid(region, n, gap, aspect): + """§5.3: n tile rectangles.""" + X, Y, W, H = region + a, b = reference(aspect) + chosen = None + for c in range(1, n + 1): + r = -(-n // c) + if (c - 1) * gap >= W or (r - 1) * gap >= H: + continue + cw, ch = (W - (c - 1) * gap) // c, (H - (r - 1) * gap) // r + if cw < 1 or ch < 1: + continue + tw, th = fit(cw, ch, a, b) + if chosen is None or tw * th >= chosen[0]: + chosen = (tw * th, c, r, cw, ch) + _, c, r, cw, ch = chosen + y0 = Y + (H - (r * ch + (r - 1) * gap)) // 2 + out = [] + for k in range(n): + i, j = k // c, k % c + m = n - (r - 1) * c if i == r - 1 else c + x0 = X + (W - (m * cw + (m - 1) * gap)) // 2 + cell = (x0 + j * (cw + gap), y0 + i * (ch + gap), cw, ch) + out.append(cell if aspect == AUTO else centred(cell, *fit(cw, ch, a, b))) + return out + + +def show(tile, size, mode): + """§5.6: (destination, source) of a source of `size` in `tile`.""" + tx, ty, tw, th = tile + sw, sh = size + wider = sw * th >= sh * tw + whole = (0, 0, sw, sh) + if mode == FILL: + return tile, whole + if mode == CONTAIN: + if wider: + dh = max(1, tw * sh // sw) + return (tx, ty + (th - dh) // 2, tw, dh), whole + dw = max(1, th * sw // sh) + return (tx + (tw - dw) // 2, ty, dw, th), whole + if wider: + cw = max(1, sh * tw // th) + return tile, ((sw - cw) // 2, 0, cw, sh) + ch = max(1, sw * th // tw) + return tile, (0, (sh - ch) // 2, sw, ch) + + +def layout(p, entrants): + """§5 and §6's voices over entrants (principal, join, video, audio, attrs): a dict.""" + check_params(p) + members = [] + for e in entrants: + featured, order, pip, gain, pan = read_attributes(p, e["attrs"]) + members.append(dict(e, featured=featured, order=order, pip=pip, gain=gain, pan=pan)) + # §4.4 + members.sort(key=lambda m: (m["order"] is None, m["order"] or 0, m["join"], m["principal"])) + voices = [{"principal": m["principal"].hex(), "gain": m["gain"], "pan": m["pan"]} + for m in members if m["audio"]][:p["max_voices"]] + # §5.2 + shown = [m for m in members if not (p["omit_stopped"] and m["video"] is None)] + pip_m = next((m for m in shown if m["pip"]), None) if p["layout"] == PIP else None + rest = [m for m in shown if m is not pip_m] + f = next((i for i, m in enumerate(rest) if m["featured"]), None) + if f is not None: + rest.insert(0, rest.pop(f)) + rest = rest[:p["max_tiles"] - (1 if pip_m is not None else 0)] + featured = f is not None and bool(rest) + window = pip_m + if pip_m is not None and not rest and p["behaviour"] == DYNAMIC: + rest, featured, window = [pip_m], pip_m["featured"], None + tiles = grid_tiles(p, rest, featured) + if window is not None: + tiles.append(pip_tile(p, window)) + return {"order": [m["principal"].hex() for m in members], "tiles": tiles, "voices": voices} + + +def tile_of(p, m, rect, place, z): + mode = p["fill"] if p["fill"] != DEFAULT else (CONTAIN if place == "featured" else COVER) + out = {"principal": m["principal"].hex(), "place": place, "z": z, "tile": list(rect), "dst": None, "src": None} + if m["video"] is not None: + dst, src = show(rect, m["video"], mode) + out["dst"], out["src"] = list(dst), list(src) + return out + + +def grid_tiles(p, ms, featured): + """§5.3, §5.4.""" + w, h, g = p["width"], p["height"], p["gap"] + if not ms: + return [] + if not featured: + return [tile_of(p, m, r, "grid", 0) for m, r in zip(ms, grid((0, 0, w, h), len(ms), g, p["aspect"]))] + if len(ms) == 1: + return [tile_of(p, ms[0], (0, 0, w, h), "featured", 0)] + mh = (h - g) * 3 // 4 + out = [tile_of(p, ms[0], (0, 0, w, mh), "featured", 0)] + band = (0, mh + g, w, h - mh - g) + out += [tile_of(p, m, r, "grid", 0) for m, r in zip(ms[1:], grid(band, len(ms) - 1, g, p["aspect"]))] + return out + + +def pip_tile(p, m): + """§5.5.""" + w, h, o = p["width"], p["height"], p["offset"] + if p["pip_width"] > 0 and p["pip_height"] > 0: + pw, ph = p["pip_width"], p["pip_height"] + else: + a, b = m["video"] if m["video"] is not None else (w, h) + if p["pip_width"] > 0: + bw = p["pip_width"] + elif p["pip_height"] > 0: + bw = w - o + else: + bw = min(w // 4, w - o) + bh = p["pip_height"] if p["pip_height"] > 0 else h - o + pw, ph = fit(bw, bh, a, b) + x = {1: o, 2: w - o - pw, 3: o, 4: w - o - pw}[p["corner"]] + y = {1: o, 2: o, 3: h - o - ph, 4: h - o - ph}[p["corner"]] + return tile_of(p, m, (x, y, pw, ph), "pip", 1) + + +# ---------------------------------------------------------------- §6 the mix + +def mix(channels, frames, inputs): + """§6: the mixed samples, or Refuse.""" + if channels not in (1, 2): + raise Refuse("mix_input_malformed") + for v in inputs: + if v["channels"] not in (1, 2) or not 0 <= v["gain"] <= 16384 or not -4096 <= v["pan"] <= 4096 \ + or len(v["pcm"]) != frames * v["channels"]: + raise Refuse("mix_input_malformed") + sums = [0] * (frames * channels) + for v in inputs: + x, g, ch = v["pcm"], v["gain"], v["channels"] + if channels == 1: + for f in range(frames): + sums[f] += (x[f] * 4096 if ch == 1 else (x[2 * f] + x[2 * f + 1]) * 2048) * g + else: + al, ar = 4096 - max(v["pan"], 0), 4096 + min(v["pan"], 0) + for f in range(frames): + left, right = (x[f], x[f]) if ch == 1 else (x[2 * f], x[2 * f + 1]) + sums[2 * f] += left * g * al + sums[2 * f + 1] += right * g * ar + return [min(32767, max(-32768, (s + (1 << 23)) >> 24)) for s in sums] + + +def pcm_of(h): + b = bytes.fromhex(h) + if len(b) % 2: + raise ValueError("odd PCM") + return list(struct.unpack("<%dh" % (len(b) // 2), b)) + + +def pcm_hex(samples): + return struct.pack("<%dh" % len(samples), *samples).hex() + + +# ---------------------------------------------------------------- §4 the room at an instant + +def render_field(f): + """MOQT §8.8.""" + return "".join(chr(c) if (chr(c).isascii() and chr(c).isalnum()) or c == 0x5F else ".%02x" % c for c in f.encode()) + + +def track_digest(room_id, owner, media, name): + """live-events §3.1's anchor track: the rendered namespace, a zero byte, the name.""" + ns = "-".join(render_field(f) for f in (room_id.hex(), owner, MEDIA_NAME[media])) + return sha(ns.encode(), b"\x00", name.encode()) + + +class RoomView: + """A room that verified (§4.1), its replay stepped record by record.""" + + def __init__(self, d, held, steps, final): + self.d, self.held, self.steps, self.final = d, held, steps, final + + def grant(self, digest): + return next(g for g in self.held if g["digest"] == digest) + + def at(self, t): + """The room at t: the state before the first record of the merged order past t.""" + return next((s for rt, s in self.steps if rt > t), self.final) + + +def snapshot(room, joins): + return {"present": dict(room.present), "own": dict(room.own), "slots": copy.deepcopy(room.slots), "joins": dict(joins)} + + +def view_room(room): + """live-rooms §9 over the room, stepped: a RoomView, or (reason, place).""" + descriptor = bytes.fromhex(room["descriptor"]) + grants = [bytes.fromhex(g) for g in room["grants"]] + head = room["key_log_head"] + chains = [[bytes.fromhex(r) for r in c] for c in room["chains"]] + try: + d = LRV.read_descriptor(descriptor) + except Refuse as e: + return e.reason, ["room", "descriptor"] + try: + revoked = LRV.check_key_log(d, head) + except Refuse as e: + return e.reason, ["room", "key_log"] + held, bad = LRV.check_grants(d, grants) + if bad: + return bad[1], ["room", "grant", bad[0]] + state = LRV.Room(d, held, revoked) + auth = LRV.authority_policy() + ver = LEV.Verifier(d["room"], auth, {}) + seen, joins, steps, at_index = {}, {}, [], [] + numbered = 0 + for c, i in LRV.merged_order(d, chains): + b = chains[c][i] + at_index.append((c, i)) + try: + ev = LEV.read_record(b) + duplicate = ev["digest"] in seen + except Refuse: + ev, duplicate = None, False + if ev is not None: + steps.append((ev["t"], snapshot(state, joins))) + try: + LRV.step(d, state, ver, seen, auth, b) + except Refuse as e: + return e.reason, ["room", "record", c, i] + if not duplicate and LRV.is_room_key(d, ev["principal"]) and ev["kind"] == JOIN: + joins[ver.accepted[-1][2]["subject"]] = numbered + numbered += 1 + if ver.gaps: + if any(LRV.is_room_key(d, p) for p, _, _ in ver.gaps): + return "lifecycle_incomplete", ["room"] + else: + mismatch = LEV.stated_tally_mismatch(ver.accepted) + if mismatch is not None: + c, i = at_index[mismatch] + return "tally_mismatch", ["room", "record", c, i] + return RoomView(d, held, steps, snapshot(state, joins)) + + +def source(view, c, profile, layers, slot, media): + """§4.2: a source and its composed layer.""" + prof = view.d["profiles"][profile] + layer = min(layers - 1, c["layer"]) + w, h = prof["layers"][layer][0], prof["layers"][layer][1] + return {"slot": slot, "media": media, "profile": profile, "layers": layers, "layer": layer, + "layering": prof["layering"], "width": w, "height": h} + + +def tracks(view, s, principal): + """§8.2: the tracks a source is read from.""" + owner = principal.hex() if s["slot"] == "" else "_" + s["slot"] + if s["layering"] == SIMULCAST: + names = [s["layer"]] + elif s["layering"] == STAGED: + names = list(range(s["layer"] + 1)) + else: + names = [0] + return [track_digest(view.d["room"], owner, s["media"], str(n)) for n in names] + + +def participants(view, c, t): + """§4.2 at t, in ascending order of key.""" + st = view.at(t) + out = [] + slots = list(zip(view.d["slots"], st["slots"])) + + def own(p, m): + h = st["own"].get((p, m)) + return None if h is None else source(view, c, h[0], h[1], "", m) + + def live_in(p, kinds): + for s, ss in slots: + if ss["live"] and ss["live"][0] == p and s["media"] in kinds: + return source(view, c, ss["live"][1], ss["live"][2], s["name"].decode(), s["media"]) + return None + + for p in sorted(st["present"]): + if p == c["compositor"]: + continue + if not (any(q == p for q, _ in st["own"]) or any(ss["live"] and ss["live"][0] == p for _, ss in slots)): + continue + video = own(p, VIDEO) or own(p, SCREEN) or live_in(p, (VIDEO, SCREEN)) + audio = own(p, AUDIO) or live_in(p, (AUDIO,)) + g = view.grant(st["present"][p]) + out.append({"principal": p, "grant": g["digest"], "join": st["joins"][p], + "attrs": LRV.read_attrs(g["attrs"]), "video": video, "audio": audio}) + return out + + +def set_digest(view, t, ps): + """§4.5.""" + def src(s): + if s is None: + return b"\x00" + slot = s["slot"].encode() + return bytes([s["media"], len(slot)]) + slot + bytes([s["profile"], s["layers"], s["layer"]]) \ + + struct.pack(" 1)["video"]["tracks"].reverse()), + mutate("grid_session: an instant moved", lambda d: case(d, "compositions", "grid_session")["instants"].__setitem__(4, 4500000)), + mutate("pip_session: a voice's pan", lambda d: frame_at(d, "pip_session", 6000000)["voices"][0].update(pan=1)), + mutate("studio: a lifecycle record not delivered", relay_drop), + mutate("studio: a byte of a grant", lambda d: d["rooms"]["studio"]["grants"].__setitem__(1, flip(d["rooms"]["studio"]["grants"][1], 200))), + mutate("receipt video: a byte of it", lambda d: case(d, "receipts", "video").update(receipt=flip(case(d, "receipts", "video")["receipt"], 150))), + mutate("receipt video: its stated digest", lambda d: case(d, "receipts", "video").update(digest="00" * 32)), + mutate("receipt inputs_missing: stated accepted", lambda d: case(d, "receipts", "inputs_missing").update(outcome="accept")), + mutate("receipt state_stale: stated inputs_mismatch", lambda d: case(d, "receipts", "state_stale").update(reason="inputs_mismatch")), + ] + + +def main(corpus_dir): + fails = [] + st = ED._self_test() + print(("PASS" if not st else "FAIL") + " Ed25519 strict rule self-test " + ",".join(st)) + if st: + fails.append("ed25519 self-test") + with open(os.path.join(corpus_dir, "vectors.json"), encoding="utf-8") as f: + doc = json.load(f) + rooms = Rooms() + fails += check(doc, rooms) + seen = {v.get("reason") for s, _ in SECTIONS for v in doc[s]} + missing = [r for r in REASONS if r not in seen] + if missing: + fails.append("no case is refused %s" % ", ".join(missing)) + print("%s every reason of §10 refuses a case" % ("PASS" if not missing else "FAIL")) + for label, mutated in mutations(doc): + caught = check(mutated, rooms, quiet=True) + print(("PASS" if caught else "FAIL") + " mutated copy fails: %s%s" % (label, " (%s)" % caught[0][:120] if caught else "")) + if not caught: + fails.append("a mutated copy verifies: %s" % label) + for f in fails: + print("FAIL " + f) + total = sum(len(doc[s]) for s, _ in SECTIONS) + print(("PASS" if not fails else "FAIL") + " live-composition corpus: %d cases" % total) + return 1 if fails else 0 + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("usage: live_compose_verify.py ", file=sys.stderr) + sys.exit(2) + sys.exit(main(sys.argv[1])) diff --git a/wai/registry/capabilities.json b/wai/registry/capabilities.json index 2de06862d..b5adf41c7 100644 --- a/wai/registry/capabilities.json +++ b/wai/registry/capabilities.json @@ -558,6 +558,20 @@ "edition": null, "registered": "2026-06-12" }, + { + "capability": "wai.live.compose", + "kind": "record", + "status": "registered", + "media": null, + "role": null, + "tier": null, + "licence": null, + "replicate": null, + "sets": [], + "spec_section": "§5 Interactive, temporal & computed content", + "edition": null, + "registered": "2026-10-17" + }, { "capability": "wai.live.events", "kind": "record", @@ -1685,6 +1699,13 @@ "section": "§5", "status": "defined" }, + { + "name": "WCD1", + "kind": "magic", + "document": "extensions/live-compose.md", + "section": "§3.1", + "status": "defined" + }, { "name": "WCN1", "kind": "magic", @@ -1692,6 +1713,13 @@ "section": "§8.1", "status": "defined" }, + { + "name": "WCR1", + "kind": "magic", + "document": "extensions/live-compose.md", + "section": "§8.1", + "status": "defined" + }, { "name": "WEP1", "kind": "magic", diff --git a/wai/vocab/v2.ttl b/wai/vocab/v2.ttl index 07a326e90..21950314d 100644 --- a/wai/vocab/v2.ttl +++ b/wai/vocab/v2.ttl @@ -522,6 +522,13 @@ wai:wai.image.png a wai:Capability ; wai:specSection "§5 Mandatory floor" ; wai:registeredOn "2026-06-12"^^xsd:date . +wai:wai.live.compose a wai:Capability ; + rdfs:label "wai.live.compose" ; + wai:kind wai:kind-record ; + wai:status wai:status-registered ; + wai:specSection "§5 Interactive, temporal & computed content" ; + wai:registeredOn "2026-10-17"^^xsd:date . + wai:wai.live.events a wai:Capability ; rdfs:label "wai.live.events" ; wai:kind wai:kind-record ; diff --git a/wai/wai-rs/Cargo.toml b/wai/wai-rs/Cargo.toml index e258798f9..cbcd10d36 100644 --- a/wai/wai-rs/Cargo.toml +++ b/wai/wai-rs/Cargo.toml @@ -192,6 +192,13 @@ live_room = ["live_events", "key_discovery"] # with its single-take, aligned, complete and publishable verdicts. Ed25519, SHA-256 and # the key log only; no new dependency. capture_take = ["live_room"] +# Live composition (extensions/live-compose.md): `wai.live.compose` — the signed +# composition descriptor (WCD1), the participant set a room's lifecycle replay gives at +# each instant, the integer layout function (grid, featured tile, picture in picture, fill +# modes) and the saturating integer mixer, and the compositor's signed receipt (WCR1). +# The layout and the mixer use nothing beyond core and alloc. Ed25519 and SHA-256 only; no +# new dependency. +live_compose = ["live_room"] # Object-based spatial audio (extensions/spatial-audio): the deterministic # Fx mixdown engine. Reuses the world `Fx` floor + blake3; no codec/ML deps # (sources arrive as decoded mono PCM — decoding the wai.audio.* assets is @@ -634,6 +641,11 @@ name = "wai_capture_take_vectors" path = "src/bin/wai_capture_take_vectors.rs" required-features = ["capture_take"] +[[bin]] +name = "wai_live_compose_vectors" +path = "src/bin/wai_live_compose_vectors.rs" +required-features = ["live_compose"] + [[bin]] name = "wai_world_meter" path = "src/bin/wai_world_meter.rs" @@ -1259,6 +1271,11 @@ name = "capture_take" path = "tests/capture_take.rs" required-features = ["capture_take"] +[[test]] +name = "live_compose" +path = "tests/live_compose.rs" +required-features = ["live_compose"] + [[test]] name = "world_replay" path = "tests/world_replay.rs" diff --git a/wai/wai-rs/src/bin/wai_live_compose_vectors.rs b/wai/wai-rs/src/bin/wai_live_compose_vectors.rs new file mode 100644 index 000000000..33e8b3d67 --- /dev/null +++ b/wai/wai-rs/src/bin/wai_live_compose_vectors.rs @@ -0,0 +1,53 @@ +//! Conformance corpus for live composition (`live-conformance/compose/`, extensions/live-compose.md §11). +//! +//! wai_live_compose_vectors gen write vectors.json, from fixed seeds +//! wai_live_compose_vectors verify vectors.json regenerates byte for byte, and +//! every case gets the outcome it states +//! +//! The generator and this verifier are one implementation. The corpus's second +//! implementation is `live-conformance/live_compose_verify.py`, written from the extension's +//! text and sharing no code with this binary. + +use std::path::Path; +use wai::live_compose::corpus; + +fn main() { + let a: Vec = std::env::args().collect(); + match (a.get(1).map(String::as_str), a.get(2)) { + (Some("gen"), Some(d)) => { + let p = Path::new(d).join("vectors.json"); + if let Err(e) = std::fs::create_dir_all(d).and_then(|_| std::fs::write(&p, corpus::generate())) { + eprintln!("write {}: {e}", p.display()); + std::process::exit(1); + } + println!("wrote {}", p.display()); + } + (Some("verify"), Some(d)) => std::process::exit(verify(Path::new(d))), + _ => { + eprintln!("usage: wai_live_compose_vectors gen|verify "); + std::process::exit(2); + } + } +} + +fn verify(dir: &Path) -> i32 { + let p = dir.join("vectors.json"); + let doc = match std::fs::read_to_string(&p) { + Ok(s) => s, + Err(e) => { + eprintln!("read {}: {e}", p.display()); + return 1; + } + }; + let mut fail = 0; + let same = doc == corpus::generate(); + println!("{} vectors.json regenerates byte for byte from its seeds", if same { "PASS" } else { "FAIL" }); + fail += (!same) as i32; + let fails = corpus::verify(&doc); + for f in &fails { + println!("FAIL {f}"); + } + println!("{} every case gets the outcome the corpus states", if fails.is_empty() { "PASS" } else { "FAIL" }); + fail += (!fails.is_empty()) as i32; + (fail != 0) as i32 +} diff --git a/wai/wai-rs/src/codecs/registry.rs b/wai/wai-rs/src/codecs/registry.rs index e998ffe6e..5da7e8e38 100644 --- a/wai/wai-rs/src/codecs/registry.rs +++ b/wai/wai-rs/src/codecs/registry.rs @@ -212,6 +212,7 @@ pub const CAP_VIDEO_CHANNEL: &str = "wai.video.channel"; pub const CAP_LIVE_EVENTS: &str = "wai.live.events"; pub const CAP_LIVE_ROOM: &str = "wai.live.room"; pub const CAP_CAPTURE_TAKE: &str = "wai.capture.take"; +pub const CAP_LIVE_COMPOSE: &str = "wai.live.compose"; /// One row per string SPEC §5 registers that is a payload, companion or record: /// `(string, SPEC section, edition, registered)`. @@ -292,6 +293,7 @@ const ROWS: &[(&str, &str, Option<&str>, &str)] = &[ (CAP_LIVE_EVENTS, S_INTERACTIVE, None, "2026-10-16"), (CAP_LIVE_ROOM, S_INTERACTIVE, None, "2026-10-16"), (CAP_CAPTURE_TAKE, S_INTERACTIVE, None, "2026-10-17"), + (CAP_LIVE_COMPOSE, S_INTERACTIVE, None, "2026-10-17"), (CAP_AUDIO_IAMF, S_IMMERSIVE, None, "2026-06-17"), (CAP_AUDIO_AC4, S_IMMERSIVE, None, "2026-06-17"), (CAP_AUDIO_IVAS, S_IMMERSIVE, None, "2026-06-17"), @@ -338,7 +340,7 @@ const DERIVATIONS_REGISTERED: &str = "2026-09-28"; const RECORDS: &[&str] = &[ CAP_ASSET_PROVENANCE, CAP_QUANTUM_CALIBRATION, CAP_QUANTUM_JOB, CAP_VIDEO_MANIFEST, CAP_VIDEO_SSAI, CAP_VIDEO_KEYS, CAP_VIDEO_PACKAGE, CAP_VIDEO_CHANNEL, - CAP_LIVE_EVENTS, CAP_LIVE_ROOM, CAP_CAPTURE_TAKE, + CAP_LIVE_EVENTS, CAP_LIVE_ROOM, CAP_CAPTURE_TAKE, CAP_LIVE_COMPOSE, ]; /// A named identifier SPEC uses that has the shape of a capability string but is @@ -479,6 +481,7 @@ const PACKAGING: &str = "extensions/packaging.md"; const LIVE_EVENTS: &str = "extensions/live-events.md"; const LIVE_ROOMS: &str = "extensions/live-rooms.md"; const CAPTURE_BINDING: &str = "extensions/capture-binding.md"; +const LIVE_COMPOSE: &str = "extensions/live-compose.md"; const fn wire(name: &'static str, kind: WireKind, document: &'static str, section: &'static str, status: WireStatus) -> WireIdentifier { @@ -487,8 +490,8 @@ const fn wire(name: &'static str, kind: WireKind, document: &'static str, sectio /// The wire identifiers of the container, of its two delivery bindings /// (http-delivery, moq-streaming-format), of the key discovery those bindings serve -/// (jwp-receipts §7), of packaging, of live events, of live rooms and of capture binding, in document order. The -/// export lists them sorted by name and kind. +/// (jwp-receipts §7), of packaging, of live events, of live rooms, of capture binding and +/// of live composition, in document order. The export lists them sorted by name and kind. pub const WIRE_IDENTIFIERS: &[WireIdentifier] = &[ wire("WAI1", WireKind::Magic, "SPEC.md", "§2", WireStatus::Defined), wire("WAI2", WireKind::Magic, "SPEC.md", "§7.1", WireStatus::Defined), @@ -542,6 +545,8 @@ pub const WIRE_IDENTIFIERS: &[WireIdentifier] = &[ wire("WUR1", WireKind::Magic, CAPTURE_BINDING, "§6.2", WireStatus::Defined), wire("WTM1", WireKind::Magic, CAPTURE_BINDING, "§7.1", WireStatus::Defined), wire("WCN1", WireKind::Magic, CAPTURE_BINDING, "§8.1", WireStatus::Defined), + wire("WCD1", WireKind::Magic, LIVE_COMPOSE, "§3.1", WireStatus::Defined), + wire("WCR1", WireKind::Magic, LIVE_COMPOSE, "§8.1", WireStatus::Defined), ]; /// A string with the shape of a capability that the reference implementation uses diff --git a/wai/wai-rs/src/lib.rs b/wai/wai-rs/src/lib.rs index 80eabe796..f72373a4b 100644 --- a/wai/wai-rs/src/lib.rs +++ b/wai/wai-rs/src/lib.rs @@ -406,6 +406,15 @@ pub mod live_room; #[cfg(feature = "capture_take")] pub mod capture_take; +// Live composition (extensions/live-compose.md): `wai.live.compose` — the signed +// composition descriptor, the participant set the room's lifecycle replay gives at each +// room-clock instant, the integer layout function and mixer that every sink runs alike, +// and the receipt a server compositor signs for a composed track. Rust-only, like the +// other live modules: its constants must not become macros in include/wai.h. +/// cbindgen:ignore +#[cfg(feature = "live_compose")] +pub mod live_compose; + // Typed receipt classes (extensions/jwp-receipts.md §2.4.3–§2.4.12, §2.6, §3.1–§3.2): // energy, lawful-basis, log-inclusion, soft-binding, binding-recovery, measurement, // operating-point, stage, delivery-gap and reconstruct-session statements about diff --git a/wai/wai-rs/src/live_compose.rs b/wai/wai-rs/src/live_compose.rs new file mode 100644 index 000000000..640a59db0 --- /dev/null +++ b/wai/wai-rs/src/live_compose.rs @@ -0,0 +1,920 @@ +//! Live composition — `wai.live.compose` ([extensions/live-compose.md]). +//! +//! A room's composition is an integer function. A signed **composition descriptor** +//! (`WCD1`), by the room authority or a principal whose grant has the compose power +//! (live-rooms §3.3), fixes the canvas, the background, the layout (a grid, or a grid with +//! a picture-in-picture window), the attribute keys it reads and its limits. The +//! **participant set** at a room-clock instant is derived from the room's lifecycle +//! replay ([`crate::live_room`]): who publishes, each one's video and audio source and its +//! dimensions, the attributes of its grant in effect, and its join order. The layout and +//! the voices of the mix are then a pure function of the two ([`layout::layout`]), and the +//! mix a pure function of decoded PCM ([`layout::mix`]), so every sink composes the same +//! rectangles locally, and a server compositor that publishes a composed track signs a +//! **composition receipt** (`WCR1`) that anyone can check against the same function. +//! +//! What this module implements, by section of the extension: +//! +//! - §3: the descriptor, read, its canvas limits and field rules, its digest and +//! signature, and who may sign it; +//! - §4: the room state at an instant, the participant set, the attributes the descriptor +//! reads, the order, and the set's digest; +//! - §5, §6: the layout and the mixer, in [`layout`], which uses nothing beyond `core`, +//! `Vec` and `String`; +//! - §8: the receipt, read, signed, and verified against the room and the descriptor. +//! +//! The corpus `live-conformance/compose/` is written by [`corpus::generate`] and checked +//! by [`corpus::verify`] here, and by `live-conformance/live_compose_verify.py`, which +//! shares no code with this module. +//! +//! [extensions/live-compose.md]: ../../extensions/live-compose.md + +use std::collections::{BTreeMap, BTreeSet}; + +use ed25519_dalek::{Signer, SigningKey}; +use sha2::{Digest, Sha256}; + +use crate::live_events::{self as events, anchor_track, kind, Event, Payload}; +use crate::live_room::{ + self as room, layering, media, media_name, power, render_namespace, track_name, track_namespace, verify_room, At, Descriptor, Grant, Held, Owner, RoomOutcome, RoomRun, + RoomState, +}; + +pub mod corpus; +pub mod layout; + +use layout::{Entrant, Layout, Params, Refusal}; + +/// The record this extension registers. +pub const CAPABILITY: &str = "wai.live.compose"; +/// The magic of a composition descriptor (§3.1). +pub const DESCRIPTOR_MAGIC: [u8; 4] = *b"WCD1"; +/// The magic of a composition receipt (§8.1). +pub const RECEIPT_MAGIC: [u8; 4] = *b"WCR1"; +/// The version of both records in this revision. +pub const RECORD_VERSION: u8 = 1; +/// The domain a descriptor's signature is made over (§3.2). +pub const DESCRIPTOR_DOMAIN: &[u8] = b"wai:live-compose\x01"; +/// The domain a receipt's signature is made over (§8.1). +pub const RECEIPT_DOMAIN: &[u8] = b"wai:live-compose-receipt\x01"; +/// The domain of a participant set's digest (§4.5). +pub const SET_DOMAIN: &[u8] = b"wai:live-compose-set\x01"; +/// A descriptor's `compositor` when no server composes (§3.1, §7). +pub const NO_COMPOSITOR: [u8; 32] = [0; 32]; + +// --------------------------------------------------------------------------------------- +// §10 Reasons +// --------------------------------------------------------------------------------------- + +/// Why a composition, a mix or a receipt is refused (§10). +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Reason { + /// A code of live-rooms §11, or of live-events §9 through it. + Room(room::Reason), + CanvasOutOfRange, + ComposeInvalid, + ComposeNotPermitted, + NotYetEffective, + LifecycleIncomplete, + AttrMalformed, + MixInputMalformed, + ReceiptInvalid, + DescriptorMismatch, + CompositorNotPermitted, + OutputNotPublished, + StateMismatch, + InputsMismatch, +} + +impl From for Reason { + fn from(r: room::Reason) -> Self { + Reason::Room(r) + } +} + +impl From for Reason { + fn from(r: events::Reason) -> Self { + Reason::Room(room::Reason::Events(r)) + } +} + +impl From for Reason { + fn from(r: Refusal) -> Self { + match r { + Refusal::CanvasOutOfRange => Reason::CanvasOutOfRange, + Refusal::ComposeInvalid => Reason::ComposeInvalid, + Refusal::AttrMalformed => Reason::AttrMalformed, + Refusal::MixInputMalformed => Reason::MixInputMalformed, + } + } +} + +const TRUNCATED: Reason = Reason::Room(room::Reason::Events(events::Reason::Truncated)); +const MALFORMED: Reason = Reason::Room(room::Reason::Events(events::Reason::Malformed)); +const UNKNOWN_VERSION: Reason = Reason::Room(room::Reason::Events(events::Reason::UnknownVersion)); +const WRONG_ROOM: Reason = Reason::Room(room::Reason::Events(events::Reason::WrongRoom)); + +impl Reason { + /// The codes this extension adds, in §10's order. + pub const ALL: [Reason; 13] = [ + Reason::CanvasOutOfRange, + Reason::ComposeInvalid, + Reason::ComposeNotPermitted, + Reason::NotYetEffective, + Reason::LifecycleIncomplete, + Reason::AttrMalformed, + Reason::MixInputMalformed, + Reason::ReceiptInvalid, + Reason::DescriptorMismatch, + Reason::CompositorNotPermitted, + Reason::OutputNotPublished, + Reason::StateMismatch, + Reason::InputsMismatch, + ]; + + /// The reason's code. + pub fn code(self) -> &'static str { + match self { + Reason::Room(r) => r.code(), + Reason::CanvasOutOfRange => "canvas_out_of_range", + Reason::ComposeInvalid => "compose_invalid", + Reason::ComposeNotPermitted => "compose_not_permitted", + Reason::NotYetEffective => "not_yet_effective", + Reason::LifecycleIncomplete => "lifecycle_incomplete", + Reason::AttrMalformed => "attr_malformed", + Reason::MixInputMalformed => "mix_input_malformed", + Reason::ReceiptInvalid => "receipt_invalid", + Reason::DescriptorMismatch => "descriptor_mismatch", + Reason::CompositorNotPermitted => "compositor_not_permitted", + Reason::OutputNotPublished => "output_not_published", + Reason::StateMismatch => "state_mismatch", + Reason::InputsMismatch => "inputs_mismatch", + } + } +} + +impl std::fmt::Display for Reason { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.code()) + } +} + +impl std::error::Error for Reason {} + +/// Where a verification stopped (§9). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Place { + /// The room: where live-rooms §9 refused it, or none for the room as a whole. + Room(Option), + Descriptor, + Receipt, + /// The participant set or the layout at this instant. + Set(u64), +} + +// --------------------------------------------------------------------------------------- +// Reading +// --------------------------------------------------------------------------------------- + +fn sha256(parts: &[&[u8]]) -> [u8; 32] { + let mut h = Sha256::new(); + for p in parts { + h.update(p); + } + h.finalize().into() +} + +/// A cursor; running out is `truncated`. +struct Rd<'a> { + b: &'a [u8], + p: usize, +} + +impl<'a> Rd<'a> { + fn take(&mut self, n: usize) -> Result<&'a [u8], Reason> { + let e = self.p.checked_add(n).filter(|&e| e <= self.b.len()).ok_or(TRUNCATED)?; + let s = &self.b[self.p..e]; + self.p = e; + Ok(s) + } + fn arr(&mut self) -> Result<[u8; N], Reason> { + Ok(self.take(N)?.try_into().expect("N bytes")) + } + fn u8(&mut self) -> Result { + Ok(self.take(1)?[0]) + } + fn u16(&mut self) -> Result { + Ok(u16::from_le_bytes(self.arr()?)) + } + fn u32(&mut self) -> Result { + Ok(u32::from_le_bytes(self.arr()?)) + } + fn u64(&mut self) -> Result { + Ok(u64::from_le_bytes(self.arr()?)) + } + /// A short field: a u8 length and that many bytes. + fn short(&mut self) -> Result<&'a [u8], Reason> { + let n = self.u8()? as usize; + self.take(n) + } +} + +/// live-events §3.3's first two steps, with `magic` for `WEV1`. +fn read_head(b: &[u8], magic: &[u8; 4]) -> Result<(), Reason> { + if b.len() < 4 { + return Err(TRUNCATED); + } + if b[..4] != *magic { + return Err(MALFORMED); + } + if b.len() < 5 { + return Err(TRUNCATED); + } + if b[4] != RECORD_VERSION { + return Err(UNKNOWN_VERSION); + } + Ok(()) +} + +fn verify_sig(key: &[u8; 32], domain: &[u8], body: &[u8], sig: &[u8; 64]) -> Result<(), Reason> { + let mut m = domain.to_vec(); + m.extend_from_slice(body); + crate::sig::verify_strict(key, &m, sig).map_err(|e| match e { + crate::sig::SigError::BadKey => events::Reason::BadKey.into(), + crate::sig::SigError::BadSignature => events::Reason::BadSignature.into(), + }) +} + +fn put_short(o: &mut Vec, s: &[u8]) { + assert!(s.len() <= u8::MAX as usize, "a short field is at most 255 bytes"); + o.push(s.len() as u8); + o.extend_from_slice(s); +} + +fn u16_of(v: u32) -> [u8; 2] { + u16::try_from(v).expect("a field of 16 bits").to_le_bytes() +} + +// --------------------------------------------------------------------------------------- +// §3 The composition descriptor +// --------------------------------------------------------------------------------------- + +/// A composition descriptor (§3.1). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Compose { + /// The room id (live-rooms §3.2). + pub room: [u8; 32], + /// The key that signs it: the room authority, or a principal with the compose power. + pub signer: [u8; 32], + /// The room-clock instant from which it applies. + pub effective: u64, + /// The principal that may publish the composed tracks; [`NO_COMPOSITOR`] for none. + pub compositor: [u8; 32], + /// sRGB, 8 bits each of red, green and blue. + pub background: [u8; 3], + /// The highest layer composed (§4.2). + pub layer: u8, + /// Everything else, as the layout reads it. + pub params: Params, + pub sig: [u8; 64], +} + +impl Compose { + /// The descriptor without `sig` (§3.1). + pub fn body(&self) -> Vec { + let p = &self.params; + let mut o = Vec::with_capacity(256); + o.extend_from_slice(&DESCRIPTOR_MAGIC); + o.push(RECORD_VERSION); + o.extend_from_slice(&self.room); + o.extend_from_slice(&self.signer); + o.extend_from_slice(&self.effective.to_le_bytes()); + o.extend_from_slice(&self.compositor); + o.extend_from_slice(&u16_of(p.width)); + o.extend_from_slice(&u16_of(p.height)); + o.push(p.fps); + o.extend_from_slice(&self.background); + o.push(self.layer); + o.push(p.layout); + o.extend_from_slice(&u16_of(p.gap)); + o.push(p.aspect); + o.push(p.fill); + put_short(&mut o, p.featured_attr.as_bytes()); + put_short(&mut o, p.order_attr.as_bytes()); + o.push(p.omit_stopped as u8); + put_short(&mut o, p.pip_attr.as_bytes()); + o.push(p.corner); + o.extend_from_slice(&u16_of(p.pip_width)); + o.extend_from_slice(&u16_of(p.pip_height)); + o.extend_from_slice(&u16_of(p.offset)); + o.push(p.behaviour); + o.push(p.channels); + o.extend_from_slice(&p.sample_rate.to_le_bytes()); + put_short(&mut o, p.gain_attr.as_bytes()); + put_short(&mut o, p.pan_attr.as_bytes()); + o.push(u8::try_from(p.max_tiles).expect("max_tiles fits a byte")); + o.push(u8::try_from(p.max_voices).expect("max_voices fits a byte")); + o + } + + pub fn to_bytes(&self) -> Vec { + let mut o = self.body(); + o.extend_from_slice(&self.sig); + o + } + + /// The descriptor's digest (§3.2): SHA-256 over [`Compose::body`]. + pub fn digest(&self) -> [u8; 32] { + sha256(&[&self.body()]) + } + + /// Signed under `key`; `signer` is left as it is. + pub fn sign(mut self, key: &SigningKey) -> Compose { + let mut m = DESCRIPTOR_DOMAIN.to_vec(); + m.extend_from_slice(&self.body()); + self.sig = key.sign(&m).to_bytes(); + self + } + + /// Read a descriptor (§3.3): the record, its canvas, its field rules, its signature. + pub fn parse(b: &[u8]) -> Result { + read_head(b, &DESCRIPTOR_MAGIC)?; + let mut r = Rd { b, p: 5 }; + let room = r.arr()?; + let signer = r.arr()?; + let effective = r.u64()?; + let compositor = r.arr()?; + let width = r.u16()? as u32; + let height = r.u16()? as u32; + let fps = r.u8()?; + let background = r.arr()?; + let layer = r.u8()?; + let layout = r.u8()?; + let gap = r.u16()? as u32; + let aspect = r.u8()?; + let fill = r.u8()?; + let featured = r.short()?; + let order = r.short()?; + let omit = r.u8()?; + let pip_attr = r.short()?; + let corner = r.u8()?; + let pip_width = r.u16()? as u32; + let pip_height = r.u16()? as u32; + let offset = r.u16()? as u32; + let behaviour = r.u8()?; + let channels = r.u8()?; + let sample_rate = r.u32()?; + let gain = r.short()?; + let pan = r.short()?; + let max_tiles = r.u8()? as u32; + let max_voices = r.u8()? as u32; + let sig = r.arr()?; + if r.p != b.len() { + return Err(MALFORMED); + } + let keys = [featured, order, pip_attr, gain, pan]; + let keys_ok = keys.iter().all(|k| k.is_empty() || layout::key_ok(k)); + let s = |k: &[u8]| String::from_utf8_lossy(k).into_owned(); + let params = Params { + width, + height, + fps, + layout, + gap, + aspect, + fill, + featured_attr: s(featured), + order_attr: s(order), + omit_stopped: omit == 1, + pip_attr: s(pip_attr), + corner, + pip_width, + pip_height, + offset, + behaviour, + channels, + sample_rate, + gain_attr: s(gain), + pan_attr: s(pan), + max_tiles, + max_voices, + }; + params.check_canvas()?; + if !keys_ok || omit > 1 { + return Err(Reason::ComposeInvalid); + } + params.check_fields()?; + let c = Compose { room, signer, effective, compositor, background, layer, params, sig }; + verify_sig(&c.signer, DESCRIPTOR_DOMAIN, &b[..b.len() - 64], &c.sig)?; + debug_assert_eq!(c.body(), b[..b.len() - 64], "a descriptor that reads re-encodes to its bytes"); + Ok(c) + } +} + +// --------------------------------------------------------------------------------------- +// §4 The participant set +// --------------------------------------------------------------------------------------- + +/// A room as live-rooms §9 is given it. +#[derive(Clone, Copy, Debug)] +pub struct RoomInput<'a> { + pub descriptor: &'a [u8], + pub grants: &'a [Vec], + pub head: Option<&'a str>, + pub chains: &'a [Vec>], +} + +/// The room at one instant (§4.1): its state, and each present principal's join order. +#[derive(Clone, Debug)] +pub struct Instant { + pub state: RoomState, + pub joins: BTreeMap<[u8; 32], u32>, +} + +/// A room that verified (§9 step 1), with what composition reads of it. +pub struct VerifiedRoom<'a> { + pub input: RoomInput<'a>, + pub run: RoomRun, + pub d: Descriptor, + pub id: [u8; 32], +} + +impl<'a> VerifiedRoom<'a> { + /// live-rooms §9 over the room: its refusal; `lifecycle_incomplete` when a room key's + /// chain has a gap (§4.1). A gap in another principal's chain is not a refusal here. + pub fn verify(input: RoomInput<'a>) -> Result, (Place, Reason)> { + let run = verify_room(input.descriptor, input.grants, input.head, input.chains); + if let RoomOutcome::Refuse { at, reason } = run.outcome { + return Err((Place::Room(Some(at)), reason.into())); + } + let d = run.descriptor.clone().expect("a room that is not refused read its descriptor"); + if let RoomOutcome::Gap(gaps) = &run.outcome + && gaps.iter().any(|g| d.is_room_key(&g.principal)) + { + return Err((Place::Room(None), Reason::LifecycleIncomplete)); + } + let id = d.room_id(); + Ok(VerifiedRoom { input, run, d, id }) + } + + /// The grant a digest names. + pub fn grant(&self, digest: &[u8; 32]) -> Option<&Grant> { + self.run.grants.iter().find(|h| h.digest == *digest).map(|h| &h.grant) + } + + /// The room at `t` (§4.1): live-rooms §9 over each chain's records up to the first + /// whose `t` is above `t`, and the join order of each `join` among them. + pub fn at(&self, t: u64) -> Instant { + let chains: Vec>> = self + .input + .chains + .iter() + .map(|c| c.iter().take_while(|r| Event::parse(r).is_ok_and(|e| e.t <= t)).cloned().collect()) + .collect(); + let run = verify_room(self.input.descriptor, self.input.grants, self.input.head, &chains); + let mut joins = BTreeMap::new(); + let mut seen = BTreeSet::new(); + let mut n = 0u32; + for &(c, i, _) in &run.order { + let Ok(ev) = Event::parse(&chains[c][i]) else { continue }; + if !seen.insert(ev.digest()) || ev.kind != kind::JOIN || !self.d.is_room_key(&ev.principal) { + continue; + } + if let Ok(Payload::Lifecycle { subject, .. }) = events::parse_payload(ev.kind, &ev.payload, u16::MAX) { + joins.insert(subject, n); + n += 1; + } + } + Instant { state: run.state, joins } + } + + /// The grant in effect of `p` at `at`, if `p` is present. + pub fn grant_in_effect(&self, at: &Instant, p: &[u8; 32]) -> Option<&Grant> { + at.state.present.get(p).and_then(|g| self.grant(g)) + } +} + +/// A participant's video or audio source (§4.2). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Source { + /// Empty for the participant's own track; otherwise the slot it is live in. + pub slot: String, + pub media: u8, + /// The index of its profile in the room's descriptor, and the layers it publishes. + pub profile: u8, + pub layers: u8, + /// The layer composed: the lower of `layers` − 1 and the descriptor's `layer`. + pub layer: u8, + pub layering: u8, + /// That layer's dimensions in the profile; 0 for audio. + pub width: u16, + pub height: u16, +} + +impl Source { + /// The tracks a compositor reads it from (§8.2), each as an anchor's `track` digest + /// (live-rooms §6.2): track 0 for `single` and `svc`, track `layer` for `simulcast`, + /// and tracks 0 to `layer` for `staged`. + pub fn tracks(&self, room_id: &[u8; 32], principal: &[u8; 32]) -> Vec<[u8; 32]> { + let owner = if self.slot.is_empty() { Owner::Principal(*principal) } else { Owner::Slot(self.slot.clone()) }; + let ns = render_namespace(&track_namespace(room_id, &owner, media_name(self.media).expect("a media kind"))); + let layers: Vec = match self.layering { + layering::SIMULCAST => vec![self.layer], + layering::STAGED => (0..=self.layer).collect(), + _ => vec![0], + }; + layers.into_iter().map(|l| anchor_track(&ns, &track_name(l))).collect() + } + + fn encode(s: Option<&Source>, o: &mut Vec) { + match s { + None => o.push(0), + Some(s) => { + o.push(s.media); + put_short(o, s.slot.as_bytes()); + o.extend_from_slice(&[s.profile, s.layers, s.layer]); + o.extend_from_slice(&s.width.to_le_bytes()); + o.extend_from_slice(&s.height.to_le_bytes()); + } + } + } +} + +/// One participant of the set (§4.2). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Participant { + pub principal: [u8; 32], + /// The digest of its grant in effect. + pub grant: [u8; 32], + pub join: u32, + /// Its grant's attributes (live-rooms §4.4). + pub attrs: Vec<(String, String)>, + pub video: Option, + pub audio: Option, +} + +fn source(d: &Descriptor, c: &Compose, held: &Held, slot: &str, m: u8) -> Source { + let p = &d.profiles[held.profile as usize]; + let layer = (held.layers - 1).min(c.layer); + let l = &p.layers[layer as usize]; + Source { slot: slot.into(), media: m, profile: held.profile, layers: held.layers, layer, layering: p.layering, width: l.width, height: l.height } +} + +/// §4.2: the participant set of `c` at `at`, in ascending order of key. +pub fn participants(c: &Compose, vr: &VerifiedRoom, at: &Instant) -> Vec { + let st = &at.state; + let d = &vr.d; + let live_in = |p: &[u8; 32], kinds: &[u8]| -> Option { + d.slots.iter().zip(&st.slots).find_map(|(s, ss)| match ss.live { + Some(h) if h.principal == *p && kinds.contains(&s.media) => Some(source(d, c, &h, &s.name, s.media)), + _ => None, + }) + }; + let own = |p: &[u8; 32], m: u8| st.own.get(&(*p, m)).map(|h| source(d, c, h, "", m)); + let mut out = Vec::new(); + for (p, g) in &st.present { + if *p == c.compositor { + continue; + } + let publishes = st.own.keys().any(|(q, _)| q == p) || st.slots.iter().any(|s| s.live.is_some_and(|h| h.principal == *p)); + if !publishes { + continue; + } + let video = own(p, media::VIDEO).or_else(|| own(p, media::SCREEN)).or_else(|| live_in(p, &[media::VIDEO, media::SCREEN])); + let audio = own(p, media::AUDIO).or_else(|| live_in(p, &[media::AUDIO])); + let attrs = vr.grant(g).map(|g| g.attrs.clone()).unwrap_or_default(); + let join = *at.joins.get(p).expect("a present principal joined"); + out.push(Participant { principal: *p, grant: *g, join, attrs, video, audio }); + } + out +} + +/// §4.5: the digest of the participant set at `t`. +pub fn set_digest(room_id: &[u8; 32], t: u64, ps: &[Participant]) -> [u8; 32] { + let mut o = Vec::new(); + o.extend_from_slice(SET_DOMAIN); + o.extend_from_slice(room_id); + o.extend_from_slice(&t.to_le_bytes()); + o.extend_from_slice(&(ps.len() as u32).to_le_bytes()); + for p in ps { + o.extend_from_slice(&p.principal); + o.extend_from_slice(&p.grant); + o.extend_from_slice(&p.join.to_le_bytes()); + Source::encode(p.video.as_ref(), &mut o); + Source::encode(p.audio.as_ref(), &mut o); + } + sha256(&[&o]) +} + +/// The composition at one instant: the set, its digest, and the layout and voices. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Frame { + pub t: u64, + pub participants: Vec, + pub set_digest: [u8; 32], + pub layout: Layout, +} + +impl Frame { + fn participant(&self, p: &[u8; 32]) -> &Participant { + self.participants.iter().find(|q| q.principal == *p).expect("a tile's participant is in the set") + } + + /// §8.2: the inputs a composed track of `m` reads, in order, as (principal, track): + /// for video, each tile that shows video, in drawing order; for audio, each voice. + pub fn inputs(&self, room_id: &[u8; 32], m: u8) -> Vec<([u8; 32], [u8; 32])> { + let mut out = Vec::new(); + let sources: Vec<(&[u8; 32], Option<&Source>)> = if m == media::AUDIO { + self.layout.voices.iter().map(|v| (&v.principal, self.participant(&v.principal).audio.as_ref())).collect() + } else { + self.layout.tiles.iter().filter(|t| t.video.is_some()).map(|t| (&t.principal, self.participant(&t.principal).video.as_ref())).collect() + }; + for (p, s) in sources { + for tr in s.expect("a composed source").tracks(room_id, p) { + out.push((*p, tr)); + } + } + out + } +} + +/// §4, §5 at `t` over the room as it is at `at`. +fn frame_at(c: &Compose, vr: &VerifiedRoom, t: u64, at: &Instant) -> Result { + if t < c.effective { + return Err(Reason::NotYetEffective); + } + let participants = participants(c, vr, at); + let entrants: Vec = participants + .iter() + .map(|p| Entrant { + principal: p.principal, + join: p.join, + video: p.video.as_ref().map(|s| (s.width as u32, s.height as u32)), + audio: p.audio.is_some(), + attrs: &p.attrs, + }) + .collect(); + let layout = layout::layout(&c.params, &entrants)?; + Ok(Frame { t, set_digest: set_digest(&vr.id, t, &participants), participants, layout }) +} + +/// The composition of `c` at `t` (§4, §5). +pub fn compose_at(c: &Compose, vr: &VerifiedRoom, t: u64) -> Result { + frame_at(c, vr, t, &vr.at(t)) +} + +/// §3.3, §3.5: a descriptor read, of this room, signed by its authority or by a principal +/// whose grant in effect at its `effective` has the compose power. +pub fn check_descriptor(b: &[u8], vr: &VerifiedRoom) -> Result { + let c = Compose::parse(b)?; + if c.room != vr.id { + return Err(WRONG_ROOM); + } + if c.signer != vr.d.authority { + let at = vr.at(c.effective); + if !vr.grant_in_effect(&at, &c.signer).is_some_and(|g| g.caps.powers & power::COMPOSE != 0) { + return Err(Reason::ComposeNotPermitted); + } + } + Ok(c) +} + +/// The outcome of composing a room at a list of instants. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ComposeOutcome { + Frames(Vec), + Refuse { at: Place, reason: Reason }, +} + +/// §9: the room, the descriptor, then the composition at each instant. +pub fn verify_composition(room: RoomInput, descriptor: &[u8], instants: &[u64]) -> (ComposeOutcome, Option<[u8; 32]>) { + let vr = match VerifiedRoom::verify(room) { + Ok(v) => v, + Err((at, reason)) => return (ComposeOutcome::Refuse { at, reason }, None), + }; + let c = match check_descriptor(descriptor, &vr) { + Ok(c) => c, + Err(reason) => return (ComposeOutcome::Refuse { at: Place::Descriptor, reason }, None), + }; + let mut frames = Vec::with_capacity(instants.len()); + for &t in instants { + match compose_at(&c, &vr, t) { + Ok(f) => frames.push(f), + Err(reason) => return (ComposeOutcome::Refuse { at: Place::Set(t), reason }, Some(c.digest())), + } + } + (ComposeOutcome::Frames(frames), Some(c.digest())) +} + +// --------------------------------------------------------------------------------------- +// §8 The composition receipt +// --------------------------------------------------------------------------------------- + +/// One MoQ object (§8.1): its track, as an anchor's `track` digest, its Location, and the +/// SHA-256 of its payload. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ObjectRef { + pub track: [u8; 32], + pub group: u64, + pub object: u64, + pub digest: [u8; 32], +} + +/// One input object, and the participant it is read from. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct InputRef { + pub principal: [u8; 32], + pub object: ObjectRef, +} + +/// A composition receipt (§8.1). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Receipt { + pub room: [u8; 32], + pub compositor: [u8; 32], + /// The descriptor's digest. + pub descriptor: [u8; 32], + /// The room-clock instant of the output object. + pub t: u64, + /// The participant set's digest at `t` (§4.5). + pub state: [u8; 32], + /// 1 audio (a mix) or 2 video (a layout). + pub media: u8, + pub output: ObjectRef, + pub inputs: Vec, + pub sig: [u8; 64], +} + +fn put_object(o: &mut Vec, r: &ObjectRef) { + o.extend_from_slice(&r.track); + o.extend_from_slice(&r.group.to_le_bytes()); + o.extend_from_slice(&r.object.to_le_bytes()); + o.extend_from_slice(&r.digest); +} + +fn read_object(r: &mut Rd) -> Result { + Ok(ObjectRef { track: r.arr()?, group: r.u64()?, object: r.u64()?, digest: r.arr()? }) +} + +impl Receipt { + /// The receipt without `sig` (§8.1). + pub fn body(&self) -> Vec { + let mut o = Vec::new(); + o.extend_from_slice(&RECEIPT_MAGIC); + o.push(RECORD_VERSION); + o.extend_from_slice(&self.room); + o.extend_from_slice(&self.compositor); + o.extend_from_slice(&self.descriptor); + o.extend_from_slice(&self.t.to_le_bytes()); + o.extend_from_slice(&self.state); + o.push(self.media); + put_object(&mut o, &self.output); + assert!(self.inputs.len() <= u8::MAX as usize, "at most 255 inputs"); + o.push(self.inputs.len() as u8); + for i in &self.inputs { + o.extend_from_slice(&i.principal); + put_object(&mut o, &i.object); + } + o + } + + pub fn to_bytes(&self) -> Vec { + let mut o = self.body(); + o.extend_from_slice(&self.sig); + o + } + + /// The receipt's digest (§8.1). + pub fn digest(&self) -> [u8; 32] { + sha256(&[&self.body()]) + } + + /// Signed under `key`; `compositor` is left as it is. + pub fn sign(mut self, key: &SigningKey) -> Receipt { + let mut m = RECEIPT_DOMAIN.to_vec(); + m.extend_from_slice(&self.body()); + self.sig = key.sign(&m).to_bytes(); + self + } + + /// Read a receipt (§8.3 step 1): the record, its rules, its signature. + pub fn parse(b: &[u8]) -> Result { + read_head(b, &RECEIPT_MAGIC)?; + let mut r = Rd { b, p: 5 }; + let room = r.arr()?; + let compositor = r.arr()?; + let descriptor = r.arr()?; + let t = r.u64()?; + let state = r.arr()?; + let media = r.u8()?; + let output = read_object(&mut r)?; + let n = r.u8()? as usize; + let mut inputs = Vec::with_capacity(n); + for _ in 0..n { + inputs.push(InputRef { principal: r.arr()?, object: read_object(&mut r)? }); + } + let sig = r.arr()?; + if r.p != b.len() { + return Err(MALFORMED); + } + let mut pairs = BTreeSet::new(); + if !matches!(media, media::AUDIO | media::VIDEO) || !inputs.iter().all(|i| pairs.insert((i.principal, i.object.track))) { + return Err(Reason::ReceiptInvalid); + } + let rc = Receipt { room, compositor, descriptor, t, state, media, output, inputs, sig }; + verify_sig(&rc.compositor, RECEIPT_DOMAIN, &b[..b.len() - 64], &rc.sig)?; + Ok(rc) + } +} + +/// The outcome of verifying a receipt (§8.3). +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ReceiptOutcome { + Accept { digest: [u8; 32], frame: Frame }, + Refuse { at: Place, reason: Reason }, +} + +/// §8.3: a receipt checked against the room and the descriptor it names. +pub fn verify_receipt(room: RoomInput, descriptor: &[u8], receipt: &[u8]) -> ReceiptOutcome { + let refuse = |at, reason| ReceiptOutcome::Refuse { at, reason }; + let vr = match VerifiedRoom::verify(room) { + Ok(v) => v, + Err((at, reason)) => return refuse(at, reason), + }; + let c = match check_descriptor(descriptor, &vr) { + Ok(c) => c, + Err(reason) => return refuse(Place::Descriptor, reason), + }; + let r = match Receipt::parse(receipt) { + Ok(r) => r, + Err(reason) => return refuse(Place::Receipt, reason), + }; + if r.room != vr.id { + return refuse(Place::Receipt, WRONG_ROOM); + } + if r.descriptor != c.digest() { + return refuse(Place::Receipt, Reason::DescriptorMismatch); + } + if r.t < c.effective { + return refuse(Place::Receipt, Reason::NotYetEffective); + } + let at = vr.at(r.t); + let composes = vr.grant_in_effect(&at, &r.compositor).is_some_and(|g| g.caps.powers & power::COMPOSE != 0); + if c.compositor == NO_COMPOSITOR || r.compositor != c.compositor || !composes { + return refuse(Place::Receipt, Reason::CompositorNotPermitted); + } + let ns = render_namespace(&track_namespace(&vr.id, &Owner::Principal(r.compositor), media_name(r.media).expect("a media kind"))); + let published = at.state.own.get(&(r.compositor, r.media)).is_some_and(|h| (0..h.layers).any(|l| anchor_track(&ns, &track_name(l)) == r.output.track)); + if !published { + return refuse(Place::Receipt, Reason::OutputNotPublished); + } + let frame = match frame_at(&c, &vr, r.t, &at) { + Ok(f) => f, + Err(reason) => return refuse(Place::Set(r.t), reason), + }; + if r.state != frame.set_digest { + return refuse(Place::Receipt, Reason::StateMismatch); + } + let stated: Vec<([u8; 32], [u8; 32])> = r.inputs.iter().map(|i| (i.principal, i.object.track)).collect(); + if stated != frame.inputs(&vr.id, r.media) { + return refuse(Place::Receipt, Reason::InputsMismatch); + } + ReceiptOutcome::Accept { digest: r.digest(), frame } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// The corpus regenerates byte for byte, and this module gives every case of it the + /// outcome it states. + #[test] + fn corpus_round_trip() { + let doc = corpus::generate(); + let fails = corpus::verify(&doc); + assert!(fails.is_empty(), "{}", fails.join("\n")); + } + + /// A descriptor re-encodes to the bytes it was read from, and one bit of its body + /// changed fails its signature. + #[test] + fn descriptor_round_trip() { + let key = SigningKey::from_bytes(&[7; 32]); + let c = Compose { + room: [1; 32], + signer: key.verifying_key().to_bytes(), + effective: 0, + compositor: NO_COMPOSITOR, + background: [0, 0, 0], + layer: 2, + params: corpus::grid_params(), + sig: [0; 64], + } + .sign(&key); + let b = c.to_bytes(); + assert_eq!(Compose::parse(&b), Ok(c)); + let mut bad = b.clone(); + bad[40] ^= 1; + assert_eq!(Compose::parse(&bad), Err(events::Reason::BadSignature.into())); + assert_eq!(Compose::parse(&b[..b.len() - 1]), Err(TRUNCATED)); + } +} diff --git a/wai/wai-rs/src/live_compose/corpus.rs b/wai/wai-rs/src/live_compose/corpus.rs new file mode 100644 index 000000000..64760a0aa --- /dev/null +++ b/wai/wai-rs/src/live_compose/corpus.rs @@ -0,0 +1,1324 @@ +//! The conformance corpus of extensions/live-compose.md §11: `live-conformance/compose/vectors.json`. +//! +//! [`generate`] writes it from fixed seeds: every key is SHA-256 of a fixed label and an +//! index, every time is a constant, every sample of PCM is SHA-256 output of a fixed +//! label, and Ed25519 signing is deterministic (RFC 8032), so the file is the same bytes on +//! every machine. Each case states the outcome it was written to have, and the generator +//! asserts that this module reaches it before writing it, so a defect here cannot write +//! itself into the corpus as expected. +//! +//! [`verify`] checks a corpus file against this module. `live-conformance/live_compose_verify.py` +//! checks the same file from the extension's text, sharing no code with this module. + +use super::*; +use crate::live_events::{Command, Policy}; +use crate::live_room::{registered_profile, Caps, Detail, Layer, Limits, Profile, Recording, Review, Role, Slot, NO_CEILING}; +use layout::{aspect, behaviour, corner, fill, kind as lkind, place, Input, Rect, Tile}; +use serde_json::{json, Map, Value}; + +/// The room's `t0`: 2026-10-17T00:00:00Z, in microseconds and in seconds. +const T0_US: u64 = 1_792_195_200_000_000; +const T0_S: u64 = T0_US / 1_000_000; +const S: u64 = 1_000_000; +const MS: u64 = 1_000; + +const AUTHORITY: u8 = 0; +const RELAY: u8 = 1; +const DIRECTOR: u8 = 2; +const PERFORMER: u8 = 3; +const GUEST: u8 = 4; +const SCREEN: u8 = 5; +const ENCODER: u8 = 6; +const MIXER: u8 = 7; +const VIEWER: u8 = 8; +const IMPOSTOR: u8 = 9; + +const PRINCIPALS: [(&str, u8); 10] = [ + ("authority", AUTHORITY), + ("relay", RELAY), + ("director", DIRECTOR), + ("performer", PERFORMER), + ("guest", GUEST), + ("screen", SCREEN), + ("encoder", ENCODER), + ("mixer", MIXER), + ("viewer", VIEWER), + ("impostor", IMPOSTOR), +]; + +fn key(i: u8) -> SigningKey { + SigningKey::from_bytes(&sha256(&[b"wai:live-compose/corpus/key\x00", &[i]])) +} + +fn pk(i: u8) -> [u8; 32] { + key(i).verifying_key().to_bytes() +} + +fn hex(b: &[u8]) -> String { + b.iter().map(|x| format!("{x:02x}")).collect() +} + +fn unhex(s: &str) -> Option> { + if !s.len().is_multiple_of(2) { + return None; + } + (0..s.len()).step_by(2).map(|i| u8::from_str_radix(s.get(i..i + 2)?, 16).ok()).collect() +} + +fn d32(s: &str) -> Option<[u8; 32]> { + unhex(s)?.try_into().ok() +} + +fn bits(ks: &[u8]) -> [u8; 32] { + let mut b = [0u8; 32]; + for &k in ks { + b[(k / 8) as usize] |= 1 << (k % 8); + } + b +} + +fn kinds_of(b: &[u8; 32]) -> Vec { + (0..=255u8).filter(|k| b[(k / 8) as usize] & (1 << (k % 8)) != 0).collect() +} + +fn attrs(kv: &[(&str, &str)]) -> Vec<(String, String)> { + kv.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect() +} + +/// A participant of a pure layout case: a fixed 32-byte name, not a key. +fn member(i: u8) -> [u8; 32] { + sha256(&[b"wai:live-compose/corpus/member\x00", &[i]]) +} + +// --------------------------------------------------------------------------------------- +// The descriptors' parameters +// --------------------------------------------------------------------------------------- + +/// The parameters of the room's grid: 1920 × 1080 at 30 fps, 16:9 tiles, an 8-pixel gap, +/// the default fill, the attributes `featured`, `order`, `gain` and `pan`, stereo at +/// 48 kHz, at most twelve tiles and twelve voices. +pub(super) fn grid_params() -> Params { + Params { + width: 1920, + height: 1080, + fps: 30, + layout: lkind::GRID, + gap: 8, + aspect: aspect::VIDEO, + fill: fill::DEFAULT, + featured_attr: "featured".into(), + order_attr: "order".into(), + omit_stopped: false, + pip_attr: String::new(), + corner: 0, + pip_width: 0, + pip_height: 0, + offset: 0, + behaviour: 0, + channels: 2, + sample_rate: 48_000, + gain_attr: "gain".into(), + pan_attr: "pan".into(), + max_tiles: 12, + max_voices: 12, + } +} + +/// The room's picture-in-picture: the grid's parameters with auto tiles, cover, a 4-pixel +/// gap, no featured attribute, stopped video omitted, the `pip` attribute's participant +/// in a 480 × 270 window 24 pixels from the bottom right corner, dynamic, six tiles. +fn pip_params() -> Params { + Params { + layout: lkind::PIP, + gap: 4, + aspect: aspect::AUTO, + fill: fill::COVER, + featured_attr: String::new(), + omit_stopped: true, + pip_attr: "pip".into(), + corner: corner::BOTTOM_RIGHT, + pip_width: 480, + pip_height: 270, + offset: 24, + behaviour: behaviour::DYNAMIC, + max_tiles: 6, + ..grid_params() + } +} + +fn params_json(p: &Params) -> Value { + json!({ + "width": p.width, "height": p.height, "fps": p.fps, "layout": p.layout, "gap": p.gap, + "aspect": p.aspect, "fill": p.fill, "featured_attr": p.featured_attr, "order_attr": p.order_attr, + "omit_stopped": p.omit_stopped, "pip_attr": p.pip_attr, "corner": p.corner, "pip_width": p.pip_width, + "pip_height": p.pip_height, "offset": p.offset, "behaviour": p.behaviour, "channels": p.channels, + "sample_rate": p.sample_rate, "gain_attr": p.gain_attr, "pan_attr": p.pan_attr, + "max_tiles": p.max_tiles, "max_voices": p.max_voices, + }) +} + +fn params_of(v: &Value) -> Option { + let n = |k: &str| v[k].as_u64().and_then(|x| u32::try_from(x).ok()); + let b = |k: &str| v[k].as_u64().and_then(|x| u8::try_from(x).ok()); + let s = |k: &str| v[k].as_str().map(String::from); + Some(Params { + width: n("width")?, + height: n("height")?, + fps: b("fps")?, + layout: b("layout")?, + gap: n("gap")?, + aspect: b("aspect")?, + fill: b("fill")?, + featured_attr: s("featured_attr")?, + order_attr: s("order_attr")?, + omit_stopped: v["omit_stopped"].as_bool()?, + pip_attr: s("pip_attr")?, + corner: b("corner")?, + pip_width: n("pip_width")?, + pip_height: n("pip_height")?, + offset: n("offset")?, + behaviour: b("behaviour")?, + channels: b("channels")?, + sample_rate: n("sample_rate")?, + gain_attr: s("gain_attr")?, + pan_attr: s("pan_attr")?, + max_tiles: n("max_tiles")?, + max_voices: n("max_voices")?, + }) +} + +// --------------------------------------------------------------------------------------- +// Rendering outcomes +// --------------------------------------------------------------------------------------- + +fn rect_json(r: &Rect) -> Value { + json!([r.x, r.y, r.w, r.h]) +} + +fn tile_json(t: &Tile) -> Value { + json!({ + "principal": hex(&t.principal), + "place": place::name(t.place), + "z": t.z, + "tile": rect_json(&t.tile), + "dst": t.video.map_or(Value::Null, |v| rect_json(&v.dst)), + "src": t.video.map_or(Value::Null, |v| rect_json(&v.src)), + }) +} + +fn layout_fields(l: &Layout, o: &mut Map) { + o.insert("order".into(), json!(l.order.iter().map(|p| hex(p)).collect::>())); + o.insert("tiles".into(), Value::Array(l.tiles.iter().map(tile_json).collect())); + o.insert( + "voices".into(), + Value::Array(l.voices.iter().map(|v| json!({"principal": hex(&v.principal), "gain": v.gain, "pan": v.pan})).collect()), + ); +} + +fn place_json(p: &Place) -> Value { + match p { + Place::Room(None) => json!(["room"]), + Place::Room(Some(at)) => { + let mut v = vec![json!("room")]; + match at { + At::Descriptor => v.push(json!("descriptor")), + At::KeyLog => v.push(json!("key_log")), + At::Grant(i) => v.extend([json!("grant"), json!(i)]), + At::Record { chain, record } => v.extend([json!("record"), json!(chain), json!(record)]), + } + Value::Array(v) + } + Place::Descriptor => json!(["descriptor"]), + Place::Receipt => json!(["receipt"]), + Place::Set(t) => json!(["set", t]), + } +} + +fn refusal(o: &mut Map, reason: Reason, at: Option<&Place>) { + o.insert("outcome".into(), json!("refuse")); + o.insert("reason".into(), json!(reason.code())); + if let Some(p) = at { + o.insert("at".into(), place_json(p)); + } +} + +fn source_json(s: &Option, room_id: &[u8; 32], p: &[u8; 32]) -> Value { + match s { + None => Value::Null, + Some(s) => json!({ + "slot": s.slot, "media": s.media, "profile": s.profile, "layers": s.layers, "layer": s.layer, + "layering": s.layering, "width": s.width, "height": s.height, + "tracks": s.tracks(room_id, p).iter().map(|t| hex(t)).collect::>(), + }), + } +} + +fn frame_json(f: &Frame, room_id: &[u8; 32]) -> Value { + let mut o = Map::new(); + o.insert("t".into(), json!(f.t)); + o.insert( + "participants".into(), + Value::Array( + f.participants + .iter() + .map(|p| { + json!({ + "principal": hex(&p.principal), + "grant": hex(&p.grant), + "join": p.join, + "attrs": p.attrs.iter().map(|(k, v)| json!([k, v])).collect::>(), + "video": source_json(&p.video, room_id, &p.principal), + "audio": source_json(&p.audio, room_id, &p.principal), + }) + }) + .collect(), + ), + ); + o.insert("set_digest".into(), json!(hex(&f.set_digest))); + layout_fields(&f.layout, &mut o); + Value::Object(o) +} + +// --------------------------------------------------------------------------------------- +// §5 Layout cases +// --------------------------------------------------------------------------------------- + +/// One entrant of a pure layout case. +#[derive(Clone)] +struct E { + principal: [u8; 32], + join: u32, + video: Option<(u32, u32)>, + audio: bool, + attrs: Vec<(String, String)>, +} + +fn e(i: u8, video: Option<(u32, u32)>, kv: &[(&str, &str)]) -> E { + E { principal: member(i), join: i as u32, video, audio: true, attrs: attrs(kv) } +} + +/// `n` entrants with 16:9 video and no attributes, joined in index order. +fn plain(n: u8) -> Vec { + (0..n).map(|i| e(i, Some((1280, 720)), &[])).collect() +} + +struct LayoutCase { + name: String, + about: String, + params: Params, + entrants: Vec, + /// The refusal it is written to have, or none. + refuse: Option, +} + +fn case(name: impl Into, about: impl Into, params: Params, entrants: Vec) -> LayoutCase { + LayoutCase { name: name.into(), about: about.into(), params, entrants, refuse: None } +} + +fn bad(name: &str, about: &str, params: Params, entrants: Vec, r: Reason) -> LayoutCase { + LayoutCase { name: name.into(), about: about.into(), params, entrants, refuse: Some(r) } +} + +fn run_layout(p: &Params, es: &[E]) -> Result { + let entrants: Vec = es.iter().map(|x| Entrant { principal: x.principal, join: x.join, video: x.video, audio: x.audio, attrs: &x.attrs }).collect(); + layout::layout(p, &entrants).map_err(Reason::from) +} + +fn layout_cases() -> Vec { + let g = grid_params(); + let mut out = Vec::new(); + // Grids of 0 to 12 tiles on the 16:9 canvas. + for n in 0..=12u8 { + out.push(case(format!("grid_{n}"), format!("{n} participants with 16:9 video on 1920 × 1080, 16:9 tiles, an 8-pixel gap (§5.3)"), g.clone(), plain(n))); + } + let portrait = Params { width: 1080, height: 1920, aspect: aspect::PORTRAIT, ..g.clone() }; + for n in [2u8, 5, 7, 12] { + out.push(case(format!("portrait_{n}"), format!("{n} participants on a 1080 × 1920 canvas with 3:4 tiles: rows before columns (§5.3)"), portrait.clone(), plain(n))); + } + let square = Params { width: 1080, height: 1080, aspect: aspect::SQUARE, gap: 2, ..g.clone() }; + for n in [3u8, 6] { + out.push(case(format!("square_{n}"), format!("{n} participants on a 1080 × 1080 canvas with 1:1 tiles (§5.3)"), square.clone(), plain(n))); + } + let auto = Params { width: 1280, height: 720, aspect: aspect::AUTO, ..g.clone() }; + out.push(case("auto_4", "four participants on 1280 × 720 with auto tiles: the 16:9 grid, each tile its whole cell (§5.2, §5.3)", auto.clone(), plain(4))); + out.push(case("auto_9_no_gap", "nine participants on 1280 × 720, auto tiles, no gap: three by three cells that tile the canvas (§5.3)", Params { gap: 0, ..auto.clone() }, plain(9))); + // Fill modes over sources of four shapes. + let shapes = vec![e(0, Some((720, 1280)), &[]), e(1, Some((1080, 1080)), &[]), e(2, Some((640, 480)), &[]), e(3, Some((1920, 1080)), &[])]; + for (f, n) in [(fill::FILL, "fill"), (fill::COVER, "cover"), (fill::CONTAIN, "contain"), (fill::DEFAULT, "default")] { + out.push(case(format!("fill_{n}"), format!("a portrait, a square, a 4:3 and a 16:9 source in 16:9 tiles, fill mode {n} (§5.6)"), Params { fill: f, ..g.clone() }, shapes.clone())); + } + out.push(case( + "extreme_aspect", + "a 1920 × 2 source and a 2 × 1080 one, cover and contain: every rectangle at least a pixel each way (§5.1, §5.6)", + Params { fill: fill::CONTAIN, ..g.clone() }, + vec![e(0, Some((1920, 2)), &[]), e(1, Some((2, 1080)), &[])], + )); + out.push(case("extreme_aspect_cover", "the same two sources under cover (§5.6)", Params { fill: fill::COVER, ..g.clone() }, vec![e(0, Some((1920, 2)), &[]), e(1, Some((2, 1080)), &[])])); + // Featured. + let star = &[("featured", "true")]; + out.push(case("featured_alone", "one participant, featured: the featured tile is the whole canvas, contained by default (§5.4)", g.clone(), vec![e(0, Some((1280, 720)), star)])); + let mut four = plain(4); + four[2] = e(2, Some((1280, 720)), star); + out.push(case("featured_4", "four participants, the third featured: it takes the region above, the other three a grid in the band below (§5.4)", g.clone(), four.clone())); + out.push(case("featured_4_portrait", "the same on a portrait canvas (§5.4)", portrait.clone(), four.clone())); + let mut twelve = plain(12); + twelve[9] = e(9, Some((1280, 720)), star); + out.push(case("featured_kept_past_the_limit", "twelve participants and at most eight tiles, the tenth featured: it is moved first, so the cut keeps it (§5.2)", Params { max_tiles: 8, ..g.clone() }, twelve)); + let mut two_stars = plain(4); + two_stars[1] = e(1, Some((1280, 720)), star); + two_stars[3] = e(3, Some((1280, 720)), star); + out.push(case("featured_first_in_order", "two participants featured: the first in order is featured, the other is a grid tile (§5.2)", g.clone(), two_stars)); + let mut not_stars = plain(4); + not_stars[0] = e(0, Some((1280, 720)), &[("featured", "false")]); + out.push(case("featured_absent", "no participant featured (one says false): a plain grid (§5.3)", g.clone(), not_stars)); + out.push(case("featured_attr_unread", "a participant featured under a descriptor that names no featured attribute: a plain grid (§4.3)", Params { featured_attr: String::new(), ..g.clone() }, four.clone())); + // Order. + let ordered = vec![ + e(0, Some((1280, 720)), &[("order", "5")]), + e(1, Some((1280, 720)), &[]), + e(2, Some((1280, 720)), &[("order", "-3")]), + e(3, Some((1280, 720)), &[("order", "5")]), + e(4, Some((1280, 720)), &[]), + ]; + out.push(case("order_attribute", "orders 5, none, -3, 5, none: -3 first, the two 5s by join order, then the two without one by join order (§4.4)", g.clone(), ordered)); + let mut tied: Vec = (0..4).map(|i| e(i, Some((1280, 720)), &[("order", "1")])).collect(); + for x in &mut tied { + x.join = 7; + } + out.push(case("order_key_tie_break", "four participants with one order and one join order: ordered by key (§4.4)", g.clone(), tied)); + // Omitting stopped video. + let stopped = vec![e(0, Some((1280, 720)), &[]), e(1, None, &[]), e(2, Some((1280, 720)), &[]), e(3, None, &[]), e(4, Some((1280, 720)), &[])]; + out.push(case("stopped_shown", "five participants, two with stopped video, which keep their tiles with no video (§5.2)", g.clone(), stopped.clone())); + out.push(case("stopped_omitted", "the same five with omit_stopped: three tiles; the mix keeps all five voices (§5.2, §6)", Params { omit_stopped: true, ..g.clone() }, stopped)); + out.push(case("tile_limit", "eight participants and at most four tiles (§5.2)", Params { max_tiles: 4, ..g.clone() }, plain(8))); + let mut voices = plain(5); + voices[1] = e(1, Some((1280, 720)), &[("gain", "0"), ("pan", "-4096")]); + voices[2] = E { audio: false, ..e(2, Some((1280, 720)), &[]) }; + voices[3] = e(3, Some((1280, 720)), &[("gain", "16384"), ("pan", "4096")]); + out.push(case("voices", "five participants, one without audio, gains 0 and 16384 and pans at both ends, at most three voices (§6)", Params { max_voices: 3, ..g.clone() }, voices)); + // Picture in picture. + let pip = Params { layout: lkind::PIP, pip_attr: "pip".into(), corner: corner::BOTTOM_RIGHT, pip_width: 480, pip_height: 270, offset: 24, behaviour: behaviour::STATIC, ..g.clone() }; + let with_pip = |n: u8, at: u8| -> Vec { + let mut v = plain(n); + v[at as usize] = e(at, Some((1280, 720)), &[("pip", "true")]); + v + }; + for (c, cn) in [(corner::TOP_LEFT, "top_left"), (corner::TOP_RIGHT, "top_right"), (corner::BOTTOM_LEFT, "bottom_left"), (corner::BOTTOM_RIGHT, "bottom_right")] { + for (b, bn) in [(behaviour::STATIC, "static"), (behaviour::DYNAMIC, "dynamic")] { + out.push(case( + format!("pip_{cn}_{bn}"), + format!("three participants and a PiP participant in a 480 × 270 window 24 pixels from the {} corner, {bn}: the others in a grid under it (§5.5)", cn.replace('_', " ")), + Params { corner: c, behaviour: b, ..pip.clone() }, + with_pip(4, 1), + )); + } + } + out.push(case("pip_alone_static", "the PiP participant alone, static: its window and the background (§5.5)", pip.clone(), with_pip(1, 0))); + out.push(case("pip_alone_dynamic", "the PiP participant alone, dynamic: laid out as if it had no pip attribute, a grid of one (§5.5)", Params { behaviour: behaviour::DYNAMIC, ..pip.clone() }, with_pip(1, 0))); + out.push(case( + "pip_alone_dynamic_featured", + "the PiP participant alone, dynamic, and featured: the featured tile, the whole canvas (§5.4, §5.5)", + Params { behaviour: behaviour::DYNAMIC, ..pip.clone() }, + vec![e(0, Some((1280, 720)), &[("featured", "true"), ("pip", "true")])], + )); + let mut portrait_pip = with_pip(3, 2); + portrait_pip[2] = e(2, Some((720, 1280)), &[("pip", "true")]); + out.push(case("pip_size_derived", "pip_width and pip_height 0: a window of the PiP source's aspect, at most a quarter of the canvas wide (§5.5)", Params { pip_width: 0, pip_height: 0, ..pip.clone() }, portrait_pip.clone())); + out.push(case("pip_height_derived", "pip_width 360 and pip_height 0: the height from the source's aspect (§5.5)", Params { pip_width: 360, pip_height: 0, ..pip.clone() }, portrait_pip.clone())); + out.push(case("pip_width_derived", "pip_height 360 and pip_width 0: the width from the source's aspect (§5.5)", Params { pip_width: 0, pip_height: 360, ..pip.clone() }, portrait_pip)); + let mut stopped_pip = plain(3); + stopped_pip[0] = e(0, None, &[("pip", "true")]); + out.push(case("pip_stopped_shown", "a PiP participant with stopped video and a derived size: a window of the canvas's aspect with no video (§5.5)", Params { pip_width: 0, pip_height: 0, ..pip.clone() }, stopped_pip.clone())); + out.push(case("pip_stopped_omitted", "the same with omit_stopped: no PiP window, a grid of the others (§5.2, §5.5)", Params { omit_stopped: true, ..pip.clone() }, stopped_pip)); + let mut two_pips = plain(4); + two_pips[0] = e(0, Some((1280, 720)), &[("order", "2"), ("pip", "true")]); + two_pips[3] = e(3, Some((1280, 720)), &[("order", "1"), ("pip", "true")]); + out.push(case("pip_first_in_order", "two PiP participants: the first in order takes the window, the other a grid tile (§5.5)", pip.clone(), two_pips)); + let mut pip_featured = with_pip(4, 3); + pip_featured[0] = e(0, Some((1280, 720)), star); + out.push(case("pip_over_featured", "a PiP participant over a grid with a featured participant (§5.4, §5.5)", pip.clone(), pip_featured)); + out.push(case("pip_limit", "a PiP participant and five others, at most four tiles: the window and three grid tiles (§5.2)", Params { max_tiles: 4, ..pip.clone() }, with_pip(6, 5))); + // Attributes that do not read. + for (name, k, v) in [ + ("order_leading_zero", "order", "01"), + ("order_negative_zero", "order", "-0"), + ("order_too_large", "order", "2147483648"), + ("order_plus", "order", "+1"), + ("featured_capital", "featured", "TRUE"), + ("gain_too_large", "gain", "16385"), + ("gain_negative", "gain", "-1"), + ("pan_too_far", "pan", "-4097"), + ] { + let mut es = plain(3); + es[1] = e(1, Some((1280, 720)), &[(k, v)]); + out.push(bad(&format!("attr_{name}"), &format!("a participant whose {k} attribute is {v:?} (§4.3)"), g.clone(), es, Reason::AttrMalformed)); + } + let mut es = plain(2); + es[0] = e(0, None, &[("pip", "yes")]); + out.push(bad("attr_pip_yes", "a PiP attribute \"yes\", read though the participant's video is stopped and omitted (§4.3)", Params { omit_stopped: true, ..pip.clone() }, es, Reason::AttrMalformed)); + out.push(bad("params_canvas", "parameters a descriptor could not hold: a 1922-pixel canvas (§3.4)", Params { width: 1922, ..g.clone() }, plain(2), Reason::CanvasOutOfRange)); + out +} + +fn layout_case_json(c: &LayoutCase) -> Value { + let got = run_layout(&c.params, &c.entrants); + match (&got, c.refuse) { + (Ok(_), None) => {} + (Err(r), Some(w)) if *r == w => {} + _ => panic!("layout case {} does not reach the outcome it was written to have ({:?}): {:?}", c.name, c.refuse, got), + } + let mut o = Map::new(); + o.insert("name".into(), json!(c.name)); + o.insert("about".into(), json!(c.about)); + o.insert("params".into(), params_json(&c.params)); + o.insert( + "entrants".into(), + Value::Array( + c.entrants + .iter() + .map(|x| { + json!({ + "principal": hex(&x.principal), + "join": x.join, + "video": x.video.map_or(Value::Null, |(w, h)| json!([w, h])), + "audio": x.audio, + "attrs": x.attrs.iter().map(|(k, v)| json!([k, v])).collect::>(), + }) + }) + .collect(), + ), + ); + o.extend(layout_outcome(&got)); + Value::Object(o) +} + +fn layout_outcome(got: &Result) -> Map { + let mut o = Map::new(); + match got { + Ok(l) => { + o.insert("outcome".into(), json!("layout")); + layout_fields(l, &mut o); + } + Err(r) => refusal(&mut o, *r, None), + } + o +} + +fn entrants_of(v: &Value) -> Option> { + v.as_array()? + .iter() + .map(|x| { + let video = match &x["video"] { + Value::Null => None, + w => Some((u32::try_from(w[0].as_u64()?).ok()?, u32::try_from(w[1].as_u64()?).ok()?)), + }; + let attrs = x["attrs"].as_array()?.iter().map(|kv| Some((kv[0].as_str()?.to_string(), kv[1].as_str()?.to_string()))).collect::>>()?; + Some(E { principal: d32(x["principal"].as_str()?)?, join: u32::try_from(x["join"].as_u64()?).ok()?, video, audio: x["audio"].as_bool()?, attrs }) + }) + .collect() +} + +// --------------------------------------------------------------------------------------- +// §6 Mix cases +// --------------------------------------------------------------------------------------- + +/// `n` samples of SHA-256 output under `label`, scaled down by `shift` bits. +fn pcm(label: &str, n: usize, shift: u32) -> Vec { + let mut out = Vec::with_capacity(n); + let mut j = 0u32; + while out.len() < n { + for c in sha256(&[b"wai:live-compose/corpus/pcm\x00", label.as_bytes(), &j.to_le_bytes()]).chunks(2) { + out.push(i16::from_le_bytes([c[0], c[1]]) >> shift); + } + j += 1; + } + out.truncate(n); + out +} + +fn pcm_hex(s: &[i16]) -> String { + hex(&s.iter().flat_map(|x| x.to_le_bytes()).collect::>()) +} + +fn pcm_of(h: &str) -> Option> { + let b = unhex(h)?; + if !b.len().is_multiple_of(2) { + return None; + } + Some(b.chunks(2).map(|c| i16::from_le_bytes([c[0], c[1]])).collect()) +} + +#[derive(Clone)] +struct V { + channels: u8, + gain: u32, + pan: i32, + pcm: Vec, +} + +struct MixCase { + name: &'static str, + about: &'static str, + channels: u8, + frames: usize, + inputs: Vec, + refuse: bool, +} + +fn mix_cases() -> Vec { + const F: usize = 16; + let u = layout::UNITY_GAIN; + let mono = |label: &str, shift: u32| pcm(label, F, shift); + let stereo = |label: &str, shift: u32| pcm(label, 2 * F, shift); + let v = |channels: u8, gain: u32, pan: i32, pcm: Vec| V { channels, gain, pan, pcm }; + let ok = |name, about, channels, inputs| MixCase { name, about, channels, frames: F, inputs, refuse: false }; + let no = |name, about, channels, inputs| MixCase { name, about, channels, frames: F, inputs, refuse: true }; + let extremes: Vec = [i16::MIN, -1, 0, 1, i16::MAX, -12345, 12345, 2, -2, 3, -3, 100, -100, 32000, -32000, 7].to_vec(); + vec![ + ok("unity_mono", "one mono voice at unity gain into mono: its samples unchanged, the extremes among them (§6)", 1, vec![v(1, u, 0, extremes.clone())]), + ok("unity_mono_to_stereo", "the same voice at the centre into stereo: both channels equal it (§6)", 2, vec![v(1, u, 0, extremes.clone())]), + ok("unity_stereo", "one stereo voice at unity gain and the centre into stereo: unchanged (§6)", 2, vec![v(2, u, 0, stereo("stereo_a", 0))]), + ok("stereo_to_mono", "a stereo voice into mono: half the sum of its channels, rounded half up (§6)", 1, vec![v(2, u, 0, stereo("stereo_a", 0))]), + ok("sum_saturates_high", "two loud voices whose sum passes 32767: saturated once, at the end (§6)", 1, vec![v(1, u, 0, vec![30_000; F]), v(1, u, 0, vec![12_000; F])]), + ok("sum_saturates_low", "two loud negative voices whose sum passes -32768 (§6)", 2, vec![v(1, u, 0, vec![-30_000; F]), v(2, u, 0, vec![-12_000; 2 * F])]), + ok("saturation_is_last", "+30000, +30000 and -30000: the exact sum 30000, with no saturation along the way (§6)", 1, vec![v(1, u, 0, vec![30_000; F]), v(1, u, 0, vec![30_000; F]), v(1, u, 0, vec![-30_000; F])]), + ok("pan_hard_left", "a mono voice panned -4096: all in the left channel (§6)", 2, vec![v(1, u, -4096, mono("mono_a", 0))]), + ok("pan_hard_right", "a mono voice panned 4096: all in the right channel (§6)", 2, vec![v(1, u, 4096, mono("mono_a", 0))]), + ok("pan_part_right", "a mono voice panned 1365: the left channel attenuated, rounded half up (§6)", 2, vec![v(1, u, 1365, mono("mono_a", 0))]), + ok("pan_stereo_balance", "a stereo voice panned -2048: its right channel at half (§6)", 2, vec![v(2, u, -2048, stereo("stereo_b", 0))]), + ok("gain_zero", "a voice at gain 0 beside one at unity: muted (§6)", 2, vec![v(1, 0, 0, mono("mono_a", 0)), v(1, u, 0, mono("mono_b", 2))]), + ok("gain_four", "a quiet voice at gain 16384, four times, saturating where it passes the range (§6)", 1, vec![v(1, layout::MAX_GAIN, 0, mono("mono_c", 1))]), + ok("half_gain_ties", "odd samples at gain 2048: each half is a tie, rounded up (§6)", 1, vec![v(1, 2048, 0, vec![1, -1, 3, -3, 5, -5, 7, -7, 32767, -32767, 9, -9, 11, -11, 13, -13])]), + ok("three_voices", "three voices of both widths, three gains and three pans (§6)", 2, vec![v(1, 3000, -1000, mono("mono_a", 2)), v(2, 5000, 700, stereo("stereo_b", 2)), v(1, 4096, 0, mono("mono_d", 2))]), + ok("silence", "no voice: silence (§6)", 2, vec![]), + no("short_input", "a voice one sample short of its block (§6)", 1, vec![v(1, u, 0, pcm("mono_a", F - 1, 0))]), + no("output_channels", "a mix into three channels (§6)", 3, vec![v(1, u, 0, mono("mono_a", 0))]), + no("input_channels", "a voice of zero channels (§6)", 1, vec![v(0, u, 0, vec![])]), + no("gain_over", "a voice at gain 16385 (§6)", 1, vec![v(1, 16_385, 0, mono("mono_a", 0))]), + no("pan_over", "a voice panned 4097 (§6)", 2, vec![v(1, u, 4097, mono("mono_a", 0))]), + ] +} + +fn run_mix(channels: u8, frames: usize, vs: &[V]) -> Result, Reason> { + let inputs: Vec = vs.iter().map(|x| Input { channels: x.channels, gain: x.gain, pan: x.pan, pcm: &x.pcm }).collect(); + layout::mix(channels, frames, &inputs).map_err(Reason::from) +} + +fn mix_outcome(got: &Result, Reason>) -> Map { + let mut o = Map::new(); + match got { + Ok(p) => { + o.insert("outcome".into(), json!("mix")); + o.insert("pcm".into(), json!(pcm_hex(p))); + } + Err(r) => refusal(&mut o, *r, None), + } + o +} + +fn mix_case_json(c: &MixCase) -> Value { + let got = run_mix(c.channels, c.frames, &c.inputs); + assert_eq!(got.is_err(), c.refuse, "mix case {} does not reach the outcome it was written to have", c.name); + let mut o = Map::new(); + o.insert("name".into(), json!(c.name)); + o.insert("about".into(), json!(c.about)); + o.insert("channels".into(), json!(c.channels)); + o.insert("frames".into(), json!(c.frames)); + o.insert( + "inputs".into(), + Value::Array(c.inputs.iter().map(|x| json!({"channels": x.channels, "gain": x.gain, "pan": x.pan, "pcm": pcm_hex(&x.pcm)})).collect()), + ); + o.extend(mix_outcome(&got)); + Value::Object(o) +} + +fn inputs_of(v: &Value) -> Option> { + v.as_array()? + .iter() + .map(|x| { + Some(V { + channels: u8::try_from(x["channels"].as_u64()?).ok()?, + gain: u32::try_from(x["gain"].as_u64()?).ok()?, + pan: i32::try_from(x["pan"].as_i64()?).ok()?, + pcm: pcm_of(x["pcm"].as_str()?)?, + }) + }) + .collect() +} + +// --------------------------------------------------------------------------------------- +// The room +// --------------------------------------------------------------------------------------- + +fn role(name: &str, publish: u8, subscribe: bool, max_layer: u8, powers: u8, events: &[u8]) -> Role { + Role { name: name.into(), caps: Caps { publish, subscribe, max_layer, powers }, events: bits(events) } +} + +const A: u8 = 1; +const VID: u8 = 2; +const SC: u8 = 4; + +fn roles() -> Vec { + use kind::*; + vec![ + role("director", A | VID, true, 2, power::DIRECT | power::COMPOSE, &[CHAT, CONTROL]), + role("performer", A | VID, true, 2, 0, &[CHAT, REACTION]), + role("guest", A | VID | SC, true, 1, 0, &[CHAT]), + role("device", SC, false, 0, 0, &[]), + role("encoder", VID, false, 0, 0, &[]), + role("mixer", A | VID, true, 2, power::COMPOSE, &[]), + role("audience", 0, true, 1, 0, &[CHAT]), + ] +} + +/// A staged profile of the room's own: a base at 960 × 540 and one refinement to 1080p. +fn stage_profile() -> Profile { + Profile { + name: "stage".into(), + media: media::VIDEO, + codecs: vec!["av01.0.08M.08".into()], + layering: layering::STAGED, + mode: String::new(), + layers: vec![ + Layer { width: 960, height: 540, fps: 30, min_kbps: 500, max_kbps: 1500 }, + Layer { width: 1920, height: 1080, fps: 30, min_kbps: 1500, max_kbps: 4000 }, + ], + sample_rate: 0, + channels: 0, + processing: 0, + } +} + +/// How a vector's room differs from the studio. +#[derive(Clone, Copy, PartialEq, Eq)] +enum Variant { + Studio, + /// The guest's first grant states its order as `third`. + BadOrder, + /// The relay's `unpublish` at 6 s is not delivered. + LifecycleGap, + /// The viewer's first chat is not delivered. + ViewerGap, + /// The viewer sends a `control`, which its grant does not permit. + Refused, +} + +const ROOMS: [(&str, Variant); 5] = [ + ("studio", Variant::Studio), + ("studio_bad_order", Variant::BadOrder), + ("studio_lifecycle_gap", Variant::LifecycleGap), + ("studio_viewer_gap", Variant::ViewerGap), + ("studio_refused", Variant::Refused), +]; + +struct Author { + who: u8, + seq: u64, + prev: [u8; 32], + records: Vec>, +} + +struct Chains { + room: [u8; 32], + authors: Vec, +} + +impl Chains { + fn emit(&mut self, who: u8, t: u64, p: &Payload) { + let room = self.room; + let a = match self.authors.iter().position(|a| a.who == who) { + Some(i) => &mut self.authors[i], + None => { + self.authors.push(Author { who, seq: 0, prev: [0; 32], records: vec![] }); + self.authors.last_mut().expect("just pushed") + } + }; + let ev = Event::sign(&key(who), room, a.seq, a.prev, t, None, p.kind(), p.encode()); + a.seq += 1; + a.prev = ev.digest(); + a.records.push(ev.to_bytes()); + } + + fn life(&mut self, t: u64, subject: u8, d: Detail) { + self.emit(RELAY, t, &Payload::Lifecycle { kind: d.kind(), subject: pk(subject), detail: d.encode() }); + } +} + +/// A room written out: what live-rooms §9 is given. +struct Written { + descriptor: Vec, + grants: Vec>, + chains: Vec>>, + id: [u8; 32], +} + +impl Written { + fn input(&self) -> RoomInput<'_> { + RoomInput { descriptor: &self.descriptor, grants: &self.grants, head: None, chains: &self.chains } + } +} + +fn studio(v: Variant) -> Written { + let d = Descriptor { + authority: pk(AUTHORITY), + clock: pk(RELAY), + t0_us: T0_US, + tick_us: S, + origin: String::new(), + limits: Limits { max_present: 16, max_publishers: 8, reval_s: 300, ceiling: Policy::default() }, + roles: roles(), + slots: vec![Slot { name: "main".into(), media: media::VIDEO, redundancy: 1, failover_ms: 0 }], + profiles: ["speech", "music", "camera-720", "camera-1080", "screen"] + .iter() + .map(|n| registered_profile(n).expect("registered")) + .chain([stage_profile()]) + .collect(), + review: Review { kinds: [0; 32], deadline_ms: 0, fallback: 0 }, + recording: Recording { mode: 0, retention_days: 0, commit_interval_ms: 0, jitter_ms: 0, regions: vec![] }, + sig: [0; 64], + } + .sign(&key(AUTHORITY)); + let id = d.room_id(); + let grant = |who: u8, role: usize, profiles: Vec, kv: &[(&str, &str)]| { + let r = &d.roles[role]; + Grant { + room: id, + principal: pk(who), + prev: [0; 32], + effective: 0, + nbf: T0_S - 3_600, + exp: T0_S + 86_400, + role: role as u8, + caps: r.caps, + precedence: 0, + once: [0; 16], + viewer: [0; 16], + policy: Policy::with_kinds(&kinds_of(&r.events)), + joules_ceiling: NO_CEILING, + funds_ceiling: NO_CEILING, + currency: [0; 3], + profiles, + origins: vec![], + attrs: attrs(kv), + sig: [0; 64], + } + }; + let sign = |g: Grant| g.sign(&key(AUTHORITY)); + let gd = sign(grant(DIRECTOR, 0, vec![0, 2], &[("order", "2"), ("pip", "true")])); + let gp = sign(grant(PERFORMER, 1, vec![1, 3], &[("featured", "true"), ("gain", "5120"), ("order", "1")])); + let guest_order = if v == Variant::BadOrder { "third" } else { "3" }; + let gg = sign(grant(GUEST, 2, vec![0, 2, 4], &[("order", guest_order)])); + let gg2 = sign(Grant { prev: gg.digest(), effective: 5 * S, ..grant(GUEST, 2, vec![0, 2, 4], &[("gain", "2048"), ("order", "0"), ("pan", "-2048")]) }); + let gs = sign(grant(SCREEN, 3, vec![4], &[("order", "4")])); + let ge = sign(grant(ENCODER, 4, vec![5], &[("order", "5")])); + let gm = sign(grant(MIXER, 5, vec![1, 3], &[])); + let gv = sign(grant(VIEWER, 6, vec![], &[])); + let grants = [&gd, &gp, &gg, &gg2, &gs, &ge, &gm, &gv].iter().map(|g| g.to_bytes()).collect(); + let own = |m: u8, profile: u8, layers: u8| Detail::Publish { slot: String::new(), media: m, profile, layers }; + let mut c = Chains { room: id, authors: vec![] }; + c.life(0, DIRECTOR, Detail::Join { grant: gd.digest() }); + c.life(0, PERFORMER, Detail::Join { grant: gp.digest() }); + c.life(0, MIXER, Detail::Join { grant: gm.digest() }); + c.life(0, VIEWER, Detail::Join { grant: gv.digest() }); + c.life(S, PERFORMER, own(media::AUDIO, 1, 1)); + c.life(S, PERFORMER, own(media::VIDEO, 3, 3)); + c.life(S, DIRECTOR, own(media::AUDIO, 0, 1)); + c.life(S, DIRECTOR, own(media::VIDEO, 2, 2)); + c.life(2 * S, MIXER, own(media::VIDEO, 3, 3)); + c.life(2 * S, MIXER, own(media::AUDIO, 1, 1)); + c.emit(VIEWER, 2_500 * MS, &Payload::Chat { text: "hello".into() }); + c.life(3 * S, GUEST, Detail::Join { grant: gg.digest() }); + c.life(3 * S, GUEST, own(media::AUDIO, 0, 1)); + c.emit(VIEWER, 3_500 * MS, &Payload::Chat { text: "welcome".into() }); + c.life(4 * S, SCREEN, Detail::Join { grant: gs.digest() }); + c.life(4 * S, SCREEN, own(media::SCREEN, 4, 1)); + c.life(4 * S, ENCODER, Detail::Join { grant: ge.digest() }); + c.life(4 * S, ENCODER, Detail::Publish { slot: "main".into(), media: media::VIDEO, profile: 5, layers: 2 }); + c.life(5 * S, GUEST, Detail::GrantExchange { old: gg.digest(), new: gg2.digest() }); + c.life(6 * S, DIRECTOR, Detail::Unpublish { slot: String::new(), media: media::VIDEO }); + c.life(7 * S, GUEST, own(media::VIDEO, 2, 1)); + if v == Variant::Refused { + c.emit(VIEWER, 7_500 * MS, &Payload::Control { target: pk(GUEST), command: Command::Mute { on: true } }); + } + c.life(8 * S, PERFORMER, Detail::Leave { reason: room::leave::LEFT }); + let mut chains: Vec>> = c.authors.into_iter().map(|a| a.records).collect(); + match v { + // The relay's chain is chains[0], the first written; its one record at 6 s is the + // director's unpublish. + Variant::LifecycleGap => { + let at = chains[0].iter().position(|r| Event::parse(r).is_ok_and(|e| e.t == 6 * S)).expect("the unpublish"); + chains[0].remove(at); + } + Variant::ViewerGap => { + chains[1].remove(0); + } + _ => {} + } + Written { descriptor: d.to_bytes(), grants, chains, id } +} + +fn room_json(w: &Written) -> Value { + json!({ + "descriptor": hex(&w.descriptor), + "grants": w.grants.iter().map(|g| hex(g)).collect::>(), + "key_log_head": Value::Null, + "chains": w.chains.iter().map(|c| c.iter().map(|r| hex(r)).collect::>()).collect::>(), + }) +} + +struct Room { + descriptor: Vec, + grants: Vec>, + head: Option, + chains: Vec>>, +} + +impl Room { + fn input(&self) -> RoomInput<'_> { + RoomInput { descriptor: &self.descriptor, grants: &self.grants, head: self.head.as_deref(), chains: &self.chains } + } +} + +fn room_of(v: &Value) -> Option { + Some(Room { + descriptor: unhex(v["descriptor"].as_str()?)?, + grants: v["grants"].as_array()?.iter().map(|g| g.as_str().and_then(unhex)).collect::>()?, + head: v["key_log_head"].as_str().map(String::from), + chains: v["chains"] + .as_array()? + .iter() + .map(|c| c.as_array().and_then(|rs| rs.iter().map(|r| r.as_str().and_then(unhex)).collect::>>())) + .collect::>()?, + }) +} + +// --------------------------------------------------------------------------------------- +// §3 Descriptor cases +// --------------------------------------------------------------------------------------- + +#[allow(clippy::too_many_arguments)] +fn compose(room_id: [u8; 32], signer: u8, effective: u64, compositor: Option, layer: u8, params: Params) -> Compose { + Compose { room: room_id, signer: pk(signer), effective, compositor: compositor.map_or(NO_COMPOSITOR, pk), background: [16, 16, 24], layer, params, sig: [0; 64] }.sign(&key(signer)) +} + +/// A body changed by `f`, signed by `who` over its new bytes. +fn patched(c: &Compose, who: u8, f: impl Fn(&mut Vec)) -> Vec { + let mut b = c.body(); + f(&mut b); + let mut m = DESCRIPTOR_DOMAIN.to_vec(); + m.extend_from_slice(&b); + let sig = key(who).sign(&m).to_bytes(); + b.extend_from_slice(&sig); + b +} + +/// The offset of `omit_stopped` in a descriptor (§3.1). +fn omit_offset(p: &Params) -> usize { + 123 + 1 + p.featured_attr.len() + 1 + p.order_attr.len() +} + +fn fields_json(c: &Compose) -> Value { + let mut o = Map::new(); + o.insert("room".into(), json!(hex(&c.room))); + o.insert("signer".into(), json!(hex(&c.signer))); + o.insert("effective".into(), json!(c.effective)); + o.insert("compositor".into(), json!(hex(&c.compositor))); + o.insert("background".into(), json!(hex(&c.background))); + o.insert("layer".into(), json!(c.layer)); + if let Value::Object(p) = params_json(&c.params) { + o.extend(p); + } + Value::Object(o) +} + +fn descriptor_outcome(got: &Result) -> Map { + let mut o = Map::new(); + match got { + Ok(c) => { + o.insert("outcome".into(), json!("read")); + o.insert("digest".into(), json!(hex(&c.digest()))); + o.insert("fields".into(), fields_json(c)); + } + Err(r) => refusal(&mut o, *r, None), + } + o +} + +fn descriptor_cases(room_id: [u8; 32]) -> Vec<(&'static str, String, Vec, Option)> { + let g = grid_params(); + let grid = compose(room_id, DIRECTOR, S, Some(MIXER), 2, g.clone()); + let mk = |p: Params| compose(room_id, DIRECTOR, S, Some(MIXER), 2, p).to_bytes(); + let canvas = Some(Reason::CanvasOutOfRange); + let invalid = Some(Reason::ComposeInvalid); + let pip = pip_params(); + let mut sig = grid.to_bytes(); + let n = sig.len(); + sig[n - 20] ^= 0x04; + let mut identity = compose(room_id, DIRECTOR, S, Some(MIXER), 2, g.clone()); + identity.signer = crate::sig::IDENTITY; + let mut trailing = grid.to_bytes(); + trailing.push(0); + let mut magic = grid.to_bytes(); + magic[3] = b'2'; + let mut version = grid.to_bytes(); + version[4] = 2; + vec![ + ("grid", "the room's grid descriptor (§3.1)".into(), grid.to_bytes(), None), + ("pip", "the room's picture-in-picture descriptor (§3.1)".into(), compose(room_id, AUTHORITY, 0, Some(MIXER), 1, pip.clone()).to_bytes(), None), + ("client_only", "a grid with no compositor: composed by each sink alone (§3.1, §7)".into(), compose(room_id, AUTHORITY, 0, None, 2, g.clone()).to_bytes(), None), + ("largest_canvas", "1920 × 1080 at 60 fps, gap 0, 64 tiles: the canvas at its limits (§3.4)".into(), mk(Params { fps: 60, gap: 0, max_tiles: 64, max_voices: 64, ..g.clone() }), None), + ("portrait_canvas", "1080 × 1920 and 1440 × 1440 hold as many pixels as 1920 × 1080 (§3.4)".into(), mk(Params { width: 1080, height: 1920, ..g.clone() }), None), + ("square_canvas", "1440 × 1440 (§3.4)".into(), mk(Params { width: 1440, height: 1440, ..g.clone() }), None), + ("smallest_canvas", "16 × 16 at 1 fps with one tile (§3.4)".into(), mk(Params { width: 16, height: 16, fps: 1, gap: 0, max_tiles: 1, ..g.clone() }), None), + ("canvas_too_wide", "a canvas 1922 pixels wide (§3.4)".into(), mk(Params { width: 1922, height: 720, ..g.clone() }), canvas), + ("canvas_too_many_pixels", "1920 × 1082: each edge within 1920, more pixels than 1920 × 1080 (§3.4)".into(), mk(Params { height: 1082, ..g.clone() }), canvas), + ("canvas_odd", "a canvas 1279 pixels wide (§3.4)".into(), mk(Params { width: 1279, height: 720, ..g.clone() }), canvas), + ("canvas_too_small", "a canvas 14 pixels high (§3.4)".into(), mk(Params { height: 14, max_tiles: 1, ..g.clone() }), canvas), + ("fps_zero", "a frame rate of 0 (§3.4)".into(), mk(Params { fps: 0, ..g.clone() }), canvas), + ("fps_61", "a frame rate of 61 (§3.4)".into(), mk(Params { fps: 61, ..g.clone() }), canvas), + ("canvas_before_fields", "a canvas 1922 wide and an aspect of 4: the canvas is checked first (§3.3)".into(), mk(Params { width: 1922, height: 720, aspect: 4, ..g.clone() }), canvas), + ("layout_unknown", "a layout of 3 (§3.3)".into(), mk(Params { layout: 3, ..g.clone() }), invalid), + ("aspect_unknown", "an aspect of 4 (§3.3)".into(), mk(Params { aspect: 4, ..g.clone() }), invalid), + ("fill_unknown", "a fill of 4 (§3.3)".into(), mk(Params { fill: 4, ..g.clone() }), invalid), + ("omit_two", "omit_stopped 2 (§3.3)".into(), patched(&grid, DIRECTOR, |b| b[omit_offset(&g)] = 2), invalid), + ("attr_key_capital", "a featured attribute key `Featured` (§3.3)".into(), mk(Params { featured_attr: "Featured".into(), ..g.clone() }), invalid), + ("attr_key_too_long", "an order attribute key of 33 bytes (§3.3)".into(), mk(Params { order_attr: "o".repeat(33), ..g.clone() }), invalid), + ("grid_with_corner", "a grid with a PiP corner (§3.3)".into(), mk(Params { corner: corner::TOP_LEFT, ..g.clone() }), invalid), + ("pip_without_corner", "a PiP layout with corner 0 (§3.3)".into(), mk(Params { corner: 0, ..pip.clone() }), invalid), + ("pip_without_behaviour", "a PiP layout with behaviour 3 (§3.3)".into(), mk(Params { behaviour: 3, ..pip.clone() }), invalid), + ("pip_too_wide", "a PiP window 1900 wide 24 pixels from the edge of a 1920 canvas (§3.3)".into(), mk(Params { pip_width: 1900, ..pip.clone() }), invalid), + ("pip_offset_too_large", "a PiP offset of 1080 on a 1080-high canvas (§3.3)".into(), mk(Params { offset: 1080, pip_width: 0, pip_height: 0, ..pip.clone() }), invalid), + ("channels_three", "a mix of three channels (§3.3)".into(), mk(Params { channels: 3, ..g.clone() }), invalid), + ("sample_rate_low", "a sample rate of 4000 Hz (§3.3)".into(), mk(Params { sample_rate: 4_000, ..g.clone() }), invalid), + ("max_tiles_zero", "at most 0 tiles (§3.3)".into(), mk(Params { max_tiles: 0, ..g.clone() }), invalid), + ("max_voices_65", "at most 65 voices (§3.3)".into(), mk(Params { max_voices: 65, ..g.clone() }), invalid), + ("gap_too_large", "a 300-pixel gap with twelve tiles: the band under a featured tile cannot hold four rows (§3.3)".into(), mk(Params { gap: 300, ..g.clone() }), invalid), + ("gap_fits", "a 60-pixel gap with twelve tiles: the band still holds four rows of a pixel (§3.3)".into(), mk(Params { gap: 60, ..g.clone() }), None), + ("truncated", "the grid descriptor less its last byte (§3.3)".into(), grid.to_bytes()[..n - 1].to_vec(), Some(TRUNCATED)), + ("magic", "magic WCD2 (§3.3)".into(), magic, Some(MALFORMED)), + ("version", "version 2 (§3.3)".into(), version, Some(UNKNOWN_VERSION)), + ("trailing", "a byte after the signature (§3.3)".into(), trailing, Some(MALFORMED)), + ("bad_signature", "one bit of the signature flipped (§3.2)".into(), sig, Some(events::Reason::BadSignature.into())), + ("bad_key", "the identity point as the signer, a key of small order (§3.2)".into(), identity.to_bytes(), Some(events::Reason::BadKey.into())), + ] +} + +// --------------------------------------------------------------------------------------- +// §9 Composition cases +// --------------------------------------------------------------------------------------- + +struct CompCase { + name: &'static str, + about: &'static str, + room: &'static str, + descriptor: Vec, + instants: Vec, + /// The refusal it is written to have, or none. + refuse: Option, +} + +fn written(name: &str) -> Written { + studio(ROOMS.iter().find(|(n, _)| *n == name).expect("a room").1) +} + +fn composition_cases() -> Vec { + let id = written("studio").id; + let g = grid_params(); + let grid = compose(id, DIRECTOR, S, Some(MIXER), 2, g.clone()).to_bytes(); + let pip = compose(id, AUTHORITY, 0, Some(MIXER), 1, pip_params()).to_bytes(); + let every: Vec = (1..=9).map(|k| k * S).collect(); + let mut flipped = grid.clone(); + let n = flipped.len(); + flipped[n - 1] ^= 0x01; + let c = |name, about, room, descriptor, instants, refuse| CompCase { name, about, room, descriptor, instants, refuse }; + vec![ + c("grid_session", "the grid over the whole session, at every second from 1 s to 9 s: publishes, a stopped video, a screen, a slot, a grant exchange that reorders, a video stopped and one started, a leave (§4, §5, §5.8)", "studio", grid.clone(), every.clone(), None), + c("pip_session", "picture in picture over the session, stopped video omitted, sources read at layer 1 (§4.2, §5.5)", "studio", pip.clone(), vec![0, S, 3 * S, 6 * S, 7 * S, 8 * S], None), + c("participant_gap", "a gap in the viewer's chat chain does not stop composition: the lifecycle is whole (§4.1)", "studio_viewer_gap", grid.clone(), vec![3 * S, 5 * S], None), + c("signer_without_power", "a grid signed by the performer, whose grant has no compose power (§3.5)", "studio", compose(id, PERFORMER, S, Some(MIXER), 2, g.clone()).to_bytes(), every.clone(), Some(Reason::ComposeNotPermitted)), + c("signer_not_present", "a grid signed by a key that is not in the room (§3.5)", "studio", compose(id, IMPOSTOR, S, Some(MIXER), 2, g.clone()).to_bytes(), every.clone(), Some(Reason::ComposeNotPermitted)), + c("signer_with_power", "a grid signed by the mixer, effective at 0 s: a principal whose grant in effect has the compose power may sign, not only the authority (§3.5)", "studio", compose(id, MIXER, 0, Some(MIXER), 2, g.clone()).to_bytes(), vec![S, 4 * S], None), + c("descriptor_wrong_room", "a grid of another room (§3.5)", "studio", compose([7; 32], DIRECTOR, S, Some(MIXER), 2, g.clone()).to_bytes(), every.clone(), Some(WRONG_ROOM)), + c("descriptor_bad_signature", "the grid with a bit of its signature flipped (§3.2)", "studio", flipped, every.clone(), Some(events::Reason::BadSignature.into())), + c("before_effective", "the grid asked for at 0.5 s, before its effective instant of 1 s (§3.1, §4)", "studio", grid.clone(), vec![S, 500 * MS], Some(Reason::NotYetEffective)), + c("attr_malformed", "the guest's grant states its order as `third`: the grid holds until the guest joins at 3 s (§4.3)", "studio_bad_order", grid.clone(), vec![S, 2 * S, 3 * S], Some(Reason::AttrMalformed)), + c("lifecycle_incomplete", "the relay's unpublish at 6 s not delivered: the room is a gap in a room key's chain (§4.1)", "studio_lifecycle_gap", grid.clone(), vec![S], Some(Reason::LifecycleIncomplete)), + c("room_refused", "the viewer sends a control its grant does not permit: the room is refused, and with it the composition (§9 step 1)", "studio_refused", grid.clone(), vec![S], Some(events::Reason::KindNotPermitted.into())), + ] +} + +fn composition_outcome(out: &(ComposeOutcome, Option<[u8; 32]>), room_id: &[u8; 32]) -> Map { + let mut o = Map::new(); + match &out.0 { + ComposeOutcome::Frames(fs) => { + o.insert("outcome".into(), json!("compose")); + o.insert("digest".into(), json!(hex(&out.1.expect("a descriptor that read")))); + o.insert("frames".into(), Value::Array(fs.iter().map(|f| frame_json(f, room_id)).collect())); + } + ComposeOutcome::Refuse { at, reason } => refusal(&mut o, *reason, Some(at)), + } + o +} + +fn room_id_of(r: &Room) -> [u8; 32] { + Descriptor::parse(&r.descriptor).map(|d| d.room_id()).unwrap_or([0; 32]) +} + +// --------------------------------------------------------------------------------------- +// §8 Receipt cases +// --------------------------------------------------------------------------------------- + +struct ReceiptCase { + name: &'static str, + about: &'static str, + room: &'static str, + descriptor: Vec, + receipt: Vec, + refuse: Option, +} + +fn object(label: &str, track: [u8; 32], t: u64) -> ObjectRef { + let frame = t / (S / 30); + ObjectRef { track, group: frame / 30, object: frame % 30, digest: sha256(&[b"wai:live-compose/corpus/object\x00", label.as_bytes(), &t.to_le_bytes()]) } +} + +/// The receipt a compositor `who` signs for the composition of `c` at `t` on its own track +/// of `m` at layer `out_layer`, its inputs the ones §8.2 requires. +fn receipt(w: &Written, c: &Compose, who: u8, t: u64, m: u8, out_layer: u8) -> Receipt { + let vr = VerifiedRoom::verify(w.input()).expect("the studio verifies"); + let frame = compose_at(c, &vr, t).expect("a frame"); + let ns = render_namespace(&track_namespace(&w.id, &Owner::Principal(pk(who)), media_name(m).expect("a media kind"))); + let inputs = frame + .inputs(&w.id, m) + .iter() + .map(|(p, tr)| InputRef { principal: *p, object: object(&hex(p), *tr, t) }) + .collect(); + Receipt { + room: w.id, + compositor: pk(who), + descriptor: c.digest(), + t, + state: frame.set_digest, + media: m, + output: object("output", anchor_track(&ns, &track_name(out_layer)), t), + inputs, + sig: [0; 64], + } +} + +fn receipt_cases() -> Vec { + let w = written("studio"); + let id = w.id; + let g = grid_params(); + let grid = compose(id, DIRECTOR, S, Some(MIXER), 2, g.clone()); + let pip = compose(id, AUTHORITY, 0, Some(MIXER), 1, pip_params()); + let client = compose(id, AUTHORITY, 0, None, 2, g.clone()); + let guest_composes = compose(id, DIRECTOR, S, Some(GUEST), 2, g.clone()); + let t = 5 * S; + let video = receipt(&w, &grid, MIXER, t, media::VIDEO, 2); + let audio = receipt(&w, &grid, MIXER, t, media::AUDIO, 0); + let signed = |r: &Receipt| r.clone().sign(&key(MIXER)).to_bytes(); + let mut missing = video.clone(); + missing.inputs.pop(); + let mut reordered = video.clone(); + reordered.inputs.swap(0, 1); + let mut wrong_layer = video.clone(); + let perf = pk(PERFORMER); + let ns = render_namespace(&track_namespace(&id, &Owner::Principal(perf), "video")); + let i = wrong_layer.inputs.iter().position(|x| x.principal == perf).expect("the performer's video"); + wrong_layer.inputs[i].object.track = anchor_track(&ns, &track_name(1)); + let mut stale = video.clone(); + stale.state = receipt(&w, &grid, MIXER, 4 * S, media::VIDEO, 2).state; + let mut other_descriptor = video.clone(); + other_descriptor.descriptor = pip.digest(); + let mut by_director = video.clone(); + by_director.compositor = pk(DIRECTOR); + let by_guest = receipt(&w, &guest_composes, GUEST, 7 * S, media::VIDEO, 0); + let early = receipt(&w, &pip, MIXER, S, media::VIDEO, 2); + let mut out_layer = video.clone(); + out_layer.output.track = anchor_track(&render_namespace(&track_namespace(&id, &Owner::Principal(pk(MIXER)), "video")), &track_name(3)); + let mut media3 = video.clone(); + media3.media = 3; + let mut duplicate = video.clone(); + duplicate.inputs[1] = InputRef { principal: duplicate.inputs[0].principal, object: duplicate.inputs[0].object }; + let mut other_room = video.clone(); + other_room.room = [7; 32]; + let mut flipped = signed(&video); + let n = flipped.len(); + flipped[n - 33] ^= 0x10; + let mut before = video.clone(); + before.t = 500 * MS; + let client_receipt = Receipt { descriptor: client.digest(), ..video.clone() }; + let c = |name, about, descriptor: &Compose, receipt: Vec, refuse| ReceiptCase { name, about, room: "studio", descriptor: descriptor.to_bytes(), receipt, refuse }; + vec![ + c("video", "the mixer's receipt for its composed video at 5 s: every input the layout reads, in drawing order (§8)", &grid, signed(&video), None), + c("audio", "the mixer's receipt for its mix at 5 s: every voice's audio track (§8)", &grid, signed(&audio), None), + c("pip_video", "the mixer's receipt for the picture in picture at 6 s, its sources read at layer 1 (§8)", &pip, signed(&receipt(&w, &pip, MIXER, 6 * S, media::VIDEO, 1)), None), + c("inputs_missing", "the video receipt less its last input (§8.3)", &grid, signed(&missing), Some(Reason::InputsMismatch)), + c("inputs_reordered", "the video receipt with its first two inputs swapped (§8.3)", &grid, signed(&reordered), Some(Reason::InputsMismatch)), + c("inputs_wrong_layer", "the performer's input read from layer 1, where the composition reads layer 2 (§8.2)", &grid, signed(&wrong_layer), Some(Reason::InputsMismatch)), + c("state_stale", "the video receipt at 5 s naming the set of 4 s, before the guest's exchange (§8.3)", &grid, signed(&stale), Some(Reason::StateMismatch)), + c("descriptor_mismatch", "the video receipt naming the picture-in-picture descriptor while checked against the grid's (§8.3)", &grid, signed(&other_descriptor), Some(Reason::DescriptorMismatch)), + c("compositor_not_named", "the video receipt signed by the director, which the descriptor does not name as its compositor (§8.3)", &grid, by_director.clone().sign(&key(DIRECTOR)).to_bytes(), Some(Reason::CompositorNotPermitted)), + c("compositor_without_power", "a descriptor naming the guest as its compositor, and the guest's receipt at 7 s: its grant has no compose power (§7, §8.3)", &guest_composes, by_guest.sign(&key(GUEST)).to_bytes(), Some(Reason::CompositorNotPermitted)), + c("client_only", "a receipt against a descriptor that names no compositor (§7)", &client, signed(&client_receipt), Some(Reason::CompositorNotPermitted)), + c("output_not_yet_published", "the mixer's picture-in-picture receipt at 1 s: it publishes its video from 2 s (§8.3)", &pip, signed(&early), Some(Reason::OutputNotPublished)), + c("output_wrong_layer", "an output on layer 3 of a video the mixer publishes in three layers, 0 to 2 (§8.3)", &grid, signed(&out_layer), Some(Reason::OutputNotPublished)), + c("before_effective", "a receipt at 0.5 s, before the grid's effective instant (§8.3)", &grid, signed(&before), Some(Reason::NotYetEffective)), + c("media_invalid", "a receipt of media 3 (§8.1)", &grid, signed(&media3), Some(Reason::ReceiptInvalid)), + c("duplicate_input", "a receipt naming one input twice (§8.1)", &grid, signed(&duplicate), Some(Reason::ReceiptInvalid)), + c("wrong_room", "a receipt of another room (§8.3)", &grid, signed(&other_room), Some(WRONG_ROOM)), + c("bad_signature", "one bit of the video receipt's signature flipped (§8.1)", &grid, flipped, Some(events::Reason::BadSignature.into())), + c("truncated", "the video receipt less its last byte (§8.1)", &grid, signed(&video)[..n - 1].to_vec(), Some(TRUNCATED)), + ] +} + +fn receipt_outcome(out: &ReceiptOutcome) -> Map { + let mut o = Map::new(); + match out { + ReceiptOutcome::Accept { digest, frame } => { + o.insert("outcome".into(), json!("accept")); + o.insert("digest".into(), json!(hex(digest))); + o.insert("set_digest".into(), json!(hex(&frame.set_digest))); + } + ReceiptOutcome::Refuse { at, reason } => refusal(&mut o, *reason, Some(at)), + } + o +} + +// --------------------------------------------------------------------------------------- +// The file +// --------------------------------------------------------------------------------------- + +/// The corpus file, `vectors.json`. +pub fn generate() -> String { + let studio_id = written("studio").id; + let mut rooms = Map::new(); + for (name, v) in ROOMS { + rooms.insert(name.into(), room_json(&studio(v))); + } + let descriptors: Vec = descriptor_cases(studio_id) + .into_iter() + .map(|(name, about, bytes, want)| { + let got = Compose::parse(&bytes); + assert_eq!(got.as_ref().err().copied(), want, "descriptor case {name} does not reach the outcome it was written to have"); + let mut o = Map::new(); + o.insert("name".into(), json!(name)); + o.insert("about".into(), json!(about)); + o.insert("bytes".into(), json!(hex(&bytes))); + o.extend(descriptor_outcome(&got)); + Value::Object(o) + }) + .collect(); + let compositions: Vec = composition_cases() + .into_iter() + .map(|c| { + let w = written(c.room); + let out = verify_composition(w.input(), &c.descriptor, &c.instants); + let reached = match (&out.0, c.refuse) { + (ComposeOutcome::Frames(_), None) => true, + (ComposeOutcome::Refuse { reason, .. }, Some(want)) => *reason == want, + _ => false, + }; + assert!(reached, "composition case {} does not reach the outcome it was written to have ({:?}): {:?}", c.name, c.refuse, out.0); + let mut o = Map::new(); + o.insert("name".into(), json!(c.name)); + o.insert("about".into(), json!(c.about)); + o.insert("room".into(), json!(c.room)); + o.insert("descriptor".into(), json!(hex(&c.descriptor))); + o.insert("instants".into(), json!(c.instants)); + o.extend(composition_outcome(&out, &w.id)); + Value::Object(o) + }) + .collect(); + let receipts: Vec = receipt_cases() + .into_iter() + .map(|c| { + let w = written(c.room); + let out = verify_receipt(w.input(), &c.descriptor, &c.receipt); + let reached = match (&out, c.refuse) { + (ReceiptOutcome::Accept { .. }, None) => true, + (ReceiptOutcome::Refuse { reason, .. }, Some(want)) => *reason == want, + _ => false, + }; + assert!(reached, "receipt case {} does not reach the outcome it was written to have ({:?}): {:?}", c.name, c.refuse, out); + let mut o = Map::new(); + o.insert("name".into(), json!(c.name)); + o.insert("about".into(), json!(c.about)); + o.insert("room".into(), json!(c.room)); + o.insert("descriptor".into(), json!(hex(&c.descriptor))); + o.insert("receipt".into(), json!(hex(&c.receipt))); + o.extend(receipt_outcome(&out)); + Value::Object(o) + }) + .collect(); + let doc = json!({ + "corpus": CAPABILITY, + "extension": "extensions/live-compose.md", + "principals": PRINCIPALS.iter().map(|(n, i)| (n.to_string(), json!(hex(&pk(*i))))).collect::>(), + "layouts": layout_cases().iter().map(layout_case_json).collect::>(), + "mixes": mix_cases().iter().map(mix_case_json).collect::>(), + "descriptors": descriptors, + "rooms": rooms, + "compositions": compositions, + "receipts": receipts, + }); + serde_json::to_string_pretty(&doc).expect("the corpus serialises") + "\n" +} + +/// Check a corpus file against this module; the failures, one line each. +pub fn verify(doc: &str) -> Vec { + let mut fails = Vec::new(); + let root: Value = match serde_json::from_str(doc) { + Ok(v) => v, + Err(e) => return vec![format!("the corpus does not parse: {e}")], + }; + let mut check = |section: &str, v: &Value, got: Map| { + let name = v["name"].as_str().unwrap_or("?"); + for (k, want) in got { + if v[&k] != want { + fails.push(format!("{section} {name}: {k} is {want}, the corpus states {}", v[&k])); + } + } + }; + for v in root["layouts"].as_array().into_iter().flatten() { + let got = match (params_of(&v["params"]), entrants_of(&v["entrants"])) { + (Some(p), Some(es)) => layout_outcome(&run_layout(&p, &es)), + _ => Map::from_iter([("outcome".to_string(), json!("unreadable"))]), + }; + check("layout", v, got); + } + for v in root["mixes"].as_array().into_iter().flatten() { + let got = match (v["channels"].as_u64().and_then(|c| u8::try_from(c).ok()), v["frames"].as_u64(), inputs_of(&v["inputs"])) { + (Some(c), Some(f), Some(vs)) => mix_outcome(&run_mix(c, f as usize, &vs)), + _ => Map::from_iter([("outcome".to_string(), json!("unreadable"))]), + }; + check("mix", v, got); + } + for v in root["descriptors"].as_array().into_iter().flatten() { + let got = match v["bytes"].as_str().and_then(unhex) { + Some(b) => descriptor_outcome(&Compose::parse(&b)), + None => Map::from_iter([("outcome".to_string(), json!("unreadable"))]), + }; + check("descriptor", v, got); + } + let rooms: BTreeMap> = root["rooms"].as_object().into_iter().flatten().map(|(k, v)| (k.clone(), room_of(v))).collect(); + for v in root["compositions"].as_array().into_iter().flatten() { + let room = v["room"].as_str().and_then(|r| rooms.get(r)).and_then(Option::as_ref); + let instants: Option> = v["instants"].as_array().and_then(|a| a.iter().map(Value::as_u64).collect()); + let got = match (room, v["descriptor"].as_str().and_then(unhex), instants) { + (Some(r), Some(d), Some(ts)) => composition_outcome(&verify_composition(r.input(), &d, &ts), &room_id_of(r)), + _ => Map::from_iter([("outcome".to_string(), json!("unreadable"))]), + }; + check("composition", v, got); + } + for v in root["receipts"].as_array().into_iter().flatten() { + let room = v["room"].as_str().and_then(|r| rooms.get(r)).and_then(Option::as_ref); + let got = match (room, v["descriptor"].as_str().and_then(unhex), v["receipt"].as_str().and_then(unhex)) { + (Some(r), Some(d), Some(rc)) => receipt_outcome(&verify_receipt(r.input(), &d, &rc)), + _ => Map::from_iter([("outcome".to_string(), json!("unreadable"))]), + }; + check("receipt", v, got); + } + fails +} diff --git a/wai/wai-rs/src/live_compose/layout.rs b/wai/wai-rs/src/live_compose/layout.rs new file mode 100644 index 000000000..73d267ce7 --- /dev/null +++ b/wai/wai-rs/src/live_compose/layout.rs @@ -0,0 +1,748 @@ +//! The layout function and the mixer of live-compose §5 and §6. +//! +//! Both are pure integer functions of their arguments: no floating point, no clock, no +//! I/O, no hashing, and nothing beyond `core`, `Vec` and `String`, so that a later slice +//! can build this file for the browser unchanged. Every division here is of non-negative +//! integers and rounds down; the mixer's one shift of a signed sum is stated where it is +//! made. [`layout`] is §5 over the participants §4 derives from a room; [`mix`] is §6. + +use core::cmp::{max, min, Ordering}; + +/// The longest canvas edge, in pixels (§3.4). +pub const MAX_EDGE: u32 = 1920; +/// The shortest canvas edge, in pixels (§3.4). +pub const MIN_EDGE: u32 = 16; +/// The most pixels a canvas holds (§3.4): 1920 × 1080. +pub const MAX_PIXELS: u32 = 2_073_600; +/// The highest frame rate (§3.4). +pub const MAX_FPS: u8 = 60; +/// The most tiles, and the most voices, a descriptor allows (§3.3). +pub const MAX_COMPOSED: u32 = 64; +/// A gain of one (§6): gains are in units of 1/4096. +pub const UNITY_GAIN: u32 = 4096; +/// The highest gain (§6): four. +pub const MAX_GAIN: u32 = 16_384; +/// The pan of a source hard right (§6); hard left is its negation. +pub const MAX_PAN: i32 = 4096; +/// The sample rates a descriptor may state (§3.3), in Hz. +pub const SAMPLE_RATES: core::ops::RangeInclusive = 8_000..=192_000; + +/// The layout kinds (§3.1). +pub mod kind { + pub const GRID: u8 = 1; + pub const PIP: u8 = 2; +} + +/// The tile aspects (§5.2): `AUTO` lays tiles out as `VIDEO` does and lets each fill its +/// cell. +pub mod aspect { + pub const AUTO: u8 = 0; + pub const VIDEO: u8 = 1; + pub const SQUARE: u8 = 2; + pub const PORTRAIT: u8 = 3; +} + +/// The fill modes (§5.6); `DEFAULT` is cover for grid tiles and the PiP window, and +/// contain for the featured tile. +pub mod fill { + pub const DEFAULT: u8 = 0; + pub const FILL: u8 = 1; + pub const COVER: u8 = 2; + pub const CONTAIN: u8 = 3; +} + +/// The PiP window's corners (§5.5). +pub mod corner { + pub const TOP_LEFT: u8 = 1; + pub const TOP_RIGHT: u8 = 2; + pub const BOTTOM_LEFT: u8 = 3; + pub const BOTTOM_RIGHT: u8 = 4; +} + +/// What the PiP participant does when it is the only one composed (§5.5). +pub mod behaviour { + pub const STATIC: u8 = 1; + pub const DYNAMIC: u8 = 2; +} + +/// Where a tile is placed (§5.7). +pub mod place { + pub const GRID: u8 = 0; + pub const FEATURED: u8 = 1; + pub const PIP: u8 = 2; + /// Each place's name, as the corpus writes it. + pub fn name(p: u8) -> &'static str { + match p { + FEATURED => "featured", + PIP => "pip", + _ => "grid", + } + } +} + +/// Why the layout or the mix is refused (§10). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Refusal { + CanvasOutOfRange, + ComposeInvalid, + AttrMalformed, + MixInputMalformed, +} + +/// A rectangle, in pixels: its left edge, its top edge, its width and its height. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub struct Rect { + pub x: u32, + pub y: u32, + pub w: u32, + pub h: u32, +} + +impl Rect { + pub fn new(x: u32, y: u32, w: u32, h: u32) -> Rect { + Rect { x, y, w, h } + } +} + +/// What the layout and the mix read of a descriptor (§3.1), its fields as integers. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Params { + pub width: u32, + pub height: u32, + pub fps: u8, + pub layout: u8, + pub gap: u32, + pub aspect: u8, + pub fill: u8, + pub featured_attr: String, + pub order_attr: String, + pub omit_stopped: bool, + pub pip_attr: String, + pub corner: u8, + pub pip_width: u32, + pub pip_height: u32, + pub offset: u32, + pub behaviour: u8, + pub channels: u8, + pub sample_rate: u32, + pub gain_attr: String, + pub pan_attr: String, + pub max_tiles: u32, + pub max_voices: u32, +} + +/// An attribute key (live-rooms §4.4): 1 to 32 of `a`–`z`, `0`–`9` and `_`. +pub fn key_ok(k: &[u8]) -> bool { + (1..=32).contains(&k.len()) && k.iter().all(|&c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == b'_') +} + +/// The least `k` with `k × k` ≥ `n`. +fn ceil_sqrt(n: u64) -> u64 { + let mut k = 0; + while k * k < n { + k += 1; + } + k +} + +/// The height of the featured tile's region (§5.4): three quarters of what the gap leaves, +/// rounded down. `gap` < `height`. +fn main_height(height: u64, gap: u64) -> u64 { + (height - gap) * 3 / 4 +} + +impl Params { + /// §3.4: the canvas within its limits. Otherwise `canvas_out_of_range`. + pub fn check_canvas(&self) -> Result<(), Refusal> { + let edge = |e: u32| (MIN_EDGE..=MAX_EDGE).contains(&e) && e.is_multiple_of(2); + if !edge(self.width) || !edge(self.height) || self.width * self.height > MAX_PIXELS || !(1..=MAX_FPS).contains(&self.fps) { + return Err(Refusal::CanvasOutOfRange); + } + Ok(()) + } + + /// §3.3's field rules after the canvas's. Otherwise `compose_invalid`. + pub fn check_fields(&self) -> Result<(), Refusal> { + let bad = Err(Refusal::ComposeInvalid); + let (w, h, g) = (self.width as u64, self.height as u64, self.gap as u64); + if !matches!(self.layout, kind::GRID | kind::PIP) || self.aspect > aspect::PORTRAIT || self.fill > fill::CONTAIN { + return bad; + } + for k in [&self.featured_attr, &self.order_attr, &self.pip_attr, &self.gain_attr, &self.pan_attr] { + if !k.is_empty() && !key_ok(k.as_bytes()) { + return bad; + } + } + if self.layout == kind::GRID { + if !self.pip_attr.is_empty() || self.corner != 0 || self.pip_width != 0 || self.pip_height != 0 || self.offset != 0 || self.behaviour != 0 { + return bad; + } + } else { + let o = self.offset as u64; + if !(corner::TOP_LEFT..=corner::BOTTOM_RIGHT).contains(&self.corner) + || !(behaviour::STATIC..=behaviour::DYNAMIC).contains(&self.behaviour) + || o >= min(w, h) + || self.pip_width as u64 + o > w + || self.pip_height as u64 + o > h + { + return bad; + } + } + if !(1..=2).contains(&self.channels) || !SAMPLE_RATES.contains(&self.sample_rate) { + return bad; + } + if !(1..=MAX_COMPOSED).contains(&self.max_tiles) || !(1..=MAX_COMPOSED).contains(&self.max_voices) { + return bad; + } + // Every grid the descriptor can lay out has cells of at least one pixel (§3.3). + let k = ceil_sqrt(self.max_tiles as u64); + let need = k + (k - 1) * g; + if g >= h || w < need || h - g - main_height(h, g) < need { + return bad; + } + Ok(()) + } + + /// Both. + pub fn check(&self) -> Result<(), Refusal> { + self.check_canvas()?; + self.check_fields() + } +} + +// --------------------------------------------------------------------------------------- +// §4.3 Attributes +// --------------------------------------------------------------------------------------- + +/// The value of `key` among `attrs`; none when `key` is empty or not there. +pub fn attr<'a>(attrs: &'a [(String, String)], key: &str) -> Option<&'a str> { + if key.is_empty() { + return None; + } + attrs.iter().find(|(k, _)| k == key).map(|(_, v)| v.as_str()) +} + +/// `true` or `false`, exactly (§4.3); absent is `false`. +pub fn read_bool(v: Option<&str>) -> Result { + match v { + None | Some("false") => Ok(false), + Some("true") => Ok(true), + Some(_) => Err(Refusal::AttrMalformed), + } +} + +/// A decimal integer (§4.3): `0`, or an optional `-` and 1 to 10 digits not starting with +/// `0`. +pub fn read_int(v: &str) -> Option { + let b = v.as_bytes(); + let (neg, digits) = match b.first() { + Some(b'-') => (true, &b[1..]), + _ => (false, b), + }; + if digits.is_empty() || digits.len() > 10 || !digits.iter().all(u8::is_ascii_digit) { + return None; + } + if digits[0] == b'0' && (digits.len() > 1 || neg) { + return None; + } + let n = digits.iter().fold(0i64, |n, &d| n * 10 + (d - b'0') as i64); + Some(if neg { -n } else { n }) +} + +fn read_ranged(v: Option<&str>, lo: i64, hi: i64, absent: i64) -> Result { + match v { + None => Ok(absent), + Some(s) => read_int(s).filter(|n| (lo..=hi).contains(n)).ok_or(Refusal::AttrMalformed), + } +} + +/// One participant as the layout reads it (§4.2). +#[derive(Clone, Copy, Debug)] +pub struct Entrant<'a> { + pub principal: [u8; 32], + /// Its join order (§4.2). + pub join: u32, + /// Its video source's width and height, each at least 1; none when its video is + /// stopped. + pub video: Option<(u32, u32)>, + /// Whether it has an audio source. + pub audio: bool, + /// The attributes of its grant in effect (live-rooms §4.4). + pub attrs: &'a [(String, String)], +} + +/// The attributes a descriptor reads, read for one participant (§4.3). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Read { + pub featured: bool, + pub order: Option, + pub pip: bool, + pub gain: u32, + pub pan: i32, +} + +/// §4.3 over one participant's attributes: `attr_malformed` when one the descriptor names +/// does not read. +pub fn read_attrs(p: &Params, attrs: &[(String, String)]) -> Result { + let featured = read_bool(attr(attrs, &p.featured_attr))?; + let order = match attr(attrs, &p.order_attr) { + None => None, + Some(v) => Some(read_int(v).filter(|n| (i32::MIN as i64..=i32::MAX as i64).contains(n)).ok_or(Refusal::AttrMalformed)? as i32), + }; + let pip = read_bool(attr(attrs, &p.pip_attr))?; + let gain = read_ranged(attr(attrs, &p.gain_attr), 0, MAX_GAIN as i64, UNITY_GAIN as i64)? as u32; + let pan = read_ranged(attr(attrs, &p.pan_attr), -(MAX_PAN as i64), MAX_PAN as i64, 0)? as i32; + Ok(Read { featured, order, pip, gain, pan }) +} + +// --------------------------------------------------------------------------------------- +// §5 The layout +// --------------------------------------------------------------------------------------- + +/// A source's video on the canvas (§5.6): the rectangle it is drawn into, and the +/// rectangle of the source drawn there. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Video { + pub dst: Rect, + pub src: Rect, +} + +/// One tile (§5.7). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Tile { + pub principal: [u8; 32], + /// [`place`]: grid, featured or PiP. + pub place: u8, + /// 0 for a grid or featured tile, 1 for the PiP window, drawn over the others. + pub z: u8, + pub tile: Rect, + /// None when the participant's video is stopped: the tile shows the background. + pub video: Option