@blockcast/mmt-container 2.1.0 → 2.2.0-main.050b52fb9b00

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.
Files changed (105) hide show
  1. package/README.md +29 -17
  2. package/dist/browser-runtime.js +1949 -374
  3. package/dist/browser-runtime.js.map +4 -4
  4. package/dist/carp-catalog.js.map +1 -1
  5. package/dist/catalog-fec-params.d.ts +17 -1
  6. package/dist/catalog-fec-params.d.ts.map +1 -1
  7. package/dist/catalog-fec-params.js +15 -0
  8. package/dist/catalog-fec-params.js.map +2 -2
  9. package/dist/catalog-network-source.js.map +1 -1
  10. package/dist/cmcd-producer.d.ts +65 -47
  11. package/dist/cmcd-producer.d.ts.map +1 -1
  12. package/dist/cmcd-producer.js +138 -109
  13. package/dist/cmcd-producer.js.map +2 -2
  14. package/dist/delivery-catalog.js +26 -16
  15. package/dist/delivery-catalog.js.map +2 -2
  16. package/dist/delta-fallback-config.js.map +1 -1
  17. package/dist/fec-manager.d.ts +70 -12
  18. package/dist/fec-manager.d.ts.map +1 -1
  19. package/dist/fec-manager.js +403 -58
  20. package/dist/fec-manager.js.map +2 -2
  21. package/dist/fec-state.js.map +1 -1
  22. package/dist/fec-worker-setup.d.ts +1 -1
  23. package/dist/fec-worker-setup.js +1 -1
  24. package/dist/fec-worker-setup.js.map +1 -1
  25. package/dist/held-layer-admission.js.map +1 -1
  26. package/dist/index.d.ts +6 -5
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +9 -1
  29. package/dist/index.js.map +2 -2
  30. package/dist/iso-block-locator.d.ts +48 -13
  31. package/dist/iso-block-locator.d.ts.map +1 -1
  32. package/dist/iso-block-locator.js +97 -25
  33. package/dist/iso-block-locator.js.map +2 -2
  34. package/dist/iso-bmff-timing.d.ts +10 -1
  35. package/dist/iso-bmff-timing.d.ts.map +1 -1
  36. package/dist/iso-bmff-timing.js +36 -2
  37. package/dist/iso-bmff-timing.js.map +2 -2
  38. package/dist/media-router.js.map +1 -1
  39. package/dist/mfu-reassembler.js +12 -19
  40. package/dist/mfu-reassembler.js.map +2 -2
  41. package/dist/mmtp-container-parser.d.ts +79 -10
  42. package/dist/mmtp-container-parser.d.ts.map +1 -1
  43. package/dist/mmtp-container-parser.js +219 -45
  44. package/dist/mmtp-container-parser.js.map +2 -2
  45. package/dist/mmtp-container-parser.no-modules.js +342 -63
  46. package/dist/mmtp-container-parser.no-modules.js.map +3 -3
  47. package/dist/mmtp-decode-pipeline.js +218 -45
  48. package/dist/mmtp-decode-pipeline.js.map +2 -2
  49. package/dist/mmtp-fec-session.d.ts +41 -3
  50. package/dist/mmtp-fec-session.d.ts.map +1 -1
  51. package/dist/mmtp-fec-session.js +118 -13
  52. package/dist/mmtp-fec-session.js.map +3 -3
  53. package/dist/mmtp-router.d.ts +43 -9
  54. package/dist/mmtp-router.d.ts.map +1 -1
  55. package/dist/mmtp-router.js +2006 -95
  56. package/dist/mmtp-router.js.map +4 -4
  57. package/dist/multicast-auth-catalog.js.map +1 -1
  58. package/dist/multicast-input.js.map +1 -1
  59. package/dist/multicast-manager.d.ts +28 -5
  60. package/dist/multicast-manager.d.ts.map +1 -1
  61. package/dist/multicast-manager.js +16116 -15005
  62. package/dist/multicast-manager.js.map +4 -4
  63. package/dist/multicast-transport.d.ts +11 -3
  64. package/dist/multicast-transport.d.ts.map +1 -1
  65. package/dist/multicast-transport.js +281 -35
  66. package/dist/multicast-transport.js.map +4 -4
  67. package/dist/multicast-unwrap.js +12 -19
  68. package/dist/multicast-unwrap.js.map +2 -2
  69. package/dist/no-modules.js +336 -59
  70. package/dist/no-modules.js.map +3 -3
  71. package/dist/repair-fetch.d.ts +36 -8
  72. package/dist/repair-fetch.d.ts.map +1 -1
  73. package/dist/repair-fetch.js +285 -26
  74. package/dist/repair-fetch.js.map +3 -3
  75. package/dist/repair-layer-subscriptions.d.ts +82 -0
  76. package/dist/repair-layer-subscriptions.d.ts.map +1 -0
  77. package/dist/repair-layer-subscriptions.js +192 -0
  78. package/dist/repair-layer-subscriptions.js.map +7 -0
  79. package/dist/signaling.js.map +2 -2
  80. package/dist/timestamp-codec.js +12 -19
  81. package/dist/timestamp-codec.js.map +2 -2
  82. package/dist/track-session.d.ts +1 -1
  83. package/dist/track-session.d.ts.map +1 -1
  84. package/dist/track-session.js +1 -0
  85. package/dist/track-session.js.map +2 -2
  86. package/dist/wasm-mfu-reassembler.js.map +1 -1
  87. package/dist/wasm-mmtp-container-parser.js +218 -45
  88. package/dist/wasm-mmtp-container-parser.js.map +2 -2
  89. package/package.json +8 -5
  90. package/schemas/catalog.schema.json +4 -0
  91. package/src/catalog-fec-params.ts +36 -1
  92. package/src/cmcd-producer.ts +194 -179
  93. package/src/fec-manager.ts +433 -32
  94. package/src/fec-worker-setup.ts +2 -2
  95. package/src/index.ts +20 -2
  96. package/src/iso-block-locator.ts +133 -31
  97. package/src/iso-bmff-timing.ts +40 -1
  98. package/src/mmtp-container-parser.ts +306 -29
  99. package/src/mmtp-fec-session.ts +115 -15
  100. package/src/mmtp-router.ts +629 -54
  101. package/src/multicast-manager.ts +70 -11
  102. package/src/multicast-transport.ts +44 -20
  103. package/src/repair-fetch.ts +363 -49
  104. package/src/repair-layer-subscriptions.ts +261 -0
  105. package/src/track-session.ts +4 -1
@@ -32,16 +32,28 @@ export type IsoRepairPlacement<T> = {
32
32
  readonly lostSsId: number;
33
33
  };
34
34
  }
35
- /** Not a block this stream can use; the repair symbol is dropped. */
35
+ /**
36
+ * Not a block this stream can use; the repair symbol is dropped. `ofSpan` is
37
+ * set when the repair stated only the first block of that repair-less span:
38
+ * the span holds more than one block, so no single repair group completes it.
39
+ */
36
40
  | {
37
41
  readonly status: 'conflict' | 'overlap' | 'stale' | 'ahead';
38
42
  readonly reason: string;
43
+ readonly ofSpan?: IsoBlockRange;
39
44
  };
40
45
  /**
41
46
  * Retention: the locator is never without one. Every call that can grow it
42
47
  * (`hold`, `placeRepair`) retires, behind the position it just saw, every
43
48
  * block, span and held source more than `retentionBlocks` blocks back, by the
44
- * one ISO horizon metric (`isoBlocksBehindLowerBound`). A block is measured
49
+ * one ISO horizon metric (`isoBlocksBehindLowerBound`). A held source stays
50
+ * while a pending hole holding it does: the hole's repair FETCH may still
51
+ * state its block, and closing the hole places it, so the span it leaves
52
+ * counts every source it received (BLO-52085). A pending hole the horizon
53
+ * passes stops being pending (its blocks can no longer be stated, and the
54
+ * release gate no longer waits for it), but keeps its sources until its
55
+ * owner closes it (`takeExpiredHoles`), so it still fails as the span it
56
+ * is. A block is measured
45
57
  * from its last SS_ID, so it stays while any SS_ID of it is inside the
46
58
  * horizon: a repair-less span has no length bound, and one measured from its
47
59
  * start could be retired the moment it is created, before the sources it
@@ -82,6 +94,15 @@ export declare class IsoBlockLocator<T> {
82
94
  get newest(): number | undefined;
83
95
  /** Advance `newest` to `position` if it is newer; retires nothing. */
84
96
  observe(position: number): void;
97
+ /**
98
+ * The newest source SS_ID noted with `noteSource` (RFC 1982 order). Unlike
99
+ * `newest`, a repair never moves it: a repair can run ahead of its sources,
100
+ * a source cannot run ahead of the sources sent before it except by
101
+ * reordering.
102
+ */
103
+ get newestSource(): number | undefined;
104
+ /** Note a received source's SS_ID; true when it is the newest one yet. */
105
+ noteSource(ssId: number): boolean;
85
106
  /** Held sources evicted by `heldCapacity` (never by the horizon itself). */
86
107
  get heldEvicted(): number;
87
108
  /** Number of known blocks and spans. */
@@ -95,8 +116,16 @@ export declare class IsoBlockLocator<T> {
95
116
  block: IsoBlockRange;
96
117
  esi: number;
97
118
  } | null;
98
- /** Number of pending holes. */
119
+ /** Number of holes not closed yet, pending or past the horizon. */
99
120
  get holeCount(): number;
121
+ /**
122
+ * The pending holes the horizon has passed since the last call, in the
123
+ * order it passed them. Each is no longer pending: no repair states a block
124
+ * in it (that repair is `stale`, as for a span the horizon retired) and the
125
+ * release gate does not wait for it. Its owner must close it
126
+ * (`closeHolesWithin`), which turns it into a span that is not kept here.
127
+ */
128
+ takeExpiredHoles(): IsoBlockRange[];
100
129
  /** The stated block (never a span) ending exactly at `end`. */
101
130
  blockEndingAt(end: number): IsoBlockRange | undefined;
102
131
  /** The known block or span starting exactly at `start`. */
@@ -119,9 +148,11 @@ export declare class IsoBlockLocator<T> {
119
148
  /**
120
149
  * Apply one repair symbol's `(SS_Start, SSB_length)`. The first repair of a
121
150
  * block states its range and places every held source in it; later repair
122
- * symbols of the same block change nothing. A range that contradicts a
123
- * known block (a different length, or an overlap with another block or a
124
- * span) fails closed: the repair symbol is dropped and no block changes.
151
+ * symbols of the same block change nothing. A repair whose range is exactly
152
+ * a repair-less span states that span's one block. A range that contradicts
153
+ * a known block (a different length, or an overlap with another block or
154
+ * with part of a span) fails closed: the repair symbol is dropped and no
155
+ * block changes.
125
156
  * A newly stated block retires behind its SS_Start (see the class note).
126
157
  * A block so far past `newest` that stating it would retire the position
127
158
  * `newest` is refused as `ahead`. When `newest` is a placed block's SS_Start
@@ -135,19 +166,23 @@ export declare class IsoBlockLocator<T> {
135
166
  */
136
167
  placeRepair(start: number, length: number): IsoRepairPlacement<T>;
137
168
  /**
138
- * Turn every pending hole inside `[start, start + length)` into a
139
- * repair-less span, claiming its held sources: its range FETCH ended, so
140
- * nothing more will state its blocks. Returns the spans, in SS_ID order.
169
+ * Turn every hole inside `[start, start + length)` into a repair-less span,
170
+ * claiming its held sources: its range FETCH ended, so nothing more will
171
+ * state its blocks. A hole the horizon passed (`takeExpiredHoles`) leaves a
172
+ * span that is not kept among the blocks, as the horizon would retire it at
173
+ * once; only `locate` finds it, until the next retirement, so its sources
174
+ * can be fed. Returns the spans, in SS_ID order.
141
175
  */
142
176
  closeHolesWithin(start: number, length: number): {
143
177
  block: IsoBlockRange;
144
178
  placed: IsoPlacedSource<T>[];
145
179
  }[];
146
180
  /**
147
- * Retire every block and span whose last SS_ID, and every held source,
148
- * lies more than `retentionBlocks` blocks behind `position`, with the shared
149
- * lower-bound metric (`isoBlocksBehindLowerBound`) every ISO interleave
150
- * horizon uses. Returns the retired block starts.
181
+ * Retire every block and span whose last SS_ID, and every held source
182
+ * outside a hole, lies more than `retentionBlocks` blocks behind
183
+ * `position`, with the shared lower-bound metric (`isoBlocksBehindLowerBound`)
184
+ * every ISO interleave horizon uses; a pending hole so far behind expires
185
+ * (`takeExpiredHoles`). Returns the retired block starts.
151
186
  */
152
187
  retireBehind(position: number): number[];
153
188
  /** Forget everything (publisher restart, track reset). */
@@ -1 +1 @@
1
- {"version":3,"file":"iso-block-locator.d.ts","sourceRoot":"","sources":["../src/iso-block-locator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"iso-block-locator.d.ts","sourceRoot":"","sources":["../src/iso-block-locator.ts"],"names":[],"mappings":"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"}
@@ -71,6 +71,15 @@ var IsoBlockLocator = class _IsoBlockLocator {
71
71
  this.#heldEvicted = 0;
72
72
  /** Pending holes (see `deferIncompleteGaps`): unstated, sources still held. */
73
73
  this.#holes = [];
74
+ /** Holes the horizon passed while pending: sources held until closed. */
75
+ this.#expired = [];
76
+ /** Of `#expired`, those `takeExpiredHoles` has not handed out yet. */
77
+ this.#newlyExpired = [];
78
+ /**
79
+ * Spans closed from expired holes: behind the horizon, so kept only for
80
+ * `locate` while their sources are fed, until the next retirement.
81
+ */
82
+ this.#closedBehind = [];
74
83
  /**
75
84
  * Keep a gap that is missing a source as a pending hole rather than a span,
76
85
  * so a repair FETCHed for it (draft-ramadan-moq-fec §7.5) can still state
@@ -92,7 +101,11 @@ var IsoBlockLocator = class _IsoBlockLocator {
92
101
  #retentionBlocks;
93
102
  #heldEvicted;
94
103
  #newest;
104
+ #newestSource;
95
105
  #holes;
106
+ #expired;
107
+ #newlyExpired;
108
+ #closedBehind;
96
109
  static #checkedRetention(retentionBlocks) {
97
110
  if (!Number.isSafeInteger(retentionBlocks) || retentionBlocks <= 0) {
98
111
  throw new Error(
@@ -129,6 +142,21 @@ var IsoBlockLocator = class _IsoBlockLocator {
129
142
  observe(position) {
130
143
  if (this.#newest === void 0 || serial32Precedes(this.#newest, position)) this.#newest = position;
131
144
  }
145
+ /**
146
+ * The newest source SS_ID noted with `noteSource` (RFC 1982 order). Unlike
147
+ * `newest`, a repair never moves it: a repair can run ahead of its sources,
148
+ * a source cannot run ahead of the sources sent before it except by
149
+ * reordering.
150
+ */
151
+ get newestSource() {
152
+ return this.#newestSource;
153
+ }
154
+ /** Note a received source's SS_ID; true when it is the newest one yet. */
155
+ noteSource(ssId) {
156
+ if (this.#newestSource !== void 0 && !serial32Precedes(this.#newestSource, ssId)) return false;
157
+ this.#newestSource = ssId;
158
+ return true;
159
+ }
132
160
  /** Held sources evicted by `heldCapacity` (never by the horizon itself). */
133
161
  get heldEvicted() {
134
162
  return this.#heldEvicted;
@@ -147,17 +175,29 @@ var IsoBlockLocator = class _IsoBlockLocator {
147
175
  }
148
176
  /** The known block or span containing `ssId`, with its ESI. */
149
177
  locate(ssId) {
150
- for (let i = this.#blocks.length - 1; i >= 0; i--) {
151
- const block = this.#blocks[i];
152
- if (isoBlockContains(block.start, block.length, ssId)) {
153
- return { block, esi: serial32Distance(block.start, ssId) };
178
+ for (const blocks of [this.#blocks, this.#closedBehind]) {
179
+ for (let i = blocks.length - 1; i >= 0; i--) {
180
+ const block = blocks[i];
181
+ if (isoBlockContains(block.start, block.length, ssId)) {
182
+ return { block, esi: serial32Distance(block.start, ssId) };
183
+ }
154
184
  }
155
185
  }
156
186
  return null;
157
187
  }
158
- /** Number of pending holes. */
188
+ /** Number of holes not closed yet, pending or past the horizon. */
159
189
  get holeCount() {
160
- return this.#holes.length;
190
+ return this.#holes.length + this.#expired.length;
191
+ }
192
+ /**
193
+ * The pending holes the horizon has passed since the last call, in the
194
+ * order it passed them. Each is no longer pending: no repair states a block
195
+ * in it (that repair is `stale`, as for a span the horizon retired) and the
196
+ * release gate does not wait for it. Its owner must close it
197
+ * (`closeHolesWithin`), which turns it into a span that is not kept here.
198
+ */
199
+ takeExpiredHoles() {
200
+ return this.#newlyExpired.splice(0);
161
201
  }
162
202
  /** The stated block (never a span) ending exactly at `end`. */
163
203
  blockEndingAt(end) {
@@ -213,9 +253,11 @@ var IsoBlockLocator = class _IsoBlockLocator {
213
253
  /**
214
254
  * Apply one repair symbol's `(SS_Start, SSB_length)`. The first repair of a
215
255
  * block states its range and places every held source in it; later repair
216
- * symbols of the same block change nothing. A range that contradicts a
217
- * known block (a different length, or an overlap with another block or a
218
- * span) fails closed: the repair symbol is dropped and no block changes.
256
+ * symbols of the same block change nothing. A repair whose range is exactly
257
+ * a repair-less span states that span's one block. A range that contradicts
258
+ * a known block (a different length, or an overlap with another block or
259
+ * with part of a span) fails closed: the repair symbol is dropped and no
260
+ * block changes.
219
261
  * A newly stated block retires behind its SS_Start (see the class note).
220
262
  * A block so far past `newest` that stating it would retire the position
221
263
  * `newest` is refused as `ahead`. When `newest` is a placed block's SS_Start
@@ -234,7 +276,16 @@ var IsoBlockLocator = class _IsoBlockLocator {
234
276
  const known = this.blockAt(start);
235
277
  if (known !== void 0) {
236
278
  if (known.span) {
237
- return { status: "overlap", reason: `repair block ${start}+${length} falls inside a repair-less span` };
279
+ if (known.length === length) {
280
+ const block2 = { start, length, span: false };
281
+ this.#blocks[this.#blocks.indexOf(known)] = block2;
282
+ return { status: "placed", block: block2, placed: [] };
283
+ }
284
+ return length < known.length ? {
285
+ status: "overlap",
286
+ reason: `repair block ${start}+${length} is only the first block of repair-less span ${known.start}+${known.length}`,
287
+ ofSpan: known
288
+ } : { status: "overlap", reason: `repair block ${start}+${length} runs past repair-less span ${known.start}+${known.length}` };
238
289
  }
239
290
  if (known.length !== length) {
240
291
  return {
@@ -302,18 +353,28 @@ var IsoBlockLocator = class _IsoBlockLocator {
302
353
  return span === void 0 ? { status: "placed", block, placed } : { status: "placed", block, placed, span };
303
354
  }
304
355
  /**
305
- * Turn every pending hole inside `[start, start + length)` into a
306
- * repair-less span, claiming its held sources: its range FETCH ended, so
307
- * nothing more will state its blocks. Returns the spans, in SS_ID order.
356
+ * Turn every hole inside `[start, start + length)` into a repair-less span,
357
+ * claiming its held sources: its range FETCH ended, so nothing more will
358
+ * state its blocks. A hole the horizon passed (`takeExpiredHoles`) leaves a
359
+ * span that is not kept among the blocks, as the horizon would retire it at
360
+ * once; only `locate` finds it, until the next retirement, so its sources
361
+ * can be fed. Returns the spans, in SS_ID order.
308
362
  */
309
363
  closeHolesWithin(start, length) {
310
364
  const closed = [];
311
- for (const hole of [...this.#holes]) {
312
- if (!isoBlockContains(start, length, hole.start)) continue;
313
- this.#holes.splice(this.#holes.indexOf(hole), 1);
314
- const spanBlock = { start: hole.start, length: hole.length, span: true };
315
- closed.push({ block: spanBlock, placed: this.#claim(spanBlock) });
316
- this.#blocks.push(spanBlock);
365
+ for (const holes of [this.#holes, this.#expired]) {
366
+ for (const hole of [...holes]) {
367
+ if (!isoBlockContains(start, length, hole.start)) continue;
368
+ holes.splice(holes.indexOf(hole), 1);
369
+ const spanBlock = { start: hole.start, length: hole.length, span: true };
370
+ closed.push({ block: spanBlock, placed: this.#claim(spanBlock) });
371
+ if (holes === this.#holes) {
372
+ this.#blocks.push(spanBlock);
373
+ } else {
374
+ this.#closedBehind.push(spanBlock);
375
+ if (this.#newlyExpired.includes(hole)) this.#newlyExpired.splice(this.#newlyExpired.indexOf(hole), 1);
376
+ }
377
+ }
317
378
  }
318
379
  return closed.sort((x, y) => serial32Distance(start, x.block.start) - serial32Distance(start, y.block.start));
319
380
  }
@@ -327,15 +388,17 @@ var IsoBlockLocator = class _IsoBlockLocator {
327
388
  return void 0;
328
389
  }
329
390
  /**
330
- * Retire every block and span whose last SS_ID, and every held source,
331
- * lies more than `retentionBlocks` blocks behind `position`, with the shared
332
- * lower-bound metric (`isoBlocksBehindLowerBound`) every ISO interleave
333
- * horizon uses. Returns the retired block starts.
391
+ * Retire every block and span whose last SS_ID, and every held source
392
+ * outside a hole, lies more than `retentionBlocks` blocks behind
393
+ * `position`, with the shared lower-bound metric (`isoBlocksBehindLowerBound`)
394
+ * every ISO interleave horizon uses; a pending hole so far behind expires
395
+ * (`takeExpiredHoles`). Returns the retired block starts.
334
396
  */
335
397
  retireBehind(position) {
336
398
  this.observe(position);
337
399
  const horizon = this.#retentionBlocks;
338
400
  const retired = [];
401
+ this.#closedBehind.length = 0;
339
402
  for (let i = this.#blocks.length - 1; i >= 0; i--) {
340
403
  const block = this.#blocks[i];
341
404
  const last = serial32Add(block.start, block.length - 1);
@@ -347,10 +410,15 @@ var IsoBlockLocator = class _IsoBlockLocator {
347
410
  for (let i = this.#holes.length - 1; i >= 0; i--) {
348
411
  const hole = this.#holes[i];
349
412
  const last = serial32Add(hole.start, hole.length - 1);
350
- if (isoBlocksBehindLowerBound(last, position, this.#kMax) > horizon) this.#holes.splice(i, 1);
413
+ if (isoBlocksBehindLowerBound(last, position, this.#kMax) <= horizon) continue;
414
+ this.#holes.splice(i, 1);
415
+ this.#expired.push(hole);
416
+ this.#newlyExpired.push(hole);
351
417
  }
352
418
  for (const ssId of [...this.#held.keys()]) {
353
- if (isoBlocksBehindLowerBound(ssId, position, this.#kMax) > horizon) this.#held.delete(ssId);
419
+ if (isoBlocksBehindLowerBound(ssId, position, this.#kMax) > horizon && !this.#holes.some((hole) => isoBlockContains(hole.start, hole.length, ssId)) && !this.#expired.some((hole) => isoBlockContains(hole.start, hole.length, ssId))) {
420
+ this.#held.delete(ssId);
421
+ }
354
422
  }
355
423
  return retired;
356
424
  }
@@ -358,9 +426,13 @@ var IsoBlockLocator = class _IsoBlockLocator {
358
426
  reset() {
359
427
  this.#blocks.length = 0;
360
428
  this.#holes.length = 0;
429
+ this.#expired.length = 0;
430
+ this.#newlyExpired.length = 0;
431
+ this.#closedBehind.length = 0;
361
432
  this.#held.clear();
362
433
  this.#coverageEnd = void 0;
363
434
  this.#newest = void 0;
435
+ this.#newestSource = void 0;
364
436
  }
365
437
  #claim(block) {
366
438
  const placed = [];