@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
package/dist/browser-runtime.js
CHANGED
|
@@ -7988,8 +7988,8 @@ var MulticastSubscriptionPool = class {
|
|
|
7988
7988
|
record.claims--;
|
|
7989
7989
|
return this.acquire(gateway, config, consumer);
|
|
7990
7990
|
}
|
|
7991
|
-
const
|
|
7992
|
-
entry.consumers.set(
|
|
7991
|
+
const token2 = Symbol(key);
|
|
7992
|
+
entry.consumers.set(token2, consumer);
|
|
7993
7993
|
let released = false;
|
|
7994
7994
|
return {
|
|
7995
7995
|
key,
|
|
@@ -7997,7 +7997,7 @@ var MulticastSubscriptionPool = class {
|
|
|
7997
7997
|
if (released)
|
|
7998
7998
|
return;
|
|
7999
7999
|
released = true;
|
|
8000
|
-
entry.consumers.delete(
|
|
8000
|
+
entry.consumers.delete(token2);
|
|
8001
8001
|
record.claims--;
|
|
8002
8002
|
if (record.claims > 0)
|
|
8003
8003
|
return;
|
|
@@ -8749,11 +8749,11 @@ var MOQT_PUBLISHER_PRIORITY = Object.freeze({
|
|
|
8749
8749
|
var AMTGatewayManager = class {
|
|
8750
8750
|
subscriptions = /* @__PURE__ */ new Map();
|
|
8751
8751
|
messageHandler;
|
|
8752
|
+
messageListenerRegistered = false;
|
|
8752
8753
|
pendingPackets = /* @__PURE__ */ new Map();
|
|
8753
8754
|
constructor() {
|
|
8754
8755
|
this.messageHandler = (event) => {
|
|
8755
8756
|
const data = event.data;
|
|
8756
|
-
console.log(`[AMT] SW message received:`, data.type);
|
|
8757
8757
|
if (data.type === "UDP_PACKET") {
|
|
8758
8758
|
this.handlePacket(data);
|
|
8759
8759
|
} else if (data.type === "SOCKET_ERROR") {
|
|
@@ -8762,12 +8762,22 @@ var AMTGatewayManager = class {
|
|
|
8762
8762
|
console.log(`[AMT SW Debug] ${data.message}`);
|
|
8763
8763
|
}
|
|
8764
8764
|
};
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8765
|
+
}
|
|
8766
|
+
ensureMessageListener() {
|
|
8767
|
+
if (this.messageListenerRegistered || typeof navigator === "undefined" || !navigator.serviceWorker || !this.messageHandler) {
|
|
8768
|
+
return;
|
|
8769
|
+
}
|
|
8770
|
+
navigator.serviceWorker.addEventListener("message", this.messageHandler);
|
|
8771
|
+
this.messageListenerRegistered = true;
|
|
8772
|
+
console.log("[AMT] Registered service worker message handler");
|
|
8773
|
+
}
|
|
8774
|
+
removeMessageListener() {
|
|
8775
|
+
if (!this.messageListenerRegistered)
|
|
8776
|
+
return;
|
|
8777
|
+
if (this.messageHandler && typeof navigator !== "undefined" && navigator.serviceWorker) {
|
|
8778
|
+
navigator.serviceWorker.removeEventListener("message", this.messageHandler);
|
|
8770
8779
|
}
|
|
8780
|
+
this.messageListenerRegistered = false;
|
|
8771
8781
|
}
|
|
8772
8782
|
/**
|
|
8773
8783
|
* Subscribe via AMT tunnel
|
|
@@ -8777,6 +8787,7 @@ var AMTGatewayManager = class {
|
|
|
8777
8787
|
if (config.protected) {
|
|
8778
8788
|
throw new Error("AMTGatewayManager refuses a protected join: it reports no per-datagram sender (multicast-02 7.2.7)");
|
|
8779
8789
|
}
|
|
8790
|
+
this.ensureMessageListener();
|
|
8780
8791
|
const keyStr = this.getKeyString(key);
|
|
8781
8792
|
if (this.subscriptions.has(keyStr)) {
|
|
8782
8793
|
console.log(`[AMT] Reusing existing subscription to ${keyStr}`);
|
|
@@ -8812,6 +8823,8 @@ var AMTGatewayManager = class {
|
|
|
8812
8823
|
this.subscriptions.delete(keyStr);
|
|
8813
8824
|
this.pendingPackets.delete(subscription.subscriptionId);
|
|
8814
8825
|
}
|
|
8826
|
+
if (this.subscriptions.size === 0)
|
|
8827
|
+
this.removeMessageListener();
|
|
8815
8828
|
throw new Error(`Failed to subscribe via AMT: ${error instanceof Error ? error.message : String(error)}`);
|
|
8816
8829
|
}
|
|
8817
8830
|
}
|
|
@@ -8833,6 +8846,8 @@ var AMTGatewayManager = class {
|
|
|
8833
8846
|
} finally {
|
|
8834
8847
|
this.subscriptions.delete(handle);
|
|
8835
8848
|
this.pendingPackets.delete(subscription.subscriptionId);
|
|
8849
|
+
if (this.subscriptions.size === 0)
|
|
8850
|
+
this.removeMessageListener();
|
|
8836
8851
|
}
|
|
8837
8852
|
}
|
|
8838
8853
|
/**
|
|
@@ -8849,10 +8864,8 @@ var AMTGatewayManager = class {
|
|
|
8849
8864
|
if (!subscriptionId)
|
|
8850
8865
|
return;
|
|
8851
8866
|
const subscription = this.subscriptions.get(subscriptionId);
|
|
8852
|
-
if (!subscription)
|
|
8853
|
-
console.warn(`[AMT] Received packet for unknown subscription: ${subscriptionId}`);
|
|
8867
|
+
if (!subscription)
|
|
8854
8868
|
return;
|
|
8855
|
-
}
|
|
8856
8869
|
if (!subscription.handshakeComplete) {
|
|
8857
8870
|
const queue = this.pendingPackets.get(subscriptionId);
|
|
8858
8871
|
const packetData2 = data;
|
|
@@ -8882,19 +8895,15 @@ var AMTGatewayManager = class {
|
|
|
8882
8895
|
if (!subscriptionId)
|
|
8883
8896
|
return;
|
|
8884
8897
|
const subscription = this.subscriptions.get(subscriptionId);
|
|
8885
|
-
if (!subscription)
|
|
8886
|
-
console.warn(`[AMT] Received error for unknown subscription: ${subscriptionId}`);
|
|
8898
|
+
if (!subscription)
|
|
8887
8899
|
return;
|
|
8888
|
-
}
|
|
8889
8900
|
subscription.config.onError(new Error(error || "Unknown error"));
|
|
8890
8901
|
}
|
|
8891
8902
|
/**
|
|
8892
8903
|
* Cleanup on destroy
|
|
8893
8904
|
*/
|
|
8894
8905
|
destroy() {
|
|
8895
|
-
|
|
8896
|
-
navigator.serviceWorker.removeEventListener("message", this.messageHandler);
|
|
8897
|
-
}
|
|
8906
|
+
this.removeMessageListener();
|
|
8898
8907
|
const handles = Array.from(this.subscriptions.keys());
|
|
8899
8908
|
for (const handle of handles) {
|
|
8900
8909
|
this.unsubscribe(handle).catch((err) => {
|
|
@@ -14052,6 +14061,10 @@ var FECManager = class _FECManager {
|
|
|
14052
14061
|
// ── Keyframe-protected repair policy (block-policy.ts) ──
|
|
14053
14062
|
// One classifier per physical stream, built from that stream's geometry.
|
|
14054
14063
|
this.#classifiers = /* @__PURE__ */ new Map();
|
|
14064
|
+
// A stream without catalog timing has no classifier, so the last RAP it
|
|
14065
|
+
// released stands in for one: "an MPU boundary bounds its RAPs" holds until
|
|
14066
|
+
// a second RAP is released inside one MPU (BLO-52085).
|
|
14067
|
+
this.#noSpanRaps = /* @__PURE__ */ new Map();
|
|
14055
14068
|
// Geometry a stream-scoped configuration gave one stream (streamKey). ABR
|
|
14056
14069
|
// rungs can share a packetId with a different framerate or GOP, so the
|
|
14057
14070
|
// packet-level geometry is only the geometry of a packet whose streams
|
|
@@ -14251,6 +14264,7 @@ var FECManager = class _FECManager {
|
|
|
14251
14264
|
#orderedFrontiers;
|
|
14252
14265
|
#orderedPendingBlocks;
|
|
14253
14266
|
#classifiers;
|
|
14267
|
+
#noSpanRaps;
|
|
14254
14268
|
#streamGeometries;
|
|
14255
14269
|
#failedBlocks;
|
|
14256
14270
|
#resolvedBlockClasses;
|
|
@@ -14912,6 +14926,7 @@ var FECManager = class _FECManager {
|
|
|
14912
14926
|
};
|
|
14913
14927
|
const discontinuity = () => {
|
|
14914
14928
|
this.#classifiers.get(streamKey)?.noteSourceDiscontinuity();
|
|
14929
|
+
this.#noSpanRaps.delete(streamKey);
|
|
14915
14930
|
this.#highestSbn.set(streamKey, { sbn, atMs: now });
|
|
14916
14931
|
this.#sourceFrontiers.set(streamKey, { sbn, atMs: now });
|
|
14917
14932
|
if (psn === void 0) this.#sourceAnchors.delete(streamKey);
|
|
@@ -15324,6 +15339,9 @@ var FECManager = class _FECManager {
|
|
|
15324
15339
|
}
|
|
15325
15340
|
if (policyChanged) {
|
|
15326
15341
|
this.#bumpEpoch(packetId);
|
|
15342
|
+
for (const key of [...this.#noSpanRaps.keys()]) {
|
|
15343
|
+
if (this.#belongsToPacket(key, packetId)) this.#noSpanRaps.delete(key);
|
|
15344
|
+
}
|
|
15327
15345
|
for (const [key, classifier] of [...this.#classifiers]) {
|
|
15328
15346
|
if (!this.#belongsToPacket(key, packetId)) continue;
|
|
15329
15347
|
const stream = this.#parseStreamKey(key);
|
|
@@ -15559,6 +15577,7 @@ var FECManager = class _FECManager {
|
|
|
15559
15577
|
resetMap(this.#isoLocators);
|
|
15560
15578
|
resetMap(this.#sourceAnchors);
|
|
15561
15579
|
this.#classifiers.delete(this.#streamKey(packetId, catalogTrackName));
|
|
15580
|
+
this.#noSpanRaps.delete(this.#streamKey(packetId, catalogTrackName));
|
|
15562
15581
|
this.#bumpEpoch(packetId);
|
|
15563
15582
|
for (const [sbn, keys] of this.#blockKeysBySbn) {
|
|
15564
15583
|
for (const key of keys.keys()) {
|
|
@@ -15665,6 +15684,7 @@ var FECManager = class _FECManager {
|
|
|
15665
15684
|
dropMap(this.#isoLocators);
|
|
15666
15685
|
dropMap(this.#sourceAnchors);
|
|
15667
15686
|
dropMap(this.#classifiers);
|
|
15687
|
+
dropMap(this.#noSpanRaps);
|
|
15668
15688
|
dropMap(this.#streamGeometries);
|
|
15669
15689
|
dropSet(this.#pendingWorkerCleanups);
|
|
15670
15690
|
dropSet(this.#completedBlocks);
|
|
@@ -16295,11 +16315,14 @@ var FECManager = class _FECManager {
|
|
|
16295
16315
|
/**
|
|
16296
16316
|
* Whether an MPU boundary still bounds this stream's RAPs (see
|
|
16297
16317
|
* `BlockClassifier.mpuBoundsRaps`). Gap decisions drop MPU evidence once
|
|
16298
|
-
* it does not. A stream with no classifier yet has shown nothing against it
|
|
16318
|
+
* it does not. A stream with no classifier yet has shown nothing against it,
|
|
16319
|
+
* and neither has a stream without catalog timing until it releases two
|
|
16320
|
+
* RAPs inside one MPU.
|
|
16299
16321
|
*/
|
|
16300
16322
|
mpuBoundsRapsFor(packetId, catalogTrackName) {
|
|
16301
|
-
|
|
16302
|
-
return this.#
|
|
16323
|
+
const streamKey = this.#streamKey(packetId, catalogTrackName);
|
|
16324
|
+
if (!this.#hasCatalogTimingForPacket(packetId)) return this.#noSpanRaps.get(streamKey)?.inside !== true;
|
|
16325
|
+
return this.#classifiers.get(streamKey)?.mpuBoundsRaps ?? true;
|
|
16303
16326
|
}
|
|
16304
16327
|
/** A block's class now, or frozen at its resolution. */
|
|
16305
16328
|
blockClassFor(sbn, packetId, catalogTrackName) {
|
|
@@ -16325,7 +16348,14 @@ var FECManager = class _FECManager {
|
|
|
16325
16348
|
* invariant (consecutive MPUs exactly one keyframe interval apart).
|
|
16326
16349
|
*/
|
|
16327
16350
|
noteReleasedRap(packetId, catalogTrackName, mpu, presentationTime, mediaTimescale) {
|
|
16328
|
-
if (!this.#trackConfigs.has(packetId)
|
|
16351
|
+
if (!this.#trackConfigs.has(packetId)) return;
|
|
16352
|
+
if (!this.#hasCatalogTimingForPacket(packetId)) {
|
|
16353
|
+
const streamKey = this.#streamKey(packetId, catalogTrackName);
|
|
16354
|
+
const last = this.#noSpanRaps.get(streamKey);
|
|
16355
|
+
const inside = last?.inside === true || last?.mpu === mpu && last.presentationTime !== presentationTime;
|
|
16356
|
+
this.#noSpanRaps.set(streamKey, { mpu, presentationTime, inside });
|
|
16357
|
+
return;
|
|
16358
|
+
}
|
|
16329
16359
|
this.#applyClassifierChanges(
|
|
16330
16360
|
packetId,
|
|
16331
16361
|
catalogTrackName,
|
|
@@ -17340,6 +17370,7 @@ var FECManager = class _FECManager {
|
|
|
17340
17370
|
this.#blockAnchorsMs.clear();
|
|
17341
17371
|
this.#blockCatalogTrackNames.clear();
|
|
17342
17372
|
this.#classifiers.clear();
|
|
17373
|
+
this.#noSpanRaps.clear();
|
|
17343
17374
|
this.#streamGeometries.clear();
|
|
17344
17375
|
this.#failedBlocks.clear();
|
|
17345
17376
|
this.#resolvedBlockClasses.clear();
|
|
@@ -18850,10 +18881,10 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
18850
18881
|
get reassemblerDataUnitsReturned() {
|
|
18851
18882
|
return this.#reassemblerDataUnitsReturned;
|
|
18852
18883
|
}
|
|
18853
|
-
#countOutcome(
|
|
18854
|
-
const count = (this.#feedOutcomes.get(
|
|
18855
|
-
this.#feedOutcomes.set(
|
|
18856
|
-
this.#lastOutcome =
|
|
18884
|
+
#countOutcome(token2) {
|
|
18885
|
+
const count = (this.#feedOutcomes.get(token2) ?? 0) + 1;
|
|
18886
|
+
this.#feedOutcomes.set(token2, count);
|
|
18887
|
+
this.#lastOutcome = token2;
|
|
18857
18888
|
this.#lastOutcomeCount = count;
|
|
18858
18889
|
}
|
|
18859
18890
|
#countDeferredOutcome(reason) {
|
|
@@ -19381,6 +19412,10 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
19381
19412
|
}
|
|
19382
19413
|
this.#emitFrame(data, meta);
|
|
19383
19414
|
}
|
|
19415
|
+
/** Whether FT=1 metadata already names this sample, without claiming it. */
|
|
19416
|
+
hasAuthoredTimingFor(packetId, mpuSequenceNumber2, movieFragmentSequenceNumber, sampleNumber, catalogTrackName) {
|
|
19417
|
+
return this.#timingResolver(this.#streamKey(packetId, catalogTrackName), packetId, false)?.sampleTiming(mpuSequenceNumber2, movieFragmentSequenceNumber, sampleNumber) != null;
|
|
19418
|
+
}
|
|
19384
19419
|
/**
|
|
19385
19420
|
* Claim and return the authored timing for a recovered sample. Recovery does
|
|
19386
19421
|
* not pass through the ordinary `feed()` completion path, so it must retire
|
|
@@ -25905,6 +25940,16 @@ var MmtpRouter = class {
|
|
|
25905
25940
|
}
|
|
25906
25941
|
);
|
|
25907
25942
|
}
|
|
25943
|
+
result = {
|
|
25944
|
+
...result,
|
|
25945
|
+
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(
|
|
25946
|
+
ownerPacketId,
|
|
25947
|
+
sym.fragment.mpuSequenceNumber,
|
|
25948
|
+
sym.fragment.movieFragmentSequenceNumber,
|
|
25949
|
+
sym.fragment.sampleNumber,
|
|
25950
|
+
catalogTrackName
|
|
25951
|
+
))
|
|
25952
|
+
};
|
|
25908
25953
|
const gated = this.#isFecTrack(ownerPacketId);
|
|
25909
25954
|
const assembler = this.#mseAssemblerFor(ownerPacketId, catalogTrackName);
|
|
25910
25955
|
if (assembler) {
|
|
@@ -29666,7 +29711,7 @@ async function setupFecWorkerForTrack(opts) {
|
|
|
29666
29711
|
blockProfile,
|
|
29667
29712
|
k: opts.fecK,
|
|
29668
29713
|
// P as this receiver joined it, not the catalog total: the worker snapshot
|
|
29669
|
-
// and CMCD `
|
|
29714
|
+
// and CMCD `com.blockcast-fp` are read from this. Identity on a single layer.
|
|
29670
29715
|
repairCount: opts.joinedRepairCount ?? opts.fecRepairCount,
|
|
29671
29716
|
symbolSize: opts.fecSymbolSize,
|
|
29672
29717
|
interleaveDepth: interleaveDepthBlocks,
|
|
@@ -30208,24 +30253,24 @@ var MediaRouter = class {
|
|
|
30208
30253
|
if (!this.#multicastVideoKeyed) return;
|
|
30209
30254
|
if (this.#requireAudio && !this.#multicastAudioReceived) return;
|
|
30210
30255
|
if (this.#requireAudio && !this.#moqAudioWarmed) return;
|
|
30211
|
-
const
|
|
30256
|
+
const token2 = ++this.#sourceSwitchToken;
|
|
30212
30257
|
const maybeReady = this.#onSourceSwitch?.("multicast");
|
|
30213
30258
|
if (!maybeReady || typeof maybeReady.then !== "function") {
|
|
30214
|
-
this.#commitMulticastActivation(
|
|
30259
|
+
this.#commitMulticastActivation(token2);
|
|
30215
30260
|
return;
|
|
30216
30261
|
}
|
|
30217
30262
|
const ready = Promise.resolve(maybeReady);
|
|
30218
|
-
this.#pendingMulticastToken =
|
|
30263
|
+
this.#pendingMulticastToken = token2;
|
|
30219
30264
|
this.#sourceSwitchReady = ready;
|
|
30220
30265
|
void ready.then(
|
|
30221
|
-
() => this.#commitMulticastActivation(
|
|
30222
|
-
(err) => this.#rejectMulticastActivation(
|
|
30266
|
+
() => this.#commitMulticastActivation(token2),
|
|
30267
|
+
(err) => this.#rejectMulticastActivation(token2, err)
|
|
30223
30268
|
).finally(() => {
|
|
30224
30269
|
if (this.#sourceSwitchReady === ready) this.#sourceSwitchReady = null;
|
|
30225
30270
|
});
|
|
30226
30271
|
}
|
|
30227
|
-
#commitMulticastActivation(
|
|
30228
|
-
if (
|
|
30272
|
+
#commitMulticastActivation(token2) {
|
|
30273
|
+
if (token2 !== this.#sourceSwitchToken) return;
|
|
30229
30274
|
this.#active = "multicast";
|
|
30230
30275
|
this.#suppressed = true;
|
|
30231
30276
|
this.#pendingMulticastToken = null;
|
|
@@ -30236,9 +30281,9 @@ var MediaRouter = class {
|
|
|
30236
30281
|
if (video) this.#onVideoFrame?.(video.data, video.meta);
|
|
30237
30282
|
if (audio) this.#onAudioFrame?.(audio.data, audio.meta);
|
|
30238
30283
|
}
|
|
30239
|
-
#rejectMulticastActivation(
|
|
30240
|
-
if (
|
|
30241
|
-
if (this.#pendingMulticastToken ===
|
|
30284
|
+
#rejectMulticastActivation(token2, err) {
|
|
30285
|
+
if (token2 !== this.#sourceSwitchToken) return;
|
|
30286
|
+
if (this.#pendingMulticastToken === token2) this.#pendingMulticastToken = null;
|
|
30242
30287
|
this.#pendingMulticastVideo = null;
|
|
30243
30288
|
this.#pendingMulticastAudio = null;
|
|
30244
30289
|
console.warn("[MediaRouter] onSourceSwitch(multicast) failed", err);
|
|
@@ -31207,63 +31252,65 @@ var FecStarvationDetector = class {
|
|
|
31207
31252
|
|
|
31208
31253
|
// src/cmcd-producer.ts
|
|
31209
31254
|
var PLAY_MODES = ["full", "base-only", "single-track"];
|
|
31210
|
-
|
|
31211
|
-
|
|
31212
|
-
|
|
31213
|
-
|
|
31214
|
-
|
|
31215
|
-
|
|
31216
|
-
|
|
31217
|
-
|
|
31218
|
-
|
|
31219
|
-
|
|
31220
|
-
|
|
31221
|
-
|
|
31222
|
-
|
|
31223
|
-
|
|
31224
|
-
|
|
31225
|
-
|
|
31226
|
-
|
|
31227
|
-
|
|
31228
|
-
}
|
|
31229
|
-
if (snap.multicastSource != null) {
|
|
31230
|
-
params["x-bc-multicast-source"] = snap.multicastSource;
|
|
31231
|
-
}
|
|
31232
|
-
if (snap.amtRelay != null) {
|
|
31233
|
-
params["x-bc-amt-relay"] = snap.amtRelay;
|
|
31234
|
-
}
|
|
31235
|
-
return params;
|
|
31236
|
-
}
|
|
31237
|
-
function formatQueryString(params) {
|
|
31238
|
-
return Object.keys(params).sort().map((key) => {
|
|
31239
|
-
const v = params[key];
|
|
31240
|
-
if (typeof v === "string") return `${key}=${sanitize(v)}`;
|
|
31241
|
-
return `${key}=${v}`;
|
|
31255
|
+
var DEFAULT_INTERVAL_MS = 3e4;
|
|
31256
|
+
var CUSTOM_PREFIX = "com.blockcast-";
|
|
31257
|
+
var MAX_CUSTOM_VALUE = 64;
|
|
31258
|
+
var TRANSPORT_TOKEN = {
|
|
31259
|
+
native: "ssm",
|
|
31260
|
+
amt: "amt",
|
|
31261
|
+
moq: "moq"
|
|
31262
|
+
};
|
|
31263
|
+
function sfString(value) {
|
|
31264
|
+
return `"${value.replace(/[^\x20-\x7e]/g, "").replace(/[\\"]/g, "\\$&")}"`;
|
|
31265
|
+
}
|
|
31266
|
+
function encodeCmcdRecord(record) {
|
|
31267
|
+
return Object.keys(record).sort().map((key) => {
|
|
31268
|
+
const value = record[key];
|
|
31269
|
+
if (typeof value === "number") return `${key}=${value}`;
|
|
31270
|
+
if (typeof value === "string") return `${key}=${sfString(value)}`;
|
|
31271
|
+
if (Array.isArray(value)) return `${key}=(${value.map(sfString).join(" ")})`;
|
|
31272
|
+
return `${key}=${value.token}`;
|
|
31242
31273
|
}).join(",");
|
|
31243
31274
|
}
|
|
31275
|
+
var token = (value) => ({ token: value });
|
|
31276
|
+
function putCustom(record, name, value) {
|
|
31277
|
+
if (value === void 0) return;
|
|
31278
|
+
if (typeof value === "number") value = String(value);
|
|
31279
|
+
if (typeof value === "string" && value.length > MAX_CUSTOM_VALUE) return;
|
|
31280
|
+
record[CUSTOM_PREFIX + name] = value;
|
|
31281
|
+
}
|
|
31244
31282
|
var CmcdProducer = class {
|
|
31245
|
-
#onCmcdParams;
|
|
31246
31283
|
#onCmcdPost;
|
|
31284
|
+
#intervalMs;
|
|
31285
|
+
#sessionId;
|
|
31286
|
+
#now;
|
|
31287
|
+
#sn = 0;
|
|
31288
|
+
#lastHeartbeat = null;
|
|
31247
31289
|
#transport;
|
|
31248
31290
|
#lastStats;
|
|
31249
|
-
// Phase 14 state — Plan 03 Task 2 (D-12, D-15).
|
|
31250
31291
|
#playMode = null;
|
|
31251
31292
|
#deltaFailRate = null;
|
|
31252
31293
|
#switchMiscount = 0;
|
|
31253
31294
|
#manifestStats = null;
|
|
31254
31295
|
#fecFailClosed = null;
|
|
31296
|
+
/** Video-block resolutions from the repair lifecycle; null until the player feeds one. */
|
|
31297
|
+
#lifecycle = null;
|
|
31255
31298
|
constructor(options) {
|
|
31256
|
-
this.#onCmcdParams = options.onCmcdParams;
|
|
31257
31299
|
this.#onCmcdPost = options.onCmcdPost;
|
|
31300
|
+
this.#intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
31301
|
+
if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {
|
|
31302
|
+
throw new Error(`[CmcdProducer] invalid intervalMs "${String(options.intervalMs)}"; expected a positive number`);
|
|
31303
|
+
}
|
|
31304
|
+
this.#sessionId = options.sessionId ?? globalThis.crypto.randomUUID();
|
|
31305
|
+
this.#now = options.now ?? Date.now;
|
|
31258
31306
|
}
|
|
31259
31307
|
/** Update the stored transport state. Called by player wiring layer. */
|
|
31260
31308
|
updateTransport(snapshot) {
|
|
31261
31309
|
this.#transport = snapshot;
|
|
31262
31310
|
}
|
|
31263
31311
|
/**
|
|
31264
|
-
* Set the current play-mode
|
|
31265
|
-
*
|
|
31266
|
-
* (CLAUDE.md: error on bad init).
|
|
31312
|
+
* Set the current play-mode, reported as `com.blockcast-pm`. Throws on any
|
|
31313
|
+
* value outside {'full','base-only','single-track'} (CLAUDE.md: error on bad init).
|
|
31267
31314
|
*/
|
|
31268
31315
|
updatePlayMode(mode) {
|
|
31269
31316
|
if (typeof mode !== "string" || !PLAY_MODES.includes(mode)) {
|
|
@@ -31274,9 +31321,8 @@ var CmcdProducer = class {
|
|
|
31274
31321
|
this.#playMode = mode;
|
|
31275
31322
|
}
|
|
31276
31323
|
/**
|
|
31277
|
-
* Set the delta-track FEC block-failure rate (0..1 inclusive)
|
|
31278
|
-
* `
|
|
31279
|
-
* Omitted on single-track streams.
|
|
31324
|
+
* Set the delta-track FEC block-failure rate (0..1 inclusive), reported as
|
|
31325
|
+
* `com.blockcast-dfr` when play-mode is 'full' or 'base-only'.
|
|
31280
31326
|
*/
|
|
31281
31327
|
updateDeltaFailRate(rate) {
|
|
31282
31328
|
if (typeof rate !== "number" || !Number.isFinite(rate) || rate < 0 || rate > 1) {
|
|
@@ -31286,112 +31332,139 @@ var CmcdProducer = class {
|
|
|
31286
31332
|
}
|
|
31287
31333
|
this.#deltaFailRate = rate;
|
|
31288
31334
|
}
|
|
31289
|
-
/**
|
|
31290
|
-
* Bump the cumulative switching-set misalignment counter. Emitted as
|
|
31291
|
-
* `x-bc-switch-miscount` on snapshots when the counter is > 0.
|
|
31292
|
-
*/
|
|
31335
|
+
/** Bump the cumulative switching-set misalignment counter (`com.blockcast-sm`). */
|
|
31293
31336
|
incrementSwitchMiscount() {
|
|
31294
31337
|
this.#switchMiscount += 1;
|
|
31295
31338
|
}
|
|
31296
31339
|
/**
|
|
31297
|
-
* Record that FEC failed closed at runtime (fec-01 6.3.9).
|
|
31298
|
-
*
|
|
31299
|
-
* `
|
|
31300
|
-
* stream playing without FEC is told apart from one
|
|
31340
|
+
* Record that FEC failed closed at runtime (fec-01 6.3.9). Reported at once
|
|
31341
|
+
* as `e=e` with the reason code in `ec`, and on every later counter report
|
|
31342
|
+
* as `com.blockcast-ffc` / `com.blockcast-ffl` (the held layer whose total
|
|
31343
|
+
* B_i was undercut), so a stream playing without FEC is told apart from one
|
|
31344
|
+
* with no loss.
|
|
31301
31345
|
*/
|
|
31302
31346
|
updateFecFailClosed(reason) {
|
|
31347
|
+
const changed = this.#fecFailClosed?.code !== reason.code || this.#fecFailClosed?.layer !== reason.layer;
|
|
31303
31348
|
this.#fecFailClosed = reason;
|
|
31349
|
+
if (changed) this.#post([{ ...this.#base("e"), ec: [reason.code] }]);
|
|
31304
31350
|
}
|
|
31305
31351
|
updateManifestVerification(stats) {
|
|
31306
31352
|
this.#manifestStats = stats;
|
|
31307
31353
|
}
|
|
31308
31354
|
/**
|
|
31309
|
-
*
|
|
31310
|
-
*
|
|
31311
|
-
*
|
|
31312
|
-
*
|
|
31355
|
+
* Count a video block's resolution from the repair lifecycle: recovered in
|
|
31356
|
+
* band (`com.blockcast-fbr`), recovered by repair FETCH (`-fbq`), or failed
|
|
31357
|
+
* as a keyframe-class block (`-fbfk`). Audio blocks are not counted, matching
|
|
31358
|
+
* the video-track `-fbf`. Until the player feeds this, the three are absent.
|
|
31313
31359
|
*/
|
|
31360
|
+
onRepairLifecycle(event) {
|
|
31361
|
+
this.#lifecycle ??= { inband: 0, fetch: 0, failedKeyframe: 0 };
|
|
31362
|
+
if (event.type === "recovered" && event.blockClass !== "audio") {
|
|
31363
|
+
if (event.via === "inband") this.#lifecycle.inband++;
|
|
31364
|
+
else this.#lifecycle.fetch++;
|
|
31365
|
+
} else if (event.type === "failed" && event.blockClass === "keyframe") {
|
|
31366
|
+
this.#lifecycle.failedKeyframe++;
|
|
31367
|
+
}
|
|
31368
|
+
}
|
|
31369
|
+
/** One-shot custom event `com.blockcast-switch-drift` for a single misalignment. */
|
|
31314
31370
|
emitSwitchDrift(driftUs) {
|
|
31315
31371
|
if (typeof driftUs !== "number" || !Number.isFinite(driftUs) || driftUs < 0) {
|
|
31316
31372
|
throw new Error(
|
|
31317
31373
|
`[CmcdProducer] invalid drift-us "${String(driftUs)}"; expected a non-negative finite number`
|
|
31318
31374
|
);
|
|
31319
31375
|
}
|
|
31320
|
-
const
|
|
31321
|
-
|
|
31322
|
-
|
|
31323
|
-
if (this.#switchMiscount > 0) params["x-bc-switch-miscount"] = this.#switchMiscount;
|
|
31324
|
-
params["x-bc-switch-drift-us"] = driftUs;
|
|
31325
|
-
this.#emit(params);
|
|
31376
|
+
const record = { ...this.#base("ce"), cen: CUSTOM_PREFIX + "switch-drift" };
|
|
31377
|
+
putCustom(record, "sdu", Math.round(driftUs));
|
|
31378
|
+
this.#post([record]);
|
|
31326
31379
|
}
|
|
31327
|
-
/**
|
|
31328
|
-
* Process a FecTrackStats snapshot. Finds the video track, builds
|
|
31329
|
-
* x-bc-* vendor keys, and fires both delivery callbacks.
|
|
31330
|
-
*/
|
|
31380
|
+
/** Take a FecTrackStats snapshot (first video track) and send the heartbeat when due. */
|
|
31331
31381
|
onSnapshot(data) {
|
|
31332
31382
|
const videoTrack = data.tracks.find((t) => t.config.trackType === "video");
|
|
31333
31383
|
if (!videoTrack) return;
|
|
31334
31384
|
this.#lastStats = videoTrack;
|
|
31335
|
-
|
|
31336
|
-
...buildFecParams(videoTrack),
|
|
31337
|
-
...buildTransportParams(this.#transport)
|
|
31338
|
-
};
|
|
31339
|
-
if (this.#playMode !== null) {
|
|
31340
|
-
params["x-bc-play-mode"] = this.#playMode;
|
|
31341
|
-
}
|
|
31342
|
-
if (this.#fecFailClosed) {
|
|
31343
|
-
params["x-bc-fec-fail-closed"] = this.#fecFailClosed.code;
|
|
31344
|
-
params["x-bc-fec-fail-layer"] = this.#fecFailClosed.layer;
|
|
31345
|
-
}
|
|
31346
|
-
if (this.#playMode !== null && this.#playMode !== "single-track" && this.#deltaFailRate !== null) {
|
|
31347
|
-
params["x-bc-delta-fail-rate"] = parseFloat(this.#deltaFailRate.toFixed(4));
|
|
31348
|
-
}
|
|
31349
|
-
if (this.#switchMiscount > 0) {
|
|
31350
|
-
params["x-bc-switch-miscount"] = this.#switchMiscount;
|
|
31351
|
-
}
|
|
31352
|
-
if (this.#manifestStats) {
|
|
31353
|
-
params["x-bc-manifest-verified"] = this.#manifestStats.verified > 0;
|
|
31354
|
-
params["x-bc-manifest-failures"] = Object.values(this.#manifestStats.failures).reduce((total, count) => total + count, 0);
|
|
31355
|
-
}
|
|
31356
|
-
this.#emit(params);
|
|
31385
|
+
this.#heartbeat();
|
|
31357
31386
|
}
|
|
31358
31387
|
/**
|
|
31359
|
-
*
|
|
31360
|
-
*
|
|
31388
|
+
* Take transport state for receivers that do not own FEC stats, and send the
|
|
31389
|
+
* heartbeat when due.
|
|
31361
31390
|
*/
|
|
31362
31391
|
onTransportSnapshot(data) {
|
|
31363
31392
|
if (!Number.isFinite(data.timestampMs) || data.timestampMs < 0) {
|
|
31364
31393
|
throw new Error("[CmcdProducer] transport snapshot timestamp must be a non-negative finite number");
|
|
31365
31394
|
}
|
|
31366
31395
|
if (data.playMode !== void 0) this.updatePlayMode(data.playMode);
|
|
31367
|
-
if (data.switchMiscount !== void 0
|
|
31368
|
-
|
|
31396
|
+
if (data.switchMiscount !== void 0) {
|
|
31397
|
+
if (!Number.isSafeInteger(data.switchMiscount) || data.switchMiscount < 0) {
|
|
31398
|
+
throw new Error("[CmcdProducer] transport snapshot switch-miscount must be a non-negative safe integer");
|
|
31399
|
+
}
|
|
31400
|
+
this.#switchMiscount = data.switchMiscount;
|
|
31369
31401
|
}
|
|
31370
31402
|
this.#transport = data.transport;
|
|
31371
|
-
|
|
31372
|
-
if (this.#playMode !== null) params["x-bc-play-mode"] = this.#playMode;
|
|
31373
|
-
const switchMiscount = data.switchMiscount ?? this.#switchMiscount;
|
|
31374
|
-
if (switchMiscount > 0) params["x-bc-switch-miscount"] = switchMiscount;
|
|
31375
|
-
this.#emit(params);
|
|
31403
|
+
this.#heartbeat();
|
|
31376
31404
|
}
|
|
31377
|
-
/**
|
|
31378
|
-
* Signal a transport transition event. Fires an immediate out-of-band
|
|
31379
|
-
* emit with x-bc-ct set. The subsequent onSnapshot() will NOT include
|
|
31380
|
-
* x-bc-ct (one-shot).
|
|
31381
|
-
*/
|
|
31405
|
+
/** Report a transport transition at once, as custom event `com.blockcast-ct`. */
|
|
31382
31406
|
onTransition(event) {
|
|
31383
|
-
const
|
|
31384
|
-
|
|
31385
|
-
|
|
31407
|
+
const record = { ...this.#base("ce"), cen: CUSTOM_PREFIX + "ct" };
|
|
31408
|
+
putCustom(record, "ct", token(event));
|
|
31409
|
+
this.#putTransport(record);
|
|
31410
|
+
this.#post([record]);
|
|
31411
|
+
}
|
|
31412
|
+
#base(event) {
|
|
31413
|
+
return { e: token(event), sid: this.#sessionId, sn: this.#sn++, ts: Math.floor(this.#now()), v: 2 };
|
|
31414
|
+
}
|
|
31415
|
+
#heartbeat() {
|
|
31416
|
+
const now = this.#now();
|
|
31417
|
+
if (this.#lastHeartbeat !== null && now - this.#lastHeartbeat < this.#intervalMs) return;
|
|
31418
|
+
this.#lastHeartbeat = now;
|
|
31419
|
+
this.#post([this.#base("t"), this.#counters()]);
|
|
31420
|
+
}
|
|
31421
|
+
#putTransport(record) {
|
|
31422
|
+
const snap = this.#transport;
|
|
31423
|
+
if (!snap) return;
|
|
31424
|
+
putCustom(record, "tr", token(TRANSPORT_TOKEN[snap.transport]));
|
|
31425
|
+
if (snap.multicastGroup != null && snap.multicastSource != null) {
|
|
31426
|
+
putCustom(record, "sg", `${snap.multicastGroup}@${snap.multicastSource}`);
|
|
31427
|
+
}
|
|
31428
|
+
putCustom(record, "ar", snap.amtRelay);
|
|
31429
|
+
}
|
|
31430
|
+
/** The `e=ce` counter report. */
|
|
31431
|
+
#counters() {
|
|
31432
|
+
const record = { ...this.#base("ce"), cen: CUSTOM_PREFIX + "fec" };
|
|
31433
|
+
const stats = this.#lastStats;
|
|
31434
|
+
if (stats) {
|
|
31435
|
+
putCustom(record, "fa", stats.config.algorithm);
|
|
31436
|
+
putCustom(record, "fk", stats.config.k);
|
|
31437
|
+
putCustom(record, "fp", stats.config.repairCount);
|
|
31438
|
+
putCustom(record, "pr", stats.sourceSymbols);
|
|
31439
|
+
putCustom(record, "pl", stats.sourcePacketsMissing);
|
|
31440
|
+
putCustom(record, "pu", stats.sourcePacketsUnrecovered);
|
|
31441
|
+
putCustom(record, "fbf", stats.blocksFailed);
|
|
31442
|
+
}
|
|
31443
|
+
if (this.#lifecycle) {
|
|
31444
|
+
putCustom(record, "fbr", this.#lifecycle.inband);
|
|
31445
|
+
putCustom(record, "fbq", this.#lifecycle.fetch);
|
|
31446
|
+
putCustom(record, "fbfk", this.#lifecycle.failedKeyframe);
|
|
31447
|
+
}
|
|
31448
|
+
this.#putTransport(record);
|
|
31449
|
+
if (this.#playMode !== null) {
|
|
31450
|
+
putCustom(record, "pm", token(this.#playMode));
|
|
31451
|
+
if (this.#playMode !== "single-track" && this.#deltaFailRate !== null) {
|
|
31452
|
+
putCustom(record, "dfr", this.#deltaFailRate.toFixed(3));
|
|
31453
|
+
}
|
|
31454
|
+
}
|
|
31455
|
+
if (this.#fecFailClosed) {
|
|
31456
|
+
putCustom(record, "ffc", token(this.#fecFailClosed.code));
|
|
31457
|
+
putCustom(record, "ffl", this.#fecFailClosed.layer);
|
|
31386
31458
|
}
|
|
31387
|
-
|
|
31388
|
-
|
|
31389
|
-
|
|
31459
|
+
if (this.#switchMiscount > 0) putCustom(record, "sm", this.#switchMiscount);
|
|
31460
|
+
if (this.#manifestStats) {
|
|
31461
|
+
putCustom(record, "mv", this.#manifestStats.verified);
|
|
31462
|
+
putCustom(record, "mf", Object.values(this.#manifestStats.failures).reduce((a, b) => a + b, 0));
|
|
31463
|
+
}
|
|
31464
|
+
return record;
|
|
31390
31465
|
}
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
this.#onCmcdParams?.(params);
|
|
31394
|
-
this.#onCmcdPost?.(formatQueryString(params));
|
|
31466
|
+
#post(records) {
|
|
31467
|
+
this.#onCmcdPost?.(records.map(encodeCmcdRecord).join("\n"));
|
|
31395
31468
|
}
|
|
31396
31469
|
};
|
|
31397
31470
|
|
|
@@ -31487,6 +31560,19 @@ function resolveRepairLayers(catalog, source) {
|
|
|
31487
31560
|
totalBaseRepairSymbols: binding.totalBaseRepairSymbols
|
|
31488
31561
|
};
|
|
31489
31562
|
}
|
|
31563
|
+
function valueAt(catalog, pointer) {
|
|
31564
|
+
let node = catalog;
|
|
31565
|
+
for (const segment of pointer.split("/").slice(1)) {
|
|
31566
|
+
if (typeof node !== "object" || node === null) return void 0;
|
|
31567
|
+
node = node[segment.replace(/~1/g, "/").replace(/~0/g, "~")];
|
|
31568
|
+
}
|
|
31569
|
+
return node;
|
|
31570
|
+
}
|
|
31571
|
+
function catalogTrackDeliveryMode(catalog, source) {
|
|
31572
|
+
const binding = bindingOf(catalog, source);
|
|
31573
|
+
const entry = binding ? valueAt(catalog, binding.pointer) : void 0;
|
|
31574
|
+
return entry?.deliveryMode === "stream" ? "stream" : "datagram";
|
|
31575
|
+
}
|
|
31490
31576
|
function moqtPriority2(value) {
|
|
31491
31577
|
return Number.isSafeInteger(value) && value >= 0 && value <= 255 ? value : null;
|
|
31492
31578
|
}
|
|
@@ -31530,6 +31616,7 @@ function fecParams(catalog, track, fps, sampleRate) {
|
|
|
31530
31616
|
repairTrackName: base.repairTrack,
|
|
31531
31617
|
repairLayers: repair.baseLayers,
|
|
31532
31618
|
repairOverlays: repair.overlays,
|
|
31619
|
+
deliveryMode: catalogTrackDeliveryMode(catalog, track),
|
|
31533
31620
|
...mediaRate
|
|
31534
31621
|
};
|
|
31535
31622
|
}
|
|
@@ -32054,7 +32141,7 @@ var RepairLayerSubscriptions = class {
|
|
|
32054
32141
|
* or interleaved sequences read as loss.
|
|
32055
32142
|
*/
|
|
32056
32143
|
noteSourceSequence(seq) {
|
|
32057
|
-
if (this.#disposed || this.#
|
|
32144
|
+
if (this.#disposed || this.#delivery() === "stream") return;
|
|
32058
32145
|
seq >>>= 0;
|
|
32059
32146
|
if (this.#lastSeq === void 0) {
|
|
32060
32147
|
this.#lastSeq = seq;
|
|
@@ -32087,12 +32174,12 @@ var RepairLayerSubscriptions = class {
|
|
|
32087
32174
|
this.#expected = 0;
|
|
32088
32175
|
this.#lost = 0;
|
|
32089
32176
|
this.#wantFewer = 0;
|
|
32090
|
-
this.#layerCount = Math.min(this.#layerCount, this.#layers().length);
|
|
32177
|
+
this.#layerCount = this.#delivery() === "stream" ? 0 : Math.min(this.#layerCount, this.#layers().length);
|
|
32091
32178
|
this.#reconcile();
|
|
32092
32179
|
}
|
|
32093
32180
|
snapshot() {
|
|
32094
32181
|
return {
|
|
32095
|
-
delivery: this.#
|
|
32182
|
+
delivery: this.#delivery(),
|
|
32096
32183
|
layerCount: this.#layerCount,
|
|
32097
32184
|
subscribedTracks: [...this.#subs.keys()],
|
|
32098
32185
|
repairPackets: this.#repairPackets,
|
|
@@ -32106,6 +32193,9 @@ var RepairLayerSubscriptions = class {
|
|
|
32106
32193
|
this.#closeAll();
|
|
32107
32194
|
this.#disposed = true;
|
|
32108
32195
|
}
|
|
32196
|
+
#delivery() {
|
|
32197
|
+
return this.#source.deliveryMode === "stream" ? "stream" : "datagram";
|
|
32198
|
+
}
|
|
32109
32199
|
#layers() {
|
|
32110
32200
|
return this.#source.repairLayers ?? [];
|
|
32111
32201
|
}
|
|
@@ -32848,6 +32938,7 @@ export {
|
|
|
32848
32938
|
catalogGroupDurationMs,
|
|
32849
32939
|
catalogKeyframeCadenceMs,
|
|
32850
32940
|
catalogRepairTarget,
|
|
32941
|
+
catalogTrackDeliveryMode,
|
|
32851
32942
|
catalogTrackFecUnavailable,
|
|
32852
32943
|
classifyH264Keyframe,
|
|
32853
32944
|
classifyHevcKeyframe,
|
|
@@ -32868,6 +32959,7 @@ export {
|
|
|
32868
32959
|
detectH264Keyframe,
|
|
32869
32960
|
detectHevcKeyframe,
|
|
32870
32961
|
driftCheck,
|
|
32962
|
+
encodeCmcdRecord,
|
|
32871
32963
|
encodeDataSegment,
|
|
32872
32964
|
encodeFecSourceInfo,
|
|
32873
32965
|
encodeLocTimestamp,
|