@blockcast/mmt-container 0.1.0-main.dd5ce397d768 → 0.1.0-main.f2d8d03d6809
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/dist/browser-runtime.js +381 -235
- package/dist/browser-runtime.js.map +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +2 -2
- package/dist/iso-bmff-timing.d.ts +12 -6
- package/dist/iso-bmff-timing.d.ts.map +1 -1
- package/dist/iso-bmff-timing.js +40 -8
- package/dist/iso-bmff-timing.js.map +2 -2
- package/dist/mmtp-container-parser.d.ts +101 -0
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +332 -199
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +332 -199
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/mmtp-decode-pipeline.js +351 -218
- package/dist/mmtp-decode-pipeline.js.map +3 -3
- package/dist/mmtp-router.js +332 -199
- package/dist/mmtp-router.js.map +2 -2
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +362 -216
- package/dist/multicast-manager.js.map +2 -2
- package/dist/multicast-transport.d.ts.map +1 -1
- package/dist/multicast-transport.js +13 -2
- package/dist/multicast-transport.js.map +2 -2
- package/dist/no-modules.js +332 -199
- package/dist/no-modules.js.map +2 -2
- package/dist/wasm-mmtp-container-parser.js +332 -199
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/package.json +6 -6
- package/src/index.ts +3 -0
- package/src/iso-bmff-timing.ts +62 -7
- package/src/mmtp-container-parser.ts +284 -48
- package/src/multicast-manager.ts +33 -24
- package/src/multicast-transport.ts +19 -4
package/dist/browser-runtime.js
CHANGED
|
@@ -11577,7 +11577,7 @@ function sameTrack(a, b) {
|
|
|
11577
11577
|
function sameSample(a, b) {
|
|
11578
11578
|
return a.decodeTime === b.decodeTime && a.presentationTime === b.presentationTime && a.duration === b.duration && a.timescale === b.timescale && a.size === b.size && a.bytePosition === b.bytePosition;
|
|
11579
11579
|
}
|
|
11580
|
-
var _track, _fragments, _pendingSamples, _lastMovieFragmentRejection, _IsoBmffTimingResolver_instances, clearSlot_fn;
|
|
11580
|
+
var _track, _fragments, _pendingSamples, _evictedSamples, _lastMovieFragmentRejection, _IsoBmffTimingResolver_instances, evictOldestFragment_fn, clearSlot_fn;
|
|
11581
11581
|
var IsoBmffTimingResolver = class {
|
|
11582
11582
|
constructor(maxPendingSamples) {
|
|
11583
11583
|
this.maxPendingSamples = maxPendingSamples;
|
|
@@ -11585,6 +11585,7 @@ var IsoBmffTimingResolver = class {
|
|
|
11585
11585
|
__privateAdd(this, _track, null);
|
|
11586
11586
|
__privateAdd(this, _fragments, /* @__PURE__ */ new Map());
|
|
11587
11587
|
__privateAdd(this, _pendingSamples, 0);
|
|
11588
|
+
__privateAdd(this, _evictedSamples, 0);
|
|
11588
11589
|
__privateAdd(this, _lastMovieFragmentRejection, null);
|
|
11589
11590
|
if (!Number.isInteger(maxPendingSamples) || maxPendingSamples <= 0) {
|
|
11590
11591
|
throw new Error("[IsoBmffTimingResolver] maxPendingSamples must be a positive integer");
|
|
@@ -11593,6 +11594,15 @@ var IsoBmffTimingResolver = class {
|
|
|
11593
11594
|
get pendingSampleCount() {
|
|
11594
11595
|
return __privateGet(this, _pendingSamples);
|
|
11595
11596
|
}
|
|
11597
|
+
/**
|
|
11598
|
+
* Slots reclaimed by window displacement rather than by delivery or
|
|
11599
|
+
* abandonment. Deliberately separate from the combiner's own release count:
|
|
11600
|
+
* "nobody ever saw this sample" and "the combiner gave up on it" are
|
|
11601
|
+
* different failures with different owners, and one number cannot say which.
|
|
11602
|
+
*/
|
|
11603
|
+
get evictedSampleCount() {
|
|
11604
|
+
return __privateGet(this, _evictedSamples);
|
|
11605
|
+
}
|
|
11596
11606
|
/** Typed reason for the most recent rejected movie fragment. */
|
|
11597
11607
|
get lastMovieFragmentRejection() {
|
|
11598
11608
|
return __privateGet(this, _lastMovieFragmentRejection);
|
|
@@ -11630,7 +11640,11 @@ var IsoBmffTimingResolver = class {
|
|
|
11630
11640
|
(sample, index) => sample !== null && sameSample(sample, parsed.samples[index])
|
|
11631
11641
|
);
|
|
11632
11642
|
}
|
|
11633
|
-
|
|
11643
|
+
let freed = 0;
|
|
11644
|
+
while (__privateGet(this, _fragments).size > 0 && (__privateGet(this, _pendingSamples) + parsed.samples.length > this.maxPendingSamples || parsed.samples.length - freed > additionalSampleLimit)) {
|
|
11645
|
+
freed += __privateMethod(this, _IsoBmffTimingResolver_instances, evictOldestFragment_fn).call(this);
|
|
11646
|
+
}
|
|
11647
|
+
if (parsed.samples.length - freed > additionalSampleLimit) {
|
|
11634
11648
|
__privateSet(this, _lastMovieFragmentRejection, "budget");
|
|
11635
11649
|
return false;
|
|
11636
11650
|
}
|
|
@@ -11663,12 +11677,11 @@ var IsoBmffTimingResolver = class {
|
|
|
11663
11677
|
* Free the budget slot of a sample that will never be delivered.
|
|
11664
11678
|
*
|
|
11665
11679
|
* `consumeSample` is the delivery path and is the only decrement on a
|
|
11666
|
-
* healthy stream.
|
|
11667
|
-
* delivered
|
|
11668
|
-
*
|
|
11669
|
-
*
|
|
11670
|
-
*
|
|
11671
|
-
* a full track reset clears it.
|
|
11680
|
+
* healthy stream. A sample whose data units never complete is never
|
|
11681
|
+
* delivered; window displacement in `addMovieFragment` eventually reclaims
|
|
11682
|
+
* it, but only after it has aged out of the whole window. This path frees
|
|
11683
|
+
* the slot as soon as the combiner knows the sample is gone, so the budget
|
|
11684
|
+
* tracks what is actually in flight rather than what has merely aged.
|
|
11672
11685
|
*
|
|
11673
11686
|
* The caller is whoever abandoned the sample, so the release is driven by
|
|
11674
11687
|
* the abandonment itself rather than by a timer, an LRU, or an age bound --
|
|
@@ -11692,8 +11705,27 @@ var IsoBmffTimingResolver = class {
|
|
|
11692
11705
|
_track = new WeakMap();
|
|
11693
11706
|
_fragments = new WeakMap();
|
|
11694
11707
|
_pendingSamples = new WeakMap();
|
|
11708
|
+
_evictedSamples = new WeakMap();
|
|
11695
11709
|
_lastMovieFragmentRejection = new WeakMap();
|
|
11696
11710
|
_IsoBmffTimingResolver_instances = new WeakSet();
|
|
11711
|
+
/**
|
|
11712
|
+
* Drop the oldest pending fragment whole and return the slots it held.
|
|
11713
|
+
*
|
|
11714
|
+
* Oldest is insertion order, which for a moof stream is arrival order, so
|
|
11715
|
+
* this is the least-recently-declared timing -- the entries least likely to
|
|
11716
|
+
* still have data units in flight.
|
|
11717
|
+
*/
|
|
11718
|
+
evictOldestFragment_fn = function() {
|
|
11719
|
+
const oldest = __privateGet(this, _fragments).keys().next().value;
|
|
11720
|
+
if (oldest === void 0) return 0;
|
|
11721
|
+
const samples = __privateGet(this, _fragments).get(oldest);
|
|
11722
|
+
let live = 0;
|
|
11723
|
+
for (const sample of samples) if (sample !== null) live++;
|
|
11724
|
+
__privateGet(this, _fragments).delete(oldest);
|
|
11725
|
+
__privateSet(this, _pendingSamples, __privateGet(this, _pendingSamples) - live);
|
|
11726
|
+
__privateSet(this, _evictedSamples, __privateGet(this, _evictedSamples) + live);
|
|
11727
|
+
return live;
|
|
11728
|
+
};
|
|
11697
11729
|
/** Null one slot, decrement the budget, and drop the fragment when empty. */
|
|
11698
11730
|
clearSlot_fn = function(mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber) {
|
|
11699
11731
|
if (!isU322(mpuSequenceNumber) || !isU322(movieFragmentSequenceNumber) || movieFragmentSequenceNumber === 0 || !isU322(sampleNumber) || sampleNumber === 0) {
|
|
@@ -11872,7 +11904,7 @@ function isFmp4Box(data) {
|
|
|
11872
11904
|
const type = String.fromCharCode(data[4], data[5], data[6], data[7]);
|
|
11873
11905
|
return FMPU_BOX_TYPES.has(type);
|
|
11874
11906
|
}
|
|
11875
|
-
var _tracks, _defaultTrack, _reassembler, _sampleCombiners, _sampleCombinerOptions, _retiredSampleCombinerStats, _timingStreams, _maxPendingTimingSamples, _pendingTimingSamples, _reclaimedTimingSamples, _rejectedMovieFragments, _sequencers, _reorderWindow, _reassemblyPolicy, _frameCb, _initCb, _sourceSymbolCb, _trackFrameCbs, _reorderStats, _reliableMoqStartupGate, _disposed2, _MmtpContainerParser_instances, streamKey_fn2, sampleCombinerFor_fn, releaseTimingSlot_fn, dropSampleCombiner_fn, emitCombinedSample_fn, passReliableMoqStartupGate_fn, timingResolver_fn, dropTimingStream_fn, validateReassemblyPolicy_fn, buildFrameMeta_fn, sequencerFor_fn, flushSequencers_fn, emitFrame_fn2, _MmtpContainerParser_static, scanForKeyframe_fn, scanLengthPrefixedHevcForKeyframe_fn, scanAnnexBForKeyframe_fn;
|
|
11907
|
+
var _tracks, _defaultTrack, _reassembler, _sampleCombiners, _sampleCombinerOptions, _retiredSampleCombinerStats, _timingStreams, _maxPendingTimingSamples, _pendingTimingSamples, _reclaimedTimingSamples, _evictedTimingSamples, _rejectedMovieFragments, _sequencers, _reorderWindow, _reassemblyPolicy, _frameCb, _initCb, _sourceSymbolCb, _trackFrameCbs, _reorderStats, _reliableMoqStartupGate, _disposed2, _fedObjects, _feedOutcomes, _deferredFeedOutcomes, _lastOutcome, _lastOutcomeCount, _MmtpContainerParser_instances, streamKey_fn2, sampleCombinerFor_fn, releaseTimingSlot_fn, dropSampleCombiner_fn, countOutcome_fn, countDeferredOutcome_fn, drop_fn, feed_fn, emitCombinedSample_fn, passReliableMoqStartupGate_fn, timingResolver_fn, dropTimingStream_fn, validateReassemblyPolicy_fn, buildFrameMeta_fn, sequencerFor_fn, flushSequencers_fn, emitFrame_fn2, _MmtpContainerParser_static, scanForKeyframe_fn, scanLengthPrefixedHevcForKeyframe_fn, scanAnnexBForKeyframe_fn;
|
|
11876
11908
|
var _MmtpContainerParser = class _MmtpContainerParser {
|
|
11877
11909
|
constructor(config) {
|
|
11878
11910
|
__privateAdd(this, _MmtpContainerParser_instances);
|
|
@@ -11906,6 +11938,7 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
11906
11938
|
__privateAdd(this, _maxPendingTimingSamples);
|
|
11907
11939
|
__privateAdd(this, _pendingTimingSamples, 0);
|
|
11908
11940
|
__privateAdd(this, _reclaimedTimingSamples, 0);
|
|
11941
|
+
__privateAdd(this, _evictedTimingSamples, 0);
|
|
11909
11942
|
__privateAdd(this, _rejectedMovieFragments, 0);
|
|
11910
11943
|
__privateAdd(this, _sequencers, /* @__PURE__ */ new Map());
|
|
11911
11944
|
__privateAdd(this, _reorderWindow, 0);
|
|
@@ -11932,6 +11965,11 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
11932
11965
|
* reordering into the parser. */
|
|
11933
11966
|
__privateAdd(this, _reliableMoqStartupGate, /* @__PURE__ */ new Map());
|
|
11934
11967
|
__privateAdd(this, _disposed2, false);
|
|
11968
|
+
__privateAdd(this, _fedObjects, 0);
|
|
11969
|
+
__privateAdd(this, _feedOutcomes, /* @__PURE__ */ new Map());
|
|
11970
|
+
__privateAdd(this, _deferredFeedOutcomes, /* @__PURE__ */ new Map());
|
|
11971
|
+
__privateAdd(this, _lastOutcome, null);
|
|
11972
|
+
__privateAdd(this, _lastOutcomeCount, 0);
|
|
11935
11973
|
/** Authored presentation timestamp of the last emitted frame, in microseconds. */
|
|
11936
11974
|
this.lastFrameTimestamp = void 0;
|
|
11937
11975
|
if (config?.reassemblyPolicy && config.mfuTimeoutMs !== void 0) {
|
|
@@ -12034,6 +12072,7 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12034
12072
|
pending: __privateGet(this, _pendingTimingSamples),
|
|
12035
12073
|
capacity: __privateGet(this, _maxPendingTimingSamples),
|
|
12036
12074
|
reclaimed: __privateGet(this, _reclaimedTimingSamples),
|
|
12075
|
+
evicted: __privateGet(this, _evictedTimingSamples),
|
|
12037
12076
|
rejectedMovieFragments: __privateGet(this, _rejectedMovieFragments)
|
|
12038
12077
|
};
|
|
12039
12078
|
}
|
|
@@ -12042,6 +12081,36 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12042
12081
|
for (const { sequencer } of __privateGet(this, _sequencers).values()) bufferedFrames += sequencer.buffered;
|
|
12043
12082
|
return { ...__privateGet(this, _reorderStats), bufferedFrames };
|
|
12044
12083
|
}
|
|
12084
|
+
/**
|
|
12085
|
+
* Feed tallies for this parser. A fresh snapshot per call, not a live view,
|
|
12086
|
+
* so a caller can hold one and compare it against a later read.
|
|
12087
|
+
*
|
|
12088
|
+
* Survives dispose() — the counters are the parser's own state and are not
|
|
12089
|
+
* cleared by teardown, because a wedged receive path is usually read after
|
|
12090
|
+
* the fact.
|
|
12091
|
+
*/
|
|
12092
|
+
get feedStats() {
|
|
12093
|
+
return {
|
|
12094
|
+
fedObjects: __privateGet(this, _fedObjects),
|
|
12095
|
+
outcomes: Object.fromEntries(__privateGet(this, _feedOutcomes)),
|
|
12096
|
+
deferredOutcomes: Object.fromEntries(__privateGet(this, _deferredFeedOutcomes))
|
|
12097
|
+
};
|
|
12098
|
+
}
|
|
12099
|
+
/**
|
|
12100
|
+
* Outcome token of the most recent feed(), or null before the first call.
|
|
12101
|
+
*
|
|
12102
|
+
* Exposed alongside `lastFeedOutcomeCount` as two scalars rather than one
|
|
12103
|
+
* object because a wrapper reads them on every packet, and feedStats()
|
|
12104
|
+
* allocates a fresh snapshot per call.
|
|
12105
|
+
*/
|
|
12106
|
+
get lastFeedOutcome() {
|
|
12107
|
+
return __privateGet(this, _lastOutcome);
|
|
12108
|
+
}
|
|
12109
|
+
/** How many times `lastFeedOutcome` has now been seen. 1 on its first
|
|
12110
|
+
* occurrence, which is what a caller logging once per novel outcome needs. */
|
|
12111
|
+
get lastFeedOutcomeCount() {
|
|
12112
|
+
return __privateGet(this, _lastOutcomeCount);
|
|
12113
|
+
}
|
|
12045
12114
|
get reorderDiagnostics() {
|
|
12046
12115
|
const streams = [];
|
|
12047
12116
|
for (const { packetId, sequencer } of __privateGet(this, _sequencers).values()) {
|
|
@@ -12091,181 +12160,16 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12091
12160
|
}
|
|
12092
12161
|
/** Feed a complete MMTP packet. For two-phase use, call parseHeader() first. */
|
|
12093
12162
|
feed(packet, options) {
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
this.cleanupTimeouts();
|
|
12097
|
-
const info = this.parseHeader(packet, options);
|
|
12098
|
-
if (!info) return null;
|
|
12099
|
-
if (info.packetType !== PACKET_TYPE_MPU2) {
|
|
12100
|
-
return {
|
|
12101
|
-
kind: info.isRepair ? "repair" : "non-media",
|
|
12102
|
-
packet: info,
|
|
12103
|
-
byteLength: packet.byteLength
|
|
12104
|
-
};
|
|
12105
|
-
}
|
|
12106
|
-
if (info.fecPayloadId !== null && __privateGet(this, _sourceSymbolCb)) {
|
|
12107
|
-
const rawSymbol = packet.subarray(0, packet.length - 4);
|
|
12108
|
-
const altaTrailer = extractAltaTrailer2(packet);
|
|
12109
|
-
const alta = altaTrailer ? { auth: altaTrailer.auth, payloadEnd: altaTrailer.signedEnd } : void 0;
|
|
12110
|
-
try {
|
|
12111
|
-
__privateGet(this, _sourceSymbolCb).call(this, info.packetId, info.fecPayloadId.ssId, rawSymbol, alta);
|
|
12112
|
-
} catch {
|
|
12113
|
-
}
|
|
12114
|
-
}
|
|
12115
|
-
const extraction = extractMFUPayload(packet, {
|
|
12116
|
-
skipFecId: options?.skipFecPayloadId
|
|
12117
|
-
});
|
|
12118
|
-
if (!extraction) return null;
|
|
12119
|
-
const { mpu, fragmentType, data, mfuDuHeader } = extraction;
|
|
12120
|
-
if (mpu.timedFlag !== 1) return null;
|
|
12121
|
-
const streamKey = __privateMethod(this, _MmtpContainerParser_instances, streamKey_fn2).call(this, info.packetId, options?.catalogTrackName);
|
|
12122
|
-
if (fragmentType === 0) {
|
|
12123
|
-
if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0) return null;
|
|
12124
|
-
const normalizedInit = normalizeMmtpInitSegment(data);
|
|
12125
|
-
if (!normalizedInit) return null;
|
|
12126
|
-
const resolver2 = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, true);
|
|
12127
|
-
if (!resolver2?.addInitialization(normalizedInit)) return null;
|
|
12128
|
-
(_a = __privateGet(this, _initCb)) == null ? void 0 : _a.call(this, normalizedInit, info.packetId, options?.catalogTrackName);
|
|
12129
|
-
return {
|
|
12130
|
-
kind: "init",
|
|
12131
|
-
packet: info,
|
|
12132
|
-
data: normalizedInit,
|
|
12133
|
-
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12134
|
-
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12135
|
-
fragmentCounter: mpu.fragmentCounter
|
|
12136
|
-
};
|
|
12137
|
-
}
|
|
12138
|
-
if (fragmentType === 1) {
|
|
12139
|
-
if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0) return null;
|
|
12140
|
-
const resolver2 = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, false);
|
|
12141
|
-
if (!resolver2) return null;
|
|
12142
|
-
const pendingBefore = resolver2.pendingSampleCount;
|
|
12143
|
-
const remaining = __privateGet(this, _maxPendingTimingSamples) - __privateGet(this, _pendingTimingSamples);
|
|
12144
|
-
if (!resolver2.addMovieFragment(mpu.mpuSequenceNumber, data, remaining)) {
|
|
12145
|
-
if (resolver2.lastMovieFragmentRejection === "budget") {
|
|
12146
|
-
__privateWrapper(this, _rejectedMovieFragments)._++;
|
|
12147
|
-
}
|
|
12148
|
-
return null;
|
|
12149
|
-
}
|
|
12150
|
-
__privateSet(this, _pendingTimingSamples, __privateGet(this, _pendingTimingSamples) + (resolver2.pendingSampleCount - pendingBefore));
|
|
12151
|
-
return {
|
|
12152
|
-
kind: "fragment",
|
|
12153
|
-
packet: info,
|
|
12154
|
-
data,
|
|
12155
|
-
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12156
|
-
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12157
|
-
fragmentCounter: mpu.fragmentCounter
|
|
12158
|
-
};
|
|
12159
|
-
}
|
|
12160
|
-
if (fragmentType !== 2) return null;
|
|
12161
|
-
const resolver = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, false);
|
|
12162
|
-
if (!resolver) return null;
|
|
12163
|
-
if (!Number.isSafeInteger(data.byteLength) || data.byteLength <= 0) return null;
|
|
12164
|
-
if (mpu.fragmentationIndicator === 0 || mpu.fragmentationIndicator === 1) {
|
|
12165
|
-
if (!mfuDuHeader || mfuDuHeader.movieFragmentSequenceNumber === 0 || mfuDuHeader.sampleNumber === 0) {
|
|
12166
|
-
return null;
|
|
12167
|
-
}
|
|
12168
|
-
const headTiming = resolver.sampleTiming(
|
|
12169
|
-
mpu.mpuSequenceNumber,
|
|
12170
|
-
mfuDuHeader.movieFragmentSequenceNumber,
|
|
12171
|
-
mfuDuHeader.sampleNumber
|
|
12172
|
-
);
|
|
12173
|
-
if (!headTiming) return null;
|
|
12174
|
-
const offset = mfuDuHeader.offset;
|
|
12175
|
-
if (!Number.isSafeInteger(offset) || offset < 0 || offset >= headTiming.size) return null;
|
|
12176
|
-
const remaining = headTiming.size - offset;
|
|
12177
|
-
if (mpu.fragmentationIndicator === 0 && data.byteLength !== remaining) return null;
|
|
12178
|
-
if (mpu.fragmentationIndicator === 1 && data.byteLength >= remaining) return null;
|
|
12179
|
-
const readyOnRegister = __privateMethod(this, _MmtpContainerParser_instances, sampleCombinerFor_fn).call(this, streamKey).registerAuthoredSize(
|
|
12180
|
-
options?.catalogTrackName,
|
|
12181
|
-
mpu.mpuSequenceNumber,
|
|
12182
|
-
mfuDuHeader.movieFragmentSequenceNumber,
|
|
12183
|
-
mfuDuHeader.sampleNumber,
|
|
12184
|
-
headTiming.size
|
|
12185
|
-
);
|
|
12186
|
-
if (readyOnRegister) {
|
|
12187
|
-
__privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, readyOnRegister, info, resolver, options?.recovered === true);
|
|
12188
|
-
}
|
|
12189
|
-
}
|
|
12190
|
-
let assembled;
|
|
12191
|
-
try {
|
|
12192
|
-
assembled = __privateGet(this, _reassembler).addFragment({
|
|
12193
|
-
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12194
|
-
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12195
|
-
fragmentCounter: mpu.fragmentCounter,
|
|
12196
|
-
data,
|
|
12197
|
-
timestamp: info.timestamp,
|
|
12198
|
-
rapFlag: info.rapFlag,
|
|
12199
|
-
priority: mfuDuHeader?.priority,
|
|
12200
|
-
sampleNumber: mfuDuHeader?.sampleNumber,
|
|
12201
|
-
movieFragmentSequenceNumber: mfuDuHeader?.movieFragmentSequenceNumber,
|
|
12202
|
-
sampleOffset: mfuDuHeader?.offset,
|
|
12203
|
-
packetSequenceNumber: info.sequenceNumber,
|
|
12204
|
-
recovered: options?.recovered === true,
|
|
12205
|
-
source: options?.source,
|
|
12206
|
-
deliveryProvenance: options?.deliveryProvenance,
|
|
12207
|
-
catalogTrackName: options?.catalogTrackName,
|
|
12208
|
-
packetId: info.packetId
|
|
12209
|
-
});
|
|
12210
|
-
} catch (error) {
|
|
12211
|
-
if (!isMfuReassemblyError(error)) throw error;
|
|
12212
|
-
console.warn(
|
|
12213
|
-
`[MmtpContainerParser] rejected MFU fragment: code=${error.code} mpu=${mpu.mpuSequenceNumber} fi=${mpu.fragmentationIndicator} counter=${mpu.fragmentCounter}`
|
|
12214
|
-
);
|
|
12215
|
-
return {
|
|
12216
|
-
kind: "rejected",
|
|
12217
|
-
packet: info,
|
|
12218
|
-
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12219
|
-
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12220
|
-
fragmentCounter: mpu.fragmentCounter,
|
|
12221
|
-
error: { code: error.code, message: error.message }
|
|
12222
|
-
};
|
|
12223
|
-
}
|
|
12224
|
-
if (!assembled) {
|
|
12225
|
-
return {
|
|
12226
|
-
kind: "pending",
|
|
12227
|
-
packet: info,
|
|
12228
|
-
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12229
|
-
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12230
|
-
fragmentCounter: mpu.fragmentCounter
|
|
12231
|
-
};
|
|
12232
|
-
}
|
|
12233
|
-
const movieFragmentSequenceNumber = assembled.movieFragmentSequenceNumber;
|
|
12234
|
-
const sampleNumber = assembled.sampleNumber;
|
|
12235
|
-
if (movieFragmentSequenceNumber === void 0 || sampleNumber === void 0) return null;
|
|
12236
|
-
if (!resolver.sampleTiming(
|
|
12237
|
-
assembled.mpuSequenceNumber,
|
|
12238
|
-
movieFragmentSequenceNumber,
|
|
12239
|
-
sampleNumber
|
|
12240
|
-
)) return null;
|
|
12241
|
-
if (assembled.mpuSequenceNumber !== mpu.mpuSequenceNumber) return null;
|
|
12242
|
-
let combined;
|
|
12163
|
+
__privateSet(this, _fedObjects, __privateGet(this, _fedObjects) + 1);
|
|
12164
|
+
let record;
|
|
12243
12165
|
try {
|
|
12244
|
-
|
|
12166
|
+
record = __privateMethod(this, _MmtpContainerParser_instances, feed_fn).call(this, packet, options);
|
|
12245
12167
|
} catch (error) {
|
|
12246
|
-
|
|
12247
|
-
|
|
12248
|
-
`[MmtpContainerParser] rejected subsample data unit: code=${error.code} mpu=${assembled.mpuSequenceNumber} sample=${sampleNumber} offset=${assembled.sampleOffset ?? 0}`
|
|
12249
|
-
);
|
|
12250
|
-
return {
|
|
12251
|
-
kind: "rejected",
|
|
12252
|
-
packet: info,
|
|
12253
|
-
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12254
|
-
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12255
|
-
fragmentCounter: mpu.fragmentCounter,
|
|
12256
|
-
error: { code: error.code, message: error.message }
|
|
12257
|
-
};
|
|
12258
|
-
}
|
|
12259
|
-
if (!combined) {
|
|
12260
|
-
return {
|
|
12261
|
-
kind: "pending",
|
|
12262
|
-
packet: info,
|
|
12263
|
-
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12264
|
-
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12265
|
-
fragmentCounter: mpu.fragmentCounter
|
|
12266
|
-
};
|
|
12168
|
+
__privateMethod(this, _MmtpContainerParser_instances, countOutcome_fn).call(this, "drop:threw");
|
|
12169
|
+
throw error;
|
|
12267
12170
|
}
|
|
12268
|
-
|
|
12171
|
+
if (record) __privateMethod(this, _MmtpContainerParser_instances, countOutcome_fn).call(this, record.kind);
|
|
12172
|
+
return record;
|
|
12269
12173
|
}
|
|
12270
12174
|
onInit(cb) {
|
|
12271
12175
|
__privateSet(this, _initCb, cb);
|
|
@@ -12433,6 +12337,7 @@ _timingStreams = new WeakMap();
|
|
|
12433
12337
|
_maxPendingTimingSamples = new WeakMap();
|
|
12434
12338
|
_pendingTimingSamples = new WeakMap();
|
|
12435
12339
|
_reclaimedTimingSamples = new WeakMap();
|
|
12340
|
+
_evictedTimingSamples = new WeakMap();
|
|
12436
12341
|
_rejectedMovieFragments = new WeakMap();
|
|
12437
12342
|
_sequencers = new WeakMap();
|
|
12438
12343
|
_reorderWindow = new WeakMap();
|
|
@@ -12444,6 +12349,11 @@ _trackFrameCbs = new WeakMap();
|
|
|
12444
12349
|
_reorderStats = new WeakMap();
|
|
12445
12350
|
_reliableMoqStartupGate = new WeakMap();
|
|
12446
12351
|
_disposed2 = new WeakMap();
|
|
12352
|
+
_fedObjects = new WeakMap();
|
|
12353
|
+
_feedOutcomes = new WeakMap();
|
|
12354
|
+
_deferredFeedOutcomes = new WeakMap();
|
|
12355
|
+
_lastOutcome = new WeakMap();
|
|
12356
|
+
_lastOutcomeCount = new WeakMap();
|
|
12447
12357
|
_MmtpContainerParser_instances = new WeakSet();
|
|
12448
12358
|
streamKey_fn2 = function(packetId, catalogTrackName) {
|
|
12449
12359
|
return JSON.stringify([packetId, catalogTrackName ?? null]);
|
|
@@ -12462,12 +12372,12 @@ sampleCombinerFor_fn = function(streamKey) {
|
|
|
12462
12372
|
/**
|
|
12463
12373
|
* Return the timing budget slot of a sample the combiner abandoned.
|
|
12464
12374
|
*
|
|
12465
|
-
* Without this, `#pendingTimingSamples` is
|
|
12466
|
-
*
|
|
12467
|
-
*
|
|
12468
|
-
*
|
|
12469
|
-
*
|
|
12470
|
-
*
|
|
12375
|
+
* Without this, `#pendingTimingSamples` is charged for every sample a moof
|
|
12376
|
+
* declares but credited only when that sample is delivered, so each sample
|
|
12377
|
+
* lost to eviction or timeout burns a slot until the window displaces it.
|
|
12378
|
+
* Window displacement bounds that leak but only reclaims the OLDEST entries;
|
|
12379
|
+
* this path returns a slot the moment the combiner knows the sample is gone,
|
|
12380
|
+
* which keeps the live window as wide as the stream actually needs.
|
|
12471
12381
|
*
|
|
12472
12382
|
* The parser total is decremented only when the resolver reports it
|
|
12473
12383
|
* actually freed a slot, so a resolver already dropped by a track reset, or
|
|
@@ -12499,11 +12409,232 @@ dropSampleCombiner_fn = function(streamKey) {
|
|
|
12499
12409
|
__privateGet(this, _retiredSampleCombinerStats).evictedSamples += stats.evictedSamples;
|
|
12500
12410
|
__privateGet(this, _sampleCombiners).delete(streamKey);
|
|
12501
12411
|
};
|
|
12412
|
+
countOutcome_fn = function(token) {
|
|
12413
|
+
const count = (__privateGet(this, _feedOutcomes).get(token) ?? 0) + 1;
|
|
12414
|
+
__privateGet(this, _feedOutcomes).set(token, count);
|
|
12415
|
+
__privateSet(this, _lastOutcome, token);
|
|
12416
|
+
__privateSet(this, _lastOutcomeCount, count);
|
|
12417
|
+
};
|
|
12418
|
+
countDeferredOutcome_fn = function(reason) {
|
|
12419
|
+
__privateGet(this, _deferredFeedOutcomes).set(
|
|
12420
|
+
reason,
|
|
12421
|
+
(__privateGet(this, _deferredFeedOutcomes).get(reason) ?? 0) + 1
|
|
12422
|
+
);
|
|
12423
|
+
};
|
|
12424
|
+
/**
|
|
12425
|
+
* Count a feed() drop and return null in one expression, so every early
|
|
12426
|
+
* return inside feed() states the reason it took instead of collapsing into
|
|
12427
|
+
* a single failure bucket. Returns null so call sites stay `return this.#drop(...)`.
|
|
12428
|
+
*/
|
|
12429
|
+
drop_fn = function(reason) {
|
|
12430
|
+
__privateMethod(this, _MmtpContainerParser_instances, countOutcome_fn).call(this, `drop:${reason}`);
|
|
12431
|
+
return null;
|
|
12432
|
+
};
|
|
12433
|
+
feed_fn = function(packet, options) {
|
|
12434
|
+
var _a;
|
|
12435
|
+
if (__privateGet(this, _disposed2)) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "disposed");
|
|
12436
|
+
this.cleanupTimeouts();
|
|
12437
|
+
const info = this.parseHeader(packet, options);
|
|
12438
|
+
if (!info) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "header-parse-failed");
|
|
12439
|
+
if (info.packetType !== PACKET_TYPE_MPU2) {
|
|
12440
|
+
return {
|
|
12441
|
+
kind: info.isRepair ? "repair" : "non-media",
|
|
12442
|
+
packet: info,
|
|
12443
|
+
byteLength: packet.byteLength
|
|
12444
|
+
};
|
|
12445
|
+
}
|
|
12446
|
+
if (info.fecPayloadId !== null && __privateGet(this, _sourceSymbolCb)) {
|
|
12447
|
+
const rawSymbol = packet.subarray(0, packet.length - 4);
|
|
12448
|
+
const altaTrailer = extractAltaTrailer2(packet);
|
|
12449
|
+
const alta = altaTrailer ? { auth: altaTrailer.auth, payloadEnd: altaTrailer.signedEnd } : void 0;
|
|
12450
|
+
try {
|
|
12451
|
+
__privateGet(this, _sourceSymbolCb).call(this, info.packetId, info.fecPayloadId.ssId, rawSymbol, alta);
|
|
12452
|
+
} catch {
|
|
12453
|
+
}
|
|
12454
|
+
}
|
|
12455
|
+
const extraction = extractMFUPayload(packet, {
|
|
12456
|
+
skipFecId: options?.skipFecPayloadId
|
|
12457
|
+
});
|
|
12458
|
+
if (!extraction) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-extract-failed");
|
|
12459
|
+
const { mpu, fragmentType, data, mfuDuHeader } = extraction;
|
|
12460
|
+
if (mpu.timedFlag !== 1) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "untimed-mpu");
|
|
12461
|
+
const streamKey = __privateMethod(this, _MmtpContainerParser_instances, streamKey_fn2).call(this, info.packetId, options?.catalogTrackName);
|
|
12462
|
+
if (fragmentType === 0) {
|
|
12463
|
+
if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0)
|
|
12464
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "init-unexpected-fragmentation");
|
|
12465
|
+
const normalizedInit = normalizeMmtpInitSegment(data);
|
|
12466
|
+
if (!normalizedInit) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "init-normalize-failed");
|
|
12467
|
+
const resolver2 = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, true);
|
|
12468
|
+
if (!resolver2?.addInitialization(normalizedInit)) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "init-timing-refused");
|
|
12469
|
+
(_a = __privateGet(this, _initCb)) == null ? void 0 : _a.call(this, normalizedInit, info.packetId, options?.catalogTrackName);
|
|
12470
|
+
return {
|
|
12471
|
+
kind: "init",
|
|
12472
|
+
packet: info,
|
|
12473
|
+
data: normalizedInit,
|
|
12474
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12475
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12476
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12477
|
+
};
|
|
12478
|
+
}
|
|
12479
|
+
if (fragmentType === 1) {
|
|
12480
|
+
if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0)
|
|
12481
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-unexpected-fragmentation");
|
|
12482
|
+
const resolver2 = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, false);
|
|
12483
|
+
if (!resolver2) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-no-resolver");
|
|
12484
|
+
const pendingBefore = resolver2.pendingSampleCount;
|
|
12485
|
+
const evictedBefore = resolver2.evictedSampleCount;
|
|
12486
|
+
const remaining = __privateGet(this, _maxPendingTimingSamples) - __privateGet(this, _pendingTimingSamples);
|
|
12487
|
+
const admitted = resolver2.addMovieFragment(mpu.mpuSequenceNumber, data, remaining);
|
|
12488
|
+
__privateSet(this, _pendingTimingSamples, __privateGet(this, _pendingTimingSamples) + (resolver2.pendingSampleCount - pendingBefore));
|
|
12489
|
+
__privateSet(this, _evictedTimingSamples, __privateGet(this, _evictedTimingSamples) + (resolver2.evictedSampleCount - evictedBefore));
|
|
12490
|
+
if (!admitted) {
|
|
12491
|
+
if (resolver2.lastMovieFragmentRejection === "budget") {
|
|
12492
|
+
__privateWrapper(this, _rejectedMovieFragments)._++;
|
|
12493
|
+
}
|
|
12494
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-timing-refused");
|
|
12495
|
+
}
|
|
12496
|
+
return {
|
|
12497
|
+
kind: "fragment",
|
|
12498
|
+
packet: info,
|
|
12499
|
+
data,
|
|
12500
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12501
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12502
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12503
|
+
};
|
|
12504
|
+
}
|
|
12505
|
+
if (fragmentType !== 2) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "unknown-fragment-type");
|
|
12506
|
+
const resolver = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, false);
|
|
12507
|
+
if (!resolver) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-no-resolver");
|
|
12508
|
+
if (!Number.isSafeInteger(data.byteLength) || data.byteLength <= 0)
|
|
12509
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-empty-payload");
|
|
12510
|
+
if (mpu.fragmentationIndicator === 0 || mpu.fragmentationIndicator === 1) {
|
|
12511
|
+
if (!mfuDuHeader || mfuDuHeader.movieFragmentSequenceNumber === 0 || mfuDuHeader.sampleNumber === 0) {
|
|
12512
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-du-header-missing");
|
|
12513
|
+
}
|
|
12514
|
+
const headTiming = resolver.sampleTiming(
|
|
12515
|
+
mpu.mpuSequenceNumber,
|
|
12516
|
+
mfuDuHeader.movieFragmentSequenceNumber,
|
|
12517
|
+
mfuDuHeader.sampleNumber
|
|
12518
|
+
);
|
|
12519
|
+
if (!headTiming) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-sample-timing-missing");
|
|
12520
|
+
const offset = mfuDuHeader.offset;
|
|
12521
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset >= headTiming.size)
|
|
12522
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-offset-out-of-range");
|
|
12523
|
+
const remaining = headTiming.size - offset;
|
|
12524
|
+
if (mpu.fragmentationIndicator === 0 && data.byteLength !== remaining)
|
|
12525
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-size-mismatch");
|
|
12526
|
+
if (mpu.fragmentationIndicator === 1 && data.byteLength >= remaining)
|
|
12527
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-size-mismatch");
|
|
12528
|
+
const readyOnRegister = __privateMethod(this, _MmtpContainerParser_instances, sampleCombinerFor_fn).call(this, streamKey).registerAuthoredSize(
|
|
12529
|
+
options?.catalogTrackName,
|
|
12530
|
+
mpu.mpuSequenceNumber,
|
|
12531
|
+
mfuDuHeader.movieFragmentSequenceNumber,
|
|
12532
|
+
mfuDuHeader.sampleNumber,
|
|
12533
|
+
headTiming.size
|
|
12534
|
+
);
|
|
12535
|
+
if (readyOnRegister) {
|
|
12536
|
+
const deferred = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, readyOnRegister, info, resolver, options?.recovered === true);
|
|
12537
|
+
if (deferred.record === void 0) __privateMethod(this, _MmtpContainerParser_instances, countDeferredOutcome_fn).call(this, deferred.reason);
|
|
12538
|
+
}
|
|
12539
|
+
}
|
|
12540
|
+
let assembled;
|
|
12541
|
+
try {
|
|
12542
|
+
assembled = __privateGet(this, _reassembler).addFragment({
|
|
12543
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12544
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12545
|
+
fragmentCounter: mpu.fragmentCounter,
|
|
12546
|
+
data,
|
|
12547
|
+
timestamp: info.timestamp,
|
|
12548
|
+
rapFlag: info.rapFlag,
|
|
12549
|
+
priority: mfuDuHeader?.priority,
|
|
12550
|
+
sampleNumber: mfuDuHeader?.sampleNumber,
|
|
12551
|
+
movieFragmentSequenceNumber: mfuDuHeader?.movieFragmentSequenceNumber,
|
|
12552
|
+
sampleOffset: mfuDuHeader?.offset,
|
|
12553
|
+
packetSequenceNumber: info.sequenceNumber,
|
|
12554
|
+
recovered: options?.recovered === true,
|
|
12555
|
+
source: options?.source,
|
|
12556
|
+
deliveryProvenance: options?.deliveryProvenance,
|
|
12557
|
+
catalogTrackName: options?.catalogTrackName,
|
|
12558
|
+
packetId: info.packetId
|
|
12559
|
+
});
|
|
12560
|
+
} catch (error) {
|
|
12561
|
+
if (!isMfuReassemblyError(error)) throw error;
|
|
12562
|
+
console.warn(
|
|
12563
|
+
`[MmtpContainerParser] rejected MFU fragment: code=${error.code} mpu=${mpu.mpuSequenceNumber} fi=${mpu.fragmentationIndicator} counter=${mpu.fragmentCounter}`
|
|
12564
|
+
);
|
|
12565
|
+
return {
|
|
12566
|
+
kind: "rejected",
|
|
12567
|
+
packet: info,
|
|
12568
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12569
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12570
|
+
fragmentCounter: mpu.fragmentCounter,
|
|
12571
|
+
error: { code: error.code, message: error.message }
|
|
12572
|
+
};
|
|
12573
|
+
}
|
|
12574
|
+
if (!assembled) {
|
|
12575
|
+
return {
|
|
12576
|
+
kind: "pending",
|
|
12577
|
+
packet: info,
|
|
12578
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12579
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12580
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12581
|
+
};
|
|
12582
|
+
}
|
|
12583
|
+
const movieFragmentSequenceNumber = assembled.movieFragmentSequenceNumber;
|
|
12584
|
+
const sampleNumber = assembled.sampleNumber;
|
|
12585
|
+
if (movieFragmentSequenceNumber === void 0 || sampleNumber === void 0)
|
|
12586
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "assembled-identity-missing");
|
|
12587
|
+
if (!resolver.sampleTiming(
|
|
12588
|
+
assembled.mpuSequenceNumber,
|
|
12589
|
+
movieFragmentSequenceNumber,
|
|
12590
|
+
sampleNumber
|
|
12591
|
+
)) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "assembled-timing-missing");
|
|
12592
|
+
if (assembled.mpuSequenceNumber !== mpu.mpuSequenceNumber)
|
|
12593
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "assembled-mpu-mismatch");
|
|
12594
|
+
let combined;
|
|
12595
|
+
try {
|
|
12596
|
+
combined = __privateMethod(this, _MmtpContainerParser_instances, sampleCombinerFor_fn).call(this, streamKey).addMfu(assembled);
|
|
12597
|
+
} catch (error) {
|
|
12598
|
+
if (!(error instanceof SampleCombineError)) throw error;
|
|
12599
|
+
console.warn(
|
|
12600
|
+
`[MmtpContainerParser] rejected subsample data unit: code=${error.code} mpu=${assembled.mpuSequenceNumber} sample=${sampleNumber} offset=${assembled.sampleOffset ?? 0}`
|
|
12601
|
+
);
|
|
12602
|
+
return {
|
|
12603
|
+
kind: "rejected",
|
|
12604
|
+
packet: info,
|
|
12605
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12606
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12607
|
+
fragmentCounter: mpu.fragmentCounter,
|
|
12608
|
+
error: { code: error.code, message: error.message }
|
|
12609
|
+
};
|
|
12610
|
+
}
|
|
12611
|
+
if (!combined) {
|
|
12612
|
+
return {
|
|
12613
|
+
kind: "pending",
|
|
12614
|
+
packet: info,
|
|
12615
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12616
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12617
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12618
|
+
};
|
|
12619
|
+
}
|
|
12620
|
+
const outcome = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, combined, info, resolver, options?.recovered === true);
|
|
12621
|
+
if (outcome.record !== void 0) return outcome.record;
|
|
12622
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, outcome.reason);
|
|
12623
|
+
};
|
|
12502
12624
|
/**
|
|
12503
12625
|
* Deliver one combined sample: resolve its authored timing, build frame
|
|
12504
12626
|
* metadata, retire the timing entry, and route it. Shared by the ordinary
|
|
12505
12627
|
* completion path and by the rarer completion that falls out of registering
|
|
12506
12628
|
* an authored size for data units that arrived before it.
|
|
12629
|
+
*
|
|
12630
|
+
* Reports a refusal as a reason rather than counting it, because the two
|
|
12631
|
+
* call sites owe different accounting. On `#feed()`'s tail return the
|
|
12632
|
+
* refusal *is* that feed()'s outcome and must be attributed; on the
|
|
12633
|
+
* register-completion path it belongs to an earlier sample while this
|
|
12634
|
+
* packet's own fragment continues to its own outcome, so counting it there
|
|
12635
|
+
* would push `outcomes` past `fedObjects` — the very invariant the
|
|
12636
|
+
* attribution exists to keep readable. Leaving the choice at the call site
|
|
12637
|
+
* is what keeps both true.
|
|
12507
12638
|
*/
|
|
12508
12639
|
emitCombinedSample_fn = function(combined, info, resolver, recovered) {
|
|
12509
12640
|
const timing = resolver.sampleTiming(
|
|
@@ -12511,27 +12642,29 @@ emitCombinedSample_fn = function(combined, info, resolver, recovered) {
|
|
|
12511
12642
|
combined.movieFragmentSequenceNumber,
|
|
12512
12643
|
combined.sampleNumber
|
|
12513
12644
|
);
|
|
12514
|
-
if (!timing) return
|
|
12515
|
-
if (combined.data.byteLength !== timing.size) return
|
|
12645
|
+
if (!timing) return { reason: "combined-timing-missing" };
|
|
12646
|
+
if (combined.data.byteLength !== timing.size) return { reason: "combined-size-mismatch" };
|
|
12516
12647
|
const meta = __privateMethod(this, _MmtpContainerParser_instances, buildFrameMeta_fn).call(this, combined, info.packetId, info.sequenceNumber, timing, recovered);
|
|
12517
|
-
if (!meta) return
|
|
12648
|
+
if (!meta) return { reason: "combined-meta-build-failed" };
|
|
12518
12649
|
if (!resolver.consumeSample(
|
|
12519
12650
|
combined.mpuSequenceNumber,
|
|
12520
12651
|
combined.movieFragmentSequenceNumber,
|
|
12521
12652
|
combined.sampleNumber,
|
|
12522
12653
|
timing
|
|
12523
|
-
)) return
|
|
12654
|
+
)) return { reason: "combined-timing-consume-refused" };
|
|
12524
12655
|
__privateWrapper(this, _pendingTimingSamples)._--;
|
|
12525
12656
|
this.routeFrame(combined.data, meta);
|
|
12526
12657
|
return {
|
|
12527
|
-
|
|
12528
|
-
|
|
12529
|
-
|
|
12530
|
-
|
|
12531
|
-
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12658
|
+
record: {
|
|
12659
|
+
kind: "frame",
|
|
12660
|
+
packet: info,
|
|
12661
|
+
data: combined.data,
|
|
12662
|
+
meta,
|
|
12663
|
+
mpuSequenceNumber: combined.mpuSequenceNumber,
|
|
12664
|
+
fragmentCount: combined.fragmentCount,
|
|
12665
|
+
rapFlag: combined.rapFlag,
|
|
12666
|
+
...combined.priority === void 0 ? {} : { priority: combined.priority }
|
|
12667
|
+
}
|
|
12535
12668
|
};
|
|
12536
12669
|
};
|
|
12537
12670
|
/** Order-independent reliable-moq startup gate: discard delta frames for a
|
|
@@ -16277,6 +16410,14 @@ function getMulticastGlobals() {
|
|
|
16277
16410
|
function hasMulticastGateway() {
|
|
16278
16411
|
return typeof getMulticastGlobals().multicast?.subscribe === "function";
|
|
16279
16412
|
}
|
|
16413
|
+
function normalizeBytesEventDetail(detail) {
|
|
16414
|
+
const value = detail && typeof detail === "object" && "data" in detail ? detail.data : detail;
|
|
16415
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
16416
|
+
if (ArrayBuffer.isView(value)) {
|
|
16417
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
16418
|
+
}
|
|
16419
|
+
return null;
|
|
16420
|
+
}
|
|
16280
16421
|
var _onPacket, _subscription2, _bytesListener, _resolvedTransport, _videoConfirmed, _audioConfirmed, _watchdog, _failbackWindowMs, _onTakeover, _onFailback, _disposed4, _stats3, _droppedPidCounts, _packetIds, _joinGeneration, _MulticastTransport_instances, releaseSubscription_fn, acceptPacket_fn, recordUnregisteredPidDrop_fn, checkTakeover_fn, resetWatchdog_fn;
|
|
16281
16422
|
var _MulticastTransport = class _MulticastTransport {
|
|
16282
16423
|
constructor(onPacket) {
|
|
@@ -16343,8 +16484,11 @@ var _MulticastTransport = class _MulticastTransport {
|
|
|
16343
16484
|
}
|
|
16344
16485
|
const onBytes = (event) => {
|
|
16345
16486
|
if (__privateGet(this, _disposed4) || generation !== __privateGet(this, _joinGeneration)) return;
|
|
16346
|
-
const
|
|
16347
|
-
|
|
16487
|
+
const packet = normalizeBytesEventDetail(event.detail);
|
|
16488
|
+
if (!packet) {
|
|
16489
|
+
__privateGet(this, _stats3).packetsDroppedUnparseable++;
|
|
16490
|
+
return;
|
|
16491
|
+
}
|
|
16348
16492
|
if (!__privateMethod(this, _MulticastTransport_instances, acceptPacket_fn).call(this, packet)) return;
|
|
16349
16493
|
__privateGet(this, _stats3).packetsReceived++;
|
|
16350
16494
|
__privateGet(this, _stats3).bytesReceived += packet.byteLength;
|
|
@@ -17101,34 +17245,35 @@ var MulticastManager = class {
|
|
|
17101
17245
|
* a factory returning a distinct decoder per stream.
|
|
17102
17246
|
*/
|
|
17103
17247
|
configureMultiTrack(catalog, wasmDecoderSource) {
|
|
17104
|
-
const
|
|
17248
|
+
const repairOwnerGroup = /* @__PURE__ */ new Map();
|
|
17249
|
+
const repairOwnerAltGroup = /* @__PURE__ */ new Map();
|
|
17250
|
+
for (const track of catalog.tracks) {
|
|
17251
|
+
if (track.fec !== void 0 && isFecCatalogConfig(track.fec) && track.fec.repairTrack) {
|
|
17252
|
+
repairOwnerGroup.set(track.fec.repairTrack, altGroupKey(track));
|
|
17253
|
+
repairOwnerAltGroup.set(track.fec.repairTrack, track.altGroup);
|
|
17254
|
+
}
|
|
17255
|
+
}
|
|
17256
|
+
const groupKeyFor = (track) => repairOwnerGroup.get(track.name) ?? altGroupKey(track);
|
|
17105
17257
|
const trackNamesByGroup = /* @__PURE__ */ new Map();
|
|
17106
17258
|
for (const track of catalog.tracks) {
|
|
17107
|
-
const groupKey =
|
|
17259
|
+
const groupKey = groupKeyFor(track);
|
|
17108
17260
|
const groupNames = trackNamesByGroup.get(groupKey) ?? [];
|
|
17109
17261
|
groupNames.push(track.name);
|
|
17110
17262
|
trackNamesByGroup.set(groupKey, groupNames);
|
|
17111
|
-
if (track.fec !== void 0 && isFecCatalogConfig(track.fec) && track.fec.repairTrack) {
|
|
17112
|
-
const explicitRepairNames = explicitRepairNamesByGroup.get(groupKey) ?? /* @__PURE__ */ new Set();
|
|
17113
|
-
explicitRepairNames.add(track.fec.repairTrack);
|
|
17114
|
-
explicitRepairNamesByGroup.set(groupKey, explicitRepairNames);
|
|
17115
|
-
}
|
|
17116
17263
|
}
|
|
17117
17264
|
const hasSwitchingSetByGroup = /* @__PURE__ */ new Map();
|
|
17118
17265
|
for (const [groupKey, trackNames] of trackNamesByGroup) {
|
|
17119
17266
|
hasSwitchingSetByGroup.set(groupKey, hasSwitchingSetRole(trackNames));
|
|
17120
17267
|
}
|
|
17121
17268
|
const resolvedRoles = catalog.tracks.map((track) => {
|
|
17122
|
-
|
|
17123
|
-
const hasSwitchingSet = hasSwitchingSetByGroup.get(
|
|
17124
|
-
const explicitRepairNames = explicitRepairNamesByGroup.get(groupKey);
|
|
17125
|
-
if (explicitRepairNames?.has(track.name)) return "repair";
|
|
17269
|
+
if (repairOwnerGroup.has(track.name)) return "repair";
|
|
17270
|
+
const hasSwitchingSet = hasSwitchingSetByGroup.get(altGroupKey(track)) ?? false;
|
|
17126
17271
|
if (!hasSwitchingSet) return "single";
|
|
17127
17272
|
return parseTrackRole(track.name);
|
|
17128
17273
|
});
|
|
17129
17274
|
const resolvedRolesByGroup = /* @__PURE__ */ new Map();
|
|
17130
17275
|
for (let i = 0; i < catalog.tracks.length; i++) {
|
|
17131
|
-
const groupKey =
|
|
17276
|
+
const groupKey = groupKeyFor(catalog.tracks[i]);
|
|
17132
17277
|
const roles = resolvedRolesByGroup.get(groupKey) ?? [];
|
|
17133
17278
|
roles.push(resolvedRoles[i]);
|
|
17134
17279
|
resolvedRolesByGroup.set(groupKey, roles);
|
|
@@ -17191,10 +17336,11 @@ var MulticastManager = class {
|
|
|
17191
17336
|
for (let i = 0; i < catalog.tracks.length; i++) {
|
|
17192
17337
|
const track = catalog.tracks[i];
|
|
17193
17338
|
const role = resolvedRoles[i];
|
|
17194
|
-
|
|
17195
|
-
|
|
17339
|
+
const altGroup = repairOwnerAltGroup.has(track.name) ? repairOwnerAltGroup.get(track.name) : track.altGroup;
|
|
17340
|
+
if (altGroup !== void 0) {
|
|
17341
|
+
const existing = __privateGet(this, _switchingSets).get(altGroup) ?? [];
|
|
17196
17342
|
existing.push(track.name);
|
|
17197
|
-
__privateGet(this, _switchingSets).set(
|
|
17343
|
+
__privateGet(this, _switchingSets).set(altGroup, existing);
|
|
17198
17344
|
}
|
|
17199
17345
|
if (track.packetId !== void 0) {
|
|
17200
17346
|
__privateGet(this, _router).setPacketIdRole(track.packetId, role);
|
|
@@ -18422,7 +18568,7 @@ _readIndex = new WeakMap();
|
|
|
18422
18568
|
_stalled = new WeakMap();
|
|
18423
18569
|
|
|
18424
18570
|
// src/mmtp-decode-pipeline.ts
|
|
18425
|
-
var _parser2, _fecClient, _frameCb2, _initCb2, _needsKeyframe, _codec, _trackType, _gateDropped, _gateEmitted,
|
|
18571
|
+
var _parser2, _fecClient, _frameCb2, _initCb2, _needsKeyframe, _codec, _trackType, _gateDropped, _gateEmitted, _fedObjects2, _warnedNoParser, _feedOutcomes2, _MmtpDecodePipeline_instances, tag_fn, gatedEmit_fn;
|
|
18426
18572
|
var MmtpDecodePipeline = class {
|
|
18427
18573
|
constructor() {
|
|
18428
18574
|
__privateAdd(this, _MmtpDecodePipeline_instances);
|
|
@@ -18442,7 +18588,7 @@ var MmtpDecodePipeline = class {
|
|
|
18442
18588
|
* emitted. Bounded logging only — these gate nothing. */
|
|
18443
18589
|
__privateAdd(this, _gateDropped, 0);
|
|
18444
18590
|
__privateAdd(this, _gateEmitted, 0);
|
|
18445
|
-
__privateAdd(this,
|
|
18591
|
+
__privateAdd(this, _fedObjects2, 0);
|
|
18446
18592
|
/** Warned-once latch for feeds arriving with no parser. Kept separate from
|
|
18447
18593
|
* #fedObjects so that counter stays a pure monotonic count. */
|
|
18448
18594
|
__privateAdd(this, _warnedNoParser, false);
|
|
@@ -18451,16 +18597,16 @@ var MmtpDecodePipeline = class {
|
|
|
18451
18597
|
* so a packet that fails header parse, fails MFU extraction, or accumulates
|
|
18452
18598
|
* forever as an unreassembled fragment is indistinguishable from one that
|
|
18453
18599
|
* produced a frame. Tally the kinds instead of guessing. */
|
|
18454
|
-
__privateAdd(this,
|
|
18600
|
+
__privateAdd(this, _feedOutcomes2, /* @__PURE__ */ new Map());
|
|
18455
18601
|
}
|
|
18456
18602
|
/** Configure the inner parser. Call before feedMoqObject(). */
|
|
18457
18603
|
configure(config) {
|
|
18458
18604
|
__privateGet(this, _parser2)?.flush();
|
|
18459
18605
|
__privateGet(this, _parser2)?.dispose();
|
|
18460
|
-
__privateSet(this,
|
|
18606
|
+
__privateSet(this, _fedObjects2, 0);
|
|
18461
18607
|
__privateSet(this, _gateDropped, 0);
|
|
18462
18608
|
__privateSet(this, _gateEmitted, 0);
|
|
18463
|
-
__privateGet(this,
|
|
18609
|
+
__privateGet(this, _feedOutcomes2).clear();
|
|
18464
18610
|
__privateSet(this, _warnedNoParser, false);
|
|
18465
18611
|
__privateSet(this, _codec, config.codec);
|
|
18466
18612
|
const trackType = isVideoCodec(config.codec) ? "video" : "audio";
|
|
@@ -18520,10 +18666,10 @@ var MmtpDecodePipeline = class {
|
|
|
18520
18666
|
return {
|
|
18521
18667
|
trackType: __privateGet(this, _trackType),
|
|
18522
18668
|
codec: __privateGet(this, _codec),
|
|
18523
|
-
fedObjects: __privateGet(this,
|
|
18669
|
+
fedObjects: __privateGet(this, _fedObjects2),
|
|
18524
18670
|
emitted: __privateGet(this, _gateEmitted),
|
|
18525
18671
|
gateDropped: __privateGet(this, _gateDropped),
|
|
18526
|
-
outcomes: Object.fromEntries(__privateGet(this,
|
|
18672
|
+
outcomes: Object.fromEntries(__privateGet(this, _feedOutcomes2))
|
|
18527
18673
|
};
|
|
18528
18674
|
}
|
|
18529
18675
|
/**
|
|
@@ -18538,8 +18684,8 @@ var MmtpDecodePipeline = class {
|
|
|
18538
18684
|
}
|
|
18539
18685
|
return;
|
|
18540
18686
|
}
|
|
18541
|
-
__privateSet(this,
|
|
18542
|
-
if (__privateGet(this,
|
|
18687
|
+
__privateSet(this, _fedObjects2, __privateGet(this, _fedObjects2) + 1);
|
|
18688
|
+
if (__privateGet(this, _fedObjects2) === 1) {
|
|
18543
18689
|
console.log(`[mmtp-pipeline] first object fed ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} bytes=${packet.length}`);
|
|
18544
18690
|
}
|
|
18545
18691
|
let outcomeKind = "threw";
|
|
@@ -18553,18 +18699,18 @@ var MmtpDecodePipeline = class {
|
|
|
18553
18699
|
const record = __privateGet(this, _parser2).feed(packet);
|
|
18554
18700
|
outcomeKind = record?.kind ?? "null(parse-or-extract-failed)";
|
|
18555
18701
|
} finally {
|
|
18556
|
-
const seen = (__privateGet(this,
|
|
18557
|
-
__privateGet(this,
|
|
18702
|
+
const seen = (__privateGet(this, _feedOutcomes2).get(outcomeKind) ?? 0) + 1;
|
|
18703
|
+
__privateGet(this, _feedOutcomes2).set(outcomeKind, seen);
|
|
18558
18704
|
if (seen === 1) {
|
|
18559
18705
|
console.log(
|
|
18560
|
-
`[mmtp-pipeline] feed outcome FIRST '${outcomeKind}' ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} at object #${__privateGet(this,
|
|
18706
|
+
`[mmtp-pipeline] feed outcome FIRST '${outcomeKind}' ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} at object #${__privateGet(this, _fedObjects2)} bytes=${packet.length}`
|
|
18561
18707
|
);
|
|
18562
18708
|
}
|
|
18563
18709
|
}
|
|
18564
|
-
if (__privateGet(this,
|
|
18565
|
-
const hist = [...__privateGet(this,
|
|
18710
|
+
if (__privateGet(this, _fedObjects2) % 200 === 0) {
|
|
18711
|
+
const hist = [...__privateGet(this, _feedOutcomes2)].map(([k, v]) => `${k}=${v}`).join(" ");
|
|
18566
18712
|
console.log(
|
|
18567
|
-
`[mmtp-pipeline] feed histogram ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} @${__privateGet(this,
|
|
18713
|
+
`[mmtp-pipeline] feed histogram ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} @${__privateGet(this, _fedObjects2)}: ${hist} | emitted=${__privateGet(this, _gateEmitted)} gateDropped=${__privateGet(this, _gateDropped)}`
|
|
18568
18714
|
);
|
|
18569
18715
|
}
|
|
18570
18716
|
}
|
|
@@ -18631,9 +18777,9 @@ _codec = new WeakMap();
|
|
|
18631
18777
|
_trackType = new WeakMap();
|
|
18632
18778
|
_gateDropped = new WeakMap();
|
|
18633
18779
|
_gateEmitted = new WeakMap();
|
|
18634
|
-
|
|
18780
|
+
_fedObjects2 = new WeakMap();
|
|
18635
18781
|
_warnedNoParser = new WeakMap();
|
|
18636
|
-
|
|
18782
|
+
_feedOutcomes2 = new WeakMap();
|
|
18637
18783
|
_MmtpDecodePipeline_instances = new WeakSet();
|
|
18638
18784
|
/** Identity prefix for diagnostics: one pipeline per track means two
|
|
18639
18785
|
* instances write to the same console, and unlabelled lines interleave into
|
|
@@ -18649,7 +18795,7 @@ gatedEmit_fn = function(data, meta) {
|
|
|
18649
18795
|
__privateSet(this, _gateDropped, __privateGet(this, _gateDropped) + 1);
|
|
18650
18796
|
if (__privateGet(this, _gateDropped) <= 3 || __privateGet(this, _gateDropped) % 200 === 0) {
|
|
18651
18797
|
console.warn(
|
|
18652
|
-
`[mmtp-pipeline] keyframe gate DROP #${__privateGet(this, _gateDropped)} ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} bytes=${data.length} fed=${__privateGet(this,
|
|
18798
|
+
`[mmtp-pipeline] keyframe gate DROP #${__privateGet(this, _gateDropped)} ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} bytes=${data.length} fed=${__privateGet(this, _fedObjects2)} emitted=${__privateGet(this, _gateEmitted)}`
|
|
18653
18799
|
);
|
|
18654
18800
|
}
|
|
18655
18801
|
return;
|
|
@@ -18657,7 +18803,7 @@ gatedEmit_fn = function(data, meta) {
|
|
|
18657
18803
|
__privateSet(this, _needsKeyframe, false);
|
|
18658
18804
|
sourceDiscontinuity = true;
|
|
18659
18805
|
console.log(
|
|
18660
|
-
`[mmtp-pipeline] keyframe gate OPENED ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} after ${__privateGet(this, _gateDropped)} drops, fed=${__privateGet(this,
|
|
18806
|
+
`[mmtp-pipeline] keyframe gate OPENED ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} after ${__privateGet(this, _gateDropped)} drops, fed=${__privateGet(this, _fedObjects2)}`
|
|
18661
18807
|
);
|
|
18662
18808
|
}
|
|
18663
18809
|
__privateSet(this, _gateEmitted, __privateGet(this, _gateEmitted) + 1);
|