@blockcast/mmt-container 0.1.0-main.dd5ce397d768 → 0.1.0-main.f24ff7b49949
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 +507 -250
- package/dist/browser-runtime.js.map +3 -3
- package/dist/catalog-fec-params.d.ts +15 -0
- package/dist/catalog-fec-params.d.ts.map +1 -1
- package/dist/catalog-fec-params.js +11 -0
- package/dist/catalog-fec-params.js.map +2 -2
- package/dist/cmaf-block-assembler.js.map +1 -1
- package/dist/cmaf-group-batcher.js.map +1 -1
- package/dist/cmcd-producer.d.ts.map +1 -1
- package/dist/cmcd-producer.js.map +2 -2
- package/dist/fec-manager.d.ts +1 -1
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +1 -1
- package/dist/fec-manager.js.map +2 -2
- package/dist/fec-worker-setup.d.ts +8 -0
- package/dist/fec-worker-setup.d.ts.map +1 -1
- package/dist/fec-worker-setup.js +3 -1
- package/dist/fec-worker-setup.js.map +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- 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/manifest-auth-plan.js +29 -11
- package/dist/manifest-auth-plan.js.map +2 -2
- package/dist/media-router.js.map +2 -2
- package/dist/mfu-reassembler.js +56 -0
- package/dist/mfu-reassembler.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 +388 -199
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +432 -214
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/mmtp-decode-pipeline.js +407 -218
- package/dist/mmtp-decode-pipeline.js.map +3 -3
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +393 -200
- package/dist/mmtp-router.js.map +2 -2
- package/dist/mmtp-to-cmaf.d.ts +11 -2
- package/dist/mmtp-to-cmaf.d.ts.map +1 -1
- package/dist/mmtp-to-cmaf.js +15 -4
- package/dist/mmtp-to-cmaf.js.map +2 -2
- package/dist/multicast-manager.d.ts +12 -0
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +459 -226
- package/dist/multicast-manager.js.map +2 -2
- package/dist/multicast-transport.d.ts.map +1 -1
- package/dist/multicast-transport.js +22 -7
- package/dist/multicast-transport.js.map +2 -2
- package/dist/no-modules.js +432 -214
- package/dist/no-modules.js.map +2 -2
- package/dist/source-auth.js +29 -11
- package/dist/source-auth.js.map +2 -2
- package/dist/track-session.d.ts +17 -1
- package/dist/track-session.d.ts.map +1 -1
- package/dist/track-session.js.map +2 -2
- package/dist/wasm-mfu-reassembler.js +56 -0
- package/dist/wasm-mfu-reassembler.js.map +2 -2
- package/dist/wasm-mmtp-container-parser.js +388 -199
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts +1 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts.map +1 -1
- package/node_modules/@blockcast/fec-worker/src/fec-worker-types.ts +1 -1
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts +3 -1
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.js +3 -1
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.js.map +1 -1
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts +2 -2
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js +2 -2
- package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts +5 -7
- package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-fec/dist/oti.js +4 -6
- package/node_modules/@blockcast/mmt-fec/dist/oti.js.map +1 -1
- package/node_modules/@blockcast/mmt-fec/src/block-manager.ts +3 -1
- package/node_modules/@blockcast/mmt-fec/src/fec-block-mapper.ts +2 -2
- package/node_modules/@blockcast/mmt-fec/src/oti.ts +5 -7
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts +10 -1
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js +40 -10
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js.map +1 -1
- package/node_modules/@blockcast/mmt-manifest-verify/src/verifier.ts +41 -8
- package/package.json +6 -6
- package/src/catalog-fec-params.ts +28 -0
- package/src/cmcd-producer.ts +5 -0
- package/src/fec-manager.ts +1 -1
- package/src/fec-worker-setup.ts +11 -1
- package/src/index.ts +4 -0
- package/src/iso-bmff-timing.ts +62 -7
- package/src/mfu-reassembler.ts +95 -0
- package/src/mmtp-container-parser.ts +284 -48
- package/src/mmtp-router.ts +5 -1
- package/src/mmtp-to-cmaf.ts +24 -2
- package/src/multicast-manager.ts +102 -29
- package/src/multicast-transport.ts +19 -4
- package/src/track-session.ts +17 -1
- package/test-vectors/source-contiguity-v1.json +131 -0
package/dist/browser-runtime.js
CHANGED
|
@@ -1936,6 +1936,62 @@ if (void 0) {
|
|
|
1936
1936
|
expect(out?.data).toEqual(new Uint8Array([161, 162]));
|
|
1937
1937
|
expect(out?.sampleOffset).toBe(4);
|
|
1938
1938
|
});
|
|
1939
|
+
test("a mid-data-unit packet sequence gap strands the data unit", () => {
|
|
1940
|
+
const reassembler = new MFUReassembler({ timeoutMs: null, maxBuffered: 10 });
|
|
1941
|
+
expect(
|
|
1942
|
+
reassembler.addFragment({
|
|
1943
|
+
fragmentationIndicator: 1,
|
|
1944
|
+
mpuSequenceNumber: 7,
|
|
1945
|
+
fragmentCounter: 2,
|
|
1946
|
+
movieFragmentSequenceNumber: 9,
|
|
1947
|
+
sampleNumber: 17,
|
|
1948
|
+
sampleOffset: 0,
|
|
1949
|
+
packetSequenceNumber: 100,
|
|
1950
|
+
data: new Uint8Array([161]),
|
|
1951
|
+
timestamp: 1100n,
|
|
1952
|
+
rapFlag: true
|
|
1953
|
+
})
|
|
1954
|
+
).toBeNull();
|
|
1955
|
+
const interleaved = reassembler.addFragment({
|
|
1956
|
+
fragmentationIndicator: 0,
|
|
1957
|
+
mpuSequenceNumber: 7,
|
|
1958
|
+
fragmentCounter: 0,
|
|
1959
|
+
movieFragmentSequenceNumber: 9,
|
|
1960
|
+
sampleNumber: 18,
|
|
1961
|
+
sampleOffset: 0,
|
|
1962
|
+
packetSequenceNumber: 101,
|
|
1963
|
+
data: new Uint8Array([255]),
|
|
1964
|
+
timestamp: 1101n,
|
|
1965
|
+
rapFlag: true
|
|
1966
|
+
});
|
|
1967
|
+
expect(interleaved?.data).toEqual(new Uint8Array([255]));
|
|
1968
|
+
expect(
|
|
1969
|
+
reassembler.addFragment({
|
|
1970
|
+
fragmentationIndicator: 2,
|
|
1971
|
+
mpuSequenceNumber: 7,
|
|
1972
|
+
fragmentCounter: 1,
|
|
1973
|
+
packetSequenceNumber: 102,
|
|
1974
|
+
data: new Uint8Array([162]),
|
|
1975
|
+
timestamp: 1102n,
|
|
1976
|
+
rapFlag: false
|
|
1977
|
+
})
|
|
1978
|
+
).toBeNull();
|
|
1979
|
+
const output = reassembler.addFragment({
|
|
1980
|
+
fragmentationIndicator: 3,
|
|
1981
|
+
mpuSequenceNumber: 7,
|
|
1982
|
+
fragmentCounter: 0,
|
|
1983
|
+
packetSequenceNumber: 103,
|
|
1984
|
+
data: new Uint8Array([163]),
|
|
1985
|
+
timestamp: 1103n,
|
|
1986
|
+
rapFlag: false
|
|
1987
|
+
});
|
|
1988
|
+
expect(output).toBeNull();
|
|
1989
|
+
expect(reassembler.stats.reassembledMFUs).toBe(1);
|
|
1990
|
+
expect(reassembler.stats.rejectedFragments).toBe(0);
|
|
1991
|
+
expect(reassembler.stats.evictedMemoryLimit).toBe(0);
|
|
1992
|
+
expect(reassembler.getStatus().bufferedMFUs).toBe(2);
|
|
1993
|
+
expect(reassembler.getStatus().pendingFragments).toBe(3);
|
|
1994
|
+
});
|
|
1939
1995
|
test("sibling subsample DUs of one sample reassemble independently by offset", () => {
|
|
1940
1996
|
const reassembler = new MFUReassembler({ timeoutMs: 1e3 });
|
|
1941
1997
|
expect(
|
|
@@ -7719,16 +7775,26 @@ var MmtpToCmaf = class {
|
|
|
7719
7775
|
return __privateGet(this, _audioInitSegment);
|
|
7720
7776
|
}
|
|
7721
7777
|
/** Convert a raw video sample to an fMP4 moof+mdat segment. */
|
|
7722
|
-
wrapVideoSample(data, timestamp, keyframe, duration) {
|
|
7723
|
-
return this.wrapVideoSampleWithTiming(data, timestamp, keyframe, duration).segment;
|
|
7778
|
+
wrapVideoSample(data, timestamp, keyframe, duration, compositionTimeOffset) {
|
|
7779
|
+
return this.wrapVideoSampleWithTiming(data, timestamp, keyframe, duration, compositionTimeOffset).segment;
|
|
7724
7780
|
}
|
|
7725
7781
|
/**
|
|
7726
7782
|
* Convert a raw video sample and return the exact browser media interval
|
|
7727
7783
|
* encoded into tfdt/trun. Consumers that correlate SourceBuffer appends with
|
|
7728
7784
|
* requestVideoFrameCallback must use this rebased timestamp, not the wire or
|
|
7729
7785
|
* caller-owned timestamp passed above.
|
|
7786
|
+
*
|
|
7787
|
+
* `compositionTimeOffset` is the signed authored PTS-DTS delta, in the same
|
|
7788
|
+
* #videoTimescale units as `timestamp` and `duration` — unlike wrapAudioSample,
|
|
7789
|
+
* which takes microseconds and rescales, because every other quantity on this
|
|
7790
|
+
* path is already denominated in #videoTimescale (see setVideoTrackParams).
|
|
7791
|
+
* Passing it therefore needs no conversion here; rescaling would double-convert.
|
|
7792
|
+
* Absent leaves the trun at version 0 with no offset field; a declared 0 is an
|
|
7793
|
+
* authored value and still promotes to version 1. Never reconstruct it from
|
|
7794
|
+
* arrival time.
|
|
7730
7795
|
*/
|
|
7731
|
-
wrapVideoSampleWithTiming(data, timestamp, keyframe, duration) {
|
|
7796
|
+
wrapVideoSampleWithTiming(data, timestamp, keyframe, duration, compositionTimeOffset) {
|
|
7797
|
+
assertCompositionTimeOffsets([{ compositionTimeOffset }]);
|
|
7732
7798
|
if (duration !== void 0 && Number.isFinite(duration) && duration > 0) {
|
|
7733
7799
|
__privateSet(this, _frameDuration, Math.round(duration));
|
|
7734
7800
|
} else if (__privateGet(this, _lastVideoTimestamp) > 0 && timestamp > __privateGet(this, _lastVideoTimestamp)) {
|
|
@@ -7746,7 +7812,8 @@ var MmtpToCmaf = class {
|
|
|
7746
7812
|
frameDuration,
|
|
7747
7813
|
keyframe,
|
|
7748
7814
|
__privateWrapper(this, _videoSeq)._++,
|
|
7749
|
-
__privateGet(this, _videoTrackId)
|
|
7815
|
+
__privateGet(this, _videoTrackId),
|
|
7816
|
+
compositionTimeOffset
|
|
7750
7817
|
),
|
|
7751
7818
|
mediaTimestamp: relTs,
|
|
7752
7819
|
duration: frameDuration
|
|
@@ -10017,7 +10084,7 @@ var FECManager = class {
|
|
|
10017
10084
|
symbolSizeForPacket(packetId) {
|
|
10018
10085
|
return __privateMethod(this, _FECManager_instances, resolveTrackConfig_fn).call(this, packetId).symbolSize;
|
|
10019
10086
|
}
|
|
10020
|
-
/** FEC
|
|
10087
|
+
/** FEC block span in milliseconds (0 = no interleaving). */
|
|
10021
10088
|
get interleaveDepthMs() {
|
|
10022
10089
|
return __privateGet(this, _fecInterleaveDepthMs);
|
|
10023
10090
|
}
|
|
@@ -11577,7 +11644,7 @@ function sameTrack(a, b) {
|
|
|
11577
11644
|
function sameSample(a, b) {
|
|
11578
11645
|
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
11646
|
}
|
|
11580
|
-
var _track, _fragments, _pendingSamples, _lastMovieFragmentRejection, _IsoBmffTimingResolver_instances, clearSlot_fn;
|
|
11647
|
+
var _track, _fragments, _pendingSamples, _evictedSamples, _lastMovieFragmentRejection, _IsoBmffTimingResolver_instances, evictOldestFragment_fn, clearSlot_fn;
|
|
11581
11648
|
var IsoBmffTimingResolver = class {
|
|
11582
11649
|
constructor(maxPendingSamples) {
|
|
11583
11650
|
this.maxPendingSamples = maxPendingSamples;
|
|
@@ -11585,6 +11652,7 @@ var IsoBmffTimingResolver = class {
|
|
|
11585
11652
|
__privateAdd(this, _track, null);
|
|
11586
11653
|
__privateAdd(this, _fragments, /* @__PURE__ */ new Map());
|
|
11587
11654
|
__privateAdd(this, _pendingSamples, 0);
|
|
11655
|
+
__privateAdd(this, _evictedSamples, 0);
|
|
11588
11656
|
__privateAdd(this, _lastMovieFragmentRejection, null);
|
|
11589
11657
|
if (!Number.isInteger(maxPendingSamples) || maxPendingSamples <= 0) {
|
|
11590
11658
|
throw new Error("[IsoBmffTimingResolver] maxPendingSamples must be a positive integer");
|
|
@@ -11593,6 +11661,15 @@ var IsoBmffTimingResolver = class {
|
|
|
11593
11661
|
get pendingSampleCount() {
|
|
11594
11662
|
return __privateGet(this, _pendingSamples);
|
|
11595
11663
|
}
|
|
11664
|
+
/**
|
|
11665
|
+
* Slots reclaimed by window displacement rather than by delivery or
|
|
11666
|
+
* abandonment. Deliberately separate from the combiner's own release count:
|
|
11667
|
+
* "nobody ever saw this sample" and "the combiner gave up on it" are
|
|
11668
|
+
* different failures with different owners, and one number cannot say which.
|
|
11669
|
+
*/
|
|
11670
|
+
get evictedSampleCount() {
|
|
11671
|
+
return __privateGet(this, _evictedSamples);
|
|
11672
|
+
}
|
|
11596
11673
|
/** Typed reason for the most recent rejected movie fragment. */
|
|
11597
11674
|
get lastMovieFragmentRejection() {
|
|
11598
11675
|
return __privateGet(this, _lastMovieFragmentRejection);
|
|
@@ -11630,7 +11707,11 @@ var IsoBmffTimingResolver = class {
|
|
|
11630
11707
|
(sample, index) => sample !== null && sameSample(sample, parsed.samples[index])
|
|
11631
11708
|
);
|
|
11632
11709
|
}
|
|
11633
|
-
|
|
11710
|
+
let freed = 0;
|
|
11711
|
+
while (__privateGet(this, _fragments).size > 0 && (__privateGet(this, _pendingSamples) + parsed.samples.length > this.maxPendingSamples || parsed.samples.length - freed > additionalSampleLimit)) {
|
|
11712
|
+
freed += __privateMethod(this, _IsoBmffTimingResolver_instances, evictOldestFragment_fn).call(this);
|
|
11713
|
+
}
|
|
11714
|
+
if (parsed.samples.length - freed > additionalSampleLimit) {
|
|
11634
11715
|
__privateSet(this, _lastMovieFragmentRejection, "budget");
|
|
11635
11716
|
return false;
|
|
11636
11717
|
}
|
|
@@ -11663,12 +11744,11 @@ var IsoBmffTimingResolver = class {
|
|
|
11663
11744
|
* Free the budget slot of a sample that will never be delivered.
|
|
11664
11745
|
*
|
|
11665
11746
|
* `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.
|
|
11747
|
+
* healthy stream. A sample whose data units never complete is never
|
|
11748
|
+
* delivered; window displacement in `addMovieFragment` eventually reclaims
|
|
11749
|
+
* it, but only after it has aged out of the whole window. This path frees
|
|
11750
|
+
* the slot as soon as the combiner knows the sample is gone, so the budget
|
|
11751
|
+
* tracks what is actually in flight rather than what has merely aged.
|
|
11672
11752
|
*
|
|
11673
11753
|
* The caller is whoever abandoned the sample, so the release is driven by
|
|
11674
11754
|
* the abandonment itself rather than by a timer, an LRU, or an age bound --
|
|
@@ -11692,8 +11772,27 @@ var IsoBmffTimingResolver = class {
|
|
|
11692
11772
|
_track = new WeakMap();
|
|
11693
11773
|
_fragments = new WeakMap();
|
|
11694
11774
|
_pendingSamples = new WeakMap();
|
|
11775
|
+
_evictedSamples = new WeakMap();
|
|
11695
11776
|
_lastMovieFragmentRejection = new WeakMap();
|
|
11696
11777
|
_IsoBmffTimingResolver_instances = new WeakSet();
|
|
11778
|
+
/**
|
|
11779
|
+
* Drop the oldest pending fragment whole and return the slots it held.
|
|
11780
|
+
*
|
|
11781
|
+
* Oldest is insertion order, which for a moof stream is arrival order, so
|
|
11782
|
+
* this is the least-recently-declared timing -- the entries least likely to
|
|
11783
|
+
* still have data units in flight.
|
|
11784
|
+
*/
|
|
11785
|
+
evictOldestFragment_fn = function() {
|
|
11786
|
+
const oldest = __privateGet(this, _fragments).keys().next().value;
|
|
11787
|
+
if (oldest === void 0) return 0;
|
|
11788
|
+
const samples = __privateGet(this, _fragments).get(oldest);
|
|
11789
|
+
let live = 0;
|
|
11790
|
+
for (const sample of samples) if (sample !== null) live++;
|
|
11791
|
+
__privateGet(this, _fragments).delete(oldest);
|
|
11792
|
+
__privateSet(this, _pendingSamples, __privateGet(this, _pendingSamples) - live);
|
|
11793
|
+
__privateSet(this, _evictedSamples, __privateGet(this, _evictedSamples) + live);
|
|
11794
|
+
return live;
|
|
11795
|
+
};
|
|
11697
11796
|
/** Null one slot, decrement the budget, and drop the fragment when empty. */
|
|
11698
11797
|
clearSlot_fn = function(mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber) {
|
|
11699
11798
|
if (!isU322(mpuSequenceNumber) || !isU322(movieFragmentSequenceNumber) || movieFragmentSequenceNumber === 0 || !isU322(sampleNumber) || sampleNumber === 0) {
|
|
@@ -11872,7 +11971,7 @@ function isFmp4Box(data) {
|
|
|
11872
11971
|
const type = String.fromCharCode(data[4], data[5], data[6], data[7]);
|
|
11873
11972
|
return FMPU_BOX_TYPES.has(type);
|
|
11874
11973
|
}
|
|
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;
|
|
11974
|
+
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
11975
|
var _MmtpContainerParser = class _MmtpContainerParser {
|
|
11877
11976
|
constructor(config) {
|
|
11878
11977
|
__privateAdd(this, _MmtpContainerParser_instances);
|
|
@@ -11906,6 +12005,7 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
11906
12005
|
__privateAdd(this, _maxPendingTimingSamples);
|
|
11907
12006
|
__privateAdd(this, _pendingTimingSamples, 0);
|
|
11908
12007
|
__privateAdd(this, _reclaimedTimingSamples, 0);
|
|
12008
|
+
__privateAdd(this, _evictedTimingSamples, 0);
|
|
11909
12009
|
__privateAdd(this, _rejectedMovieFragments, 0);
|
|
11910
12010
|
__privateAdd(this, _sequencers, /* @__PURE__ */ new Map());
|
|
11911
12011
|
__privateAdd(this, _reorderWindow, 0);
|
|
@@ -11932,6 +12032,11 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
11932
12032
|
* reordering into the parser. */
|
|
11933
12033
|
__privateAdd(this, _reliableMoqStartupGate, /* @__PURE__ */ new Map());
|
|
11934
12034
|
__privateAdd(this, _disposed2, false);
|
|
12035
|
+
__privateAdd(this, _fedObjects, 0);
|
|
12036
|
+
__privateAdd(this, _feedOutcomes, /* @__PURE__ */ new Map());
|
|
12037
|
+
__privateAdd(this, _deferredFeedOutcomes, /* @__PURE__ */ new Map());
|
|
12038
|
+
__privateAdd(this, _lastOutcome, null);
|
|
12039
|
+
__privateAdd(this, _lastOutcomeCount, 0);
|
|
11935
12040
|
/** Authored presentation timestamp of the last emitted frame, in microseconds. */
|
|
11936
12041
|
this.lastFrameTimestamp = void 0;
|
|
11937
12042
|
if (config?.reassemblyPolicy && config.mfuTimeoutMs !== void 0) {
|
|
@@ -12034,6 +12139,7 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12034
12139
|
pending: __privateGet(this, _pendingTimingSamples),
|
|
12035
12140
|
capacity: __privateGet(this, _maxPendingTimingSamples),
|
|
12036
12141
|
reclaimed: __privateGet(this, _reclaimedTimingSamples),
|
|
12142
|
+
evicted: __privateGet(this, _evictedTimingSamples),
|
|
12037
12143
|
rejectedMovieFragments: __privateGet(this, _rejectedMovieFragments)
|
|
12038
12144
|
};
|
|
12039
12145
|
}
|
|
@@ -12042,6 +12148,36 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12042
12148
|
for (const { sequencer } of __privateGet(this, _sequencers).values()) bufferedFrames += sequencer.buffered;
|
|
12043
12149
|
return { ...__privateGet(this, _reorderStats), bufferedFrames };
|
|
12044
12150
|
}
|
|
12151
|
+
/**
|
|
12152
|
+
* Feed tallies for this parser. A fresh snapshot per call, not a live view,
|
|
12153
|
+
* so a caller can hold one and compare it against a later read.
|
|
12154
|
+
*
|
|
12155
|
+
* Survives dispose() — the counters are the parser's own state and are not
|
|
12156
|
+
* cleared by teardown, because a wedged receive path is usually read after
|
|
12157
|
+
* the fact.
|
|
12158
|
+
*/
|
|
12159
|
+
get feedStats() {
|
|
12160
|
+
return {
|
|
12161
|
+
fedObjects: __privateGet(this, _fedObjects),
|
|
12162
|
+
outcomes: Object.fromEntries(__privateGet(this, _feedOutcomes)),
|
|
12163
|
+
deferredOutcomes: Object.fromEntries(__privateGet(this, _deferredFeedOutcomes))
|
|
12164
|
+
};
|
|
12165
|
+
}
|
|
12166
|
+
/**
|
|
12167
|
+
* Outcome token of the most recent feed(), or null before the first call.
|
|
12168
|
+
*
|
|
12169
|
+
* Exposed alongside `lastFeedOutcomeCount` as two scalars rather than one
|
|
12170
|
+
* object because a wrapper reads them on every packet, and feedStats()
|
|
12171
|
+
* allocates a fresh snapshot per call.
|
|
12172
|
+
*/
|
|
12173
|
+
get lastFeedOutcome() {
|
|
12174
|
+
return __privateGet(this, _lastOutcome);
|
|
12175
|
+
}
|
|
12176
|
+
/** How many times `lastFeedOutcome` has now been seen. 1 on its first
|
|
12177
|
+
* occurrence, which is what a caller logging once per novel outcome needs. */
|
|
12178
|
+
get lastFeedOutcomeCount() {
|
|
12179
|
+
return __privateGet(this, _lastOutcomeCount);
|
|
12180
|
+
}
|
|
12045
12181
|
get reorderDiagnostics() {
|
|
12046
12182
|
const streams = [];
|
|
12047
12183
|
for (const { packetId, sequencer } of __privateGet(this, _sequencers).values()) {
|
|
@@ -12091,181 +12227,16 @@ var _MmtpContainerParser = class _MmtpContainerParser {
|
|
|
12091
12227
|
}
|
|
12092
12228
|
/** Feed a complete MMTP packet. For two-phase use, call parseHeader() first. */
|
|
12093
12229
|
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;
|
|
12230
|
+
__privateSet(this, _fedObjects, __privateGet(this, _fedObjects) + 1);
|
|
12231
|
+
let record;
|
|
12243
12232
|
try {
|
|
12244
|
-
|
|
12233
|
+
record = __privateMethod(this, _MmtpContainerParser_instances, feed_fn).call(this, packet, options);
|
|
12245
12234
|
} 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
|
-
};
|
|
12235
|
+
__privateMethod(this, _MmtpContainerParser_instances, countOutcome_fn).call(this, "drop:threw");
|
|
12236
|
+
throw error;
|
|
12267
12237
|
}
|
|
12268
|
-
|
|
12238
|
+
if (record) __privateMethod(this, _MmtpContainerParser_instances, countOutcome_fn).call(this, record.kind);
|
|
12239
|
+
return record;
|
|
12269
12240
|
}
|
|
12270
12241
|
onInit(cb) {
|
|
12271
12242
|
__privateSet(this, _initCb, cb);
|
|
@@ -12433,6 +12404,7 @@ _timingStreams = new WeakMap();
|
|
|
12433
12404
|
_maxPendingTimingSamples = new WeakMap();
|
|
12434
12405
|
_pendingTimingSamples = new WeakMap();
|
|
12435
12406
|
_reclaimedTimingSamples = new WeakMap();
|
|
12407
|
+
_evictedTimingSamples = new WeakMap();
|
|
12436
12408
|
_rejectedMovieFragments = new WeakMap();
|
|
12437
12409
|
_sequencers = new WeakMap();
|
|
12438
12410
|
_reorderWindow = new WeakMap();
|
|
@@ -12444,6 +12416,11 @@ _trackFrameCbs = new WeakMap();
|
|
|
12444
12416
|
_reorderStats = new WeakMap();
|
|
12445
12417
|
_reliableMoqStartupGate = new WeakMap();
|
|
12446
12418
|
_disposed2 = new WeakMap();
|
|
12419
|
+
_fedObjects = new WeakMap();
|
|
12420
|
+
_feedOutcomes = new WeakMap();
|
|
12421
|
+
_deferredFeedOutcomes = new WeakMap();
|
|
12422
|
+
_lastOutcome = new WeakMap();
|
|
12423
|
+
_lastOutcomeCount = new WeakMap();
|
|
12447
12424
|
_MmtpContainerParser_instances = new WeakSet();
|
|
12448
12425
|
streamKey_fn2 = function(packetId, catalogTrackName) {
|
|
12449
12426
|
return JSON.stringify([packetId, catalogTrackName ?? null]);
|
|
@@ -12462,12 +12439,12 @@ sampleCombinerFor_fn = function(streamKey) {
|
|
|
12462
12439
|
/**
|
|
12463
12440
|
* Return the timing budget slot of a sample the combiner abandoned.
|
|
12464
12441
|
*
|
|
12465
|
-
* Without this, `#pendingTimingSamples` is
|
|
12466
|
-
*
|
|
12467
|
-
*
|
|
12468
|
-
*
|
|
12469
|
-
*
|
|
12470
|
-
*
|
|
12442
|
+
* Without this, `#pendingTimingSamples` is charged for every sample a moof
|
|
12443
|
+
* declares but credited only when that sample is delivered, so each sample
|
|
12444
|
+
* lost to eviction or timeout burns a slot until the window displaces it.
|
|
12445
|
+
* Window displacement bounds that leak but only reclaims the OLDEST entries;
|
|
12446
|
+
* this path returns a slot the moment the combiner knows the sample is gone,
|
|
12447
|
+
* which keeps the live window as wide as the stream actually needs.
|
|
12471
12448
|
*
|
|
12472
12449
|
* The parser total is decremented only when the resolver reports it
|
|
12473
12450
|
* actually freed a slot, so a resolver already dropped by a track reset, or
|
|
@@ -12499,11 +12476,232 @@ dropSampleCombiner_fn = function(streamKey) {
|
|
|
12499
12476
|
__privateGet(this, _retiredSampleCombinerStats).evictedSamples += stats.evictedSamples;
|
|
12500
12477
|
__privateGet(this, _sampleCombiners).delete(streamKey);
|
|
12501
12478
|
};
|
|
12479
|
+
countOutcome_fn = function(token) {
|
|
12480
|
+
const count = (__privateGet(this, _feedOutcomes).get(token) ?? 0) + 1;
|
|
12481
|
+
__privateGet(this, _feedOutcomes).set(token, count);
|
|
12482
|
+
__privateSet(this, _lastOutcome, token);
|
|
12483
|
+
__privateSet(this, _lastOutcomeCount, count);
|
|
12484
|
+
};
|
|
12485
|
+
countDeferredOutcome_fn = function(reason) {
|
|
12486
|
+
__privateGet(this, _deferredFeedOutcomes).set(
|
|
12487
|
+
reason,
|
|
12488
|
+
(__privateGet(this, _deferredFeedOutcomes).get(reason) ?? 0) + 1
|
|
12489
|
+
);
|
|
12490
|
+
};
|
|
12491
|
+
/**
|
|
12492
|
+
* Count a feed() drop and return null in one expression, so every early
|
|
12493
|
+
* return inside feed() states the reason it took instead of collapsing into
|
|
12494
|
+
* a single failure bucket. Returns null so call sites stay `return this.#drop(...)`.
|
|
12495
|
+
*/
|
|
12496
|
+
drop_fn = function(reason) {
|
|
12497
|
+
__privateMethod(this, _MmtpContainerParser_instances, countOutcome_fn).call(this, `drop:${reason}`);
|
|
12498
|
+
return null;
|
|
12499
|
+
};
|
|
12500
|
+
feed_fn = function(packet, options) {
|
|
12501
|
+
var _a;
|
|
12502
|
+
if (__privateGet(this, _disposed2)) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "disposed");
|
|
12503
|
+
this.cleanupTimeouts();
|
|
12504
|
+
const info = this.parseHeader(packet, options);
|
|
12505
|
+
if (!info) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "header-parse-failed");
|
|
12506
|
+
if (info.packetType !== PACKET_TYPE_MPU2) {
|
|
12507
|
+
return {
|
|
12508
|
+
kind: info.isRepair ? "repair" : "non-media",
|
|
12509
|
+
packet: info,
|
|
12510
|
+
byteLength: packet.byteLength
|
|
12511
|
+
};
|
|
12512
|
+
}
|
|
12513
|
+
if (info.fecPayloadId !== null && __privateGet(this, _sourceSymbolCb)) {
|
|
12514
|
+
const rawSymbol = packet.subarray(0, packet.length - 4);
|
|
12515
|
+
const altaTrailer = extractAltaTrailer2(packet);
|
|
12516
|
+
const alta = altaTrailer ? { auth: altaTrailer.auth, payloadEnd: altaTrailer.signedEnd } : void 0;
|
|
12517
|
+
try {
|
|
12518
|
+
__privateGet(this, _sourceSymbolCb).call(this, info.packetId, info.fecPayloadId.ssId, rawSymbol, alta);
|
|
12519
|
+
} catch {
|
|
12520
|
+
}
|
|
12521
|
+
}
|
|
12522
|
+
const extraction = extractMFUPayload(packet, {
|
|
12523
|
+
skipFecId: options?.skipFecPayloadId
|
|
12524
|
+
});
|
|
12525
|
+
if (!extraction) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-extract-failed");
|
|
12526
|
+
const { mpu, fragmentType, data, mfuDuHeader } = extraction;
|
|
12527
|
+
if (mpu.timedFlag !== 1) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "untimed-mpu");
|
|
12528
|
+
const streamKey = __privateMethod(this, _MmtpContainerParser_instances, streamKey_fn2).call(this, info.packetId, options?.catalogTrackName);
|
|
12529
|
+
if (fragmentType === 0) {
|
|
12530
|
+
if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0)
|
|
12531
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "init-unexpected-fragmentation");
|
|
12532
|
+
const normalizedInit = normalizeMmtpInitSegment(data);
|
|
12533
|
+
if (!normalizedInit) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "init-normalize-failed");
|
|
12534
|
+
const resolver2 = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, true);
|
|
12535
|
+
if (!resolver2?.addInitialization(normalizedInit)) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "init-timing-refused");
|
|
12536
|
+
(_a = __privateGet(this, _initCb)) == null ? void 0 : _a.call(this, normalizedInit, info.packetId, options?.catalogTrackName);
|
|
12537
|
+
return {
|
|
12538
|
+
kind: "init",
|
|
12539
|
+
packet: info,
|
|
12540
|
+
data: normalizedInit,
|
|
12541
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12542
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12543
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12544
|
+
};
|
|
12545
|
+
}
|
|
12546
|
+
if (fragmentType === 1) {
|
|
12547
|
+
if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0)
|
|
12548
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-unexpected-fragmentation");
|
|
12549
|
+
const resolver2 = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, false);
|
|
12550
|
+
if (!resolver2) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-no-resolver");
|
|
12551
|
+
const pendingBefore = resolver2.pendingSampleCount;
|
|
12552
|
+
const evictedBefore = resolver2.evictedSampleCount;
|
|
12553
|
+
const remaining = __privateGet(this, _maxPendingTimingSamples) - __privateGet(this, _pendingTimingSamples);
|
|
12554
|
+
const admitted = resolver2.addMovieFragment(mpu.mpuSequenceNumber, data, remaining);
|
|
12555
|
+
__privateSet(this, _pendingTimingSamples, __privateGet(this, _pendingTimingSamples) + (resolver2.pendingSampleCount - pendingBefore));
|
|
12556
|
+
__privateSet(this, _evictedTimingSamples, __privateGet(this, _evictedTimingSamples) + (resolver2.evictedSampleCount - evictedBefore));
|
|
12557
|
+
if (!admitted) {
|
|
12558
|
+
if (resolver2.lastMovieFragmentRejection === "budget") {
|
|
12559
|
+
__privateWrapper(this, _rejectedMovieFragments)._++;
|
|
12560
|
+
}
|
|
12561
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-timing-refused");
|
|
12562
|
+
}
|
|
12563
|
+
return {
|
|
12564
|
+
kind: "fragment",
|
|
12565
|
+
packet: info,
|
|
12566
|
+
data,
|
|
12567
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12568
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12569
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12570
|
+
};
|
|
12571
|
+
}
|
|
12572
|
+
if (fragmentType !== 2) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "unknown-fragment-type");
|
|
12573
|
+
const resolver = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, false);
|
|
12574
|
+
if (!resolver) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-no-resolver");
|
|
12575
|
+
if (!Number.isSafeInteger(data.byteLength) || data.byteLength <= 0)
|
|
12576
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-empty-payload");
|
|
12577
|
+
if (mpu.fragmentationIndicator === 0 || mpu.fragmentationIndicator === 1) {
|
|
12578
|
+
if (!mfuDuHeader || mfuDuHeader.movieFragmentSequenceNumber === 0 || mfuDuHeader.sampleNumber === 0) {
|
|
12579
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-du-header-missing");
|
|
12580
|
+
}
|
|
12581
|
+
const headTiming = resolver.sampleTiming(
|
|
12582
|
+
mpu.mpuSequenceNumber,
|
|
12583
|
+
mfuDuHeader.movieFragmentSequenceNumber,
|
|
12584
|
+
mfuDuHeader.sampleNumber
|
|
12585
|
+
);
|
|
12586
|
+
if (!headTiming) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-sample-timing-missing");
|
|
12587
|
+
const offset = mfuDuHeader.offset;
|
|
12588
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset >= headTiming.size)
|
|
12589
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-offset-out-of-range");
|
|
12590
|
+
const remaining = headTiming.size - offset;
|
|
12591
|
+
if (mpu.fragmentationIndicator === 0 && data.byteLength !== remaining)
|
|
12592
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-size-mismatch");
|
|
12593
|
+
if (mpu.fragmentationIndicator === 1 && data.byteLength >= remaining)
|
|
12594
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-size-mismatch");
|
|
12595
|
+
const readyOnRegister = __privateMethod(this, _MmtpContainerParser_instances, sampleCombinerFor_fn).call(this, streamKey).registerAuthoredSize(
|
|
12596
|
+
options?.catalogTrackName,
|
|
12597
|
+
mpu.mpuSequenceNumber,
|
|
12598
|
+
mfuDuHeader.movieFragmentSequenceNumber,
|
|
12599
|
+
mfuDuHeader.sampleNumber,
|
|
12600
|
+
headTiming.size
|
|
12601
|
+
);
|
|
12602
|
+
if (readyOnRegister) {
|
|
12603
|
+
const deferred = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, readyOnRegister, info, resolver, options?.recovered === true);
|
|
12604
|
+
if (deferred.record === void 0) __privateMethod(this, _MmtpContainerParser_instances, countDeferredOutcome_fn).call(this, deferred.reason);
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
let assembled;
|
|
12608
|
+
try {
|
|
12609
|
+
assembled = __privateGet(this, _reassembler).addFragment({
|
|
12610
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12611
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12612
|
+
fragmentCounter: mpu.fragmentCounter,
|
|
12613
|
+
data,
|
|
12614
|
+
timestamp: info.timestamp,
|
|
12615
|
+
rapFlag: info.rapFlag,
|
|
12616
|
+
priority: mfuDuHeader?.priority,
|
|
12617
|
+
sampleNumber: mfuDuHeader?.sampleNumber,
|
|
12618
|
+
movieFragmentSequenceNumber: mfuDuHeader?.movieFragmentSequenceNumber,
|
|
12619
|
+
sampleOffset: mfuDuHeader?.offset,
|
|
12620
|
+
packetSequenceNumber: info.sequenceNumber,
|
|
12621
|
+
recovered: options?.recovered === true,
|
|
12622
|
+
source: options?.source,
|
|
12623
|
+
deliveryProvenance: options?.deliveryProvenance,
|
|
12624
|
+
catalogTrackName: options?.catalogTrackName,
|
|
12625
|
+
packetId: info.packetId
|
|
12626
|
+
});
|
|
12627
|
+
} catch (error) {
|
|
12628
|
+
if (!isMfuReassemblyError(error)) throw error;
|
|
12629
|
+
console.warn(
|
|
12630
|
+
`[MmtpContainerParser] rejected MFU fragment: code=${error.code} mpu=${mpu.mpuSequenceNumber} fi=${mpu.fragmentationIndicator} counter=${mpu.fragmentCounter}`
|
|
12631
|
+
);
|
|
12632
|
+
return {
|
|
12633
|
+
kind: "rejected",
|
|
12634
|
+
packet: info,
|
|
12635
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12636
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12637
|
+
fragmentCounter: mpu.fragmentCounter,
|
|
12638
|
+
error: { code: error.code, message: error.message }
|
|
12639
|
+
};
|
|
12640
|
+
}
|
|
12641
|
+
if (!assembled) {
|
|
12642
|
+
return {
|
|
12643
|
+
kind: "pending",
|
|
12644
|
+
packet: info,
|
|
12645
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12646
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12647
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12648
|
+
};
|
|
12649
|
+
}
|
|
12650
|
+
const movieFragmentSequenceNumber = assembled.movieFragmentSequenceNumber;
|
|
12651
|
+
const sampleNumber = assembled.sampleNumber;
|
|
12652
|
+
if (movieFragmentSequenceNumber === void 0 || sampleNumber === void 0)
|
|
12653
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "assembled-identity-missing");
|
|
12654
|
+
if (!resolver.sampleTiming(
|
|
12655
|
+
assembled.mpuSequenceNumber,
|
|
12656
|
+
movieFragmentSequenceNumber,
|
|
12657
|
+
sampleNumber
|
|
12658
|
+
)) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "assembled-timing-missing");
|
|
12659
|
+
if (assembled.mpuSequenceNumber !== mpu.mpuSequenceNumber)
|
|
12660
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "assembled-mpu-mismatch");
|
|
12661
|
+
let combined;
|
|
12662
|
+
try {
|
|
12663
|
+
combined = __privateMethod(this, _MmtpContainerParser_instances, sampleCombinerFor_fn).call(this, streamKey).addMfu(assembled);
|
|
12664
|
+
} catch (error) {
|
|
12665
|
+
if (!(error instanceof SampleCombineError)) throw error;
|
|
12666
|
+
console.warn(
|
|
12667
|
+
`[MmtpContainerParser] rejected subsample data unit: code=${error.code} mpu=${assembled.mpuSequenceNumber} sample=${sampleNumber} offset=${assembled.sampleOffset ?? 0}`
|
|
12668
|
+
);
|
|
12669
|
+
return {
|
|
12670
|
+
kind: "rejected",
|
|
12671
|
+
packet: info,
|
|
12672
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12673
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12674
|
+
fragmentCounter: mpu.fragmentCounter,
|
|
12675
|
+
error: { code: error.code, message: error.message }
|
|
12676
|
+
};
|
|
12677
|
+
}
|
|
12678
|
+
if (!combined) {
|
|
12679
|
+
return {
|
|
12680
|
+
kind: "pending",
|
|
12681
|
+
packet: info,
|
|
12682
|
+
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
12683
|
+
fragmentationIndicator: mpu.fragmentationIndicator,
|
|
12684
|
+
fragmentCounter: mpu.fragmentCounter
|
|
12685
|
+
};
|
|
12686
|
+
}
|
|
12687
|
+
const outcome = __privateMethod(this, _MmtpContainerParser_instances, emitCombinedSample_fn).call(this, combined, info, resolver, options?.recovered === true);
|
|
12688
|
+
if (outcome.record !== void 0) return outcome.record;
|
|
12689
|
+
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, outcome.reason);
|
|
12690
|
+
};
|
|
12502
12691
|
/**
|
|
12503
12692
|
* Deliver one combined sample: resolve its authored timing, build frame
|
|
12504
12693
|
* metadata, retire the timing entry, and route it. Shared by the ordinary
|
|
12505
12694
|
* completion path and by the rarer completion that falls out of registering
|
|
12506
12695
|
* an authored size for data units that arrived before it.
|
|
12696
|
+
*
|
|
12697
|
+
* Reports a refusal as a reason rather than counting it, because the two
|
|
12698
|
+
* call sites owe different accounting. On `#feed()`'s tail return the
|
|
12699
|
+
* refusal *is* that feed()'s outcome and must be attributed; on the
|
|
12700
|
+
* register-completion path it belongs to an earlier sample while this
|
|
12701
|
+
* packet's own fragment continues to its own outcome, so counting it there
|
|
12702
|
+
* would push `outcomes` past `fedObjects` — the very invariant the
|
|
12703
|
+
* attribution exists to keep readable. Leaving the choice at the call site
|
|
12704
|
+
* is what keeps both true.
|
|
12507
12705
|
*/
|
|
12508
12706
|
emitCombinedSample_fn = function(combined, info, resolver, recovered) {
|
|
12509
12707
|
const timing = resolver.sampleTiming(
|
|
@@ -12511,27 +12709,29 @@ emitCombinedSample_fn = function(combined, info, resolver, recovered) {
|
|
|
12511
12709
|
combined.movieFragmentSequenceNumber,
|
|
12512
12710
|
combined.sampleNumber
|
|
12513
12711
|
);
|
|
12514
|
-
if (!timing) return
|
|
12515
|
-
if (combined.data.byteLength !== timing.size) return
|
|
12712
|
+
if (!timing) return { reason: "combined-timing-missing" };
|
|
12713
|
+
if (combined.data.byteLength !== timing.size) return { reason: "combined-size-mismatch" };
|
|
12516
12714
|
const meta = __privateMethod(this, _MmtpContainerParser_instances, buildFrameMeta_fn).call(this, combined, info.packetId, info.sequenceNumber, timing, recovered);
|
|
12517
|
-
if (!meta) return
|
|
12715
|
+
if (!meta) return { reason: "combined-meta-build-failed" };
|
|
12518
12716
|
if (!resolver.consumeSample(
|
|
12519
12717
|
combined.mpuSequenceNumber,
|
|
12520
12718
|
combined.movieFragmentSequenceNumber,
|
|
12521
12719
|
combined.sampleNumber,
|
|
12522
12720
|
timing
|
|
12523
|
-
)) return
|
|
12721
|
+
)) return { reason: "combined-timing-consume-refused" };
|
|
12524
12722
|
__privateWrapper(this, _pendingTimingSamples)._--;
|
|
12525
12723
|
this.routeFrame(combined.data, meta);
|
|
12526
12724
|
return {
|
|
12527
|
-
|
|
12528
|
-
|
|
12529
|
-
|
|
12530
|
-
|
|
12531
|
-
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12725
|
+
record: {
|
|
12726
|
+
kind: "frame",
|
|
12727
|
+
packet: info,
|
|
12728
|
+
data: combined.data,
|
|
12729
|
+
meta,
|
|
12730
|
+
mpuSequenceNumber: combined.mpuSequenceNumber,
|
|
12731
|
+
fragmentCount: combined.fragmentCount,
|
|
12732
|
+
rapFlag: combined.rapFlag,
|
|
12733
|
+
...combined.priority === void 0 ? {} : { priority: combined.priority }
|
|
12734
|
+
}
|
|
12535
12735
|
};
|
|
12536
12736
|
};
|
|
12537
12737
|
/** Order-independent reliable-moq startup gate: discard delta frames for a
|
|
@@ -14319,7 +14519,11 @@ admitRecoveredResult_fn = function(blockId, result, ownerPacketId, catalogTrackN
|
|
|
14319
14519
|
__privateMethod(this, _MmtpRouter_instances, routeProcessedFecSymbols_fn).call(this, blockId, { ...result, symbols: [symbol] }, ownerPacketId, catalogTrackName);
|
|
14320
14520
|
}
|
|
14321
14521
|
admitNext(index + 1);
|
|
14322
|
-
}
|
|
14522
|
+
},
|
|
14523
|
+
// A stalled symbol that is later discarded instead of played must still
|
|
14524
|
+
// advance this loop; enforce mode never calls the release callback for
|
|
14525
|
+
// it (BLO-30095).
|
|
14526
|
+
() => admitNext(index + 1)
|
|
14323
14527
|
);
|
|
14324
14528
|
if (admission.action === "drop") admitNext(index + 1);
|
|
14325
14529
|
};
|
|
@@ -15092,12 +15296,16 @@ var driadDiscovery = new DRIADDiscovery();
|
|
|
15092
15296
|
function endpointKey(endpoint) {
|
|
15093
15297
|
return `${endpoint.sourceAddress ?? ""}|${endpoint.groupAddress}|${endpoint.port}`;
|
|
15094
15298
|
}
|
|
15299
|
+
function carriesMedia(endpoint) {
|
|
15300
|
+
return endpoint.carriesMedia !== false;
|
|
15301
|
+
}
|
|
15095
15302
|
function selectMulticastTier(endpoints, estimate) {
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15303
|
+
const media = endpoints.filter(carriesMedia);
|
|
15304
|
+
if (media.length <= 1)
|
|
15305
|
+
return media[0];
|
|
15306
|
+
const ranked = media.filter((endpoint) => typeof endpoint.bandwidth === "number" && endpoint.bandwidth > 0).sort((a, b) => a.bandwidth - b.bandwidth);
|
|
15099
15307
|
if (ranked.length < 2)
|
|
15100
|
-
return
|
|
15308
|
+
return media[0];
|
|
15101
15309
|
if (estimate === void 0)
|
|
15102
15310
|
return ranked[0];
|
|
15103
15311
|
const budget = estimate * 0.8;
|
|
@@ -15346,7 +15554,7 @@ var MulticastOrchestrator = class {
|
|
|
15346
15554
|
const currentBandwidth = __privateGet(this, _current).bandwidth;
|
|
15347
15555
|
if (typeof currentBandwidth !== "number")
|
|
15348
15556
|
return void 0;
|
|
15349
|
-
const desired = this.options.endpoints.filter((endpoint) => typeof endpoint.bandwidth === "number" && endpoint.bandwidth > currentBandwidth).sort((a, b) => a.bandwidth - b.bandwidth)[0];
|
|
15557
|
+
const desired = this.options.endpoints.filter((endpoint) => carriesMedia(endpoint) && typeof endpoint.bandwidth === "number" && endpoint.bandwidth > currentBandwidth).sort((a, b) => a.bandwidth - b.bandwidth)[0];
|
|
15350
15558
|
if (!desired) {
|
|
15351
15559
|
__privateSet(this, _favored, void 0);
|
|
15352
15560
|
return void 0;
|
|
@@ -16277,6 +16485,14 @@ function getMulticastGlobals() {
|
|
|
16277
16485
|
function hasMulticastGateway() {
|
|
16278
16486
|
return typeof getMulticastGlobals().multicast?.subscribe === "function";
|
|
16279
16487
|
}
|
|
16488
|
+
function normalizeBytesEventDetail(detail) {
|
|
16489
|
+
const value = detail && typeof detail === "object" && "data" in detail ? detail.data : detail;
|
|
16490
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
16491
|
+
if (ArrayBuffer.isView(value)) {
|
|
16492
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
16493
|
+
}
|
|
16494
|
+
return null;
|
|
16495
|
+
}
|
|
16280
16496
|
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
16497
|
var _MulticastTransport = class _MulticastTransport {
|
|
16282
16498
|
constructor(onPacket) {
|
|
@@ -16343,8 +16559,11 @@ var _MulticastTransport = class _MulticastTransport {
|
|
|
16343
16559
|
}
|
|
16344
16560
|
const onBytes = (event) => {
|
|
16345
16561
|
if (__privateGet(this, _disposed4) || generation !== __privateGet(this, _joinGeneration)) return;
|
|
16346
|
-
const
|
|
16347
|
-
|
|
16562
|
+
const packet = normalizeBytesEventDetail(event.detail);
|
|
16563
|
+
if (!packet) {
|
|
16564
|
+
__privateGet(this, _stats3).packetsDroppedUnparseable++;
|
|
16565
|
+
return;
|
|
16566
|
+
}
|
|
16348
16567
|
if (!__privateMethod(this, _MulticastTransport_instances, acceptPacket_fn).call(this, packet)) return;
|
|
16349
16568
|
__privateGet(this, _stats3).packetsReceived++;
|
|
16350
16569
|
__privateGet(this, _stats3).bytesReceived += packet.byteLength;
|
|
@@ -16641,6 +16860,24 @@ function publishFecDiagnostics(packetId, stats) {
|
|
|
16641
16860
|
function altGroupKey(track) {
|
|
16642
16861
|
return track.altGroup === void 0 ? DEFAULT_ALT_GROUP : String(track.altGroup);
|
|
16643
16862
|
}
|
|
16863
|
+
function repairTrackNamesBySource(tracks) {
|
|
16864
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
16865
|
+
const add = (source, repair) => {
|
|
16866
|
+
if (!source || !repair) return;
|
|
16867
|
+
const names = bySource.get(source) ?? /* @__PURE__ */ new Set();
|
|
16868
|
+
names.add(repair);
|
|
16869
|
+
bySource.set(source, names);
|
|
16870
|
+
};
|
|
16871
|
+
for (const track of tracks) {
|
|
16872
|
+
if (track.fec !== void 0 && isFecCatalogConfig(track.fec) && track.fec.repairTrack) {
|
|
16873
|
+
add(track.name, track.fec.repairTrack);
|
|
16874
|
+
}
|
|
16875
|
+
if (track.packaging === "fec-repair" && Array.isArray(track.depends) && track.depends.length === 1) {
|
|
16876
|
+
add(track.depends[0], track.name);
|
|
16877
|
+
}
|
|
16878
|
+
}
|
|
16879
|
+
return bySource;
|
|
16880
|
+
}
|
|
16644
16881
|
var _fec, _router, _transport, _reportedFecDiagnosticsFailure, _streamFecBaseline, _trackFecTiming, _switchingSets, _repairPacketIds, _repairInFlight, _repairLifecycleObservers, _trackResetObservers, _onRepairSubscribeCb, _MulticastManager_instances, configureTrackMapper_fn, applyStreamGlobalFecTiming_fn, _onTrackTypeDiscovered, emitRepairLifecycle_fn;
|
|
16645
16882
|
var MulticastManager = class {
|
|
16646
16883
|
constructor(options) {
|
|
@@ -17101,34 +17338,36 @@ var MulticastManager = class {
|
|
|
17101
17338
|
* a factory returning a distinct decoder per stream.
|
|
17102
17339
|
*/
|
|
17103
17340
|
configureMultiTrack(catalog, wasmDecoderSource) {
|
|
17104
|
-
const
|
|
17341
|
+
const repairNamesBySource = repairTrackNamesBySource(catalog.tracks);
|
|
17342
|
+
const repairOwnerGroup = /* @__PURE__ */ new Map();
|
|
17343
|
+
const repairOwnerAltGroup = /* @__PURE__ */ new Map();
|
|
17344
|
+
for (const track of catalog.tracks) {
|
|
17345
|
+
for (const repairName of repairNamesBySource.get(track.name) ?? []) {
|
|
17346
|
+
repairOwnerGroup.set(repairName, altGroupKey(track));
|
|
17347
|
+
repairOwnerAltGroup.set(repairName, track.altGroup);
|
|
17348
|
+
}
|
|
17349
|
+
}
|
|
17350
|
+
const groupKeyFor = (track) => repairOwnerGroup.get(track.name) ?? altGroupKey(track);
|
|
17105
17351
|
const trackNamesByGroup = /* @__PURE__ */ new Map();
|
|
17106
17352
|
for (const track of catalog.tracks) {
|
|
17107
|
-
const groupKey =
|
|
17353
|
+
const groupKey = groupKeyFor(track);
|
|
17108
17354
|
const groupNames = trackNamesByGroup.get(groupKey) ?? [];
|
|
17109
17355
|
groupNames.push(track.name);
|
|
17110
17356
|
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
17357
|
}
|
|
17117
17358
|
const hasSwitchingSetByGroup = /* @__PURE__ */ new Map();
|
|
17118
17359
|
for (const [groupKey, trackNames] of trackNamesByGroup) {
|
|
17119
17360
|
hasSwitchingSetByGroup.set(groupKey, hasSwitchingSetRole(trackNames));
|
|
17120
17361
|
}
|
|
17121
17362
|
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";
|
|
17363
|
+
if (repairOwnerGroup.has(track.name)) return "repair";
|
|
17364
|
+
const hasSwitchingSet = hasSwitchingSetByGroup.get(altGroupKey(track)) ?? false;
|
|
17126
17365
|
if (!hasSwitchingSet) return "single";
|
|
17127
17366
|
return parseTrackRole(track.name);
|
|
17128
17367
|
});
|
|
17129
17368
|
const resolvedRolesByGroup = /* @__PURE__ */ new Map();
|
|
17130
17369
|
for (let i = 0; i < catalog.tracks.length; i++) {
|
|
17131
|
-
const groupKey =
|
|
17370
|
+
const groupKey = groupKeyFor(catalog.tracks[i]);
|
|
17132
17371
|
const roles = resolvedRolesByGroup.get(groupKey) ?? [];
|
|
17133
17372
|
roles.push(resolvedRoles[i]);
|
|
17134
17373
|
resolvedRolesByGroup.set(groupKey, roles);
|
|
@@ -17191,10 +17430,11 @@ var MulticastManager = class {
|
|
|
17191
17430
|
for (let i = 0; i < catalog.tracks.length; i++) {
|
|
17192
17431
|
const track = catalog.tracks[i];
|
|
17193
17432
|
const role = resolvedRoles[i];
|
|
17194
|
-
|
|
17195
|
-
|
|
17433
|
+
const altGroup = repairOwnerAltGroup.has(track.name) ? repairOwnerAltGroup.get(track.name) : track.altGroup;
|
|
17434
|
+
if (altGroup !== void 0) {
|
|
17435
|
+
const existing = __privateGet(this, _switchingSets).get(altGroup) ?? [];
|
|
17196
17436
|
existing.push(track.name);
|
|
17197
|
-
__privateGet(this, _switchingSets).set(
|
|
17437
|
+
__privateGet(this, _switchingSets).set(altGroup, existing);
|
|
17198
17438
|
}
|
|
17199
17439
|
if (track.packetId !== void 0) {
|
|
17200
17440
|
__privateGet(this, _router).setPacketIdRole(track.packetId, role);
|
|
@@ -17207,9 +17447,13 @@ var MulticastManager = class {
|
|
|
17207
17447
|
}
|
|
17208
17448
|
if (track.fec !== void 0) {
|
|
17209
17449
|
const fecCfg = track.fec;
|
|
17210
|
-
|
|
17211
|
-
|
|
17212
|
-
|
|
17450
|
+
if (track.packetId !== void 0) {
|
|
17451
|
+
for (const repairName of repairNamesBySource.get(track.name) ?? []) {
|
|
17452
|
+
const repairTrack = catalogTracksByName.get(repairName);
|
|
17453
|
+
if (repairTrack?.packetId !== void 0) {
|
|
17454
|
+
__privateGet(this, _router).setRepairPacketIdOwner(repairTrack.packetId, track.packetId);
|
|
17455
|
+
}
|
|
17456
|
+
}
|
|
17213
17457
|
}
|
|
17214
17458
|
const wasmDecoder = fecDecoders.get(i);
|
|
17215
17459
|
if (track.packetId !== void 0 && wasmDecoder !== void 0) {
|
|
@@ -17499,7 +17743,9 @@ async function setupFecWorkerForTrack(opts) {
|
|
|
17499
17743
|
sampleRate: opts.sampleRate,
|
|
17500
17744
|
algorithm: "raptor",
|
|
17501
17745
|
k: opts.fecK,
|
|
17502
|
-
|
|
17746
|
+
// P as this receiver joined it, not the catalog total: the worker snapshot
|
|
17747
|
+
// and CMCD `x-bc-fec-p` are read from this. Identity on a single layer.
|
|
17748
|
+
repairCount: opts.joinedRepairCount ?? opts.fecRepairCount,
|
|
17503
17749
|
symbolSize: opts.fecSymbolSize,
|
|
17504
17750
|
interleaveDepth: interleaveDepthBlocks,
|
|
17505
17751
|
interleaveMs: opts.fecInterleaveMs,
|
|
@@ -18422,7 +18668,7 @@ _readIndex = new WeakMap();
|
|
|
18422
18668
|
_stalled = new WeakMap();
|
|
18423
18669
|
|
|
18424
18670
|
// src/mmtp-decode-pipeline.ts
|
|
18425
|
-
var _parser2, _fecClient, _frameCb2, _initCb2, _needsKeyframe, _codec, _trackType, _gateDropped, _gateEmitted,
|
|
18671
|
+
var _parser2, _fecClient, _frameCb2, _initCb2, _needsKeyframe, _codec, _trackType, _gateDropped, _gateEmitted, _fedObjects2, _warnedNoParser, _feedOutcomes2, _MmtpDecodePipeline_instances, tag_fn, gatedEmit_fn;
|
|
18426
18672
|
var MmtpDecodePipeline = class {
|
|
18427
18673
|
constructor() {
|
|
18428
18674
|
__privateAdd(this, _MmtpDecodePipeline_instances);
|
|
@@ -18442,7 +18688,7 @@ var MmtpDecodePipeline = class {
|
|
|
18442
18688
|
* emitted. Bounded logging only — these gate nothing. */
|
|
18443
18689
|
__privateAdd(this, _gateDropped, 0);
|
|
18444
18690
|
__privateAdd(this, _gateEmitted, 0);
|
|
18445
|
-
__privateAdd(this,
|
|
18691
|
+
__privateAdd(this, _fedObjects2, 0);
|
|
18446
18692
|
/** Warned-once latch for feeds arriving with no parser. Kept separate from
|
|
18447
18693
|
* #fedObjects so that counter stays a pure monotonic count. */
|
|
18448
18694
|
__privateAdd(this, _warnedNoParser, false);
|
|
@@ -18451,16 +18697,16 @@ var MmtpDecodePipeline = class {
|
|
|
18451
18697
|
* so a packet that fails header parse, fails MFU extraction, or accumulates
|
|
18452
18698
|
* forever as an unreassembled fragment is indistinguishable from one that
|
|
18453
18699
|
* produced a frame. Tally the kinds instead of guessing. */
|
|
18454
|
-
__privateAdd(this,
|
|
18700
|
+
__privateAdd(this, _feedOutcomes2, /* @__PURE__ */ new Map());
|
|
18455
18701
|
}
|
|
18456
18702
|
/** Configure the inner parser. Call before feedMoqObject(). */
|
|
18457
18703
|
configure(config) {
|
|
18458
18704
|
__privateGet(this, _parser2)?.flush();
|
|
18459
18705
|
__privateGet(this, _parser2)?.dispose();
|
|
18460
|
-
__privateSet(this,
|
|
18706
|
+
__privateSet(this, _fedObjects2, 0);
|
|
18461
18707
|
__privateSet(this, _gateDropped, 0);
|
|
18462
18708
|
__privateSet(this, _gateEmitted, 0);
|
|
18463
|
-
__privateGet(this,
|
|
18709
|
+
__privateGet(this, _feedOutcomes2).clear();
|
|
18464
18710
|
__privateSet(this, _warnedNoParser, false);
|
|
18465
18711
|
__privateSet(this, _codec, config.codec);
|
|
18466
18712
|
const trackType = isVideoCodec(config.codec) ? "video" : "audio";
|
|
@@ -18520,10 +18766,10 @@ var MmtpDecodePipeline = class {
|
|
|
18520
18766
|
return {
|
|
18521
18767
|
trackType: __privateGet(this, _trackType),
|
|
18522
18768
|
codec: __privateGet(this, _codec),
|
|
18523
|
-
fedObjects: __privateGet(this,
|
|
18769
|
+
fedObjects: __privateGet(this, _fedObjects2),
|
|
18524
18770
|
emitted: __privateGet(this, _gateEmitted),
|
|
18525
18771
|
gateDropped: __privateGet(this, _gateDropped),
|
|
18526
|
-
outcomes: Object.fromEntries(__privateGet(this,
|
|
18772
|
+
outcomes: Object.fromEntries(__privateGet(this, _feedOutcomes2))
|
|
18527
18773
|
};
|
|
18528
18774
|
}
|
|
18529
18775
|
/**
|
|
@@ -18538,8 +18784,8 @@ var MmtpDecodePipeline = class {
|
|
|
18538
18784
|
}
|
|
18539
18785
|
return;
|
|
18540
18786
|
}
|
|
18541
|
-
__privateSet(this,
|
|
18542
|
-
if (__privateGet(this,
|
|
18787
|
+
__privateSet(this, _fedObjects2, __privateGet(this, _fedObjects2) + 1);
|
|
18788
|
+
if (__privateGet(this, _fedObjects2) === 1) {
|
|
18543
18789
|
console.log(`[mmtp-pipeline] first object fed ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} bytes=${packet.length}`);
|
|
18544
18790
|
}
|
|
18545
18791
|
let outcomeKind = "threw";
|
|
@@ -18553,18 +18799,18 @@ var MmtpDecodePipeline = class {
|
|
|
18553
18799
|
const record = __privateGet(this, _parser2).feed(packet);
|
|
18554
18800
|
outcomeKind = record?.kind ?? "null(parse-or-extract-failed)";
|
|
18555
18801
|
} finally {
|
|
18556
|
-
const seen = (__privateGet(this,
|
|
18557
|
-
__privateGet(this,
|
|
18802
|
+
const seen = (__privateGet(this, _feedOutcomes2).get(outcomeKind) ?? 0) + 1;
|
|
18803
|
+
__privateGet(this, _feedOutcomes2).set(outcomeKind, seen);
|
|
18558
18804
|
if (seen === 1) {
|
|
18559
18805
|
console.log(
|
|
18560
|
-
`[mmtp-pipeline] feed outcome FIRST '${outcomeKind}' ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} at object #${__privateGet(this,
|
|
18806
|
+
`[mmtp-pipeline] feed outcome FIRST '${outcomeKind}' ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} at object #${__privateGet(this, _fedObjects2)} bytes=${packet.length}`
|
|
18561
18807
|
);
|
|
18562
18808
|
}
|
|
18563
18809
|
}
|
|
18564
|
-
if (__privateGet(this,
|
|
18565
|
-
const hist = [...__privateGet(this,
|
|
18810
|
+
if (__privateGet(this, _fedObjects2) % 200 === 0) {
|
|
18811
|
+
const hist = [...__privateGet(this, _feedOutcomes2)].map(([k, v]) => `${k}=${v}`).join(" ");
|
|
18566
18812
|
console.log(
|
|
18567
|
-
`[mmtp-pipeline] feed histogram ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} @${__privateGet(this,
|
|
18813
|
+
`[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
18814
|
);
|
|
18569
18815
|
}
|
|
18570
18816
|
}
|
|
@@ -18631,9 +18877,9 @@ _codec = new WeakMap();
|
|
|
18631
18877
|
_trackType = new WeakMap();
|
|
18632
18878
|
_gateDropped = new WeakMap();
|
|
18633
18879
|
_gateEmitted = new WeakMap();
|
|
18634
|
-
|
|
18880
|
+
_fedObjects2 = new WeakMap();
|
|
18635
18881
|
_warnedNoParser = new WeakMap();
|
|
18636
|
-
|
|
18882
|
+
_feedOutcomes2 = new WeakMap();
|
|
18637
18883
|
_MmtpDecodePipeline_instances = new WeakSet();
|
|
18638
18884
|
/** Identity prefix for diagnostics: one pipeline per track means two
|
|
18639
18885
|
* instances write to the same console, and unlabelled lines interleave into
|
|
@@ -18649,7 +18895,7 @@ gatedEmit_fn = function(data, meta) {
|
|
|
18649
18895
|
__privateSet(this, _gateDropped, __privateGet(this, _gateDropped) + 1);
|
|
18650
18896
|
if (__privateGet(this, _gateDropped) <= 3 || __privateGet(this, _gateDropped) % 200 === 0) {
|
|
18651
18897
|
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,
|
|
18898
|
+
`[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
18899
|
);
|
|
18654
18900
|
}
|
|
18655
18901
|
return;
|
|
@@ -18657,7 +18903,7 @@ gatedEmit_fn = function(data, meta) {
|
|
|
18657
18903
|
__privateSet(this, _needsKeyframe, false);
|
|
18658
18904
|
sourceDiscontinuity = true;
|
|
18659
18905
|
console.log(
|
|
18660
|
-
`[mmtp-pipeline] keyframe gate OPENED ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} after ${__privateGet(this, _gateDropped)} drops, fed=${__privateGet(this,
|
|
18906
|
+
`[mmtp-pipeline] keyframe gate OPENED ${__privateMethod(this, _MmtpDecodePipeline_instances, tag_fn).call(this)} after ${__privateGet(this, _gateDropped)} drops, fed=${__privateGet(this, _fedObjects2)}`
|
|
18661
18907
|
);
|
|
18662
18908
|
}
|
|
18663
18909
|
__privateSet(this, _gateEmitted, __privateGet(this, _gateEmitted) + 1);
|
|
@@ -19361,6 +19607,16 @@ var NO_FEC = {
|
|
|
19361
19607
|
fecSymbolSize: 0,
|
|
19362
19608
|
fecInterleaveMs: 0
|
|
19363
19609
|
};
|
|
19610
|
+
function joinedRepairSymbolCount(params, joinedRepairTrackNames) {
|
|
19611
|
+
const layers = params.repairLayers;
|
|
19612
|
+
if (layers === void 0 || layers.length === 0) return params.fecRepairCount;
|
|
19613
|
+
const joined = new Set(joinedRepairTrackNames);
|
|
19614
|
+
let total = 0;
|
|
19615
|
+
for (const layer of layers) {
|
|
19616
|
+
if (joined.has(layer.repairTrackName)) total += layer.repairSymbols;
|
|
19617
|
+
}
|
|
19618
|
+
return total;
|
|
19619
|
+
}
|
|
19364
19620
|
function recordOf(value) {
|
|
19365
19621
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
19366
19622
|
}
|
|
@@ -19790,6 +20046,7 @@ export {
|
|
|
19790
20046
|
isSignalingPacket,
|
|
19791
20047
|
isSourcePacket,
|
|
19792
20048
|
isTrackTimingConfig,
|
|
20049
|
+
joinedRepairSymbolCount,
|
|
19793
20050
|
mergeOverrideIntoCmsfTracks,
|
|
19794
20051
|
mergeOverrideIntoHangRenditions,
|
|
19795
20052
|
mfuReassemblyTimeoutMs,
|