@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.
- package/README.md +21 -16
- package/dist/browser-runtime.js +1024 -1078
- package/dist/browser-runtime.js.map +4 -4
- package/dist/carp-catalog.d.ts +33 -87
- package/dist/carp-catalog.d.ts.map +1 -1
- package/dist/carp-catalog.js +12 -434
- package/dist/carp-catalog.js.map +4 -4
- package/dist/catalog-fec-params.d.ts +48 -161
- package/dist/catalog-fec-params.d.ts.map +1 -1
- package/dist/catalog-fec-params.js +567 -592
- package/dist/catalog-fec-params.js.map +4 -4
- package/dist/catalog-network-source.js +6 -2
- package/dist/catalog-network-source.js.map +3 -3
- package/dist/delivery-catalog.js +12 -4
- package/dist/delivery-catalog.js.map +4 -4
- package/dist/delta-fallback-config.d.ts +21 -26
- package/dist/delta-fallback-config.d.ts.map +1 -1
- package/dist/delta-fallback-config.js +582 -24
- package/dist/delta-fallback-config.js.map +4 -4
- package/dist/fec-manager.js +6 -2
- package/dist/fec-manager.js.map +3 -3
- package/dist/fec-state.d.ts +5 -43
- package/dist/fec-state.d.ts.map +1 -1
- package/dist/fec-state.js +529 -34
- package/dist/fec-state.js.map +4 -4
- package/dist/fec-worker-setup.js +6 -2
- package/dist/fec-worker-setup.js.map +3 -3
- package/dist/held-layer-admission.js +6 -2
- package/dist/held-layer-admission.js.map +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -39
- package/dist/index.js.map +2 -2
- package/dist/iso-block-locator.js +6 -2
- package/dist/iso-block-locator.js.map +3 -3
- package/dist/mfu-reassembler.js +6 -2
- package/dist/mfu-reassembler.js.map +3 -3
- package/dist/mmtp-container-parser.js +6 -2
- package/dist/mmtp-container-parser.js.map +3 -3
- package/dist/mmtp-container-parser.no-modules.js +551 -452
- package/dist/mmtp-container-parser.no-modules.js.map +4 -4
- package/dist/mmtp-decode-pipeline.js +6 -2
- package/dist/mmtp-decode-pipeline.js.map +3 -3
- package/dist/mmtp-fec-session.d.ts +7 -6
- package/dist/mmtp-fec-session.d.ts.map +1 -1
- package/dist/mmtp-fec-session.js +13 -9
- package/dist/mmtp-fec-session.js.map +3 -3
- package/dist/mmtp-router.d.ts +7 -16
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +19 -29
- package/dist/mmtp-router.js.map +3 -3
- package/dist/multicast-auth-catalog.js +7 -3
- package/dist/multicast-auth-catalog.js.map +3 -3
- package/dist/multicast-input.js +7 -3
- package/dist/multicast-input.js.map +3 -3
- package/dist/multicast-manager.d.ts +29 -32
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +682 -253
- package/dist/multicast-manager.js.map +4 -4
- package/dist/multicast-transport.d.ts +23 -2
- package/dist/multicast-transport.d.ts.map +1 -1
- package/dist/multicast-transport.js +57 -16
- package/dist/multicast-transport.js.map +4 -4
- package/dist/multicast-unwrap.js +6 -2
- package/dist/multicast-unwrap.js.map +3 -3
- package/dist/no-modules.js +551 -452
- package/dist/no-modules.js.map +4 -4
- package/dist/phase14-catalog-override.d.ts +10 -5
- package/dist/phase14-catalog-override.d.ts.map +1 -1
- package/dist/phase14-catalog-override.js +35 -11
- package/dist/phase14-catalog-override.js.map +2 -2
- package/dist/repair-fetch.d.ts +3 -1
- package/dist/repair-fetch.d.ts.map +1 -1
- package/dist/repair-fetch.js +16 -3
- package/dist/repair-fetch.js.map +3 -3
- package/dist/repair-layers.d.ts +0 -123
- package/dist/repair-layers.d.ts.map +1 -1
- package/dist/repair-layers.js +1 -349
- package/dist/repair-layers.js.map +3 -3
- package/dist/signaling.js +6 -2
- package/dist/signaling.js.map +3 -3
- package/dist/timestamp-codec.js +6 -2
- package/dist/timestamp-codec.js.map +3 -3
- package/dist/wasm-mfu-reassembler.js +6 -2
- package/dist/wasm-mfu-reassembler.js.map +3 -3
- package/dist/wasm-mmtp-container-parser.js +6 -2
- package/dist/wasm-mmtp-container-parser.js.map +3 -3
- package/package.json +9 -5
- package/schemas/catalog.schema.json +53 -58
- package/src/carp-catalog.ts +39 -229
- package/src/catalog-fec-params.ts +130 -493
- package/src/delta-fallback-config.ts +63 -50
- package/src/fec-state.ts +7 -62
- package/src/index.ts +10 -30
- package/src/mmtp-fec-session.ts +11 -10
- package/src/mmtp-router.ts +14 -29
- package/src/multicast-manager.ts +89 -121
- package/src/multicast-transport.ts +65 -12
- package/src/phase14-catalog-override.ts +67 -16
- package/src/repair-fetch.ts +27 -3
- package/src/repair-layers.ts +7 -520
- package/test-vectors/catalog/README.md +39 -67
- package/test-vectors/catalog/fec-01-runtime/README.md +15 -0
- package/test-vectors/catalog/{negative/fec-block-profile-retired.json → fec-01-runtime/fec-iso-ssbg1.json} +1 -1
- package/test-vectors/catalog/fec-01-runtime/fec-layered-repair.json +106 -0
- package/test-vectors/catalog/{negative/fec-block-profile-unknown.json → fec-01-runtime/fec-multicast.json} +2 -1
- package/test-vectors/catalog/fec-01-runtime/multicast-native-ssm-no-network-source.json +44 -0
- package/test-vectors/catalog/negative/fec-block-profile-missing.json +24 -11
- package/test-vectors/catalog/negative/fec-iso-symbol-size-below-floor.json +13 -8
- package/test-vectors/catalog/negative/fec-reed-solomon-iso-symbol-size-13.json +13 -8
- package/test-vectors/catalog/negative/fec-repair-layer-geometry.json +20 -10
- package/test-vectors/catalog/negative/fec-repair-layer-missing-symbols.json +20 -10
- package/test-vectors/catalog/negative/fec-repair-overlay-source-symbols-zero.json +25 -17
- package/test-vectors/catalog/negative/fec-repair-symbols-zero.json +13 -8
- package/test-vectors/catalog/negative/fec-source-symbols-zero.json +13 -8
- package/test-vectors/catalog/negative/fec-symbol-size-zero.json +13 -8
- package/test-vectors/catalog/negative/raptorq-source-symbols-over-max.json +18 -9
- package/test-vectors/catalog/negative/raptorq-unaligned-symbol.json +13 -8
- package/test-vectors/catalog/positive/fec-algorithm-unimplemented.json +14 -9
- package/test-vectors/catalog/positive/fec-iso-ssbg1.json +25 -12
- package/test-vectors/catalog/positive/fec-layered-repair.json +79 -35
- package/test-vectors/catalog/positive/fec-multicast.json +26 -13
- package/test-vectors/catalog/positive/fec-reed-solomon-layered.json +29 -18
- package/test-vectors/catalog/positive/multicast-draft01-4-1-example.json +28 -20
- package/test-vectors/catalog/positive/multicast-draft01-7-2-6-example.json +14 -10
- package/test-vectors/catalog/positive/multicast-native-ssm-no-network-source.json +22 -12
- package/test-vectors/catalog/section-codes.json +13 -22
- package/test-vectors/catalog-timing.json +2 -2
- package/test-vectors/catalog-validation.json +30 -243
- package/test-vectors/catalog/negative/fec-enhancement-repair-removed.json +0 -28
- package/test-vectors/catalog/negative/fec-reed-solomon-k-plus-p-over-255.json +0 -39
- package/test-vectors/catalog/negative/fec-reed-solomon-overlay-over-255.json +0 -40
- package/test-vectors/catalog/negative/fec-repair-multiple-depends.json +0 -32
- package/test-vectors/catalog/negative/fec-repair-overlay-with-layer.json +0 -34
- package/test-vectors/catalog/negative/fec-repair-priority-out-of-band.json +0 -24
- package/test-vectors/catalog/negative/fec-repair-source-symbols-without-scope.json +0 -33
|
@@ -477,34 +477,6 @@ var BlockcastMmt = (() => {
|
|
|
477
477
|
return serial32Precedes(a, b) ? Math.floor(serial32Distance(a, b) / kMax) : 0;
|
|
478
478
|
}
|
|
479
479
|
|
|
480
|
-
// ../mmt-base/dist/catalog-fec-source.js
|
|
481
|
-
var ALL_ROLES = Object.freeze(["video", "audio"]);
|
|
482
|
-
function recordOf(value) {
|
|
483
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
484
|
-
}
|
|
485
|
-
function isoBlockSpanUsable(fec) {
|
|
486
|
-
const block = recordOf(fec);
|
|
487
|
-
if (block === void 0 || block["blockProfile"] !== "iso-ssbg1-v1")
|
|
488
|
-
return true;
|
|
489
|
-
const ms = block["interleaveDepthMs"];
|
|
490
|
-
return ms === void 0 || typeof ms === "number" && Number.isSafeInteger(ms) && ms >= 0;
|
|
491
|
-
}
|
|
492
|
-
function fecAlgorithmUnimplemented(algorithm) {
|
|
493
|
-
return typeof algorithm === "string" && algorithm !== "none" && algorithm !== "raptorq" && algorithm !== "reed-solomon";
|
|
494
|
-
}
|
|
495
|
-
function isPositiveSafeInteger(value) {
|
|
496
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
497
|
-
}
|
|
498
|
-
var ISO_SSBG1_MIN_SYMBOL_SIZE = 14;
|
|
499
|
-
function catalogFecDeclaresUnconfigurableInstance(fec) {
|
|
500
|
-
const block = recordOf(fec);
|
|
501
|
-
if (block === void 0 || block["algorithm"] === "none" || fecAlgorithmUnimplemented(block["algorithm"]))
|
|
502
|
-
return false;
|
|
503
|
-
if (!(isPositiveSafeInteger(block["sourceSymbols"]) && isPositiveSafeInteger(block["symbolSize"])))
|
|
504
|
-
return true;
|
|
505
|
-
return block["blockProfile"] === "iso-ssbg1-v1" && block["symbolSize"] < ISO_SSBG1_MIN_SYMBOL_SIZE;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
480
|
// ../mmt-base/dist/multicast-catalog.js
|
|
509
481
|
var ED25519_PUBLIC_KEY_BASE64URL = /^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/;
|
|
510
482
|
var UINT32_MAX = 4294967295;
|
|
@@ -753,6 +725,538 @@ var BlockcastMmt = (() => {
|
|
|
753
725
|
return issues;
|
|
754
726
|
}
|
|
755
727
|
|
|
728
|
+
// ../mmt-base/dist/fec-catalog.js
|
|
729
|
+
var DEFAULT_SCHEMES = ["reed-solomon", "raptorq"];
|
|
730
|
+
var DEFAULT_PROFILES = ["moq-object-v1", "iso-ssbg1-v1"];
|
|
731
|
+
var RS_MAX_BLOCK = 255;
|
|
732
|
+
var RAPTORQ_MAX_K = 56403;
|
|
733
|
+
var MAX_24 = 16777215;
|
|
734
|
+
var ISO_MIN_T = 14;
|
|
735
|
+
var GEOMETRY_KEYS = [
|
|
736
|
+
"scheme",
|
|
737
|
+
"blockProfile",
|
|
738
|
+
"mmtpMode",
|
|
739
|
+
"timescale",
|
|
740
|
+
"symbolSize",
|
|
741
|
+
"interleaveDepthMs",
|
|
742
|
+
"reorderToleranceMs",
|
|
743
|
+
"sourceSymbols",
|
|
744
|
+
"fec"
|
|
745
|
+
];
|
|
746
|
+
var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
747
|
+
var has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
|
748
|
+
var isInt = (v) => typeof v === "number" && Number.isInteger(v);
|
|
749
|
+
var intIn = (v, lo, hi = Number.MAX_SAFE_INTEGER) => isInt(v) && v >= lo && v <= hi;
|
|
750
|
+
var profileAdmits = (profile, packaging) => profile !== "iso-ssbg1-v1" || packaging === "mmtp";
|
|
751
|
+
function validateFecCatalog(catalog, receiver = {}) {
|
|
752
|
+
const schemes = receiver.schemes ?? DEFAULT_SCHEMES;
|
|
753
|
+
const profiles = receiver.blockProfiles ?? DEFAULT_PROFILES;
|
|
754
|
+
const overlays = receiver.overlays ?? true;
|
|
755
|
+
const all = [];
|
|
756
|
+
const report = (code, path, inst) => {
|
|
757
|
+
const issue = { code, path };
|
|
758
|
+
all.push(issue);
|
|
759
|
+
inst?.issues.push(issue);
|
|
760
|
+
};
|
|
761
|
+
const tracks = isObj(catalog) && Array.isArray(catalog.tracks) ? catalog.tracks : [];
|
|
762
|
+
if (!isObj(catalog) || !Array.isArray(catalog.tracks))
|
|
763
|
+
report("fec_member", "/tracks");
|
|
764
|
+
let rejectAll = false;
|
|
765
|
+
tracks.forEach((t, ti) => {
|
|
766
|
+
if (!isObj(t))
|
|
767
|
+
return;
|
|
768
|
+
if (has(t, "enhancementRepair")) {
|
|
769
|
+
rejectAll = true;
|
|
770
|
+
report("fec_enhancement_repair", `/tracks/${ti}/enhancementRepair`);
|
|
771
|
+
}
|
|
772
|
+
if (Array.isArray(t.fec))
|
|
773
|
+
t.fec.forEach((o, ii) => {
|
|
774
|
+
if (isObj(o) && has(o, "enhancementRepair")) {
|
|
775
|
+
rejectAll = true;
|
|
776
|
+
report("fec_enhancement_repair", `/tracks/${ti}/fec/${ii}/enhancementRepair`);
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
});
|
|
780
|
+
const key = (ns, name) => JSON.stringify([ns ?? null, name]);
|
|
781
|
+
const byName = /* @__PURE__ */ new Map();
|
|
782
|
+
tracks.forEach((t, ti) => {
|
|
783
|
+
if (isObj(t) && typeof t.name === "string") {
|
|
784
|
+
const k = key(t.namespace, t.name);
|
|
785
|
+
if (!byName.has(k))
|
|
786
|
+
byName.set(k, ti);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
const trackAt = (ti) => tracks[ti];
|
|
790
|
+
const insts = [];
|
|
791
|
+
tracks.forEach((t, ti) => {
|
|
792
|
+
if (!isObj(t) || !has(t, "fec") || t.packaging === "fec-repair" || t.packaging === "fec-source")
|
|
793
|
+
return;
|
|
794
|
+
if (!Array.isArray(t.fec)) {
|
|
795
|
+
report("fec_member", `/tracks/${ti}/fec`);
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
t.fec.forEach((o, ii) => {
|
|
799
|
+
const path = `/tracks/${ti}/fec/${ii}`;
|
|
800
|
+
const inst = {
|
|
801
|
+
path,
|
|
802
|
+
ti,
|
|
803
|
+
track: t,
|
|
804
|
+
obj: isObj(o) ? o : null,
|
|
805
|
+
id: null,
|
|
806
|
+
unavailable: false,
|
|
807
|
+
overlay: false,
|
|
808
|
+
issues: [],
|
|
809
|
+
layer0: null,
|
|
810
|
+
symbolNamed: null,
|
|
811
|
+
attached: []
|
|
812
|
+
};
|
|
813
|
+
insts.push(inst);
|
|
814
|
+
if (!inst.obj)
|
|
815
|
+
return report("fec_member", path, inst);
|
|
816
|
+
const o2 = inst.obj;
|
|
817
|
+
if (!has(o2, "instanceId"))
|
|
818
|
+
inst.id = 0;
|
|
819
|
+
else if (intIn(o2.instanceId, 0, 255))
|
|
820
|
+
inst.id = o2.instanceId;
|
|
821
|
+
else
|
|
822
|
+
report("fec_member", `${path}/instanceId`, inst);
|
|
823
|
+
inst.overlay = has(o2, "scope");
|
|
824
|
+
});
|
|
825
|
+
});
|
|
826
|
+
const declaresFec = insts.length > 0;
|
|
827
|
+
for (const inst of insts) {
|
|
828
|
+
const o = inst.obj;
|
|
829
|
+
if (!o)
|
|
830
|
+
continue;
|
|
831
|
+
const avail = (field, impl) => {
|
|
832
|
+
const p = `${inst.path}/${field}`;
|
|
833
|
+
const absent = field === "scheme" ? "fec_scheme_absent" : "fec_block_profile_absent";
|
|
834
|
+
const unimpl = field === "scheme" ? "fec_scheme_unimplemented" : "fec_block_profile_unimplemented";
|
|
835
|
+
if (!has(o, field))
|
|
836
|
+
return report(absent, p, inst), false;
|
|
837
|
+
if (typeof o[field] !== "string")
|
|
838
|
+
return report("fec_member", p, inst), true;
|
|
839
|
+
if (!impl.includes(o[field]))
|
|
840
|
+
return report(unimpl, p, inst), false;
|
|
841
|
+
return true;
|
|
842
|
+
};
|
|
843
|
+
if (!avail("scheme", schemes) || !avail("blockProfile", profiles))
|
|
844
|
+
inst.unavailable = true;
|
|
845
|
+
else if (typeof o.blockProfile === "string" && !profileAdmits(o.blockProfile, inst.track.packaging)) {
|
|
846
|
+
report("fec_block_profile_packaging", `${inst.path}/blockProfile`, inst);
|
|
847
|
+
inst.unavailable = true;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const live = (i) => !i.unavailable;
|
|
851
|
+
for (const inst of insts.filter(live)) {
|
|
852
|
+
const o = inst.obj;
|
|
853
|
+
if (!o)
|
|
854
|
+
continue;
|
|
855
|
+
const p = inst.path;
|
|
856
|
+
for (const m of ["sourceSymbols", "repairSymbols", "symbolSize"])
|
|
857
|
+
if (!intIn(o[m], 1))
|
|
858
|
+
report("fec_member", `${p}/${m}`, inst);
|
|
859
|
+
if (typeof o.repairTrack !== "string")
|
|
860
|
+
report("fec_member", `${p}/repairTrack`, inst);
|
|
861
|
+
if (has(o, "symbolTrack") && typeof o.symbolTrack !== "string")
|
|
862
|
+
report("fec_member", `${p}/symbolTrack`, inst);
|
|
863
|
+
if (has(o, "interleaveDepthMs")) {
|
|
864
|
+
const d = o.interleaveDepthMs;
|
|
865
|
+
if (!intIn(d, 0) || d === 0 && o.blockProfile !== "iso-ssbg1-v1")
|
|
866
|
+
report("fec_member", `${p}/interleaveDepthMs`, inst);
|
|
867
|
+
}
|
|
868
|
+
if (has(o, "reorderToleranceMs")) {
|
|
869
|
+
const r = o.reorderToleranceMs;
|
|
870
|
+
if (typeof r !== "number" || !Number.isFinite(r) || r < 0)
|
|
871
|
+
report("fec_member", `${p}/reorderToleranceMs`, inst);
|
|
872
|
+
}
|
|
873
|
+
if (has(o, "label") && typeof o.label !== "string")
|
|
874
|
+
report("fec_member", `${p}/label`, inst);
|
|
875
|
+
if (inst.overlay && o.scope !== "keyframe")
|
|
876
|
+
report("fec_member", `${p}/scope`, inst);
|
|
877
|
+
}
|
|
878
|
+
const idGroups = /* @__PURE__ */ new Map();
|
|
879
|
+
for (const inst of insts)
|
|
880
|
+
if (inst.id !== null) {
|
|
881
|
+
const k = `${inst.ti}:${inst.id}`;
|
|
882
|
+
idGroups.set(k, [...idGroups.get(k) ?? [], inst]);
|
|
883
|
+
}
|
|
884
|
+
for (const group of idGroups.values())
|
|
885
|
+
if (group.length > 1)
|
|
886
|
+
for (const inst of group.filter(live))
|
|
887
|
+
report("fec_instance_id", inst.obj && has(inst.obj, "instanceId") ? `${inst.path}/instanceId` : inst.path, inst);
|
|
888
|
+
const nameUses = /* @__PURE__ */ new Map();
|
|
889
|
+
for (const inst of insts)
|
|
890
|
+
for (const field of ["repairTrack", "symbolTrack"])
|
|
891
|
+
if (inst.obj && typeof inst.obj[field] === "string") {
|
|
892
|
+
const k = key(inst.track.namespace, inst.obj[field]);
|
|
893
|
+
nameUses.set(k, [...nameUses.get(k) ?? [], { inst, field }]);
|
|
894
|
+
}
|
|
895
|
+
const namedBy = /* @__PURE__ */ new Map();
|
|
896
|
+
for (const [k, uses] of nameUses) {
|
|
897
|
+
const tj = byName.get(k);
|
|
898
|
+
for (const { inst, field } of uses) {
|
|
899
|
+
const path = `${inst.path}/${field}`;
|
|
900
|
+
if (tj === void 0 || trackAt(tj).packaging !== (field === "repairTrack" ? "fec-repair" : "fec-source")) {
|
|
901
|
+
if (live(inst))
|
|
902
|
+
report("fec_naming", path, inst);
|
|
903
|
+
} else if (uses.length > 1) {
|
|
904
|
+
if (live(inst))
|
|
905
|
+
report("fec_naming", path, inst);
|
|
906
|
+
if (!namedBy.has(tj))
|
|
907
|
+
namedBy.set(tj, inst);
|
|
908
|
+
} else {
|
|
909
|
+
namedBy.set(tj, inst);
|
|
910
|
+
if (field === "repairTrack")
|
|
911
|
+
inst.layer0 = tj;
|
|
912
|
+
else
|
|
913
|
+
inst.symbolNamed = tj;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
const owner = /* @__PURE__ */ new Map();
|
|
918
|
+
if (declaresFec)
|
|
919
|
+
tracks.forEach((t, tj) => {
|
|
920
|
+
if (!isObj(t) || t.packaging !== "fec-repair" && t.packaging !== "fec-source")
|
|
921
|
+
return;
|
|
922
|
+
const tp = `/tracks/${tj}`;
|
|
923
|
+
const named = namedBy.get(tj);
|
|
924
|
+
if (named) {
|
|
925
|
+
owner.set(tj, named);
|
|
926
|
+
if (!live(named))
|
|
927
|
+
return;
|
|
928
|
+
if (has(t, "source") && t.source !== named.track.name)
|
|
929
|
+
report("fec_resolution", `${tp}/source`, named);
|
|
930
|
+
if (has(t, "instanceId") && t.instanceId !== named.id)
|
|
931
|
+
report("fec_resolution", `${tp}/instanceId`, named);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
if (!has(t, "source"))
|
|
935
|
+
return report("fec_orphan", tp);
|
|
936
|
+
const id = has(t, "instanceId") ? t.instanceId : 0;
|
|
937
|
+
const src = typeof t.source === "string" ? byName.get(key(t.namespace, t.source)) : void 0;
|
|
938
|
+
const target = src === void 0 ? void 0 : insts.find((i) => i.ti === src && i.id === id);
|
|
939
|
+
if (!target)
|
|
940
|
+
return report("fec_naming", has(t, "instanceId") && src !== void 0 ? `${tp}/instanceId` : `${tp}/source`);
|
|
941
|
+
owner.set(tj, target);
|
|
942
|
+
target.attached.push(tj);
|
|
943
|
+
});
|
|
944
|
+
for (const [tj, inst] of owner) {
|
|
945
|
+
if (!live(inst))
|
|
946
|
+
continue;
|
|
947
|
+
const t = trackAt(tj);
|
|
948
|
+
const tp = `/tracks/${tj}`;
|
|
949
|
+
const symbol = t.packaging === "fec-source";
|
|
950
|
+
if (has(t, "source") && typeof t.source !== "string")
|
|
951
|
+
report("fec_member", `${tp}/source`, inst);
|
|
952
|
+
if (has(t, "instanceId") && !intIn(t.instanceId, 0, 255))
|
|
953
|
+
report("fec_member", `${tp}/instanceId`, inst);
|
|
954
|
+
for (const m of ["repairLayer", "repairSymbols"]) {
|
|
955
|
+
if (!has(t, m))
|
|
956
|
+
continue;
|
|
957
|
+
if (symbol || !intIn(t[m], m === "repairLayer" ? 0 : 1))
|
|
958
|
+
report("fec_member", `${tp}/${m}`, inst);
|
|
959
|
+
}
|
|
960
|
+
if (has(t, "priority") && !intIn(t.priority, symbol ? 0 : 192, 255))
|
|
961
|
+
report("fec_member", `${tp}/priority`, inst);
|
|
962
|
+
for (const k of Object.keys(t))
|
|
963
|
+
if (GEOMETRY_KEYS.includes(k) || k.startsWith("groupDuration"))
|
|
964
|
+
report("fec_track_geometry", `${tp}/${k.replace(/~/g, "~0").replace(/\//g, "~1")}`, inst);
|
|
965
|
+
}
|
|
966
|
+
for (const inst of insts.filter(live)) {
|
|
967
|
+
const o = inst.obj;
|
|
968
|
+
if (!o)
|
|
969
|
+
continue;
|
|
970
|
+
const repairs = inst.attached.filter((tj) => trackAt(tj).packaging === "fec-repair");
|
|
971
|
+
const symbols = inst.attached.filter((tj) => trackAt(tj).packaging === "fec-source");
|
|
972
|
+
if (symbols.length + (inst.symbolNamed !== null ? 1 : 0) > 1)
|
|
973
|
+
for (const tj of symbols)
|
|
974
|
+
report("fec_symbol_tracks", `/tracks/${tj}`, inst);
|
|
975
|
+
const l0 = inst.layer0 === null ? null : trackAt(inst.layer0);
|
|
976
|
+
const l0p = `/tracks/${inst.layer0}`;
|
|
977
|
+
if (inst.overlay) {
|
|
978
|
+
if (l0 && has(l0, "repairLayer"))
|
|
979
|
+
report("fec_overlay", `${l0p}/repairLayer`, inst);
|
|
980
|
+
for (const tj of repairs)
|
|
981
|
+
report("fec_overlay", has(trackAt(tj), "repairLayer") ? `/tracks/${tj}/repairLayer` : `/tracks/${tj}`, inst);
|
|
982
|
+
} else {
|
|
983
|
+
if (l0 && has(l0, "repairLayer") && l0.repairLayer !== 0)
|
|
984
|
+
report("fec_layers", `${l0p}/repairLayer`, inst);
|
|
985
|
+
if (l0 && has(l0, "repairSymbols") && intIn(o.repairSymbols, 1) && l0.repairSymbols !== o.repairSymbols)
|
|
986
|
+
report("fec_layer0", `${l0p}/repairSymbols`, inst);
|
|
987
|
+
const layers = [];
|
|
988
|
+
for (const tj of repairs) {
|
|
989
|
+
const t = trackAt(tj);
|
|
990
|
+
if (!has(t, "repairLayer"))
|
|
991
|
+
report("fec_member", `/tracks/${tj}/repairLayer`, inst);
|
|
992
|
+
else if (t.repairLayer === 0)
|
|
993
|
+
report("fec_layers", `/tracks/${tj}/repairLayer`, inst);
|
|
994
|
+
else if (intIn(t.repairLayer, 1))
|
|
995
|
+
layers.push({ tj, layer: t.repairLayer });
|
|
996
|
+
if (!has(t, "repairSymbols"))
|
|
997
|
+
report("fec_member", `/tracks/${tj}/repairSymbols`, inst);
|
|
998
|
+
}
|
|
999
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1000
|
+
for (const { layer } of layers)
|
|
1001
|
+
counts.set(layer, (counts.get(layer) ?? 0) + 1);
|
|
1002
|
+
let missing = 1;
|
|
1003
|
+
while (counts.has(missing))
|
|
1004
|
+
missing++;
|
|
1005
|
+
for (const { tj, layer } of layers)
|
|
1006
|
+
if (counts.get(layer) > 1 || layer > missing)
|
|
1007
|
+
report("fec_layers", `/tracks/${tj}/repairLayer`, inst);
|
|
1008
|
+
const chain = [
|
|
1009
|
+
{ layer: 0, tj: inst.layer0, pri: l0 && intIn(l0.priority, 192, 255) ? l0.priority : l0 && has(l0, "priority") ? null : 240 },
|
|
1010
|
+
...layers.map(({ tj, layer }) => {
|
|
1011
|
+
const pr = trackAt(tj).priority;
|
|
1012
|
+
return { layer, tj, pri: intIn(pr, 192, 255) ? pr : null };
|
|
1013
|
+
})
|
|
1014
|
+
].sort((a, b) => a.layer - b.layer);
|
|
1015
|
+
let prev = null;
|
|
1016
|
+
for (const c of chain) {
|
|
1017
|
+
if (c.pri === null)
|
|
1018
|
+
continue;
|
|
1019
|
+
if (prev !== null && c.pri < prev)
|
|
1020
|
+
report("fec_priority", `/tracks/${c.tj}/priority`, inst);
|
|
1021
|
+
prev = Math.max(prev ?? c.pri, c.pri);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
const K = o.sourceSymbols;
|
|
1025
|
+
const T = o.symbolSize;
|
|
1026
|
+
const P0 = o.repairSymbols;
|
|
1027
|
+
if (intIn(K, 1) && intIn(P0, 1)) {
|
|
1028
|
+
let P = P0;
|
|
1029
|
+
if (!inst.overlay)
|
|
1030
|
+
for (const tj of repairs) {
|
|
1031
|
+
const t = trackAt(tj);
|
|
1032
|
+
if (intIn(t.repairLayer, 1) && intIn(t.repairSymbols, 1))
|
|
1033
|
+
P += t.repairSymbols;
|
|
1034
|
+
}
|
|
1035
|
+
if (P > MAX_24 || K + P - 1 > MAX_24)
|
|
1036
|
+
report("fec_bounds", inst.path, inst);
|
|
1037
|
+
else if (o.scheme === "reed-solomon" && K + P > RS_MAX_BLOCK)
|
|
1038
|
+
report("fec_bounds", inst.path, inst);
|
|
1039
|
+
}
|
|
1040
|
+
if (o.scheme === "raptorq" && intIn(K, 1) && K > RAPTORQ_MAX_K)
|
|
1041
|
+
report("fec_bounds", `${inst.path}/sourceSymbols`, inst);
|
|
1042
|
+
if (intIn(T, 1)) {
|
|
1043
|
+
if (o.scheme === "raptorq" && T % 8 !== 0)
|
|
1044
|
+
report("fec_bounds", `${inst.path}/symbolSize`, inst);
|
|
1045
|
+
else if (o.blockProfile === "iso-ssbg1-v1" && T < ISO_MIN_T)
|
|
1046
|
+
report("fec_bounds", `${inst.path}/symbolSize`, inst);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
const overlayTracks = new Set(insts.filter((i) => live(i) && i.overlay).map((i) => i.ti));
|
|
1050
|
+
for (const ti of overlayTracks) {
|
|
1051
|
+
const ofTrack = insts.filter((i) => i.ti === ti && live(i));
|
|
1052
|
+
const ovs = ofTrack.filter((i) => i.overlay);
|
|
1053
|
+
if (!overlays) {
|
|
1054
|
+
for (const ov of ovs)
|
|
1055
|
+
report("fec_overlay_unsupported", `${ov.path}/scope`, ov);
|
|
1056
|
+
for (const i of ofTrack)
|
|
1057
|
+
i.issues.length === 0 && i.issues.push({ code: "fec_overlay_unsupported", path: `${ovs[0].path}/scope` });
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
if (ovs.length > 1)
|
|
1061
|
+
for (const ov of ovs)
|
|
1062
|
+
report("fec_overlay", `${ov.path}/scope`, ov);
|
|
1063
|
+
for (const ov of ovs)
|
|
1064
|
+
if (ov.obj?.blockProfile !== "iso-ssbg1-v1")
|
|
1065
|
+
report("fec_overlay", `${ov.path}/blockProfile`, ov);
|
|
1066
|
+
const cause = ovs.flatMap((ov) => ov.issues).find((x) => x.code === "fec_overlay");
|
|
1067
|
+
if (cause) {
|
|
1068
|
+
for (const ov of ovs)
|
|
1069
|
+
if (ov.issues.length === 0)
|
|
1070
|
+
ov.issues.push(cause);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
const rule4 = all.find((x) => x.code === "fec_enhancement_repair");
|
|
1074
|
+
if (rejectAll && rule4) {
|
|
1075
|
+
for (const i of insts)
|
|
1076
|
+
if (i.issues.length === 0)
|
|
1077
|
+
i.issues.push(rule4);
|
|
1078
|
+
}
|
|
1079
|
+
return {
|
|
1080
|
+
instances: insts.map((i) => ({
|
|
1081
|
+
path: i.path,
|
|
1082
|
+
track: typeof i.track.name === "string" ? i.track.name : null,
|
|
1083
|
+
instanceId: i.id,
|
|
1084
|
+
outcome: rejectAll || !i.unavailable && i.issues.length > 0 ? "violation" : i.unavailable ? "unavailable" : "ok",
|
|
1085
|
+
issues: i.issues,
|
|
1086
|
+
trackIndex: i.ti,
|
|
1087
|
+
repairTrack: i.layer0,
|
|
1088
|
+
boundRepairTracks: i.attached.filter((tj) => trackAt(tj).packaging === "fec-repair"),
|
|
1089
|
+
symbolTrack: i.symbolNamed ?? i.attached.find((tj) => trackAt(tj).packaging === "fec-source") ?? null
|
|
1090
|
+
})),
|
|
1091
|
+
issues: all
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// ../mmt-base/dist/fec-bindings.js
|
|
1096
|
+
var RUNTIME_FEC_RECEIVER = Object.freeze({
|
|
1097
|
+
schemes: Object.freeze(["raptorq", "reed-solomon"]),
|
|
1098
|
+
blockProfiles: Object.freeze(["iso-ssbg1-v1"]),
|
|
1099
|
+
overlays: true
|
|
1100
|
+
});
|
|
1101
|
+
var DEFAULT_FEC_REPAIR_PRIORITY = 240;
|
|
1102
|
+
var recordOf = (v) => typeof v === "object" && v !== null && !Array.isArray(v) ? v : void 0;
|
|
1103
|
+
var escape = (s) => s.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
1104
|
+
function fecCatalogTracks(catalog) {
|
|
1105
|
+
const root = recordOf(catalog) ?? {};
|
|
1106
|
+
const tracks = [];
|
|
1107
|
+
const pointers = [];
|
|
1108
|
+
const hangNames = /* @__PURE__ */ new Set();
|
|
1109
|
+
for (const role of ["video", "audio"]) {
|
|
1110
|
+
for (const [name, r] of Object.entries(recordOf(recordOf(root[role])?.["renditions"]) ?? {})) {
|
|
1111
|
+
const entry = recordOf(r);
|
|
1112
|
+
if (!entry)
|
|
1113
|
+
continue;
|
|
1114
|
+
hangNames.add(name);
|
|
1115
|
+
const kind = recordOf(entry["container"])?.["kind"];
|
|
1116
|
+
const view2 = { name, packaging: kind === void 0 || kind === "mmtp-fec" ? "mmtp" : kind };
|
|
1117
|
+
if (entry["fec"] !== void 0)
|
|
1118
|
+
view2["fec"] = entry["fec"];
|
|
1119
|
+
tracks.push(view2);
|
|
1120
|
+
pointers.push(`/${role}/renditions/${escape(name)}`);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
const hangRenditions = tracks.length;
|
|
1124
|
+
for (const [name, r] of Object.entries(recordOf(recordOf(root["repair"])?.["renditions"]) ?? {})) {
|
|
1125
|
+
hangNames.add(name);
|
|
1126
|
+
tracks.push({ packaging: "fec-repair", ...recordOf(r), name });
|
|
1127
|
+
pointers.push(`/repair/renditions/${escape(name)}`);
|
|
1128
|
+
}
|
|
1129
|
+
const raw = Array.isArray(root["tracks"]) ? root["tracks"] : [];
|
|
1130
|
+
const named = new Set(hangNames);
|
|
1131
|
+
raw.forEach((t, i) => {
|
|
1132
|
+
const name = recordOf(t)?.["name"];
|
|
1133
|
+
if (typeof name === "string")
|
|
1134
|
+
named.add(name);
|
|
1135
|
+
if (typeof name === "string" && hangNames.has(name))
|
|
1136
|
+
return;
|
|
1137
|
+
tracks.push(t);
|
|
1138
|
+
pointers.push(`/tracks/${i}`);
|
|
1139
|
+
});
|
|
1140
|
+
tracks.slice(0, hangRenditions).forEach((t, ti) => {
|
|
1141
|
+
const view2 = t;
|
|
1142
|
+
if (!Array.isArray(view2["fec"]))
|
|
1143
|
+
return;
|
|
1144
|
+
view2["fec"].forEach((o, ii) => {
|
|
1145
|
+
const repairTrack = recordOf(o)?.["repairTrack"];
|
|
1146
|
+
if (typeof repairTrack !== "string" || named.has(repairTrack))
|
|
1147
|
+
return;
|
|
1148
|
+
named.add(repairTrack);
|
|
1149
|
+
const instanceId = recordOf(o)?.["instanceId"];
|
|
1150
|
+
tracks.push({ name: repairTrack, packaging: "fec-repair", source: view2["name"], ...instanceId === void 0 ? {} : { instanceId } });
|
|
1151
|
+
pointers.push(`${pointers[ti]}/fec/${ii}/repairTrack`);
|
|
1152
|
+
});
|
|
1153
|
+
});
|
|
1154
|
+
return { tracks, pointers };
|
|
1155
|
+
}
|
|
1156
|
+
function resolveFecBindings(catalog, receiver = RUNTIME_FEC_RECEIVER) {
|
|
1157
|
+
const { tracks, pointers } = fecCatalogTracks(catalog);
|
|
1158
|
+
const report = validateFecCatalog({ tracks }, receiver);
|
|
1159
|
+
const at = (path) => {
|
|
1160
|
+
const m = /^\/tracks\/(\d+)(.*)$/.exec(path);
|
|
1161
|
+
return m ? pointers[Number(m[1])] + m[2] : path;
|
|
1162
|
+
};
|
|
1163
|
+
const trackAt = (i) => recordOf(tracks[i]) ?? {};
|
|
1164
|
+
const nameAt = (i) => i === null ? void 0 : trackAt(i)["name"];
|
|
1165
|
+
const why = (i) => Object.freeze({
|
|
1166
|
+
code: i.issues[0]?.code ?? "fec_member",
|
|
1167
|
+
path: at(i.issues[0]?.path ?? i.path),
|
|
1168
|
+
outcome: i.outcome === "unavailable" ? "unavailable" : "violation"
|
|
1169
|
+
});
|
|
1170
|
+
const out = /* @__PURE__ */ new Map();
|
|
1171
|
+
tracks.forEach((t, ti) => {
|
|
1172
|
+
const track = recordOf(t);
|
|
1173
|
+
const name = track?.["name"];
|
|
1174
|
+
if (!track || typeof name !== "string" || out.has(name))
|
|
1175
|
+
return;
|
|
1176
|
+
if (track["packaging"] === "fec-repair" || track["packaging"] === "fec-source")
|
|
1177
|
+
return;
|
|
1178
|
+
const fec = track["fec"];
|
|
1179
|
+
if (fec === void 0)
|
|
1180
|
+
return;
|
|
1181
|
+
if (!Array.isArray(fec)) {
|
|
1182
|
+
const reason = { code: "fec_member", path: at(`/tracks/${ti}/fec`), outcome: "violation" };
|
|
1183
|
+
out.set(name, Object.freeze({ status: "unavailable", track: name, pointer: pointers[ti], reason: Object.freeze(reason) }));
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
if (fec.length === 0)
|
|
1187
|
+
return;
|
|
1188
|
+
const insts = report.instances.filter((i) => i.trackIndex === ti);
|
|
1189
|
+
const isOverlay = (i) => Object.hasOwn(recordOf(fec[Number(i.path.split("/").pop())]) ?? {}, "scope");
|
|
1190
|
+
const bases = insts.filter((i) => !isOverlay(i));
|
|
1191
|
+
const okBases = bases.filter((i) => i.outcome === "ok");
|
|
1192
|
+
if (okBases.length !== 1) {
|
|
1193
|
+
const reason = (
|
|
1194
|
+
// No base instance at all (overlay-only `fec`) is a count of 0, not
|
|
1195
|
+
// the overlay's own issue.
|
|
1196
|
+
okBases.length > 1 || bases.length === 0 ? Object.freeze({ code: "fec_base_instances", path: at(`/tracks/${ti}/fec`), outcome: "violation" }) : why(bases[0] ?? insts[0])
|
|
1197
|
+
);
|
|
1198
|
+
out.set(name, Object.freeze({ status: "unavailable", track: name, pointer: pointers[ti], reason }));
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
const b = okBases[0];
|
|
1202
|
+
const base = geometry(recordOf(fec[Number(b.path.split("/").pop())]), b.instanceId, nameAt(b.symbolTrack));
|
|
1203
|
+
const priorityOf = (i) => {
|
|
1204
|
+
const p = i === null ? void 0 : trackAt(i)["priority"];
|
|
1205
|
+
return typeof p === "number" ? p : DEFAULT_FEC_REPAIR_PRIORITY;
|
|
1206
|
+
};
|
|
1207
|
+
const layers = [
|
|
1208
|
+
{ layer: 0, repairTrackName: base.repairTrack, repairSymbols: base.repairSymbols, rsIdOffset: 0, priority: priorityOf(b.repairTrack) }
|
|
1209
|
+
];
|
|
1210
|
+
const more = b.boundRepairTracks.map((tj) => ({ tj, layer: trackAt(tj)["repairLayer"] })).sort((x, y) => x.layer - y.layer);
|
|
1211
|
+
let offset = base.repairSymbols;
|
|
1212
|
+
for (const { tj, layer } of more) {
|
|
1213
|
+
const repairSymbols = trackAt(tj)["repairSymbols"];
|
|
1214
|
+
layers.push({ layer, repairTrackName: nameAt(tj), repairSymbols, rsIdOffset: offset, priority: priorityOf(tj) });
|
|
1215
|
+
offset += repairSymbols;
|
|
1216
|
+
}
|
|
1217
|
+
let overlay;
|
|
1218
|
+
let overlayUnavailable;
|
|
1219
|
+
const ov = insts.find(isOverlay);
|
|
1220
|
+
if (ov?.outcome === "ok") {
|
|
1221
|
+
const g = geometry(recordOf(fec[Number(ov.path.split("/").pop())]), ov.instanceId, nameAt(ov.symbolTrack));
|
|
1222
|
+
overlay = Object.freeze({
|
|
1223
|
+
repairTrackName: g.repairTrack,
|
|
1224
|
+
scope: "keyframe",
|
|
1225
|
+
sourceSymbols: g.sourceSymbols,
|
|
1226
|
+
repairSymbols: g.repairSymbols,
|
|
1227
|
+
priority: priorityOf(ov.repairTrack),
|
|
1228
|
+
geometry: g
|
|
1229
|
+
});
|
|
1230
|
+
} else if (ov)
|
|
1231
|
+
overlayUnavailable = why(ov);
|
|
1232
|
+
out.set(name, Object.freeze({
|
|
1233
|
+
status: "ok",
|
|
1234
|
+
track: name,
|
|
1235
|
+
pointer: pointers[ti],
|
|
1236
|
+
base,
|
|
1237
|
+
layers: Object.freeze(layers.map((l) => Object.freeze(l))),
|
|
1238
|
+
totalBaseRepairSymbols: offset,
|
|
1239
|
+
...overlay ? { overlay } : {},
|
|
1240
|
+
...overlayUnavailable ? { overlayUnavailable } : {}
|
|
1241
|
+
}));
|
|
1242
|
+
});
|
|
1243
|
+
return out;
|
|
1244
|
+
}
|
|
1245
|
+
function geometry(o, instanceId, symbolTrack) {
|
|
1246
|
+
return Object.freeze({
|
|
1247
|
+
instanceId,
|
|
1248
|
+
scheme: o["scheme"],
|
|
1249
|
+
blockProfile: o["blockProfile"],
|
|
1250
|
+
sourceSymbols: o["sourceSymbols"],
|
|
1251
|
+
repairSymbols: o["repairSymbols"],
|
|
1252
|
+
symbolSize: o["symbolSize"],
|
|
1253
|
+
...typeof o["interleaveDepthMs"] === "number" ? { interleaveDepthMs: o["interleaveDepthMs"] } : {},
|
|
1254
|
+
...typeof o["reorderToleranceMs"] === "number" ? { reorderToleranceMs: o["reorderToleranceMs"] } : {},
|
|
1255
|
+
repairTrack: o["repairTrack"],
|
|
1256
|
+
...symbolTrack !== void 0 ? { symbolTrack } : {}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
|
|
756
1260
|
// src/mfu-reassembler.ts
|
|
757
1261
|
function fragmentProvenance(fragment) {
|
|
758
1262
|
if (fragment.deliveryProvenance !== void 0) return fragment.deliveryProvenance;
|
|
@@ -7464,321 +7968,6 @@ var BlockcastMmt = (() => {
|
|
|
7464
7968
|
});
|
|
7465
7969
|
}
|
|
7466
7970
|
|
|
7467
|
-
// src/repair-layers.ts
|
|
7468
|
-
var REPAIR_PRIORITY_MIN = 192;
|
|
7469
|
-
var REPAIR_PRIORITY_MAX = 255;
|
|
7470
|
-
var DEFAULT_REPAIR_PRIORITY = 240;
|
|
7471
|
-
var MAX_RAPTORQ_SOURCE_SYMBOLS = 56403;
|
|
7472
|
-
var MAX_REPAIR_SYMBOLS = 16777215;
|
|
7473
|
-
var MAX_ENCODING_SYMBOL_ID = 16777215;
|
|
7474
|
-
var MAX_REED_SOLOMON_BLOCK_SYMBOLS = 255;
|
|
7475
|
-
var RepairContractError = class extends Error {
|
|
7476
|
-
constructor(code, path, message) {
|
|
7477
|
-
super(`[repair-layers:${code}] ${path}: ${message}`);
|
|
7478
|
-
this.code = code;
|
|
7479
|
-
this.path = path;
|
|
7480
|
-
this.name = "RepairContractError";
|
|
7481
|
-
}
|
|
7482
|
-
};
|
|
7483
|
-
var throwRepairContractError = (code, path, message) => {
|
|
7484
|
-
throw new RepairContractError(code, path, message);
|
|
7485
|
-
};
|
|
7486
|
-
function readFecBlockProfile(value, path, declaresFecInstance, fail) {
|
|
7487
|
-
if (value === void 0 && !declaresFecInstance) return void 0;
|
|
7488
|
-
if (isFecBlockProfile(value)) return value;
|
|
7489
|
-
if (typeof value === "string" && value.length > 0) {
|
|
7490
|
-
return fail(
|
|
7491
|
-
"track_fec_block_profile_unimplemented",
|
|
7492
|
-
path,
|
|
7493
|
-
`${JSON.stringify(value)} is not an implemented FEC block profile; only "iso-ssbg1-v1" is implemented`
|
|
7494
|
-
);
|
|
7495
|
-
}
|
|
7496
|
-
try {
|
|
7497
|
-
return parseFecBlockProfile(value, "blockProfile");
|
|
7498
|
-
} catch (error) {
|
|
7499
|
-
return fail("track_fec_block_profile", path, error.message);
|
|
7500
|
-
}
|
|
7501
|
-
}
|
|
7502
|
-
var REPAIR_FIELDS = ["depends", "repairLayer", "repairSymbols", "priority", "scope", "sourceSymbols"];
|
|
7503
|
-
var REPAIR_TRACK_GEOMETRY_KEYS = [
|
|
7504
|
-
"mmtpMode",
|
|
7505
|
-
"timescale",
|
|
7506
|
-
"groupDurationMs",
|
|
7507
|
-
"groupDurationTicks",
|
|
7508
|
-
"keyframeIntervalMs",
|
|
7509
|
-
"keyframeIntervalTicks",
|
|
7510
|
-
"fec",
|
|
7511
|
-
"symbolSize",
|
|
7512
|
-
"interleaveDepthMs"
|
|
7513
|
-
];
|
|
7514
|
-
var REPAIR_TRACK_ONLY_KEYS = ["repairLayer", "repairSymbols", "sourceSymbols", "scope"];
|
|
7515
|
-
function rejectRepairTrackGeometry(path, fields, fail) {
|
|
7516
|
-
for (const key of REPAIR_TRACK_GEOMETRY_KEYS) {
|
|
7517
|
-
if (fields[key] !== void 0) {
|
|
7518
|
-
fail(
|
|
7519
|
-
"track_repair_geometry",
|
|
7520
|
-
`${path}.${key}`,
|
|
7521
|
-
"a repair track carries no block geometry; it is shared with the source track's fec object"
|
|
7522
|
-
);
|
|
7523
|
-
}
|
|
7524
|
-
}
|
|
7525
|
-
}
|
|
7526
|
-
function repairReachability(fecObjects) {
|
|
7527
|
-
let declaresFecSource = false;
|
|
7528
|
-
const layerZeroNames = /* @__PURE__ */ new Set();
|
|
7529
|
-
for (const candidate of fecObjects) {
|
|
7530
|
-
if (typeof candidate !== "object" || candidate === null || Array.isArray(candidate)) continue;
|
|
7531
|
-
const fec = candidate;
|
|
7532
|
-
if (fec["algorithm"] === "none") continue;
|
|
7533
|
-
declaresFecSource = true;
|
|
7534
|
-
const repairTrack = fec["repairTrack"];
|
|
7535
|
-
if (typeof repairTrack === "string" && repairTrack.length > 0) layerZeroNames.add(repairTrack);
|
|
7536
|
-
}
|
|
7537
|
-
return { declaresFecSource, layerZeroNames };
|
|
7538
|
-
}
|
|
7539
|
-
function assertRepairTrackReachable(descriptor, reachability, fail) {
|
|
7540
|
-
if (dependsTarget(descriptor) !== void 0) return;
|
|
7541
|
-
if (reachability.declaresFecSource && !reachability.layerZeroNames.has(descriptor.name)) {
|
|
7542
|
-
fail(
|
|
7543
|
-
"track_repair_depends",
|
|
7544
|
-
`${descriptor.path}.depends`,
|
|
7545
|
-
"no source names this repair track in fec.repairTrack and it declares no depends"
|
|
7546
|
-
);
|
|
7547
|
-
}
|
|
7548
|
-
}
|
|
7549
|
-
function rejectRepairFieldsOnMediaTrack(path, fields, fail) {
|
|
7550
|
-
for (const key of REPAIR_TRACK_ONLY_KEYS) {
|
|
7551
|
-
if (fields[key] !== void 0) {
|
|
7552
|
-
fail("track_repair_layer", `${path}.${key}`, `${key} is a repair track field`);
|
|
7553
|
-
}
|
|
7554
|
-
}
|
|
7555
|
-
}
|
|
7556
|
-
function describeRepairTrack(name, path, fields) {
|
|
7557
|
-
const descriptor = { name, path };
|
|
7558
|
-
for (const field of REPAIR_FIELDS) {
|
|
7559
|
-
if (field in fields) descriptor[field] = fields[field];
|
|
7560
|
-
}
|
|
7561
|
-
return descriptor;
|
|
7562
|
-
}
|
|
7563
|
-
function isSafeInteger(value) {
|
|
7564
|
-
return typeof value === "number" && Number.isSafeInteger(value);
|
|
7565
|
-
}
|
|
7566
|
-
function positiveInteger(value) {
|
|
7567
|
-
return isSafeInteger(value) && value > 0;
|
|
7568
|
-
}
|
|
7569
|
-
function dependsTarget(descriptor) {
|
|
7570
|
-
const depends = descriptor.depends;
|
|
7571
|
-
return Array.isArray(depends) && depends.length === 1 && typeof depends[0] === "string" && depends[0].length > 0 ? depends[0] : void 0;
|
|
7572
|
-
}
|
|
7573
|
-
function validateRepairTrackFields(descriptor, fail) {
|
|
7574
|
-
const { path } = descriptor;
|
|
7575
|
-
if (descriptor.depends !== void 0 && dependsTarget(descriptor) === void 0) {
|
|
7576
|
-
fail("track_repair_depends", `${path}.depends`, "must name exactly one source track");
|
|
7577
|
-
}
|
|
7578
|
-
if (descriptor.repairLayer !== void 0 && (!isSafeInteger(descriptor.repairLayer) || descriptor.repairLayer < 0)) {
|
|
7579
|
-
fail("track_repair_layer", `${path}.repairLayer`, "must be a non-negative integer");
|
|
7580
|
-
}
|
|
7581
|
-
if (descriptor.repairSymbols !== void 0 && (!positiveInteger(descriptor.repairSymbols) || descriptor.repairSymbols > MAX_REPAIR_SYMBOLS)) {
|
|
7582
|
-
fail("track_repair_layer", `${path}.repairSymbols`, `must be a positive integer at most ${MAX_REPAIR_SYMBOLS}`);
|
|
7583
|
-
}
|
|
7584
|
-
if (descriptor.priority !== void 0 && (!isSafeInteger(descriptor.priority) || descriptor.priority < REPAIR_PRIORITY_MIN || descriptor.priority > REPAIR_PRIORITY_MAX)) {
|
|
7585
|
-
fail(
|
|
7586
|
-
"track_repair_priority",
|
|
7587
|
-
`${path}.priority`,
|
|
7588
|
-
`must be an integer from ${REPAIR_PRIORITY_MIN} to ${REPAIR_PRIORITY_MAX} (MoQT scale, lower first)`
|
|
7589
|
-
);
|
|
7590
|
-
}
|
|
7591
|
-
if (descriptor.scope !== void 0) {
|
|
7592
|
-
if (descriptor.scope !== "keyframe") {
|
|
7593
|
-
fail("track_repair_overlay", `${path}.scope`, 'must be "keyframe"');
|
|
7594
|
-
}
|
|
7595
|
-
if (descriptor.repairLayer !== void 0) {
|
|
7596
|
-
fail("track_repair_overlay", `${path}.repairLayer`, "an overlay is a separate FEC instance and carries no repairLayer");
|
|
7597
|
-
}
|
|
7598
|
-
for (const field of ["depends", "sourceSymbols", "repairSymbols", "priority"]) {
|
|
7599
|
-
if (descriptor[field] === void 0) {
|
|
7600
|
-
fail("track_repair_overlay", `${path}.${field}`, `an overlay must declare ${field}`);
|
|
7601
|
-
}
|
|
7602
|
-
}
|
|
7603
|
-
}
|
|
7604
|
-
if (descriptor.sourceSymbols !== void 0) {
|
|
7605
|
-
if (descriptor.scope === void 0) {
|
|
7606
|
-
fail("track_repair_overlay", `${path}.sourceSymbols`, "only an overlay (scope: keyframe) declares its own sourceSymbols");
|
|
7607
|
-
}
|
|
7608
|
-
if (!positiveInteger(descriptor.sourceSymbols) || descriptor.sourceSymbols > MAX_RAPTORQ_SOURCE_SYMBOLS) {
|
|
7609
|
-
fail(
|
|
7610
|
-
"track_fec_bounds",
|
|
7611
|
-
`${path}.sourceSymbols`,
|
|
7612
|
-
`must be a positive integer at most ${MAX_RAPTORQ_SOURCE_SYMBOLS} (RFC 6330 source block limit)`
|
|
7613
|
-
);
|
|
7614
|
-
}
|
|
7615
|
-
}
|
|
7616
|
-
if (isSafeInteger(descriptor.repairLayer) && descriptor.repairLayer >= 1) {
|
|
7617
|
-
for (const field of ["depends", "repairSymbols", "priority"]) {
|
|
7618
|
-
if (descriptor[field] === void 0) {
|
|
7619
|
-
fail("track_repair_layer", `${path}.${field}`, `repair layer ${descriptor.repairLayer} must declare ${field}`);
|
|
7620
|
-
}
|
|
7621
|
-
}
|
|
7622
|
-
}
|
|
7623
|
-
}
|
|
7624
|
-
function assembleRepairLayers(source, descriptors, fail = throwRepairContractError, options = {}) {
|
|
7625
|
-
const layerZeroName = typeof source.repairTrack === "string" && source.repairTrack.length > 0 ? source.repairTrack : void 0;
|
|
7626
|
-
const layerZero = layerZeroName === void 0 ? void 0 : descriptors.find((d) => d.name === layerZeroName);
|
|
7627
|
-
if (layerZeroName !== void 0 && layerZero === void 0 && options.layerZeroMustBeDeclared) {
|
|
7628
|
-
fail("track_repair_track", `${source.path}.repairTrack`, `unknown FEC repair track ${JSON.stringify(layerZeroName)}`);
|
|
7629
|
-
}
|
|
7630
|
-
const dependents = descriptors.filter((d) => d.name !== layerZeroName && dependsTarget(d) === source.name);
|
|
7631
|
-
const k = positiveInteger(source.sourceSymbols) ? source.sourceSymbols : 0;
|
|
7632
|
-
if (source.algorithm === "raptorq" && k > MAX_RAPTORQ_SOURCE_SYMBOLS) {
|
|
7633
|
-
fail(
|
|
7634
|
-
"track_fec_bounds",
|
|
7635
|
-
`${source.path}.sourceSymbols`,
|
|
7636
|
-
`must be at most ${MAX_RAPTORQ_SOURCE_SYMBOLS} (RFC 6330 source block limit)`
|
|
7637
|
-
);
|
|
7638
|
-
}
|
|
7639
|
-
if (layerZeroName === void 0) {
|
|
7640
|
-
if (dependents.length === 0) return void 0;
|
|
7641
|
-
fail(
|
|
7642
|
-
"track_repair_layer",
|
|
7643
|
-
`${dependents[0].path}.depends`,
|
|
7644
|
-
`repair layers of ${JSON.stringify(source.name)} require a layer 0 (fec.repairTrack) on the source`
|
|
7645
|
-
);
|
|
7646
|
-
}
|
|
7647
|
-
const layered = dependents.length > 0;
|
|
7648
|
-
let layerZeroSymbols = 0;
|
|
7649
|
-
if (positiveInteger(source.repairSymbols)) {
|
|
7650
|
-
layerZeroSymbols = source.repairSymbols;
|
|
7651
|
-
} else if (layered) {
|
|
7652
|
-
fail("track_fec", `${source.path}.repairSymbols`, "layered or overlay repair needs a positive integer repairSymbols on layer 0");
|
|
7653
|
-
}
|
|
7654
|
-
if (layered && !positiveInteger(source.sourceSymbols)) {
|
|
7655
|
-
fail("track_fec", `${source.path}.sourceSymbols`, "layered or overlay repair needs a positive integer sourceSymbols on the source");
|
|
7656
|
-
}
|
|
7657
|
-
const reedSolomon = source.algorithm === "reed-solomon";
|
|
7658
|
-
if (layered && source.algorithm !== "raptorq" && !reedSolomon) {
|
|
7659
|
-
fail(
|
|
7660
|
-
"track_fec",
|
|
7661
|
-
`${source.path}.algorithm`,
|
|
7662
|
-
"repair layers and overlays are defined only for raptorq and reed-solomon (draft-ramadan-moq-fec-01 6.3.4 rule 7)"
|
|
7663
|
-
);
|
|
7664
|
-
}
|
|
7665
|
-
let layerZeroPriority = DEFAULT_REPAIR_PRIORITY;
|
|
7666
|
-
if (layerZero !== void 0) {
|
|
7667
|
-
if (layerZero.depends !== void 0 && dependsTarget(layerZero) !== source.name) {
|
|
7668
|
-
fail(
|
|
7669
|
-
"track_repair_depends",
|
|
7670
|
-
`${layerZero.path}.depends`,
|
|
7671
|
-
`layer 0 of ${JSON.stringify(source.name)} must depend on that source`
|
|
7672
|
-
);
|
|
7673
|
-
}
|
|
7674
|
-
if (layerZero.repairLayer !== void 0 && layerZero.repairLayer !== 0) {
|
|
7675
|
-
fail("track_repair_layer", `${layerZero.path}.repairLayer`, "the track named by fec.repairTrack is layer 0");
|
|
7676
|
-
}
|
|
7677
|
-
if (layerZero.scope !== void 0) {
|
|
7678
|
-
fail("track_repair_overlay", `${layerZero.path}.scope`, "the track named by fec.repairTrack is base layer 0, not an overlay");
|
|
7679
|
-
}
|
|
7680
|
-
if (layerZero.repairSymbols !== void 0 && layerZero.repairSymbols !== layerZeroSymbols) {
|
|
7681
|
-
fail(
|
|
7682
|
-
"track_repair_layer",
|
|
7683
|
-
`${layerZero.path}.repairSymbols`,
|
|
7684
|
-
`must agree with the source's fec.repairSymbols (${layerZeroSymbols})`
|
|
7685
|
-
);
|
|
7686
|
-
}
|
|
7687
|
-
if (typeof layerZero.priority === "number") layerZeroPriority = layerZero.priority;
|
|
7688
|
-
}
|
|
7689
|
-
const baseLayers = [
|
|
7690
|
-
{ layer: 0, repairTrackName: layerZeroName, repairSymbols: layerZeroSymbols, rsIdOffset: 0, priority: layerZeroPriority }
|
|
7691
|
-
];
|
|
7692
|
-
const overlays = [];
|
|
7693
|
-
for (const d of dependents) {
|
|
7694
|
-
if (d.scope === void 0 && d.repairLayer === void 0) {
|
|
7695
|
-
fail(
|
|
7696
|
-
"track_repair_layer",
|
|
7697
|
-
`${d.path}.repairLayer`,
|
|
7698
|
-
`a repair track that depends on ${JSON.stringify(source.name)} must declare repairLayer (1..n) or scope: "keyframe"`
|
|
7699
|
-
);
|
|
7700
|
-
}
|
|
7701
|
-
}
|
|
7702
|
-
const layerTracks = dependents.filter((d) => d.scope === void 0).sort((a, b) => a.repairLayer - b.repairLayer);
|
|
7703
|
-
for (const d of dependents) {
|
|
7704
|
-
if (d.scope !== "keyframe") continue;
|
|
7705
|
-
if (overlays.length === 1) {
|
|
7706
|
-
fail(
|
|
7707
|
-
"track_repair_overlay",
|
|
7708
|
-
`${d.path}.scope`,
|
|
7709
|
-
`${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`
|
|
7710
|
-
);
|
|
7711
|
-
}
|
|
7712
|
-
const sourceSymbols = d.sourceSymbols;
|
|
7713
|
-
const repairSymbols = d.repairSymbols;
|
|
7714
|
-
if (sourceSymbols + repairSymbols - 1 > MAX_ENCODING_SYMBOL_ID) {
|
|
7715
|
-
fail(
|
|
7716
|
-
"track_fec_bounds",
|
|
7717
|
-
`${d.path}.repairSymbols`,
|
|
7718
|
-
`overlay sourceSymbols + repairSymbols - 1 exceeds the 24-bit ESI space (${MAX_ENCODING_SYMBOL_ID})`
|
|
7719
|
-
);
|
|
7720
|
-
}
|
|
7721
|
-
if (reedSolomon && sourceSymbols + repairSymbols > MAX_REED_SOLOMON_BLOCK_SYMBOLS) {
|
|
7722
|
-
fail(
|
|
7723
|
-
"track_fec_bounds",
|
|
7724
|
-
`${d.path}.repairSymbols`,
|
|
7725
|
-
`reed-solomon overlay sourceSymbols + repairSymbols exceeds ${MAX_REED_SOLOMON_BLOCK_SYMBOLS} (draft-ramadan-moq-fec-01 6.3.4 rule 12)`
|
|
7726
|
-
);
|
|
7727
|
-
}
|
|
7728
|
-
overlays.push({ repairTrackName: d.name, scope: "keyframe", sourceSymbols, repairSymbols, priority: d.priority });
|
|
7729
|
-
}
|
|
7730
|
-
let offset = layerZeroSymbols;
|
|
7731
|
-
let previousPriority = layerZeroPriority;
|
|
7732
|
-
layerTracks.forEach((d, i) => {
|
|
7733
|
-
const expected = i + 1;
|
|
7734
|
-
if (d.repairLayer === 0) {
|
|
7735
|
-
fail("track_repair_layer", `${d.path}.repairLayer`, `layer 0 of ${JSON.stringify(source.name)} is ${JSON.stringify(layerZeroName)}, named by fec.repairTrack`);
|
|
7736
|
-
}
|
|
7737
|
-
if (d.repairLayer !== expected) {
|
|
7738
|
-
fail(
|
|
7739
|
-
"track_repair_layer",
|
|
7740
|
-
`${d.path}.repairLayer`,
|
|
7741
|
-
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}`
|
|
7742
|
-
);
|
|
7743
|
-
}
|
|
7744
|
-
const priority = d.priority;
|
|
7745
|
-
if (priority < previousPriority) {
|
|
7746
|
-
fail(
|
|
7747
|
-
"track_repair_priority",
|
|
7748
|
-
`${d.path}.priority`,
|
|
7749
|
-
`must be at least ${previousPriority}, the priority of layer ${expected - 1}: priority is monotonic non-decreasing with layer index`
|
|
7750
|
-
);
|
|
7751
|
-
}
|
|
7752
|
-
previousPriority = priority;
|
|
7753
|
-
const repairSymbols = d.repairSymbols;
|
|
7754
|
-
baseLayers.push({ layer: expected, repairTrackName: d.name, repairSymbols, rsIdOffset: offset, priority });
|
|
7755
|
-
offset += repairSymbols;
|
|
7756
|
-
});
|
|
7757
|
-
const totalBaseRepairSymbols = offset;
|
|
7758
|
-
if (totalBaseRepairSymbols > MAX_REPAIR_SYMBOLS) {
|
|
7759
|
-
fail(
|
|
7760
|
-
"track_fec_bounds",
|
|
7761
|
-
`${layerTracks.length === 0 ? source.path : layerTracks[layerTracks.length - 1].path}.repairSymbols`,
|
|
7762
|
-
`total repair symbols across base layers exceeds the 24-bit RS_ID space (${MAX_REPAIR_SYMBOLS})`
|
|
7763
|
-
);
|
|
7764
|
-
}
|
|
7765
|
-
if (k + totalBaseRepairSymbols - 1 > MAX_ENCODING_SYMBOL_ID) {
|
|
7766
|
-
fail(
|
|
7767
|
-
"track_fec_bounds",
|
|
7768
|
-
`${source.path}.sourceSymbols`,
|
|
7769
|
-
`sourceSymbols + total base repair symbols - 1 exceeds the 24-bit ESI space (${MAX_ENCODING_SYMBOL_ID})`
|
|
7770
|
-
);
|
|
7771
|
-
}
|
|
7772
|
-
if (reedSolomon && k + totalBaseRepairSymbols > MAX_REED_SOLOMON_BLOCK_SYMBOLS) {
|
|
7773
|
-
fail(
|
|
7774
|
-
"track_fec_bounds",
|
|
7775
|
-
`${source.path}.sourceSymbols`,
|
|
7776
|
-
`reed-solomon sourceSymbols + total base repair symbols exceeds ${MAX_REED_SOLOMON_BLOCK_SYMBOLS} (draft-ramadan-moq-fec-01 6.3.4 rule 12)`
|
|
7777
|
-
);
|
|
7778
|
-
}
|
|
7779
|
-
return { sourceTrackName: source.name, baseLayers, overlays, totalBaseRepairSymbols };
|
|
7780
|
-
}
|
|
7781
|
-
|
|
7782
7971
|
// src/carp-catalog.ts
|
|
7783
7972
|
function isTrackTimingConfig(obj) {
|
|
7784
7973
|
if (typeof obj !== "object" || obj === null) return false;
|
|
@@ -7911,7 +8100,7 @@ var BlockcastMmt = (() => {
|
|
|
7911
8100
|
}
|
|
7912
8101
|
const tracks = catalog["tracks"];
|
|
7913
8102
|
const trackRecords = [];
|
|
7914
|
-
const
|
|
8103
|
+
const positiveInteger = (input) => Number.isSafeInteger(input) && input > 0;
|
|
7915
8104
|
const positiveNumber = (input) => typeof input === "number" && Number.isFinite(input) && input > 0;
|
|
7916
8105
|
for (let index = 0; index < tracks.length; index++) {
|
|
7917
8106
|
const raw = tracks[index];
|
|
@@ -7943,7 +8132,7 @@ var BlockcastMmt = (() => {
|
|
|
7943
8132
|
);
|
|
7944
8133
|
}
|
|
7945
8134
|
const codec = track["codec"];
|
|
7946
|
-
if (packaging !== "timeline" && packaging !== "mediatimeline" && packaging !== "eventtimeline" && packaging !== "fec-repair" && (typeof codec !== "string" || codec.length === 0)) {
|
|
8135
|
+
if (packaging !== "timeline" && packaging !== "mediatimeline" && packaging !== "eventtimeline" && packaging !== "fec-repair" && packaging !== "fec-source" && (typeof codec !== "string" || codec.length === 0)) {
|
|
7947
8136
|
catalogError("track_codec", `${path}.codec`, `codec is required for packaging=${packaging}`);
|
|
7948
8137
|
}
|
|
7949
8138
|
const timescale = track["timescale"];
|
|
@@ -7951,13 +8140,13 @@ var BlockcastMmt = (() => {
|
|
|
7951
8140
|
const groupDurationTicks = track["groupDurationTicks"];
|
|
7952
8141
|
const keyframeIntervalMs = track["keyframeIntervalMs"];
|
|
7953
8142
|
const keyframeIntervalTicks = track["keyframeIntervalTicks"];
|
|
7954
|
-
if (groupDurationMs !== void 0 && !
|
|
8143
|
+
if (groupDurationMs !== void 0 && !positiveInteger(groupDurationMs)) {
|
|
7955
8144
|
catalogError("track_group_duration_ms", `${path}.groupDurationMs`, "must be a positive integer");
|
|
7956
8145
|
}
|
|
7957
|
-
if (groupDurationTicks !== void 0 && !
|
|
8146
|
+
if (groupDurationTicks !== void 0 && !positiveInteger(groupDurationTicks)) {
|
|
7958
8147
|
catalogError("track_group_duration_ticks", `${path}.groupDurationTicks`, "must be a positive integer");
|
|
7959
8148
|
}
|
|
7960
|
-
if (keyframeIntervalMs !== void 0 && !positiveNumber(keyframeIntervalMs) || keyframeIntervalTicks !== void 0 && !
|
|
8149
|
+
if (keyframeIntervalMs !== void 0 && !positiveNumber(keyframeIntervalMs) || keyframeIntervalTicks !== void 0 && !positiveInteger(keyframeIntervalTicks)) {
|
|
7961
8150
|
catalogError("track_keyframe_interval", path, "keyframe interval fields must be positive numbers");
|
|
7962
8151
|
}
|
|
7963
8152
|
const anchor = track["presentationAnchorTicks"];
|
|
@@ -7968,17 +8157,11 @@ var BlockcastMmt = (() => {
|
|
|
7968
8157
|
if (initRef !== void 0 && (typeof initRef !== "string" || initRef.length === 0)) {
|
|
7969
8158
|
catalogError("track_init_ref", `${path}.initRef`, "must be a non-empty string");
|
|
7970
8159
|
}
|
|
7971
|
-
if (packaging === "fec-repair") {
|
|
7972
|
-
rejectRepairTrackGeometry(path, track, catalogError);
|
|
7973
|
-
validateRepairTrackFields(describeRepairTrack(name, path, track), catalogError);
|
|
7974
|
-
} else {
|
|
7975
|
-
rejectRepairFieldsOnMediaTrack(path, track, catalogError);
|
|
7976
|
-
}
|
|
7977
8160
|
if (packaging === "mmtp") {
|
|
7978
8161
|
if (track["mmtpMode"] !== "mfu") {
|
|
7979
8162
|
catalogError("track_mmtp_mode", `${path}.mmtpMode`, "must be mfu");
|
|
7980
8163
|
}
|
|
7981
|
-
if (!
|
|
8164
|
+
if (!positiveInteger(timescale)) {
|
|
7982
8165
|
catalogError("track_timescale", `${path}.timescale`, "must be a positive integer");
|
|
7983
8166
|
}
|
|
7984
8167
|
if (groupDurationMs === void 0 && groupDurationTicks === void 0) {
|
|
@@ -7992,85 +8175,6 @@ var BlockcastMmt = (() => {
|
|
|
7992
8175
|
catalogError("track_group_duration_exact", `${path}.groupDurationMs`, "does not resolve to an exact integer tick count");
|
|
7993
8176
|
}
|
|
7994
8177
|
}
|
|
7995
|
-
if (track["fec"] !== void 0) {
|
|
7996
|
-
const fec = track["fec"];
|
|
7997
|
-
if (typeof fec !== "object" || fec === null || Array.isArray(fec)) {
|
|
7998
|
-
catalogError("track_fec", `${path}.fec`, "FEC must be an object");
|
|
7999
|
-
}
|
|
8000
|
-
const config = fec;
|
|
8001
|
-
const algorithm = config["algorithm"];
|
|
8002
|
-
if (typeof algorithm !== "string" || algorithm.length === 0) {
|
|
8003
|
-
catalogError("track_fec", `${path}.fec.algorithm`, "must be a non-empty string");
|
|
8004
|
-
}
|
|
8005
|
-
if ("interleaveDepth" in config || "interleaveMs" in config) {
|
|
8006
|
-
catalogError("track_fec", `${path}.fec`, "interleaveDepthMs is the only supported interleave field");
|
|
8007
|
-
}
|
|
8008
|
-
if ("enhancementRepair" in config) {
|
|
8009
|
-
catalogError(
|
|
8010
|
-
"track_fec",
|
|
8011
|
-
`${path}.fec.enhancementRepair`,
|
|
8012
|
-
"repair layers are self-describing fec-repair tracks (depends, repairLayer); fec.enhancementRepair is not supported"
|
|
8013
|
-
);
|
|
8014
|
-
}
|
|
8015
|
-
if (config["interleaveDepthMs"] !== void 0 && (!Number.isSafeInteger(config["interleaveDepthMs"]) || config["interleaveDepthMs"] < 0)) {
|
|
8016
|
-
catalogError("track_fec", `${path}.fec.interleaveDepthMs`, "must be a non-negative safe integer");
|
|
8017
|
-
}
|
|
8018
|
-
if (algorithm !== "none") {
|
|
8019
|
-
for (const field of ["sourceSymbols", "repairSymbols", "symbolSize"]) {
|
|
8020
|
-
if (!positiveInteger2(config[field])) {
|
|
8021
|
-
catalogError("track_fec", `${path}.fec.${field}`, "must be a positive integer");
|
|
8022
|
-
}
|
|
8023
|
-
}
|
|
8024
|
-
if (algorithm === "raptorq" && config["symbolSize"] % 8 !== 0) {
|
|
8025
|
-
catalogError("track_fec", `${path}.fec.symbolSize`, "RaptorQ symbolSize must be a multiple of 8");
|
|
8026
|
-
}
|
|
8027
|
-
if (typeof config["repairTrack"] !== "string" || config["repairTrack"].length === 0) {
|
|
8028
|
-
catalogError("track_fec", `${path}.fec.repairTrack`, "must be a non-empty string");
|
|
8029
|
-
}
|
|
8030
|
-
}
|
|
8031
|
-
readFecBlockProfile(config["blockProfile"], `${path}.fec.blockProfile`, algorithm !== "none", catalogError);
|
|
8032
|
-
if (algorithm !== "none" && config["symbolSize"] < ISO_SSBG1_MIN_SYMBOL_SIZE) {
|
|
8033
|
-
catalogError("track_fec", `${path}.fec.symbolSize`, "iso-ssbg1-v1 symbolSize must be at least 14");
|
|
8034
|
-
}
|
|
8035
|
-
}
|
|
8036
|
-
}
|
|
8037
|
-
const repairDescriptors = trackRecords.flatMap(
|
|
8038
|
-
(track, index) => track["packaging"] === "fec-repair" ? [describeRepairTrack(track["name"], `$.tracks[${index}]`, track)] : []
|
|
8039
|
-
);
|
|
8040
|
-
const reachability = repairReachability(
|
|
8041
|
-
trackRecords.filter((track) => track["packaging"] !== "fec-repair").map((track) => track["fec"])
|
|
8042
|
-
);
|
|
8043
|
-
for (const descriptor of repairDescriptors) {
|
|
8044
|
-
assertRepairTrackReachable(descriptor, reachability, catalogError);
|
|
8045
|
-
const target = dependsTarget(descriptor);
|
|
8046
|
-
if (target === void 0) continue;
|
|
8047
|
-
const source = trackRecords.find((candidate) => candidate["name"] === target);
|
|
8048
|
-
const sourceFec = source?.["fec"];
|
|
8049
|
-
if (!source || source["packaging"] !== "mmtp" || !sourceFec || sourceFec["algorithm"] === "none") {
|
|
8050
|
-
catalogError(
|
|
8051
|
-
"track_repair_depends",
|
|
8052
|
-
`${descriptor.path}.depends`,
|
|
8053
|
-
`${JSON.stringify(target)} is not an mmtp track with FEC`
|
|
8054
|
-
);
|
|
8055
|
-
}
|
|
8056
|
-
}
|
|
8057
|
-
for (let index = 0; index < trackRecords.length; index++) {
|
|
8058
|
-
const track = trackRecords[index];
|
|
8059
|
-
const fec = track["fec"];
|
|
8060
|
-
if (!fec || fec["algorithm"] === "none") continue;
|
|
8061
|
-
assembleRepairLayers(
|
|
8062
|
-
{
|
|
8063
|
-
name: track["name"],
|
|
8064
|
-
path: `$.tracks[${index}].fec`,
|
|
8065
|
-
algorithm: fec["algorithm"],
|
|
8066
|
-
sourceSymbols: fec["sourceSymbols"],
|
|
8067
|
-
repairSymbols: fec["repairSymbols"],
|
|
8068
|
-
repairTrack: fec["repairTrack"]
|
|
8069
|
-
},
|
|
8070
|
-
repairDescriptors,
|
|
8071
|
-
catalogError,
|
|
8072
|
-
{ layerZeroMustBeDeclared: true }
|
|
8073
|
-
);
|
|
8074
8178
|
}
|
|
8075
8179
|
const switchingSets = /* @__PURE__ */ new Map();
|
|
8076
8180
|
for (let index = 0; index < trackRecords.length; index++) {
|
|
@@ -8218,13 +8322,8 @@ var BlockcastMmt = (() => {
|
|
|
8218
8322
|
function recordOf2(value) {
|
|
8219
8323
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
8220
8324
|
}
|
|
8221
|
-
function
|
|
8222
|
-
return
|
|
8223
|
-
}
|
|
8224
|
-
function catalogDeclaresFec(fec) {
|
|
8225
|
-
const block = recordOf2(fec);
|
|
8226
|
-
if (block === void 0 || block["algorithm"] === "none" || fecAlgorithmUnimplemented(block["algorithm"])) return false;
|
|
8227
|
-
return isPositiveSafeInteger2(block["sourceSymbols"]) && isPositiveSafeInteger2(block["symbolSize"]) && isFecBlockProfile(block["blockProfile"]) && isoBlockSpanUsable(block) && !catalogFecDeclaresUnconfigurableInstance(block);
|
|
8325
|
+
function catalogDeclaresFec(catalog, track) {
|
|
8326
|
+
return resolveFecBindings(catalog).get(track)?.status === "ok";
|
|
8228
8327
|
}
|
|
8229
8328
|
function requireBoolean(value, field) {
|
|
8230
8329
|
if (typeof value !== "boolean") {
|
|
@@ -8334,9 +8433,9 @@ var BlockcastMmt = (() => {
|
|
|
8334
8433
|
var _decoder, _blocks, _settled, _have, _newest, _prunedAt, _repairPacketId, _newestSource, _heldLayers, _anchorHorizon, _stats3, _MmtpFecSession_instances, drop_fn2, noteNewest_fn, blockStartOf_fn, countHeld_fn, noteMixed_fn, behindHorizon_fn, settle_fn, settleClean_fn, settleDecoded_fn, retireBehindHorizon_fn;
|
|
8335
8434
|
var MmtpFecSession = class {
|
|
8336
8435
|
/**
|
|
8337
|
-
* @throws when the
|
|
8338
|
-
*
|
|
8339
|
-
* `reorderToleranceMs`. None is defaulted.
|
|
8436
|
+
* @throws when the instance lacks or misstates a field the session needs:
|
|
8437
|
+
* the scheme, the block profile, K, P_0 (`repairSymbols`), T,
|
|
8438
|
+
* `interleaveDepthMs` or `reorderToleranceMs`. None is defaulted.
|
|
8340
8439
|
*/
|
|
8341
8440
|
constructor(config) {
|
|
8342
8441
|
__privateAdd(this, _MmtpFecSession_instances);
|
|
@@ -8374,13 +8473,13 @@ var BlockcastMmt = (() => {
|
|
|
8374
8473
|
});
|
|
8375
8474
|
const fec = config?.fec;
|
|
8376
8475
|
if (!fec || typeof fec !== "object") {
|
|
8377
|
-
throw new Error("MmtpFecSession: the catalog fec
|
|
8476
|
+
throw new Error("MmtpFecSession: the catalog fec instance is required");
|
|
8378
8477
|
}
|
|
8379
8478
|
this.blockProfile = parseFecBlockProfile(fec.blockProfile, "fec.blockProfile");
|
|
8380
|
-
if (fec.
|
|
8381
|
-
throw new Error(`MmtpFecSession: fec.
|
|
8479
|
+
if (fec.scheme !== "raptorq" && fec.scheme !== "reed-solomon") {
|
|
8480
|
+
throw new Error(`MmtpFecSession: fec.scheme ${JSON.stringify(fec.scheme)} is not implemented`);
|
|
8382
8481
|
}
|
|
8383
|
-
this.algorithm = fec.
|
|
8482
|
+
this.algorithm = fec.scheme;
|
|
8384
8483
|
this.sourceSymbols = requirePositiveInteger(fec.sourceSymbols, "fec.sourceSymbols");
|
|
8385
8484
|
this.repairSymbols = requirePositiveInteger(fec.repairSymbols, "fec.repairSymbols");
|
|
8386
8485
|
this.symbolSize = requirePositiveInteger(fec.symbolSize, "fec.symbolSize");
|
|
@@ -8734,7 +8833,7 @@ var BlockcastMmt = (() => {
|
|
|
8734
8833
|
}
|
|
8735
8834
|
return void 0;
|
|
8736
8835
|
}
|
|
8737
|
-
function
|
|
8836
|
+
function intIn2(value, min, max) {
|
|
8738
8837
|
return Number.isInteger(value) && value >= min && value <= max;
|
|
8739
8838
|
}
|
|
8740
8839
|
function catalogAtsc3NetworkSource(networkSource) {
|
|
@@ -8742,12 +8841,12 @@ var BlockcastMmt = (() => {
|
|
|
8742
8841
|
for (const raw of entries) {
|
|
8743
8842
|
if (!raw || typeof raw !== "object") continue;
|
|
8744
8843
|
const ns = raw;
|
|
8745
|
-
if (ns.type !== "atsc3" || !
|
|
8844
|
+
if (ns.type !== "atsc3" || !intIn2(ns.frequency, 1, Number.MAX_SAFE_INTEGER)) continue;
|
|
8746
8845
|
const slsUri = typeof ns.slsUri === "string" ? ns.slsUri.trim() : "";
|
|
8747
8846
|
return {
|
|
8748
8847
|
frequency: ns.frequency,
|
|
8749
|
-
...
|
|
8750
|
-
...
|
|
8848
|
+
...intIn2(ns.plpId, 0, 63) ? { plpId: ns.plpId } : {},
|
|
8849
|
+
...intIn2(ns.serviceId, 0, 65535) ? { serviceId: ns.serviceId } : {},
|
|
8751
8850
|
...slsUri ? { slsUri } : {}
|
|
8752
8851
|
};
|
|
8753
8852
|
}
|