@blockcast/mmt-container 2.2.0-main.c4fa878f4ff4 → 2.2.0-main.da2e7cd1dd5d
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 +29 -17
- package/dist/browser-runtime.js +241 -149
- package/dist/browser-runtime.js.map +3 -3
- package/dist/catalog-fec-params.d.ts +17 -1
- package/dist/catalog-fec-params.d.ts.map +1 -1
- package/dist/catalog-fec-params.js +15 -0
- package/dist/catalog-fec-params.js.map +2 -2
- package/dist/cmcd-producer.d.ts +60 -47
- package/dist/cmcd-producer.d.ts.map +1 -1
- package/dist/cmcd-producer.js +138 -109
- package/dist/cmcd-producer.js.map +2 -2
- package/dist/delivery-catalog.js +24 -15
- package/dist/delivery-catalog.js.map +2 -2
- package/dist/delta-fallback-config.js.map +1 -1
- package/dist/fec-manager.d.ts +3 -1
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +26 -4
- package/dist/fec-manager.js.map +2 -2
- package/dist/fec-worker-setup.d.ts +1 -1
- package/dist/fec-worker-setup.js +1 -1
- package/dist/fec-worker-setup.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +2 -2
- package/dist/media-router.js.map +1 -1
- package/dist/mmtp-container-parser.d.ts +2 -0
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +4 -0
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +4 -0
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/mmtp-decode-pipeline.js +4 -0
- package/dist/mmtp-decode-pipeline.js.map +2 -2
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +38 -15
- package/dist/mmtp-router.js.map +2 -2
- package/dist/multicast-manager.js +64 -19
- package/dist/multicast-manager.js.map +2 -2
- package/dist/multicast-transport.js +24 -15
- package/dist/multicast-transport.js.map +2 -2
- package/dist/no-modules.js +4 -0
- package/dist/no-modules.js.map +2 -2
- package/dist/repair-layer-subscriptions.d.ts +6 -2
- package/dist/repair-layer-subscriptions.d.ts.map +1 -1
- package/dist/repair-layer-subscriptions.js +6 -3
- package/dist/repair-layer-subscriptions.js.map +2 -2
- package/dist/track-session.d.ts +1 -1
- package/dist/track-session.js.map +1 -1
- package/dist/wasm-mmtp-container-parser.js +4 -0
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/package.json +8 -5
- package/schemas/catalog.schema.json +4 -0
- package/src/catalog-fec-params.ts +36 -1
- package/src/cmcd-producer.ts +189 -179
- package/src/fec-manager.ts +26 -4
- package/src/fec-worker-setup.ts +2 -2
- package/src/index.ts +6 -2
- package/src/mmtp-container-parser.ts +12 -0
- package/src/mmtp-router.ts +21 -0
- package/src/repair-layer-subscriptions.ts +13 -5
- package/src/track-session.ts +1 -1
|
@@ -2292,6 +2292,10 @@ var FECManager = class _FECManager {
|
|
|
2292
2292
|
// ── Keyframe-protected repair policy (block-policy.ts) ──
|
|
2293
2293
|
// One classifier per physical stream, built from that stream's geometry.
|
|
2294
2294
|
this.#classifiers = /* @__PURE__ */ new Map();
|
|
2295
|
+
// A stream without catalog timing has no classifier, so the last RAP it
|
|
2296
|
+
// released stands in for one: "an MPU boundary bounds its RAPs" holds until
|
|
2297
|
+
// a second RAP is released inside one MPU (BLO-52085).
|
|
2298
|
+
this.#noSpanRaps = /* @__PURE__ */ new Map();
|
|
2295
2299
|
// Geometry a stream-scoped configuration gave one stream (streamKey). ABR
|
|
2296
2300
|
// rungs can share a packetId with a different framerate or GOP, so the
|
|
2297
2301
|
// packet-level geometry is only the geometry of a packet whose streams
|
|
@@ -2491,6 +2495,7 @@ var FECManager = class _FECManager {
|
|
|
2491
2495
|
#orderedFrontiers;
|
|
2492
2496
|
#orderedPendingBlocks;
|
|
2493
2497
|
#classifiers;
|
|
2498
|
+
#noSpanRaps;
|
|
2494
2499
|
#streamGeometries;
|
|
2495
2500
|
#failedBlocks;
|
|
2496
2501
|
#resolvedBlockClasses;
|
|
@@ -3152,6 +3157,7 @@ var FECManager = class _FECManager {
|
|
|
3152
3157
|
};
|
|
3153
3158
|
const discontinuity = () => {
|
|
3154
3159
|
this.#classifiers.get(streamKey)?.noteSourceDiscontinuity();
|
|
3160
|
+
this.#noSpanRaps.delete(streamKey);
|
|
3155
3161
|
this.#highestSbn.set(streamKey, { sbn, atMs: now });
|
|
3156
3162
|
this.#sourceFrontiers.set(streamKey, { sbn, atMs: now });
|
|
3157
3163
|
if (psn === void 0) this.#sourceAnchors.delete(streamKey);
|
|
@@ -3564,6 +3570,9 @@ var FECManager = class _FECManager {
|
|
|
3564
3570
|
}
|
|
3565
3571
|
if (policyChanged) {
|
|
3566
3572
|
this.#bumpEpoch(packetId);
|
|
3573
|
+
for (const key of [...this.#noSpanRaps.keys()]) {
|
|
3574
|
+
if (this.#belongsToPacket(key, packetId)) this.#noSpanRaps.delete(key);
|
|
3575
|
+
}
|
|
3567
3576
|
for (const [key, classifier] of [...this.#classifiers]) {
|
|
3568
3577
|
if (!this.#belongsToPacket(key, packetId)) continue;
|
|
3569
3578
|
const stream = this.#parseStreamKey(key);
|
|
@@ -3799,6 +3808,7 @@ var FECManager = class _FECManager {
|
|
|
3799
3808
|
resetMap(this.#isoLocators);
|
|
3800
3809
|
resetMap(this.#sourceAnchors);
|
|
3801
3810
|
this.#classifiers.delete(this.#streamKey(packetId, catalogTrackName));
|
|
3811
|
+
this.#noSpanRaps.delete(this.#streamKey(packetId, catalogTrackName));
|
|
3802
3812
|
this.#bumpEpoch(packetId);
|
|
3803
3813
|
for (const [sbn, keys] of this.#blockKeysBySbn) {
|
|
3804
3814
|
for (const key of keys.keys()) {
|
|
@@ -3905,6 +3915,7 @@ var FECManager = class _FECManager {
|
|
|
3905
3915
|
dropMap(this.#isoLocators);
|
|
3906
3916
|
dropMap(this.#sourceAnchors);
|
|
3907
3917
|
dropMap(this.#classifiers);
|
|
3918
|
+
dropMap(this.#noSpanRaps);
|
|
3908
3919
|
dropMap(this.#streamGeometries);
|
|
3909
3920
|
dropSet(this.#pendingWorkerCleanups);
|
|
3910
3921
|
dropSet(this.#completedBlocks);
|
|
@@ -4535,11 +4546,14 @@ var FECManager = class _FECManager {
|
|
|
4535
4546
|
/**
|
|
4536
4547
|
* Whether an MPU boundary still bounds this stream's RAPs (see
|
|
4537
4548
|
* `BlockClassifier.mpuBoundsRaps`). Gap decisions drop MPU evidence once
|
|
4538
|
-
* it does not. A stream with no classifier yet has shown nothing against it
|
|
4549
|
+
* it does not. A stream with no classifier yet has shown nothing against it,
|
|
4550
|
+
* and neither has a stream without catalog timing until it releases two
|
|
4551
|
+
* RAPs inside one MPU.
|
|
4539
4552
|
*/
|
|
4540
4553
|
mpuBoundsRapsFor(packetId, catalogTrackName) {
|
|
4541
|
-
|
|
4542
|
-
return this.#
|
|
4554
|
+
const streamKey = this.#streamKey(packetId, catalogTrackName);
|
|
4555
|
+
if (!this.#hasCatalogTimingForPacket(packetId)) return this.#noSpanRaps.get(streamKey)?.inside !== true;
|
|
4556
|
+
return this.#classifiers.get(streamKey)?.mpuBoundsRaps ?? true;
|
|
4543
4557
|
}
|
|
4544
4558
|
/** A block's class now, or frozen at its resolution. */
|
|
4545
4559
|
blockClassFor(sbn, packetId, catalogTrackName) {
|
|
@@ -4565,7 +4579,14 @@ var FECManager = class _FECManager {
|
|
|
4565
4579
|
* invariant (consecutive MPUs exactly one keyframe interval apart).
|
|
4566
4580
|
*/
|
|
4567
4581
|
noteReleasedRap(packetId, catalogTrackName, mpu, presentationTime, mediaTimescale) {
|
|
4568
|
-
if (!this.#trackConfigs.has(packetId)
|
|
4582
|
+
if (!this.#trackConfigs.has(packetId)) return;
|
|
4583
|
+
if (!this.#hasCatalogTimingForPacket(packetId)) {
|
|
4584
|
+
const streamKey = this.#streamKey(packetId, catalogTrackName);
|
|
4585
|
+
const last = this.#noSpanRaps.get(streamKey);
|
|
4586
|
+
const inside = last?.inside === true || last?.mpu === mpu && last.presentationTime !== presentationTime;
|
|
4587
|
+
this.#noSpanRaps.set(streamKey, { mpu, presentationTime, inside });
|
|
4588
|
+
return;
|
|
4589
|
+
}
|
|
4569
4590
|
this.#applyClassifierChanges(
|
|
4570
4591
|
packetId,
|
|
4571
4592
|
catalogTrackName,
|
|
@@ -5580,6 +5601,7 @@ var FECManager = class _FECManager {
|
|
|
5580
5601
|
this.#blockAnchorsMs.clear();
|
|
5581
5602
|
this.#blockCatalogTrackNames.clear();
|
|
5582
5603
|
this.#classifiers.clear();
|
|
5604
|
+
this.#noSpanRaps.clear();
|
|
5583
5605
|
this.#streamGeometries.clear();
|
|
5584
5606
|
this.#failedBlocks.clear();
|
|
5585
5607
|
this.#resolvedBlockClasses.clear();
|
|
@@ -7057,11 +7079,11 @@ var MOQT_PUBLISHER_PRIORITY = Object.freeze({
|
|
|
7057
7079
|
var AMTGatewayManager = class {
|
|
7058
7080
|
subscriptions = /* @__PURE__ */ new Map();
|
|
7059
7081
|
messageHandler;
|
|
7082
|
+
messageListenerRegistered = false;
|
|
7060
7083
|
pendingPackets = /* @__PURE__ */ new Map();
|
|
7061
7084
|
constructor() {
|
|
7062
7085
|
this.messageHandler = (event) => {
|
|
7063
7086
|
const data = event.data;
|
|
7064
|
-
console.log(`[AMT] SW message received:`, data.type);
|
|
7065
7087
|
if (data.type === "UDP_PACKET") {
|
|
7066
7088
|
this.handlePacket(data);
|
|
7067
7089
|
} else if (data.type === "SOCKET_ERROR") {
|
|
@@ -7070,12 +7092,22 @@ var AMTGatewayManager = class {
|
|
|
7070
7092
|
console.log(`[AMT SW Debug] ${data.message}`);
|
|
7071
7093
|
}
|
|
7072
7094
|
};
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
console.warn("[AMT] Service worker not available");
|
|
7095
|
+
}
|
|
7096
|
+
ensureMessageListener() {
|
|
7097
|
+
if (this.messageListenerRegistered || typeof navigator === "undefined" || !navigator.serviceWorker || !this.messageHandler) {
|
|
7098
|
+
return;
|
|
7078
7099
|
}
|
|
7100
|
+
navigator.serviceWorker.addEventListener("message", this.messageHandler);
|
|
7101
|
+
this.messageListenerRegistered = true;
|
|
7102
|
+
console.log("[AMT] Registered service worker message handler");
|
|
7103
|
+
}
|
|
7104
|
+
removeMessageListener() {
|
|
7105
|
+
if (!this.messageListenerRegistered)
|
|
7106
|
+
return;
|
|
7107
|
+
if (this.messageHandler && typeof navigator !== "undefined" && navigator.serviceWorker) {
|
|
7108
|
+
navigator.serviceWorker.removeEventListener("message", this.messageHandler);
|
|
7109
|
+
}
|
|
7110
|
+
this.messageListenerRegistered = false;
|
|
7079
7111
|
}
|
|
7080
7112
|
/**
|
|
7081
7113
|
* Subscribe via AMT tunnel
|
|
@@ -7085,6 +7117,7 @@ var AMTGatewayManager = class {
|
|
|
7085
7117
|
if (config.protected) {
|
|
7086
7118
|
throw new Error("AMTGatewayManager refuses a protected join: it reports no per-datagram sender (multicast-02 7.2.7)");
|
|
7087
7119
|
}
|
|
7120
|
+
this.ensureMessageListener();
|
|
7088
7121
|
const keyStr = this.getKeyString(key);
|
|
7089
7122
|
if (this.subscriptions.has(keyStr)) {
|
|
7090
7123
|
console.log(`[AMT] Reusing existing subscription to ${keyStr}`);
|
|
@@ -7120,6 +7153,8 @@ var AMTGatewayManager = class {
|
|
|
7120
7153
|
this.subscriptions.delete(keyStr);
|
|
7121
7154
|
this.pendingPackets.delete(subscription.subscriptionId);
|
|
7122
7155
|
}
|
|
7156
|
+
if (this.subscriptions.size === 0)
|
|
7157
|
+
this.removeMessageListener();
|
|
7123
7158
|
throw new Error(`Failed to subscribe via AMT: ${error instanceof Error ? error.message : String(error)}`);
|
|
7124
7159
|
}
|
|
7125
7160
|
}
|
|
@@ -7141,6 +7176,8 @@ var AMTGatewayManager = class {
|
|
|
7141
7176
|
} finally {
|
|
7142
7177
|
this.subscriptions.delete(handle);
|
|
7143
7178
|
this.pendingPackets.delete(subscription.subscriptionId);
|
|
7179
|
+
if (this.subscriptions.size === 0)
|
|
7180
|
+
this.removeMessageListener();
|
|
7144
7181
|
}
|
|
7145
7182
|
}
|
|
7146
7183
|
/**
|
|
@@ -7157,10 +7194,8 @@ var AMTGatewayManager = class {
|
|
|
7157
7194
|
if (!subscriptionId)
|
|
7158
7195
|
return;
|
|
7159
7196
|
const subscription = this.subscriptions.get(subscriptionId);
|
|
7160
|
-
if (!subscription)
|
|
7161
|
-
console.warn(`[AMT] Received packet for unknown subscription: ${subscriptionId}`);
|
|
7197
|
+
if (!subscription)
|
|
7162
7198
|
return;
|
|
7163
|
-
}
|
|
7164
7199
|
if (!subscription.handshakeComplete) {
|
|
7165
7200
|
const queue = this.pendingPackets.get(subscriptionId);
|
|
7166
7201
|
const packetData2 = data;
|
|
@@ -7190,19 +7225,15 @@ var AMTGatewayManager = class {
|
|
|
7190
7225
|
if (!subscriptionId)
|
|
7191
7226
|
return;
|
|
7192
7227
|
const subscription = this.subscriptions.get(subscriptionId);
|
|
7193
|
-
if (!subscription)
|
|
7194
|
-
console.warn(`[AMT] Received error for unknown subscription: ${subscriptionId}`);
|
|
7228
|
+
if (!subscription)
|
|
7195
7229
|
return;
|
|
7196
|
-
}
|
|
7197
7230
|
subscription.config.onError(new Error(error || "Unknown error"));
|
|
7198
7231
|
}
|
|
7199
7232
|
/**
|
|
7200
7233
|
* Cleanup on destroy
|
|
7201
7234
|
*/
|
|
7202
7235
|
destroy() {
|
|
7203
|
-
|
|
7204
|
-
navigator.serviceWorker.removeEventListener("message", this.messageHandler);
|
|
7205
|
-
}
|
|
7236
|
+
this.removeMessageListener();
|
|
7206
7237
|
const handles = Array.from(this.subscriptions.keys());
|
|
7207
7238
|
for (const handle of handles) {
|
|
7208
7239
|
this.unsubscribe(handle).catch((err) => {
|
|
@@ -14622,6 +14653,10 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
14622
14653
|
}
|
|
14623
14654
|
this.#emitFrame(data, meta);
|
|
14624
14655
|
}
|
|
14656
|
+
/** Whether FT=1 metadata already names this sample, without claiming it. */
|
|
14657
|
+
hasAuthoredTimingFor(packetId, mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber, catalogTrackName) {
|
|
14658
|
+
return this.#timingResolver(this.#streamKey(packetId, catalogTrackName), packetId, false)?.sampleTiming(mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber) != null;
|
|
14659
|
+
}
|
|
14625
14660
|
/**
|
|
14626
14661
|
* Claim and return the authored timing for a recovered sample. Recovery does
|
|
14627
14662
|
* not pass through the ordinary `feed()` completion path, so it must retire
|
|
@@ -21145,6 +21180,16 @@ var MmtpRouter = class {
|
|
|
21145
21180
|
}
|
|
21146
21181
|
);
|
|
21147
21182
|
}
|
|
21183
|
+
result = {
|
|
21184
|
+
...result,
|
|
21185
|
+
symbols: result.symbols.filter((sym) => sym.fragmentType !== 2 || sym.fragment.fragmentationIndicator !== 1 || sym.fragment.movieFragmentSequenceNumber === void 0 || sym.fragment.sampleNumber === void 0 || this.#parser.hasAuthoredTimingFor(
|
|
21186
|
+
ownerPacketId,
|
|
21187
|
+
sym.fragment.mpuSequenceNumber,
|
|
21188
|
+
sym.fragment.movieFragmentSequenceNumber,
|
|
21189
|
+
sym.fragment.sampleNumber,
|
|
21190
|
+
catalogTrackName
|
|
21191
|
+
))
|
|
21192
|
+
};
|
|
21148
21193
|
const gated = this.#isFecTrack(ownerPacketId);
|
|
21149
21194
|
const assembler = this.#mseAssemblerFor(ownerPacketId, catalogTrackName);
|
|
21150
21195
|
if (assembler) {
|