@blockcast/mmt-container 0.5.0 → 1.0.0-main.3cb7359ea316

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 (136) hide show
  1. package/README.md +21 -16
  2. package/dist/browser-runtime.js +1024 -1078
  3. package/dist/browser-runtime.js.map +4 -4
  4. package/dist/carp-catalog.d.ts +33 -87
  5. package/dist/carp-catalog.d.ts.map +1 -1
  6. package/dist/carp-catalog.js +12 -434
  7. package/dist/carp-catalog.js.map +4 -4
  8. package/dist/catalog-fec-params.d.ts +48 -161
  9. package/dist/catalog-fec-params.d.ts.map +1 -1
  10. package/dist/catalog-fec-params.js +567 -592
  11. package/dist/catalog-fec-params.js.map +4 -4
  12. package/dist/catalog-network-source.js +6 -2
  13. package/dist/catalog-network-source.js.map +3 -3
  14. package/dist/delivery-catalog.js +12 -4
  15. package/dist/delivery-catalog.js.map +4 -4
  16. package/dist/delta-fallback-config.d.ts +21 -26
  17. package/dist/delta-fallback-config.d.ts.map +1 -1
  18. package/dist/delta-fallback-config.js +582 -24
  19. package/dist/delta-fallback-config.js.map +4 -4
  20. package/dist/fec-manager.js +6 -2
  21. package/dist/fec-manager.js.map +3 -3
  22. package/dist/fec-state.d.ts +5 -43
  23. package/dist/fec-state.d.ts.map +1 -1
  24. package/dist/fec-state.js +529 -34
  25. package/dist/fec-state.js.map +4 -4
  26. package/dist/fec-worker-setup.js +6 -2
  27. package/dist/fec-worker-setup.js.map +3 -3
  28. package/dist/held-layer-admission.js +6 -2
  29. package/dist/held-layer-admission.js.map +3 -3
  30. package/dist/index.d.ts +3 -3
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +5 -39
  33. package/dist/index.js.map +2 -2
  34. package/dist/iso-block-locator.js +6 -2
  35. package/dist/iso-block-locator.js.map +3 -3
  36. package/dist/mfu-reassembler.js +6 -2
  37. package/dist/mfu-reassembler.js.map +3 -3
  38. package/dist/mmtp-container-parser.js +6 -2
  39. package/dist/mmtp-container-parser.js.map +3 -3
  40. package/dist/mmtp-container-parser.no-modules.js +551 -452
  41. package/dist/mmtp-container-parser.no-modules.js.map +4 -4
  42. package/dist/mmtp-decode-pipeline.js +6 -2
  43. package/dist/mmtp-decode-pipeline.js.map +3 -3
  44. package/dist/mmtp-fec-session.d.ts +7 -6
  45. package/dist/mmtp-fec-session.d.ts.map +1 -1
  46. package/dist/mmtp-fec-session.js +13 -9
  47. package/dist/mmtp-fec-session.js.map +3 -3
  48. package/dist/mmtp-router.d.ts +7 -16
  49. package/dist/mmtp-router.d.ts.map +1 -1
  50. package/dist/mmtp-router.js +19 -29
  51. package/dist/mmtp-router.js.map +3 -3
  52. package/dist/multicast-auth-catalog.js +7 -3
  53. package/dist/multicast-auth-catalog.js.map +3 -3
  54. package/dist/multicast-input.js +7 -3
  55. package/dist/multicast-input.js.map +3 -3
  56. package/dist/multicast-manager.d.ts +29 -32
  57. package/dist/multicast-manager.d.ts.map +1 -1
  58. package/dist/multicast-manager.js +682 -253
  59. package/dist/multicast-manager.js.map +4 -4
  60. package/dist/multicast-transport.d.ts +23 -2
  61. package/dist/multicast-transport.d.ts.map +1 -1
  62. package/dist/multicast-transport.js +57 -16
  63. package/dist/multicast-transport.js.map +4 -4
  64. package/dist/multicast-unwrap.js +6 -2
  65. package/dist/multicast-unwrap.js.map +3 -3
  66. package/dist/no-modules.js +551 -452
  67. package/dist/no-modules.js.map +4 -4
  68. package/dist/phase14-catalog-override.d.ts +10 -5
  69. package/dist/phase14-catalog-override.d.ts.map +1 -1
  70. package/dist/phase14-catalog-override.js +35 -11
  71. package/dist/phase14-catalog-override.js.map +2 -2
  72. package/dist/repair-fetch.d.ts +3 -1
  73. package/dist/repair-fetch.d.ts.map +1 -1
  74. package/dist/repair-fetch.js +16 -3
  75. package/dist/repair-fetch.js.map +3 -3
  76. package/dist/repair-layers.d.ts +0 -123
  77. package/dist/repair-layers.d.ts.map +1 -1
  78. package/dist/repair-layers.js +1 -349
  79. package/dist/repair-layers.js.map +3 -3
  80. package/dist/signaling.js +6 -2
  81. package/dist/signaling.js.map +3 -3
  82. package/dist/timestamp-codec.js +6 -2
  83. package/dist/timestamp-codec.js.map +3 -3
  84. package/dist/wasm-mfu-reassembler.js +6 -2
  85. package/dist/wasm-mfu-reassembler.js.map +3 -3
  86. package/dist/wasm-mmtp-container-parser.js +6 -2
  87. package/dist/wasm-mmtp-container-parser.js.map +3 -3
  88. package/package.json +9 -5
  89. package/schemas/catalog.schema.json +53 -58
  90. package/src/carp-catalog.ts +39 -229
  91. package/src/catalog-fec-params.ts +130 -493
  92. package/src/delta-fallback-config.ts +63 -50
  93. package/src/fec-state.ts +7 -62
  94. package/src/index.ts +10 -30
  95. package/src/mmtp-fec-session.ts +11 -10
  96. package/src/mmtp-router.ts +14 -29
  97. package/src/multicast-manager.ts +89 -121
  98. package/src/multicast-transport.ts +65 -12
  99. package/src/phase14-catalog-override.ts +67 -16
  100. package/src/repair-fetch.ts +27 -3
  101. package/src/repair-layers.ts +7 -520
  102. package/test-vectors/catalog/README.md +39 -67
  103. package/test-vectors/catalog/fec-01-runtime/README.md +15 -0
  104. package/test-vectors/catalog/{negative/fec-block-profile-retired.json → fec-01-runtime/fec-iso-ssbg1.json} +1 -1
  105. package/test-vectors/catalog/fec-01-runtime/fec-layered-repair.json +106 -0
  106. package/test-vectors/catalog/{negative/fec-block-profile-unknown.json → fec-01-runtime/fec-multicast.json} +2 -1
  107. package/test-vectors/catalog/fec-01-runtime/multicast-native-ssm-no-network-source.json +44 -0
  108. package/test-vectors/catalog/negative/fec-block-profile-missing.json +24 -11
  109. package/test-vectors/catalog/negative/fec-iso-symbol-size-below-floor.json +13 -8
  110. package/test-vectors/catalog/negative/fec-reed-solomon-iso-symbol-size-13.json +13 -8
  111. package/test-vectors/catalog/negative/fec-repair-layer-geometry.json +20 -10
  112. package/test-vectors/catalog/negative/fec-repair-layer-missing-symbols.json +20 -10
  113. package/test-vectors/catalog/negative/fec-repair-overlay-source-symbols-zero.json +25 -17
  114. package/test-vectors/catalog/negative/fec-repair-symbols-zero.json +13 -8
  115. package/test-vectors/catalog/negative/fec-source-symbols-zero.json +13 -8
  116. package/test-vectors/catalog/negative/fec-symbol-size-zero.json +13 -8
  117. package/test-vectors/catalog/negative/raptorq-source-symbols-over-max.json +18 -9
  118. package/test-vectors/catalog/negative/raptorq-unaligned-symbol.json +13 -8
  119. package/test-vectors/catalog/positive/fec-algorithm-unimplemented.json +14 -9
  120. package/test-vectors/catalog/positive/fec-iso-ssbg1.json +25 -12
  121. package/test-vectors/catalog/positive/fec-layered-repair.json +79 -35
  122. package/test-vectors/catalog/positive/fec-multicast.json +26 -13
  123. package/test-vectors/catalog/positive/fec-reed-solomon-layered.json +29 -18
  124. package/test-vectors/catalog/positive/multicast-draft01-4-1-example.json +28 -20
  125. package/test-vectors/catalog/positive/multicast-draft01-7-2-6-example.json +14 -10
  126. package/test-vectors/catalog/positive/multicast-native-ssm-no-network-source.json +22 -12
  127. package/test-vectors/catalog/section-codes.json +13 -22
  128. package/test-vectors/catalog-timing.json +2 -2
  129. package/test-vectors/catalog-validation.json +30 -243
  130. package/test-vectors/catalog/negative/fec-enhancement-repair-removed.json +0 -28
  131. package/test-vectors/catalog/negative/fec-reed-solomon-k-plus-p-over-255.json +0 -39
  132. package/test-vectors/catalog/negative/fec-reed-solomon-overlay-over-255.json +0 -40
  133. package/test-vectors/catalog/negative/fec-repair-multiple-depends.json +0 -32
  134. package/test-vectors/catalog/negative/fec-repair-overlay-with-layer.json +0 -34
  135. package/test-vectors/catalog/negative/fec-repair-priority-out-of-band.json +0 -24
  136. package/test-vectors/catalog/negative/fec-repair-source-symbols-without-scope.json +0 -33
@@ -14,21 +14,6 @@ var NTP_SHORT_HALF_RANGE = 2 ** (NTP_SHORT_BITS - 1);
14
14
  var FEC_BLOCK_PROFILES = Object.freeze([
15
15
  "iso-ssbg1-v1"
16
16
  ]);
17
- function isFecBlockProfile(value) {
18
- return value === "iso-ssbg1-v1";
19
- }
20
- function parseFecBlockProfile(value, where) {
21
- if (isFecBlockProfile(value))
22
- return value;
23
- if (value === void 0) {
24
- throw new Error(`${where} is required: name the FEC block profile ("iso-ssbg1-v1")`);
25
- }
26
- throw new Error(`${where} must be "iso-ssbg1-v1" (got ${JSON.stringify(value)})`);
27
- }
28
-
29
- // ../mmt-base/dist/catalog-fec-source.js
30
- var ALL_ROLES = Object.freeze(["video", "audio"]);
31
- var ISO_SSBG1_MIN_SYMBOL_SIZE = 14;
32
17
 
33
18
  // ../mmt-base/dist/multicast-catalog.js
34
19
  var ED25519_PUBLIC_KEY_BASE64URL = /^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/;
@@ -278,320 +263,12 @@ function multicastCatalogIssues(catalog, options = {}) {
278
263
  return issues;
279
264
  }
280
265
 
281
- // src/repair-layers.ts
282
- var REPAIR_PRIORITY_MIN = 192;
283
- var REPAIR_PRIORITY_MAX = 255;
284
- var DEFAULT_REPAIR_PRIORITY = 240;
285
- var MAX_RAPTORQ_SOURCE_SYMBOLS = 56403;
286
- var MAX_REPAIR_SYMBOLS = 16777215;
287
- var MAX_ENCODING_SYMBOL_ID = 16777215;
288
- var MAX_REED_SOLOMON_BLOCK_SYMBOLS = 255;
289
- var RepairContractError = class extends Error {
290
- constructor(code, path, message) {
291
- super(`[repair-layers:${code}] ${path}: ${message}`);
292
- this.code = code;
293
- this.path = path;
294
- this.name = "RepairContractError";
295
- }
296
- };
297
- var throwRepairContractError = (code, path, message) => {
298
- throw new RepairContractError(code, path, message);
299
- };
300
- function readFecBlockProfile(value, path, declaresFecInstance, fail) {
301
- if (value === void 0 && !declaresFecInstance) return void 0;
302
- if (isFecBlockProfile(value)) return value;
303
- if (typeof value === "string" && value.length > 0) {
304
- return fail(
305
- "track_fec_block_profile_unimplemented",
306
- path,
307
- `${JSON.stringify(value)} is not an implemented FEC block profile; only "iso-ssbg1-v1" is implemented`
308
- );
309
- }
310
- try {
311
- return parseFecBlockProfile(value, "blockProfile");
312
- } catch (error) {
313
- return fail("track_fec_block_profile", path, error.message);
314
- }
315
- }
316
- var REPAIR_FIELDS = ["depends", "repairLayer", "repairSymbols", "priority", "scope", "sourceSymbols"];
317
- var REPAIR_TRACK_GEOMETRY_KEYS = [
318
- "mmtpMode",
319
- "timescale",
320
- "groupDurationMs",
321
- "groupDurationTicks",
322
- "keyframeIntervalMs",
323
- "keyframeIntervalTicks",
324
- "fec",
325
- "symbolSize",
326
- "interleaveDepthMs"
327
- ];
328
- var REPAIR_TRACK_ONLY_KEYS = ["repairLayer", "repairSymbols", "sourceSymbols", "scope"];
329
- function rejectRepairTrackGeometry(path, fields, fail) {
330
- for (const key of REPAIR_TRACK_GEOMETRY_KEYS) {
331
- if (fields[key] !== void 0) {
332
- fail(
333
- "track_repair_geometry",
334
- `${path}.${key}`,
335
- "a repair track carries no block geometry; it is shared with the source track's fec object"
336
- );
337
- }
338
- }
339
- }
340
- function repairReachability(fecObjects) {
341
- let declaresFecSource = false;
342
- const layerZeroNames = /* @__PURE__ */ new Set();
343
- for (const candidate of fecObjects) {
344
- if (typeof candidate !== "object" || candidate === null || Array.isArray(candidate)) continue;
345
- const fec = candidate;
346
- if (fec["algorithm"] === "none") continue;
347
- declaresFecSource = true;
348
- const repairTrack = fec["repairTrack"];
349
- if (typeof repairTrack === "string" && repairTrack.length > 0) layerZeroNames.add(repairTrack);
350
- }
351
- return { declaresFecSource, layerZeroNames };
352
- }
353
- function assertRepairTrackReachable(descriptor, reachability, fail) {
354
- if (dependsTarget(descriptor) !== void 0) return;
355
- if (reachability.declaresFecSource && !reachability.layerZeroNames.has(descriptor.name)) {
356
- fail(
357
- "track_repair_depends",
358
- `${descriptor.path}.depends`,
359
- "no source names this repair track in fec.repairTrack and it declares no depends"
360
- );
361
- }
362
- }
363
- function rejectRepairFieldsOnMediaTrack(path, fields, fail) {
364
- for (const key of REPAIR_TRACK_ONLY_KEYS) {
365
- if (fields[key] !== void 0) {
366
- fail("track_repair_layer", `${path}.${key}`, `${key} is a repair track field`);
367
- }
368
- }
369
- }
370
- function describeRepairTrack(name, path, fields) {
371
- const descriptor = { name, path };
372
- for (const field of REPAIR_FIELDS) {
373
- if (field in fields) descriptor[field] = fields[field];
374
- }
375
- return descriptor;
376
- }
377
- function isSafeInteger(value) {
378
- return typeof value === "number" && Number.isSafeInteger(value);
379
- }
380
- function positiveInteger(value) {
381
- return isSafeInteger(value) && value > 0;
382
- }
383
- function dependsTarget(descriptor) {
384
- const depends = descriptor.depends;
385
- return Array.isArray(depends) && depends.length === 1 && typeof depends[0] === "string" && depends[0].length > 0 ? depends[0] : void 0;
386
- }
387
- function validateRepairTrackFields(descriptor, fail) {
388
- const { path } = descriptor;
389
- if (descriptor.depends !== void 0 && dependsTarget(descriptor) === void 0) {
390
- fail("track_repair_depends", `${path}.depends`, "must name exactly one source track");
391
- }
392
- if (descriptor.repairLayer !== void 0 && (!isSafeInteger(descriptor.repairLayer) || descriptor.repairLayer < 0)) {
393
- fail("track_repair_layer", `${path}.repairLayer`, "must be a non-negative integer");
394
- }
395
- if (descriptor.repairSymbols !== void 0 && (!positiveInteger(descriptor.repairSymbols) || descriptor.repairSymbols > MAX_REPAIR_SYMBOLS)) {
396
- fail("track_repair_layer", `${path}.repairSymbols`, `must be a positive integer at most ${MAX_REPAIR_SYMBOLS}`);
397
- }
398
- if (descriptor.priority !== void 0 && (!isSafeInteger(descriptor.priority) || descriptor.priority < REPAIR_PRIORITY_MIN || descriptor.priority > REPAIR_PRIORITY_MAX)) {
399
- fail(
400
- "track_repair_priority",
401
- `${path}.priority`,
402
- `must be an integer from ${REPAIR_PRIORITY_MIN} to ${REPAIR_PRIORITY_MAX} (MoQT scale, lower first)`
403
- );
404
- }
405
- if (descriptor.scope !== void 0) {
406
- if (descriptor.scope !== "keyframe") {
407
- fail("track_repair_overlay", `${path}.scope`, 'must be "keyframe"');
408
- }
409
- if (descriptor.repairLayer !== void 0) {
410
- fail("track_repair_overlay", `${path}.repairLayer`, "an overlay is a separate FEC instance and carries no repairLayer");
411
- }
412
- for (const field of ["depends", "sourceSymbols", "repairSymbols", "priority"]) {
413
- if (descriptor[field] === void 0) {
414
- fail("track_repair_overlay", `${path}.${field}`, `an overlay must declare ${field}`);
415
- }
416
- }
417
- }
418
- if (descriptor.sourceSymbols !== void 0) {
419
- if (descriptor.scope === void 0) {
420
- fail("track_repair_overlay", `${path}.sourceSymbols`, "only an overlay (scope: keyframe) declares its own sourceSymbols");
421
- }
422
- if (!positiveInteger(descriptor.sourceSymbols) || descriptor.sourceSymbols > MAX_RAPTORQ_SOURCE_SYMBOLS) {
423
- fail(
424
- "track_fec_bounds",
425
- `${path}.sourceSymbols`,
426
- `must be a positive integer at most ${MAX_RAPTORQ_SOURCE_SYMBOLS} (RFC 6330 source block limit)`
427
- );
428
- }
429
- }
430
- if (isSafeInteger(descriptor.repairLayer) && descriptor.repairLayer >= 1) {
431
- for (const field of ["depends", "repairSymbols", "priority"]) {
432
- if (descriptor[field] === void 0) {
433
- fail("track_repair_layer", `${path}.${field}`, `repair layer ${descriptor.repairLayer} must declare ${field}`);
434
- }
435
- }
436
- }
437
- }
438
- function assembleRepairLayers(source, descriptors, fail = throwRepairContractError, options = {}) {
439
- const layerZeroName = typeof source.repairTrack === "string" && source.repairTrack.length > 0 ? source.repairTrack : void 0;
440
- const layerZero = layerZeroName === void 0 ? void 0 : descriptors.find((d) => d.name === layerZeroName);
441
- if (layerZeroName !== void 0 && layerZero === void 0 && options.layerZeroMustBeDeclared) {
442
- fail("track_repair_track", `${source.path}.repairTrack`, `unknown FEC repair track ${JSON.stringify(layerZeroName)}`);
443
- }
444
- const dependents = descriptors.filter((d) => d.name !== layerZeroName && dependsTarget(d) === source.name);
445
- const k = positiveInteger(source.sourceSymbols) ? source.sourceSymbols : 0;
446
- if (source.algorithm === "raptorq" && k > MAX_RAPTORQ_SOURCE_SYMBOLS) {
447
- fail(
448
- "track_fec_bounds",
449
- `${source.path}.sourceSymbols`,
450
- `must be at most ${MAX_RAPTORQ_SOURCE_SYMBOLS} (RFC 6330 source block limit)`
451
- );
452
- }
453
- if (layerZeroName === void 0) {
454
- if (dependents.length === 0) return void 0;
455
- fail(
456
- "track_repair_layer",
457
- `${dependents[0].path}.depends`,
458
- `repair layers of ${JSON.stringify(source.name)} require a layer 0 (fec.repairTrack) on the source`
459
- );
460
- }
461
- const layered = dependents.length > 0;
462
- let layerZeroSymbols = 0;
463
- if (positiveInteger(source.repairSymbols)) {
464
- layerZeroSymbols = source.repairSymbols;
465
- } else if (layered) {
466
- fail("track_fec", `${source.path}.repairSymbols`, "layered or overlay repair needs a positive integer repairSymbols on layer 0");
467
- }
468
- if (layered && !positiveInteger(source.sourceSymbols)) {
469
- fail("track_fec", `${source.path}.sourceSymbols`, "layered or overlay repair needs a positive integer sourceSymbols on the source");
470
- }
471
- const reedSolomon = source.algorithm === "reed-solomon";
472
- if (layered && source.algorithm !== "raptorq" && !reedSolomon) {
473
- fail(
474
- "track_fec",
475
- `${source.path}.algorithm`,
476
- "repair layers and overlays are defined only for raptorq and reed-solomon (draft-ramadan-moq-fec-01 6.3.4 rule 7)"
477
- );
478
- }
479
- let layerZeroPriority = DEFAULT_REPAIR_PRIORITY;
480
- if (layerZero !== void 0) {
481
- if (layerZero.depends !== void 0 && dependsTarget(layerZero) !== source.name) {
482
- fail(
483
- "track_repair_depends",
484
- `${layerZero.path}.depends`,
485
- `layer 0 of ${JSON.stringify(source.name)} must depend on that source`
486
- );
487
- }
488
- if (layerZero.repairLayer !== void 0 && layerZero.repairLayer !== 0) {
489
- fail("track_repair_layer", `${layerZero.path}.repairLayer`, "the track named by fec.repairTrack is layer 0");
490
- }
491
- if (layerZero.scope !== void 0) {
492
- fail("track_repair_overlay", `${layerZero.path}.scope`, "the track named by fec.repairTrack is base layer 0, not an overlay");
493
- }
494
- if (layerZero.repairSymbols !== void 0 && layerZero.repairSymbols !== layerZeroSymbols) {
495
- fail(
496
- "track_repair_layer",
497
- `${layerZero.path}.repairSymbols`,
498
- `must agree with the source's fec.repairSymbols (${layerZeroSymbols})`
499
- );
500
- }
501
- if (typeof layerZero.priority === "number") layerZeroPriority = layerZero.priority;
502
- }
503
- const baseLayers = [
504
- { layer: 0, repairTrackName: layerZeroName, repairSymbols: layerZeroSymbols, rsIdOffset: 0, priority: layerZeroPriority }
505
- ];
506
- const overlays = [];
507
- for (const d of dependents) {
508
- if (d.scope === void 0 && d.repairLayer === void 0) {
509
- fail(
510
- "track_repair_layer",
511
- `${d.path}.repairLayer`,
512
- `a repair track that depends on ${JSON.stringify(source.name)} must declare repairLayer (1..n) or scope: "keyframe"`
513
- );
514
- }
515
- }
516
- const layerTracks = dependents.filter((d) => d.scope === void 0).sort((a, b) => a.repairLayer - b.repairLayer);
517
- for (const d of dependents) {
518
- if (d.scope !== "keyframe") continue;
519
- if (overlays.length === 1) {
520
- fail(
521
- "track_repair_overlay",
522
- `${d.path}.scope`,
523
- `${JSON.stringify(source.name)} already has keyframe overlay ${JSON.stringify(overlays[0].repairTrackName)}: a RAP packet carries exactly two Source FEC Payload IDs (base, then overlay), so one overlay per source`
524
- );
525
- }
526
- const sourceSymbols = d.sourceSymbols;
527
- const repairSymbols = d.repairSymbols;
528
- if (sourceSymbols + repairSymbols - 1 > MAX_ENCODING_SYMBOL_ID) {
529
- fail(
530
- "track_fec_bounds",
531
- `${d.path}.repairSymbols`,
532
- `overlay sourceSymbols + repairSymbols - 1 exceeds the 24-bit ESI space (${MAX_ENCODING_SYMBOL_ID})`
533
- );
534
- }
535
- if (reedSolomon && sourceSymbols + repairSymbols > MAX_REED_SOLOMON_BLOCK_SYMBOLS) {
536
- fail(
537
- "track_fec_bounds",
538
- `${d.path}.repairSymbols`,
539
- `reed-solomon overlay sourceSymbols + repairSymbols exceeds ${MAX_REED_SOLOMON_BLOCK_SYMBOLS} (draft-ramadan-moq-fec-01 6.3.4 rule 12)`
540
- );
541
- }
542
- overlays.push({ repairTrackName: d.name, scope: "keyframe", sourceSymbols, repairSymbols, priority: d.priority });
543
- }
544
- let offset = layerZeroSymbols;
545
- let previousPriority = layerZeroPriority;
546
- layerTracks.forEach((d, i) => {
547
- const expected = i + 1;
548
- if (d.repairLayer === 0) {
549
- fail("track_repair_layer", `${d.path}.repairLayer`, `layer 0 of ${JSON.stringify(source.name)} is ${JSON.stringify(layerZeroName)}, named by fec.repairTrack`);
550
- }
551
- if (d.repairLayer !== expected) {
552
- fail(
553
- "track_repair_layer",
554
- `${d.path}.repairLayer`,
555
- i > 0 && d.repairLayer === layerTracks[i - 1].repairLayer ? `repair layer ${d.repairLayer} is declared twice for ${JSON.stringify(source.name)}` : `repair layers must be contiguous from 1: expected ${expected}, found ${d.repairLayer}`
556
- );
557
- }
558
- const priority = d.priority;
559
- if (priority < previousPriority) {
560
- fail(
561
- "track_repair_priority",
562
- `${d.path}.priority`,
563
- `must be at least ${previousPriority}, the priority of layer ${expected - 1}: priority is monotonic non-decreasing with layer index`
564
- );
565
- }
566
- previousPriority = priority;
567
- const repairSymbols = d.repairSymbols;
568
- baseLayers.push({ layer: expected, repairTrackName: d.name, repairSymbols, rsIdOffset: offset, priority });
569
- offset += repairSymbols;
570
- });
571
- const totalBaseRepairSymbols = offset;
572
- if (totalBaseRepairSymbols > MAX_REPAIR_SYMBOLS) {
573
- fail(
574
- "track_fec_bounds",
575
- `${layerTracks.length === 0 ? source.path : layerTracks[layerTracks.length - 1].path}.repairSymbols`,
576
- `total repair symbols across base layers exceeds the 24-bit RS_ID space (${MAX_REPAIR_SYMBOLS})`
577
- );
578
- }
579
- if (k + totalBaseRepairSymbols - 1 > MAX_ENCODING_SYMBOL_ID) {
580
- fail(
581
- "track_fec_bounds",
582
- `${source.path}.sourceSymbols`,
583
- `sourceSymbols + total base repair symbols - 1 exceeds the 24-bit ESI space (${MAX_ENCODING_SYMBOL_ID})`
584
- );
585
- }
586
- if (reedSolomon && k + totalBaseRepairSymbols > MAX_REED_SOLOMON_BLOCK_SYMBOLS) {
587
- fail(
588
- "track_fec_bounds",
589
- `${source.path}.sourceSymbols`,
590
- `reed-solomon sourceSymbols + total base repair symbols exceeds ${MAX_REED_SOLOMON_BLOCK_SYMBOLS} (draft-ramadan-moq-fec-01 6.3.4 rule 12)`
591
- );
592
- }
593
- return { sourceTrackName: source.name, baseLayers, overlays, totalBaseRepairSymbols };
594
- }
266
+ // ../mmt-base/dist/fec-bindings.js
267
+ var RUNTIME_FEC_RECEIVER = Object.freeze({
268
+ schemes: Object.freeze(["raptorq", "reed-solomon"]),
269
+ blockProfiles: Object.freeze(["iso-ssbg1-v1"]),
270
+ overlays: true
271
+ });
595
272
 
596
273
  // src/carp-catalog.ts
597
274
  var VALID_ROLE_SUFFIXES = /* @__PURE__ */ new Set(["base", "delta", "repair"]);
@@ -646,18 +323,6 @@ function validateSwitchingSet(trackNames) {
646
323
  }
647
324
  return { ok: true };
648
325
  }
649
- function isFecCatalogGeometry(obj) {
650
- if (typeof obj !== "object" || obj === null) return false;
651
- const o = obj;
652
- const algorithm = o["algorithm"];
653
- const symbolSize = o["symbolSize"];
654
- return typeof algorithm === "string" && algorithm.length > 0 && typeof o["sourceSymbols"] === "number" && o["sourceSymbols"] >= 1 && typeof o["repairSymbols"] === "number" && o["repairSymbols"] >= 1 && typeof symbolSize === "number" && symbolSize >= 1 && (algorithm !== "raptorq" || symbolSize % 8 === 0) && typeof o["repairTrack"] === "string" && o["repairTrack"].length > 0;
655
- }
656
- function isFecCatalogConfig(obj) {
657
- if (!isFecCatalogGeometry(obj)) return false;
658
- const o = obj;
659
- return isFecBlockProfile(o["blockProfile"]) || o["algorithm"] === "none" && o["blockProfile"] === void 0;
660
- }
661
326
  function isMulticastTrackObject(obj) {
662
327
  if (typeof obj !== "object" || obj === null) return false;
663
328
  const o = obj;
@@ -818,7 +483,7 @@ function validateCmsfMmtpCatalog(value, options = {}) {
818
483
  }
819
484
  const tracks = catalog["tracks"];
820
485
  const trackRecords = [];
821
- const positiveInteger2 = (input) => Number.isSafeInteger(input) && input > 0;
486
+ const positiveInteger = (input) => Number.isSafeInteger(input) && input > 0;
822
487
  const positiveNumber = (input) => typeof input === "number" && Number.isFinite(input) && input > 0;
823
488
  for (let index = 0; index < tracks.length; index++) {
824
489
  const raw = tracks[index];
@@ -850,7 +515,7 @@ function validateCmsfMmtpCatalog(value, options = {}) {
850
515
  );
851
516
  }
852
517
  const codec = track["codec"];
853
- if (packaging !== "timeline" && packaging !== "mediatimeline" && packaging !== "eventtimeline" && packaging !== "fec-repair" && (typeof codec !== "string" || codec.length === 0)) {
518
+ if (packaging !== "timeline" && packaging !== "mediatimeline" && packaging !== "eventtimeline" && packaging !== "fec-repair" && packaging !== "fec-source" && (typeof codec !== "string" || codec.length === 0)) {
854
519
  catalogError("track_codec", `${path}.codec`, `codec is required for packaging=${packaging}`);
855
520
  }
856
521
  const timescale = track["timescale"];
@@ -858,13 +523,13 @@ function validateCmsfMmtpCatalog(value, options = {}) {
858
523
  const groupDurationTicks = track["groupDurationTicks"];
859
524
  const keyframeIntervalMs = track["keyframeIntervalMs"];
860
525
  const keyframeIntervalTicks = track["keyframeIntervalTicks"];
861
- if (groupDurationMs !== void 0 && !positiveInteger2(groupDurationMs)) {
526
+ if (groupDurationMs !== void 0 && !positiveInteger(groupDurationMs)) {
862
527
  catalogError("track_group_duration_ms", `${path}.groupDurationMs`, "must be a positive integer");
863
528
  }
864
- if (groupDurationTicks !== void 0 && !positiveInteger2(groupDurationTicks)) {
529
+ if (groupDurationTicks !== void 0 && !positiveInteger(groupDurationTicks)) {
865
530
  catalogError("track_group_duration_ticks", `${path}.groupDurationTicks`, "must be a positive integer");
866
531
  }
867
- if (keyframeIntervalMs !== void 0 && !positiveNumber(keyframeIntervalMs) || keyframeIntervalTicks !== void 0 && !positiveInteger2(keyframeIntervalTicks)) {
532
+ if (keyframeIntervalMs !== void 0 && !positiveNumber(keyframeIntervalMs) || keyframeIntervalTicks !== void 0 && !positiveInteger(keyframeIntervalTicks)) {
868
533
  catalogError("track_keyframe_interval", path, "keyframe interval fields must be positive numbers");
869
534
  }
870
535
  const anchor = track["presentationAnchorTicks"];
@@ -875,17 +540,11 @@ function validateCmsfMmtpCatalog(value, options = {}) {
875
540
  if (initRef !== void 0 && (typeof initRef !== "string" || initRef.length === 0)) {
876
541
  catalogError("track_init_ref", `${path}.initRef`, "must be a non-empty string");
877
542
  }
878
- if (packaging === "fec-repair") {
879
- rejectRepairTrackGeometry(path, track, catalogError);
880
- validateRepairTrackFields(describeRepairTrack(name, path, track), catalogError);
881
- } else {
882
- rejectRepairFieldsOnMediaTrack(path, track, catalogError);
883
- }
884
543
  if (packaging === "mmtp") {
885
544
  if (track["mmtpMode"] !== "mfu") {
886
545
  catalogError("track_mmtp_mode", `${path}.mmtpMode`, "must be mfu");
887
546
  }
888
- if (!positiveInteger2(timescale)) {
547
+ if (!positiveInteger(timescale)) {
889
548
  catalogError("track_timescale", `${path}.timescale`, "must be a positive integer");
890
549
  }
891
550
  if (groupDurationMs === void 0 && groupDurationTicks === void 0) {
@@ -899,85 +558,6 @@ function validateCmsfMmtpCatalog(value, options = {}) {
899
558
  catalogError("track_group_duration_exact", `${path}.groupDurationMs`, "does not resolve to an exact integer tick count");
900
559
  }
901
560
  }
902
- if (track["fec"] !== void 0) {
903
- const fec = track["fec"];
904
- if (typeof fec !== "object" || fec === null || Array.isArray(fec)) {
905
- catalogError("track_fec", `${path}.fec`, "FEC must be an object");
906
- }
907
- const config = fec;
908
- const algorithm = config["algorithm"];
909
- if (typeof algorithm !== "string" || algorithm.length === 0) {
910
- catalogError("track_fec", `${path}.fec.algorithm`, "must be a non-empty string");
911
- }
912
- if ("interleaveDepth" in config || "interleaveMs" in config) {
913
- catalogError("track_fec", `${path}.fec`, "interleaveDepthMs is the only supported interleave field");
914
- }
915
- if ("enhancementRepair" in config) {
916
- catalogError(
917
- "track_fec",
918
- `${path}.fec.enhancementRepair`,
919
- "repair layers are self-describing fec-repair tracks (depends, repairLayer); fec.enhancementRepair is not supported"
920
- );
921
- }
922
- if (config["interleaveDepthMs"] !== void 0 && (!Number.isSafeInteger(config["interleaveDepthMs"]) || config["interleaveDepthMs"] < 0)) {
923
- catalogError("track_fec", `${path}.fec.interleaveDepthMs`, "must be a non-negative safe integer");
924
- }
925
- if (algorithm !== "none") {
926
- for (const field of ["sourceSymbols", "repairSymbols", "symbolSize"]) {
927
- if (!positiveInteger2(config[field])) {
928
- catalogError("track_fec", `${path}.fec.${field}`, "must be a positive integer");
929
- }
930
- }
931
- if (algorithm === "raptorq" && config["symbolSize"] % 8 !== 0) {
932
- catalogError("track_fec", `${path}.fec.symbolSize`, "RaptorQ symbolSize must be a multiple of 8");
933
- }
934
- if (typeof config["repairTrack"] !== "string" || config["repairTrack"].length === 0) {
935
- catalogError("track_fec", `${path}.fec.repairTrack`, "must be a non-empty string");
936
- }
937
- }
938
- readFecBlockProfile(config["blockProfile"], `${path}.fec.blockProfile`, algorithm !== "none", catalogError);
939
- if (algorithm !== "none" && config["symbolSize"] < ISO_SSBG1_MIN_SYMBOL_SIZE) {
940
- catalogError("track_fec", `${path}.fec.symbolSize`, "iso-ssbg1-v1 symbolSize must be at least 14");
941
- }
942
- }
943
- }
944
- const repairDescriptors = trackRecords.flatMap(
945
- (track, index) => track["packaging"] === "fec-repair" ? [describeRepairTrack(track["name"], `$.tracks[${index}]`, track)] : []
946
- );
947
- const reachability = repairReachability(
948
- trackRecords.filter((track) => track["packaging"] !== "fec-repair").map((track) => track["fec"])
949
- );
950
- for (const descriptor of repairDescriptors) {
951
- assertRepairTrackReachable(descriptor, reachability, catalogError);
952
- const target = dependsTarget(descriptor);
953
- if (target === void 0) continue;
954
- const source = trackRecords.find((candidate) => candidate["name"] === target);
955
- const sourceFec = source?.["fec"];
956
- if (!source || source["packaging"] !== "mmtp" || !sourceFec || sourceFec["algorithm"] === "none") {
957
- catalogError(
958
- "track_repair_depends",
959
- `${descriptor.path}.depends`,
960
- `${JSON.stringify(target)} is not an mmtp track with FEC`
961
- );
962
- }
963
- }
964
- for (let index = 0; index < trackRecords.length; index++) {
965
- const track = trackRecords[index];
966
- const fec = track["fec"];
967
- if (!fec || fec["algorithm"] === "none") continue;
968
- assembleRepairLayers(
969
- {
970
- name: track["name"],
971
- path: `$.tracks[${index}].fec`,
972
- algorithm: fec["algorithm"],
973
- sourceSymbols: fec["sourceSymbols"],
974
- repairSymbols: fec["repairSymbols"],
975
- repairTrack: fec["repairTrack"]
976
- },
977
- repairDescriptors,
978
- catalogError,
979
- { layerZeroMustBeDeclared: true }
980
- );
981
561
  }
982
562
  const switchingSets = /* @__PURE__ */ new Map();
983
563
  for (let index = 0; index < trackRecords.length; index++) {
@@ -1106,8 +686,6 @@ export {
1106
686
  CmsfCatalogValidationError,
1107
687
  archiveOrigin,
1108
688
  hasSwitchingSetRole,
1109
- isFecCatalogConfig,
1110
- isFecCatalogGeometry,
1111
689
  isMulticastCatalogConfig,
1112
690
  isMulticastEndpoint,
1113
691
  isMulticastTrackObject,