@blockcast/mmt-base 0.3.0 → 0.4.0-main.86f861ac235a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -17
- package/dist/catalog-fec-source.d.ts +75 -0
- package/dist/catalog-fec-source.d.ts.map +1 -0
- package/dist/catalog-fec-source.js +135 -0
- package/dist/catalog-fec-source.js.map +1 -0
- package/dist/fec-block-profile.d.ts +7 -7
- package/dist/fec-block-profile.d.ts.map +1 -1
- package/dist/fec-block-profile.js +22 -18
- package/dist/fec-block-profile.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mmtp.d.ts +0 -13
- package/dist/mmtp.d.ts.map +1 -1
- package/dist/mmtp.js +35 -23
- package/dist/mmtp.js.map +1 -1
- package/dist/serial-number.d.ts +0 -29
- package/dist/serial-number.d.ts.map +1 -1
- package/dist/serial-number.js +0 -54
- package/dist/serial-number.js.map +1 -1
- package/dist/signalling.d.ts +26 -24
- package/dist/signalling.d.ts.map +1 -1
- package/dist/signalling.js +16 -16
- package/dist/signalling.js.map +1 -1
- package/package.json +2 -4
- package/src/catalog-fec-source.ts +164 -0
- package/src/fec-block-profile.ts +24 -24
- package/src/index.ts +1 -0
- package/src/mmtp.ts +18 -33
- package/src/serial-number.ts +0 -58
- package/src/signalling.ts +27 -29
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @blockcast/mmt-base
|
|
2
2
|
|
|
3
|
-
The shared MMTP packet-parsing leaf for libmmt's TypeScript packages. It hosts the low-level MMTP / MPU / MFU header parsers, FEC payload-id predicates
|
|
3
|
+
The shared MMTP packet-parsing leaf for libmmt's TypeScript packages. It hosts the low-level MMTP / MPU / MFU header parsers, and FEC payload-id predicates — everything that operates on raw MMTP packet bytes **with zero FEC-decode dependency**. RFC 6330 OTI geometry belongs to `@blockcast/mmt-fec`.
|
|
4
4
|
|
|
5
|
-
It exists for one structural reason. Both `@blockcast/mmt-fec` and `@blockcast/mmt-container` need these primitives. Before this package they lived in `mmt-container`, so `mmt-fec` had to import `mmt-container` for them — while `mmt-container`'s `FecManager` already imports `mmt-fec`. That is a circular dependency. Extracting the primitives into this leaf breaks the cycle: both packages now import **down** into `mmt-base` rather than across into each other.
|
|
5
|
+
It exists for one structural reason. Both `@blockcast/mmt-fec` and `@blockcast/mmt-container` need these primitives. Before this package they lived in `mmt-container`, so `mmt-fec` had to import `mmt-container` for them — while `mmt-container`'s `FecManager` already imports `mmt-fec`. That is a circular dependency. Extracting the primitives into this leaf breaks the cycle: both packages now import **down** into `mmt-base` rather than across into each other. It has no runtime dependencies.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
pnpm add @blockcast/mmt-base
|
|
@@ -46,7 +46,7 @@ Single entry point — `package.json#exports` declares only `.`, and `src/index.
|
|
|
46
46
|
| `MMTP_HEADER_SIZE` (12), `MPU_HEADER_SIZE` (8), `MFU_DU_HEADER_SIZE_TIMED` (14), `MFU_DU_HEADER_SIZE_NONTIMED` (4) | const | Fixed header sizes |
|
|
47
47
|
| `PACKET_TYPE_MPU` (0x00), `PACKET_TYPE_SIGNALING` (0x02), `PACKET_TYPE_REPAIR` (0x03) | const | MMTP `packet_type` values |
|
|
48
48
|
|
|
49
|
-
MPU `payload_length` is interpreted strictly as ISO's length-after-field value: six remaining MPU-header bytes plus the data-unit header and media.
|
|
49
|
+
MPU `payload_length` is interpreted strictly as ISO's length-after-field value: six remaining MPU-header bytes plus the data-unit header and media. The legacy `0xf0a1` authenticator trailer (skipped, never verified — provenance is `@blockcast/mmt-manifest-verify`) and the Source FEC Payload ID are outside that span; malformed, zero-length, media-only, and ambiguous declarations are rejected.
|
|
50
50
|
|
|
51
51
|
### FEC payload-id, repair & AL-FEC signaling
|
|
52
52
|
|
|
@@ -69,22 +69,12 @@ replaced by Amd 1:2025.
|
|
|
69
69
|
|
|
70
70
|
| Symbol | Kind | Purpose |
|
|
71
71
|
|--------|------|---------|
|
|
72
|
-
| `parseSignallingPayload` | function | Split a signalling packet into complete messages
|
|
72
|
+
| `parseSignallingPayload` | function | Split a signalling packet into complete messages behind the 9.3.4.2 header (Figure 15); the payload form is always `iso-9.3.4.2`. A message straight after the MMTP header (the retired bare AL-FEC form) is refused |
|
|
73
73
|
| `parseSignallingPacket` | function | Decode every message of a signalling packet → `al-fec` / `pa` / `mpt` / `other` |
|
|
74
74
|
| `parseAlFecMessage`, `parseAlFecMessageBody` | function | Every FEC flow of an AL-FEC message: all asset packet_ids, one-stage / two-stage / LA-FEC repair flows, private fields → `AlFecMessage` |
|
|
75
|
-
| `alFecRaptorQFlowConfig` | function | One flow's decoder geometry under the Blockcast one-stage RaptorQ profile (private field = OTI + interleave depth
|
|
75
|
+
| `alFecRaptorQFlowConfig` | function | One flow's decoder geometry under the Blockcast one-stage RaptorQ profile: coding byte 0x14 (`iso-ssbg1-v1`) or 0x15 (its low bit, reserved "1" in the unamended 2023 Table C.3, is reported, not interpreted), private field = OTI + interleave depth → `AlFecRaptorQFlowConfig`; any other coding byte (0x10 ssbg_mode0 included) → `null` |
|
|
76
76
|
| `parsePaMessageBody`, `parseMptMessageBody`, `parseMpTable`, `mpAssetPacketIds` | function | PA / MPT messages and the MP table: asset → packet_id mapping |
|
|
77
77
|
|
|
78
|
-
### ALTA trailer (re-exported from `@blockcast/mmt-alta-parse`)
|
|
79
|
-
|
|
80
|
-
| Symbol | Kind | Purpose |
|
|
81
|
-
|--------|------|---------|
|
|
82
|
-
| `extractAltaTrailer` | function | Extract the ALTA authentication trailer from an MMTP packet |
|
|
83
|
-
| `AltaTrailer` | type | Parsed trailer shape |
|
|
84
|
-
| `MMTP_EXT_TYPE_ALTA_AUTH`, `MMTP_EXT_TRAILER_HEADER_SIZE` | const | ALTA extension-header identifiers |
|
|
85
|
-
|
|
86
|
-
These four are re-exported so callers that already pull MMTP primitives from here don't need a second import from `@blockcast/mmt-alta-parse` just for the trailer.
|
|
87
|
-
|
|
88
78
|
## Why this package exists
|
|
89
79
|
|
|
90
80
|
```
|
|
@@ -119,13 +109,12 @@ npm test # vitest run
|
|
|
119
109
|
|
|
120
110
|
The direct suite owns header parsing, MFU extraction, payload-ID predicates,
|
|
121
111
|
declared-boundary rejection, C/X optional headers, and
|
|
122
|
-
|
|
112
|
+
legacy-authenticator/FEC suffix coverage. Downstream suites exercise integration only.
|
|
123
113
|
|
|
124
114
|
## Related packages
|
|
125
115
|
|
|
126
116
|
| Package | Relationship |
|
|
127
117
|
|---------|-------------|
|
|
128
|
-
| [`@blockcast/mmt-alta-parse`](../mmt-alta-parse) | Only dependency — supplies the ALTA trailer types this package re-exports |
|
|
129
118
|
| [`@blockcast/mmt-fec`](../fec) | Imports these parsers in `block-processor` to turn decoded FEC blocks back into MFU fragments |
|
|
130
119
|
| [`@blockcast/mmt-container`](../container) | Imports these primitives directly and builds the `FecManager`, MFU reassembler, and CMAF demuxer on top |
|
|
131
120
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** The catalog media roles that carry hang renditions. */
|
|
2
|
+
export type CatalogFecRole = 'video' | 'audio';
|
|
3
|
+
/** One media source's `fec` block, as `locateCatalogFecSource` found it. */
|
|
4
|
+
export type CatalogFecSource = {
|
|
5
|
+
readonly dialect: 'hang';
|
|
6
|
+
readonly role: CatalogFecRole;
|
|
7
|
+
/** The rendition object. */
|
|
8
|
+
readonly entry: Record<string, unknown>;
|
|
9
|
+
/** The rendition's `fec` value, unvalidated (may be undefined). */
|
|
10
|
+
readonly fec: unknown;
|
|
11
|
+
/** JSON path of that `fec` block. */
|
|
12
|
+
readonly fecPath: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly dialect: 'msf';
|
|
15
|
+
/** Index of the entry in `tracks[]`. */
|
|
16
|
+
readonly index: number;
|
|
17
|
+
/** The `tracks[]` entry (an empty object when the entry is not an object). */
|
|
18
|
+
readonly entry: Record<string, unknown>;
|
|
19
|
+
/** The entry's `fec` value, unvalidated (may be undefined). */
|
|
20
|
+
readonly fec: unknown;
|
|
21
|
+
/** JSON path of that `fec` block. */
|
|
22
|
+
readonly fecPath: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Locate the catalog entry that declares one media source's `fec` block, in
|
|
26
|
+
* either catalog dialect.
|
|
27
|
+
*
|
|
28
|
+
* A hang `video`/`audio` rendition named `source` wins, in `roles` order, over
|
|
29
|
+
* a `tracks[]` entry of the same name: when a catalog carries rendition blocks
|
|
30
|
+
* beside a `tracks[]` switching-set index (the unified ABR ladder catalog),
|
|
31
|
+
* the rendition blocks are authoritative, exactly as they are for hang's own
|
|
32
|
+
* catalog decode. The precedence is keyed on the rendition EXISTING as an
|
|
33
|
+
* object, not on it carrying `fec`: a rendition without `fec` locates with
|
|
34
|
+
* `fec: undefined` and never falls through to `tracks[]`.
|
|
35
|
+
*
|
|
36
|
+
* Otherwise the first `tracks[]` entry named `source` locates. Returns
|
|
37
|
+
* undefined when neither dialect names it, or when `catalog` is not an object.
|
|
38
|
+
*
|
|
39
|
+
* @param roles the hang roles to search, in order (both by default). A typed
|
|
40
|
+
* track reference passes its own role only.
|
|
41
|
+
*/
|
|
42
|
+
export declare function locateCatalogFecSource(catalog: unknown, source: string, roles?: readonly CatalogFecRole[]): CatalogFecSource | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Whether an `iso-ssbg1-v1` block's optional `interleaveDepthMs` span is
|
|
45
|
+
* usable: absent, or a non-negative safe integer. Zero or absence supplies no
|
|
46
|
+
* elapsed deadline and still permits in-band FEC. True for every block that
|
|
47
|
+
* names another profile (the span is not read) and for a non-object.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isoBlockSpanUsable(fec: unknown): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Whether one catalog `fec` block leaves its FEC available
|
|
52
|
+
* (draft-ramadan-moq-fec §5.1): the decision the container's
|
|
53
|
+
* `catalogFecUnavailable` explains with a typed reason.
|
|
54
|
+
*
|
|
55
|
+
* False when the block declares an FEC instance (any `algorithm` but `"none"`)
|
|
56
|
+
* and names no implemented `blockProfile` (the retired `k-padded-v1`
|
|
57
|
+
* included), or carries an `iso-ssbg1-v1` span it cannot use; and when a block
|
|
58
|
+
* declaring no FEC instance carries a profile token that is not implemented.
|
|
59
|
+
* True for a non-object and for every other block. It reads only the profile
|
|
60
|
+
* and the span: malformed geometry (`sourceSymbols`, `symbolSize`) is
|
|
61
|
+
* `catalogFecDeclaresUnconfigurableInstance`'s.
|
|
62
|
+
*
|
|
63
|
+
* A receiver applies no FEC to a source whose block is unavailable and joins
|
|
64
|
+
* none of its repair tracks, without failing the session.
|
|
65
|
+
*/
|
|
66
|
+
export declare function catalogFecAvailable(fec: unknown): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Whether a source's `fec` block declares an FEC instance (any `algorithm`
|
|
69
|
+
* but `"none"`) whose `sourceSymbols` or `symbolSize` is not a positive
|
|
70
|
+
* integer. Geometry a decoder cannot configure is a malformed catalog, not
|
|
71
|
+
* "no FEC": the container's per-track resolver throws `track_fec` for exactly
|
|
72
|
+
* this block, whatever its profile or span.
|
|
73
|
+
*/
|
|
74
|
+
export declare function catalogFecDeclaresUnconfigurableInstance(fec: unknown): boolean;
|
|
75
|
+
//# sourceMappingURL=catalog-fec-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-fec-source.d.ts","sourceRoot":"","sources":["../src/catalog-fec-source.ts"],"names":[],"mappings":"AAuBA,0DAA0D;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,CAAA;AAE9C,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GACxB;IACE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;IAC7B,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACvC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,GACD;IACE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAA;IACvB,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACvC,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,CAAA;AAUL;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,SAAS,cAAc,EAAc,GAC3C,gBAAgB,GAAG,SAAS,CA4B9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAKxD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAOzD;AAMD;;;;;;GAMG;AACH,wBAAgB,wCAAwC,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAI9E"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog FEC source rules shared by every catalog reader (BLO-40851).
|
|
3
|
+
*
|
|
4
|
+
* These are the dialect-level reads the container resolvers
|
|
5
|
+
* (`resolveRepairLayers`, `catalogFecUnavailable`), the transport endpoint
|
|
6
|
+
* selection (`selectEndpointPacketIds`) and a player's repair inventory all
|
|
7
|
+
* need to agree on. They live here, in the leaf package every one of those
|
|
8
|
+
* depends on, so there is one copy of each rule instead of copies pinned
|
|
9
|
+
* against each other by tests.
|
|
10
|
+
*
|
|
11
|
+
* - `locateCatalogFecSource`: which catalog entry declares a source's `fec`
|
|
12
|
+
* block. hang `video`/`audio` rendition blocks are authoritative over an MSF
|
|
13
|
+
* `tracks[]` entry of the same name.
|
|
14
|
+
* - `catalogFecAvailable`: draft-ramadan-moq-fec §5.1, whether a block's FEC
|
|
15
|
+
* is usable at all (implemented `blockProfile`, usable span).
|
|
16
|
+
* - `catalogFecDeclaresUnconfigurableInstance`: a declared FEC instance whose
|
|
17
|
+
* geometry a decoder cannot configure, which is a malformed catalog rather
|
|
18
|
+
* than "no FEC".
|
|
19
|
+
*
|
|
20
|
+
* Every function is total: it never throws, whatever the input.
|
|
21
|
+
*/
|
|
22
|
+
import { isFecBlockProfile } from './fec-block-profile.js';
|
|
23
|
+
const ALL_ROLES = Object.freeze(['video', 'audio']);
|
|
24
|
+
function recordOf(value) {
|
|
25
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
26
|
+
? value
|
|
27
|
+
: undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Locate the catalog entry that declares one media source's `fec` block, in
|
|
31
|
+
* either catalog dialect.
|
|
32
|
+
*
|
|
33
|
+
* A hang `video`/`audio` rendition named `source` wins, in `roles` order, over
|
|
34
|
+
* a `tracks[]` entry of the same name: when a catalog carries rendition blocks
|
|
35
|
+
* beside a `tracks[]` switching-set index (the unified ABR ladder catalog),
|
|
36
|
+
* the rendition blocks are authoritative, exactly as they are for hang's own
|
|
37
|
+
* catalog decode. The precedence is keyed on the rendition EXISTING as an
|
|
38
|
+
* object, not on it carrying `fec`: a rendition without `fec` locates with
|
|
39
|
+
* `fec: undefined` and never falls through to `tracks[]`.
|
|
40
|
+
*
|
|
41
|
+
* Otherwise the first `tracks[]` entry named `source` locates. Returns
|
|
42
|
+
* undefined when neither dialect names it, or when `catalog` is not an object.
|
|
43
|
+
*
|
|
44
|
+
* @param roles the hang roles to search, in order (both by default). A typed
|
|
45
|
+
* track reference passes its own role only.
|
|
46
|
+
*/
|
|
47
|
+
export function locateCatalogFecSource(catalog, source, roles = ALL_ROLES) {
|
|
48
|
+
const root = recordOf(catalog);
|
|
49
|
+
if (root === undefined)
|
|
50
|
+
return undefined;
|
|
51
|
+
for (const role of roles) {
|
|
52
|
+
const renditions = recordOf(recordOf(root[role])?.['renditions']);
|
|
53
|
+
if (renditions === undefined || !Object.hasOwn(renditions, source))
|
|
54
|
+
continue;
|
|
55
|
+
const entry = recordOf(renditions[source]);
|
|
56
|
+
if (entry === undefined)
|
|
57
|
+
continue;
|
|
58
|
+
return Object.freeze({
|
|
59
|
+
dialect: 'hang',
|
|
60
|
+
role,
|
|
61
|
+
entry,
|
|
62
|
+
fec: entry['fec'],
|
|
63
|
+
fecPath: `$.${role}.renditions[${JSON.stringify(source)}].fec`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const tracks = root['tracks'];
|
|
67
|
+
if (!Array.isArray(tracks))
|
|
68
|
+
return undefined;
|
|
69
|
+
const index = tracks.findIndex((track) => recordOf(track)?.['name'] === source);
|
|
70
|
+
if (index < 0)
|
|
71
|
+
return undefined;
|
|
72
|
+
const entry = recordOf(tracks[index]) ?? {};
|
|
73
|
+
return Object.freeze({
|
|
74
|
+
dialect: 'msf',
|
|
75
|
+
index,
|
|
76
|
+
entry,
|
|
77
|
+
fec: entry['fec'],
|
|
78
|
+
fecPath: `$.tracks[${index}].fec`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Whether an `iso-ssbg1-v1` block's optional `interleaveDepthMs` span is
|
|
83
|
+
* usable: absent, or a non-negative safe integer. Zero or absence supplies no
|
|
84
|
+
* elapsed deadline and still permits in-band FEC. True for every block that
|
|
85
|
+
* names another profile (the span is not read) and for a non-object.
|
|
86
|
+
*/
|
|
87
|
+
export function isoBlockSpanUsable(fec) {
|
|
88
|
+
const block = recordOf(fec);
|
|
89
|
+
if (block === undefined || block['blockProfile'] !== 'iso-ssbg1-v1')
|
|
90
|
+
return true;
|
|
91
|
+
const ms = block['interleaveDepthMs'];
|
|
92
|
+
return ms === undefined || (typeof ms === 'number' && Number.isSafeInteger(ms) && ms >= 0);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Whether one catalog `fec` block leaves its FEC available
|
|
96
|
+
* (draft-ramadan-moq-fec §5.1): the decision the container's
|
|
97
|
+
* `catalogFecUnavailable` explains with a typed reason.
|
|
98
|
+
*
|
|
99
|
+
* False when the block declares an FEC instance (any `algorithm` but `"none"`)
|
|
100
|
+
* and names no implemented `blockProfile` (the retired `k-padded-v1`
|
|
101
|
+
* included), or carries an `iso-ssbg1-v1` span it cannot use; and when a block
|
|
102
|
+
* declaring no FEC instance carries a profile token that is not implemented.
|
|
103
|
+
* True for a non-object and for every other block. It reads only the profile
|
|
104
|
+
* and the span: malformed geometry (`sourceSymbols`, `symbolSize`) is
|
|
105
|
+
* `catalogFecDeclaresUnconfigurableInstance`'s.
|
|
106
|
+
*
|
|
107
|
+
* A receiver applies no FEC to a source whose block is unavailable and joins
|
|
108
|
+
* none of its repair tracks, without failing the session.
|
|
109
|
+
*/
|
|
110
|
+
export function catalogFecAvailable(fec) {
|
|
111
|
+
const block = recordOf(fec);
|
|
112
|
+
if (block === undefined)
|
|
113
|
+
return true;
|
|
114
|
+
const declaresFecInstance = block['algorithm'] !== 'none';
|
|
115
|
+
const profile = block['blockProfile'];
|
|
116
|
+
const profileOk = isFecBlockProfile(profile) || (profile === undefined && !declaresFecInstance);
|
|
117
|
+
return profileOk && (!declaresFecInstance || isoBlockSpanUsable(block));
|
|
118
|
+
}
|
|
119
|
+
function isPositiveSafeInteger(value) {
|
|
120
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Whether a source's `fec` block declares an FEC instance (any `algorithm`
|
|
124
|
+
* but `"none"`) whose `sourceSymbols` or `symbolSize` is not a positive
|
|
125
|
+
* integer. Geometry a decoder cannot configure is a malformed catalog, not
|
|
126
|
+
* "no FEC": the container's per-track resolver throws `track_fec` for exactly
|
|
127
|
+
* this block, whatever its profile or span.
|
|
128
|
+
*/
|
|
129
|
+
export function catalogFecDeclaresUnconfigurableInstance(fec) {
|
|
130
|
+
const block = recordOf(fec);
|
|
131
|
+
if (block === undefined || block['algorithm'] === 'none')
|
|
132
|
+
return false;
|
|
133
|
+
return !(isPositiveSafeInteger(block['sourceSymbols']) && isPositiveSafeInteger(block['symbolSize']));
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=catalog-fec-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-fec-source.js","sourceRoot":"","sources":["../src/catalog-fec-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
/** The
|
|
2
|
-
export type FecBlockProfile = '
|
|
3
|
-
/** Every accepted `fec.blockProfile` token
|
|
1
|
+
/** The block profile a catalog `fec.blockProfile` may name: the one this library implements. */
|
|
2
|
+
export type FecBlockProfile = 'iso-ssbg1-v1';
|
|
3
|
+
/** Every accepted `fec.blockProfile` token. */
|
|
4
4
|
export declare const FEC_BLOCK_PROFILES: readonly FecBlockProfile[];
|
|
5
|
-
/** True for a
|
|
5
|
+
/** True for a block-profile token this library implements. */
|
|
6
6
|
export declare function isFecBlockProfile(value: unknown): value is FecBlockProfile;
|
|
7
7
|
/**
|
|
8
|
-
* Read a required `fec.blockProfile`. Throws on an absent
|
|
9
|
-
* there is no default and nothing is
|
|
10
|
-
*
|
|
8
|
+
* Read a required `fec.blockProfile`. Throws on an absent token and on any
|
|
9
|
+
* token other than `iso-ssbg1-v1`: there is no default and nothing is
|
|
10
|
+
* inferred from the wire (draft-ramadan-moq-fec §5.1).
|
|
11
11
|
*
|
|
12
12
|
* @param where the catalog path of the field, for the error message.
|
|
13
13
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fec-block-profile.d.ts","sourceRoot":"","sources":["../src/fec-block-profile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fec-block-profile.d.ts","sourceRoot":"","sources":["../src/fec-block-profile.ts"],"names":[],"mappings":"AA6BA,gGAAgG;AAChG,MAAM,MAAM,eAAe,GAAG,cAAc,CAAA;AAE5C,+CAA+C;AAC/C,eAAO,MAAM,kBAAkB,EAAE,SAAS,eAAe,EAEvD,CAAA;AAEF,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAE1E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAMnF;AAED,2EAA2E;AAC3E,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAOjF;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CAczF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAS3E;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKpF"}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FEC block profile (BLO-35597, ISO/IEC 23008-1 Annex C).
|
|
3
3
|
*
|
|
4
|
-
* Every catalog `fec` object that declares an FEC instance names
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Every catalog `fec` object that declares an FEC instance names its block
|
|
5
|
+
* profile in `fec.blockProfile`. A receiver applies all of a profile's rules
|
|
6
|
+
* or none of them, so the token is the one explicit per-stream discriminator:
|
|
7
|
+
* it is never defaulted and never inferred from the wire.
|
|
8
|
+
*
|
|
9
|
+
* draft-ramadan-moq-fec §5.1 defines exactly one value, and it is the only
|
|
10
|
+
* profile this library implements:
|
|
8
11
|
*
|
|
9
|
-
* - `k-padded-v1` (legacy, Blockcast-private): a source symbol is the
|
|
10
|
-
* protected MMTP packet zero-padded to T with no length field; every block
|
|
11
|
-
* is a K-symbol RaptorQ block whose ESIs `SSB_length..K-1` are implicit
|
|
12
|
-
* zero padding; `SS_ID = SBN*K + ESI`, so `SS_Start = SBN*K`; repair
|
|
13
|
-
* ESI = K + RS_ID; the MoQ repair group id is the SBN.
|
|
14
12
|
* - `iso-ssbg1-v1`: ssbg_mode1 (C.3.3): a source symbol is
|
|
15
13
|
* `u16 length || protected packet || zero padding` to T; a block is a
|
|
16
14
|
* K' = SSB_length RaptorQ block (C.5.3) and repair ESI = SSB_length + RS_ID;
|
|
@@ -19,21 +17,27 @@
|
|
|
19
17
|
* under RFC 1982 serial arithmetic; the MoQ repair group id is the 62-bit
|
|
20
18
|
* wrap-epoch-extended SS_Start. The AL-FEC coding byte for this profile is
|
|
21
19
|
* 0x14 (one-stage, ssbg_mode1, fec_payload_id_mode 0, Amd 1:2025 Table C.3).
|
|
20
|
+
*
|
|
21
|
+
* A track whose `blockProfile` is absent or names any other token (the
|
|
22
|
+
* retired Blockcast-private `k-padded-v1` included) has no FEC: a receiver
|
|
23
|
+
* consumes its source without FEC and joins none of its repair tracks
|
|
24
|
+
* (draft-ramadan-moq-fec §5.1). `parseFecBlockProfile` throws for such a
|
|
25
|
+
* token; the per-track catalog resolver turns the same rule into a typed
|
|
26
|
+
* per-track "FEC unavailable" outcome instead of failing the session.
|
|
22
27
|
*/
|
|
23
28
|
import { serial32Add, serial32Distance, serial32Precedes } from './serial-number.js';
|
|
24
|
-
/** Every accepted `fec.blockProfile` token
|
|
29
|
+
/** Every accepted `fec.blockProfile` token. */
|
|
25
30
|
export const FEC_BLOCK_PROFILES = Object.freeze([
|
|
26
|
-
'k-padded-v1',
|
|
27
31
|
'iso-ssbg1-v1',
|
|
28
32
|
]);
|
|
29
|
-
/** True for a
|
|
33
|
+
/** True for a block-profile token this library implements. */
|
|
30
34
|
export function isFecBlockProfile(value) {
|
|
31
|
-
return value === '
|
|
35
|
+
return value === 'iso-ssbg1-v1';
|
|
32
36
|
}
|
|
33
37
|
/**
|
|
34
|
-
* Read a required `fec.blockProfile`. Throws on an absent
|
|
35
|
-
* there is no default and nothing is
|
|
36
|
-
*
|
|
38
|
+
* Read a required `fec.blockProfile`. Throws on an absent token and on any
|
|
39
|
+
* token other than `iso-ssbg1-v1`: there is no default and nothing is
|
|
40
|
+
* inferred from the wire (draft-ramadan-moq-fec §5.1).
|
|
37
41
|
*
|
|
38
42
|
* @param where the catalog path of the field, for the error message.
|
|
39
43
|
*/
|
|
@@ -41,9 +45,9 @@ export function parseFecBlockProfile(value, where) {
|
|
|
41
45
|
if (isFecBlockProfile(value))
|
|
42
46
|
return value;
|
|
43
47
|
if (value === undefined) {
|
|
44
|
-
throw new Error(`${where} is required: name the FEC block profile ("
|
|
48
|
+
throw new Error(`${where} is required: name the FEC block profile ("iso-ssbg1-v1")`);
|
|
45
49
|
}
|
|
46
|
-
throw new Error(`${where} must be "
|
|
50
|
+
throw new Error(`${where} must be "iso-ssbg1-v1" (got ${JSON.stringify(value)})`);
|
|
47
51
|
}
|
|
48
52
|
/** ISO/IEC 23008-1 C.3.3 ssbg_mode1: the two-octet packet length field. */
|
|
49
53
|
export const SSBG1_LENGTH_FIELD_BYTES = 2;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fec-block-profile.js","sourceRoot":"","sources":["../src/fec-block-profile.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fec-block-profile.js","sourceRoot":"","sources":["../src/fec-block-profile.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,oBAAoB,CAAA;AAClC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA"}
|
package/dist/mmtp.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { extractAltaTrailer as _leafExtractAltaTrailer, type AltaTrailer as _LeafAltaTrailer } from '@blockcast/mmt-alta-parse';
|
|
2
1
|
/**
|
|
3
2
|
* @mmt/container - MMTP Parser
|
|
4
3
|
*
|
|
@@ -220,18 +219,6 @@ export declare function hasSourceFecPayloadId(mmtpPacket: Uint8Array): boolean;
|
|
|
220
219
|
export declare function sourceFecPayloadIdOf(mmtpPacket: Uint8Array, header: MMTPHeader): {
|
|
221
220
|
ssId: number;
|
|
222
221
|
} | null;
|
|
223
|
-
/**
|
|
224
|
-
* MMTP header-extension ext_type assigned to the detached ALTA authenticator
|
|
225
|
-
* trailer (Path 2 / 08-07). Carried in an `[ext_type][ext_length][auth]`
|
|
226
|
-
* block appended after the MPU's declared payload bytes, before the 4-byte
|
|
227
|
-
* Source FEC Payload ID. MMTP X-bit stays 0 — non-ALTA MMTP receivers treat
|
|
228
|
-
* the trailer as bytes past `payload_length` and skip it (per ISO 23008-1
|
|
229
|
-
* §9.2.2 "may be discarded without impacting correct processing").
|
|
230
|
-
*/
|
|
231
|
-
export declare const MMTP_EXT_TYPE_ALTA_AUTH = 61601;
|
|
232
|
-
export declare const MMTP_EXT_TRAILER_HEADER_SIZE = 4;
|
|
233
|
-
export type AltaTrailer = _LeafAltaTrailer;
|
|
234
|
-
export declare const extractAltaTrailer: typeof _leafExtractAltaTrailer;
|
|
235
222
|
/** Size of Repair FEC Payload ID per ISO/IEC 23008-1 Section C.5.3 */
|
|
236
223
|
export declare const REPAIR_FEC_PID_SIZE = 13;
|
|
237
224
|
/**
|
package/dist/mmtp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mmtp.d.ts","sourceRoot":"","sources":["../src/mmtp.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mmtp.d.ts","sourceRoot":"","sources":["../src/mmtp.ts"],"names":[],"mappings":"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"}
|
package/dist/mmtp.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @mmt/container - MMTP Parser
|
|
3
|
+
*
|
|
4
|
+
* MMTP (MMT Protocol) packet parser based on ISO/IEC 23008-1:2023 Section 9.2
|
|
5
|
+
*
|
|
6
|
+
* MMTP header format (12 bytes):
|
|
7
|
+
* - Byte 0: V(2) | C(1) | FEC_type(2) | r(1) | X(1) | R(1)
|
|
8
|
+
* - Byte 1: reserved(2) | packet_type(6)
|
|
9
|
+
* - Bytes 2-3: packet_id (big-endian)
|
|
10
|
+
* - Bytes 4-7: timestamp (big-endian, 32-bit)
|
|
11
|
+
* - Bytes 8-11: sequence_number (big-endian)
|
|
12
|
+
*
|
|
13
|
+
* FEC_type values:
|
|
14
|
+
* - 0: No FEC / source packet
|
|
15
|
+
* - 1: FEC mode 0 (source with FEC payload ID)
|
|
16
|
+
* - 2: FEC repair packet mode 0
|
|
17
|
+
* - 3: FEC repair packet mode 1
|
|
18
|
+
*
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
2
21
|
export const MMTP_HEADER_SIZE = 12;
|
|
3
22
|
export const MPU_HEADER_SIZE = 8;
|
|
4
23
|
export const MFU_DU_HEADER_SIZE_TIMED = 14; // T=1: timed media (video/audio samples)
|
|
@@ -217,36 +236,43 @@ function resolveMfuPayloadLayout(mpu, fragmentType, payload) {
|
|
|
217
236
|
},
|
|
218
237
|
};
|
|
219
238
|
}
|
|
220
|
-
|
|
239
|
+
// Legacy detached per-packet authenticator suffix `[0xf0a1][len][auth]`. Its
|
|
240
|
+
// producer was removed (BLO-16483) and nothing verifies it any more; provenance
|
|
241
|
+
// is the signed per-group manifest. Receivers still skip an exact suffix so a
|
|
242
|
+
// stale producer degrades to unauthenticated playback instead of dropped
|
|
243
|
+
// packets. ponytail: hard-cut to reject once no deployed producer can emit it.
|
|
244
|
+
const LEGACY_TRAILER_EXT_TYPE = 0xf0a1;
|
|
245
|
+
const LEGACY_TRAILER_HEADER_SIZE = 4;
|
|
246
|
+
function isEmptyOrExactLegacyTrailer(payload, start, end) {
|
|
221
247
|
if (start === end)
|
|
222
248
|
return true;
|
|
223
|
-
if (start < 0 || end > payload.length || start +
|
|
249
|
+
if (start < 0 || end > payload.length || start + LEGACY_TRAILER_HEADER_SIZE > end) {
|
|
224
250
|
return false;
|
|
225
251
|
}
|
|
226
252
|
const view = new DataView(payload.buffer, payload.byteOffset + start, end - start);
|
|
227
|
-
if (view.getUint16(0, false) !==
|
|
253
|
+
if (view.getUint16(0, false) !== LEGACY_TRAILER_EXT_TYPE)
|
|
228
254
|
return false;
|
|
229
255
|
const authLength = view.getUint16(2, false);
|
|
230
|
-
return start +
|
|
256
|
+
return start + LEGACY_TRAILER_HEADER_SIZE + authLength === end;
|
|
231
257
|
}
|
|
232
258
|
function resolveDeclaredTrailers(payload, declaredEnd, fecType, options) {
|
|
233
259
|
if (declaredEnd > payload.length)
|
|
234
260
|
return null;
|
|
235
261
|
if (options?.skipFecId) {
|
|
236
|
-
return
|
|
262
|
+
return isEmptyOrExactLegacyTrailer(payload, declaredEnd, payload.length)
|
|
237
263
|
? { hasFecId: false }
|
|
238
264
|
: null;
|
|
239
265
|
}
|
|
240
266
|
if (fecType === 1) {
|
|
241
267
|
const fecStart = payload.length - SOURCE_FEC_PAYLOAD_ID_SIZE;
|
|
242
|
-
if (fecStart < declaredEnd || !
|
|
268
|
+
if (fecStart < declaredEnd || !isEmptyOrExactLegacyTrailer(payload, declaredEnd, fecStart)) {
|
|
243
269
|
return null;
|
|
244
270
|
}
|
|
245
271
|
return { hasFecId: true };
|
|
246
272
|
}
|
|
247
273
|
if (fecType !== 0)
|
|
248
274
|
return null;
|
|
249
|
-
if (
|
|
275
|
+
if (isEmptyOrExactLegacyTrailer(payload, declaredEnd, payload.length)) {
|
|
250
276
|
return { hasFecId: false };
|
|
251
277
|
}
|
|
252
278
|
return null;
|
|
@@ -344,7 +370,7 @@ function planMfuExtraction(mmtpPacket, options, parsedHeader) {
|
|
|
344
370
|
rejection: {
|
|
345
371
|
gate: 'declared-trailers-unresolved',
|
|
346
372
|
detail: `trailer bytes [${layout.dataEnd}, ${payload.length}) are neither empty ` +
|
|
347
|
-
`nor an exact
|
|
373
|
+
`nor an exact legacy authenticator trailer (fecType=${header.fecType})`,
|
|
348
374
|
},
|
|
349
375
|
};
|
|
350
376
|
}
|
|
@@ -484,20 +510,6 @@ export function sourceFecPayloadIdOf(mmtpPacket, header) {
|
|
|
484
510
|
0,
|
|
485
511
|
};
|
|
486
512
|
}
|
|
487
|
-
/**
|
|
488
|
-
* MMTP header-extension ext_type assigned to the detached ALTA authenticator
|
|
489
|
-
* trailer (Path 2 / 08-07). Carried in an `[ext_type][ext_length][auth]`
|
|
490
|
-
* block appended after the MPU's declared payload bytes, before the 4-byte
|
|
491
|
-
* Source FEC Payload ID. MMTP X-bit stays 0 — non-ALTA MMTP receivers treat
|
|
492
|
-
* the trailer as bytes past `payload_length` and skip it (per ISO 23008-1
|
|
493
|
-
* §9.2.2 "may be discarded without impacting correct processing").
|
|
494
|
-
*/
|
|
495
|
-
// Re-export the ALTA trailer helper from the zero-dep leaf package. The leaf
|
|
496
|
-
// owns the implementation so container and FEC consumers share one parser
|
|
497
|
-
// without creating a package cycle.
|
|
498
|
-
export const MMTP_EXT_TYPE_ALTA_AUTH = _LEAF_MMTP_EXT_TYPE_ALTA_AUTH;
|
|
499
|
-
export const MMTP_EXT_TRAILER_HEADER_SIZE = _LEAF_MMTP_EXT_TRAILER_HEADER_SIZE;
|
|
500
|
-
export const extractAltaTrailer = _leafExtractAltaTrailer;
|
|
501
513
|
/** Size of Repair FEC Payload ID per ISO/IEC 23008-1 Section C.5.3 */
|
|
502
514
|
export const REPAIR_FEC_PID_SIZE = 13;
|
|
503
515
|
/**
|