@blockcast/mmt-container 2.2.0-main.02321582f1ca → 2.2.0-main.0a7228501631
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 +274 -52
- package/dist/browser-runtime.js.map +3 -3
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +11 -2
- package/dist/fec-manager.js.map +2 -2
- package/dist/mmtp-container-parser.d.ts +42 -8
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +121 -17
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +120 -18
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/mmtp-decode-pipeline.js +121 -17
- package/dist/mmtp-decode-pipeline.js.map +2 -2
- package/dist/mmtp-router.d.ts +14 -3
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +261 -48
- package/dist/mmtp-router.js.map +2 -2
- package/dist/multicast-manager.js +274 -52
- package/dist/multicast-manager.js.map +2 -2
- package/dist/multicast-transport.js +2 -2
- package/dist/multicast-transport.js.map +2 -2
- package/dist/no-modules.js +121 -17
- package/dist/no-modules.js.map +2 -2
- package/dist/wasm-mmtp-container-parser.js +121 -17
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/package.json +5 -5
- package/src/fec-manager.ts +23 -2
- package/src/mmtp-container-parser.ts +210 -21
- package/src/mmtp-router.ts +232 -54
package/dist/browser-runtime.js
CHANGED
|
@@ -8625,9 +8625,9 @@ async function openSubscription(rx, openedPromise, options, packetIds) {
|
|
|
8625
8625
|
} catch (error) {
|
|
8626
8626
|
throw new MulticastError("subscription-failed", "MulticastReceiver did not open", error);
|
|
8627
8627
|
}
|
|
8628
|
-
if (
|
|
8628
|
+
if (opened.integrityScheme !== INTEGRITY_SCHEME) {
|
|
8629
8629
|
await rx.close();
|
|
8630
|
-
throw unsupported(`integrity scheme ${String(
|
|
8630
|
+
throw unsupported(`integrity scheme ${String(opened.integrityScheme)} is not ${INTEGRITY_SCHEME}`);
|
|
8631
8631
|
}
|
|
8632
8632
|
const events = new EventTarget();
|
|
8633
8633
|
let state = "connected";
|
|
@@ -16844,9 +16844,15 @@ var FECManager = class _FECManager {
|
|
|
16844
16844
|
rebuilt = /* @__PURE__ */ new Set();
|
|
16845
16845
|
this.#blockRebuiltEsis.set(key, rebuilt);
|
|
16846
16846
|
}
|
|
16847
|
+
const config = this.#trackConfigs.get(packetId);
|
|
16848
|
+
const wasShort = config !== void 0 && this.#lateSourceWaitMs(key, sbn, packetId, catalogTrackName, config) !== void 0;
|
|
16847
16849
|
rebuilt.add(located.esi);
|
|
16848
16850
|
const recovered = this.#feedDecoderSource(packetId, ssId, symbolData, catalogTrackName, sbn);
|
|
16849
|
-
if (recovered === null
|
|
16851
|
+
if (recovered === null && !this.#completeWhenSourcesPresent(key, sbn, located.block.length, packetId, catalogTrackName)) {
|
|
16852
|
+
if (wasShort && this.#activeBlocks.has(key) && this.#lateSourceWaitMs(key, sbn, packetId, catalogTrackName, config) === void 0) {
|
|
16853
|
+
this.#armBlockTimeout(sbn, packetId, catalogTrackName, this.#multicastWaitMs(config));
|
|
16854
|
+
}
|
|
16855
|
+
}
|
|
16850
16856
|
return { taken: true, recovered };
|
|
16851
16857
|
}
|
|
16852
16858
|
/**
|
|
@@ -17113,7 +17119,10 @@ var FECManager = class _FECManager {
|
|
|
17113
17119
|
const authoredLength = this.#blockAuthoredLengths.get(key);
|
|
17114
17120
|
const rsbLength = this.#blockRsbLengths.get(key);
|
|
17115
17121
|
if (authoredLength === void 0 || rsbLength === void 0) return void 0;
|
|
17116
|
-
|
|
17122
|
+
let present = this.#blockSourceCounts.get(key) ?? 0;
|
|
17123
|
+
const received = this.#blockSourceEsis.get(key);
|
|
17124
|
+
for (const esi of this.#blockRebuiltEsis.get(key) ?? []) if (!received?.has(esi)) present++;
|
|
17125
|
+
if (present + rsbLength >= authoredLength) return void 0;
|
|
17117
17126
|
const newestSource = this.#isoLocators.get(this.#streamKey(packetId, catalogTrackName))?.newestSource;
|
|
17118
17127
|
if (newestSource === void 0 || !serial32Precedes(serial32Add(sbn, authoredLength - 1), newestSource)) {
|
|
17119
17128
|
return void 0;
|
|
@@ -18433,6 +18442,9 @@ function authoredGap(before, after) {
|
|
|
18433
18442
|
function ssIdAfter(a, b) {
|
|
18434
18443
|
return (a - b | 0) > 0;
|
|
18435
18444
|
}
|
|
18445
|
+
function holdsRebuilt(stream) {
|
|
18446
|
+
return stream.buf.some(({ meta }) => meta.fecSbnFirst !== void 0);
|
|
18447
|
+
}
|
|
18436
18448
|
var FecReleaseSequencer = class {
|
|
18437
18449
|
#streams = /* @__PURE__ */ new Map();
|
|
18438
18450
|
#gate;
|
|
@@ -18495,6 +18507,7 @@ var FecReleaseSequencer = class {
|
|
|
18495
18507
|
stream.lastSbn = void 0;
|
|
18496
18508
|
stream.discontinuity = false;
|
|
18497
18509
|
stream.rapSsId = void 0;
|
|
18510
|
+
stream.sourced = false;
|
|
18498
18511
|
}
|
|
18499
18512
|
if (stream.last !== null && compareFrameOrder(frame, stream.last) <= 0) {
|
|
18500
18513
|
this.#recordStat("droppedStale");
|
|
@@ -18521,6 +18534,7 @@ var FecReleaseSequencer = class {
|
|
|
18521
18534
|
if (compareFrameOrder(stream.buf[mid], frame) < 0) lo = mid + 1;
|
|
18522
18535
|
else hi = mid;
|
|
18523
18536
|
}
|
|
18537
|
+
if (stream.buf[lo]?.passed === true) frame.passed = true;
|
|
18524
18538
|
stream.buf.splice(lo, 0, frame);
|
|
18525
18539
|
this.#drainUnlessDeferred(stream);
|
|
18526
18540
|
}
|
|
@@ -18556,6 +18570,41 @@ var FecReleaseSequencer = class {
|
|
|
18556
18570
|
}
|
|
18557
18571
|
return false;
|
|
18558
18572
|
}
|
|
18573
|
+
/**
|
|
18574
|
+
* These streams' sink is being replaced by one that has seen no source
|
|
18575
|
+
* frame yet. First, from a stream that holds a frame the overlay rebuilt,
|
|
18576
|
+
* release to the sink being replaced the frames the unanchored path had
|
|
18577
|
+
* already released to it (#cursorPassed): there they waited in its queue,
|
|
18578
|
+
* which its replacement flushes. A stream that holds none is not drained:
|
|
18579
|
+
* it holds nothing the anchor kept back, and a drain would still force out
|
|
18580
|
+
* a frame held past the hold limit, which before the anchor waited for the
|
|
18581
|
+
* next push. Then treat the streams as unsourced until a source frame is
|
|
18582
|
+
* released.
|
|
18583
|
+
*/
|
|
18584
|
+
unsource(packetId, catalogTrackName) {
|
|
18585
|
+
for (const stream of this.#streams.values()) {
|
|
18586
|
+
if (stream.packetId === packetId && (catalogTrackName === void 0 || stream.catalogTrackName === catalogTrackName)) {
|
|
18587
|
+
if (stream.draining === 0 && holdsRebuilt(stream)) {
|
|
18588
|
+
if (this.#deferDepth > 0) this.#deferredStreams.add(stream);
|
|
18589
|
+
else this.#drain(stream, true);
|
|
18590
|
+
}
|
|
18591
|
+
stream.sourced = false;
|
|
18592
|
+
}
|
|
18593
|
+
}
|
|
18594
|
+
}
|
|
18595
|
+
/**
|
|
18596
|
+
* Whether a stream of `packetId` holds a frame the keyframe overlay rebuilt
|
|
18597
|
+
* (FrameMeta.fecSbnFirst). Without `catalogTrackName`, every stream of the
|
|
18598
|
+
* packetId.
|
|
18599
|
+
*/
|
|
18600
|
+
holdsRebuilt(packetId, catalogTrackName) {
|
|
18601
|
+
for (const stream of this.#streams.values()) {
|
|
18602
|
+
if (stream.packetId !== packetId) continue;
|
|
18603
|
+
if (catalogTrackName !== void 0 && stream.catalogTrackName !== catalogTrackName) continue;
|
|
18604
|
+
if (holdsRebuilt(stream)) return true;
|
|
18605
|
+
}
|
|
18606
|
+
return false;
|
|
18607
|
+
}
|
|
18559
18608
|
/** Re-evaluate held gaps after FEC state changed. */
|
|
18560
18609
|
poke(streamKey) {
|
|
18561
18610
|
if (streamKey !== void 0) {
|
|
@@ -18647,16 +18696,32 @@ var FecReleaseSequencer = class {
|
|
|
18647
18696
|
last: null,
|
|
18648
18697
|
lastSbn: void 0,
|
|
18649
18698
|
discontinuity: false,
|
|
18650
|
-
rapSsId: void 0
|
|
18699
|
+
rapSsId: void 0,
|
|
18700
|
+
sourced: false,
|
|
18701
|
+
draining: 0
|
|
18651
18702
|
};
|
|
18652
18703
|
this.#streams.set(streamKey, stream);
|
|
18653
18704
|
}
|
|
18654
18705
|
return stream;
|
|
18655
18706
|
}
|
|
18656
|
-
#
|
|
18707
|
+
/** `asUnanchored`: release overlay-rebuilt frames when unanchored did (#cursorPassed). */
|
|
18708
|
+
#drain(stream, asUnanchored = false) {
|
|
18709
|
+
stream.draining++;
|
|
18710
|
+
try {
|
|
18711
|
+
this.#drainLoop(stream, asUnanchored);
|
|
18712
|
+
} finally {
|
|
18713
|
+
stream.draining--;
|
|
18714
|
+
}
|
|
18715
|
+
}
|
|
18716
|
+
#drainLoop(stream, asUnanchored) {
|
|
18657
18717
|
while (stream.buf.length > 0 && stream.last !== null) {
|
|
18658
18718
|
const head = stream.buf[0];
|
|
18659
18719
|
const last = stream.last;
|
|
18720
|
+
if (compareFrameOrder(head, last) <= 0) {
|
|
18721
|
+
stream.buf.shift();
|
|
18722
|
+
this.#release(stream, head, void 0);
|
|
18723
|
+
continue;
|
|
18724
|
+
}
|
|
18660
18725
|
if (stream.discontinuity) {
|
|
18661
18726
|
stream.discontinuity = false;
|
|
18662
18727
|
stream.buf.shift();
|
|
@@ -18670,9 +18735,10 @@ var FecReleaseSequencer = class {
|
|
|
18670
18735
|
}
|
|
18671
18736
|
const headSbn = head.meta.fecSbn;
|
|
18672
18737
|
const from = stream.lastSbn ?? headSbn;
|
|
18673
|
-
const to = headSbn ?? stream.lastSbn;
|
|
18738
|
+
const to = head.meta.fecSbnFirst ?? headSbn ?? stream.lastSbn;
|
|
18674
18739
|
let lost = [];
|
|
18675
18740
|
const unanchored = from === void 0 && to === void 0;
|
|
18741
|
+
let unresolved = false;
|
|
18676
18742
|
if (from !== void 0 && to !== void 0) {
|
|
18677
18743
|
const resolved = this.#gate.resolvedLoss(
|
|
18678
18744
|
stream.packetId,
|
|
@@ -18681,7 +18747,8 @@ var FecReleaseSequencer = class {
|
|
|
18681
18747
|
Math.max(from, to),
|
|
18682
18748
|
from
|
|
18683
18749
|
);
|
|
18684
|
-
|
|
18750
|
+
unresolved = resolved === null;
|
|
18751
|
+
if (unresolved && !this.#cursorPassed(stream, asUnanchored)) {
|
|
18685
18752
|
const heldMs = performance.now() - head.arrivedAtMs;
|
|
18686
18753
|
if (heldMs <= this.#gate.holdLimitMs(stream.packetId, stream.catalogTrackName)) return;
|
|
18687
18754
|
this.#recordStat("forcedWindowFlushes");
|
|
@@ -18689,22 +18756,56 @@ var FecReleaseSequencer = class {
|
|
|
18689
18756
|
this.#release(stream, head, this.#gate.decide(last, head, [], true));
|
|
18690
18757
|
continue;
|
|
18691
18758
|
}
|
|
18692
|
-
lost = resolved;
|
|
18759
|
+
lost = resolved ?? [];
|
|
18693
18760
|
}
|
|
18694
18761
|
stream.buf.shift();
|
|
18695
18762
|
this.#release(
|
|
18696
18763
|
stream,
|
|
18697
18764
|
head,
|
|
18698
|
-
lost.length > 0 || unanchored || authoredGap(last.meta, head.meta) ? this.#gate.decide(last, head, lost, false) : void 0
|
|
18765
|
+
lost.length > 0 || unanchored || unresolved || authoredGap(last.meta, head.meta) ? this.#gate.decide(last, head, lost, false) : void 0
|
|
18699
18766
|
);
|
|
18700
18767
|
}
|
|
18701
18768
|
}
|
|
18769
|
+
/**
|
|
18770
|
+
* An overlay-rebuilt frame (fecSbnFirst) waits no longer than the BLO-53342
|
|
18771
|
+
* source cursor holds it unanchored, and neither does a later frame behind
|
|
18772
|
+
* it. Unanchored, a frame that waits on no block (fecSbnFirst set, or no
|
|
18773
|
+
* fecSbn) left the gate once every frame ahead of it had: mark it `passed`,
|
|
18774
|
+
* like each frame that arrived in front of it since (stale there). The head
|
|
18775
|
+
* then goes, decided as it would be unanchored, once a frame the base path
|
|
18776
|
+
* delivered (a source frame, or one base FEC recovered) is buffered after a
|
|
18777
|
+
* marked one: the base path has passed that one, so a frame still missing
|
|
18778
|
+
* before it can only come from a repair. It also goes while no source frame
|
|
18779
|
+
* has been released, when the direct path shows a recovered frame at once.
|
|
18780
|
+
* And it goes at once while a staged switch decides on when frames arrive
|
|
18781
|
+
* (FecReleaseGate.releaseUnanchored), and when unsource releases into a
|
|
18782
|
+
* sink being replaced: unanchored, it had already reached the sink.
|
|
18783
|
+
* The scan also writes: the `passed` marks it sets stay on the frames,
|
|
18784
|
+
* and push marks a frame it inserts in front of a marked one from them.
|
|
18785
|
+
*/
|
|
18786
|
+
#cursorPassed(stream, asUnanchored) {
|
|
18787
|
+
let at2 = -1;
|
|
18788
|
+
for (let i = 0; i < stream.buf.length; i++) {
|
|
18789
|
+
const frame = stream.buf[i];
|
|
18790
|
+
if (frame.meta.fecSbnFirst !== void 0 || frame.meta.fecSbn === void 0) {
|
|
18791
|
+
frame.passed = true;
|
|
18792
|
+
if (at2 < 0) at2 = i;
|
|
18793
|
+
} else if (frame.passed !== true) break;
|
|
18794
|
+
}
|
|
18795
|
+
if (at2 < 0) return false;
|
|
18796
|
+
return asUnanchored || !stream.sourced || this.#gate.releaseUnanchored?.(stream.packetId, stream.catalogTrackName) === true || stream.buf.some(({ meta }, i) => i > at2 && meta.fecSbnFirst === void 0 && (meta.recovered !== true || meta.fecSbn !== void 0));
|
|
18797
|
+
}
|
|
18702
18798
|
#release(stream, frame, decision) {
|
|
18799
|
+
const stale = stream.last !== null && compareFrameOrder(frame, stream.last) <= 0;
|
|
18800
|
+
if (stale) this.#recordStat("droppedStale");
|
|
18703
18801
|
if (decision) frame.meta.gapBefore = decision;
|
|
18704
18802
|
stream.last = frame;
|
|
18705
|
-
if (frame.meta.fecSbn !== void 0
|
|
18803
|
+
if (frame.meta.fecSbn !== void 0 && (frame.meta.fecSbnFirst === void 0 || stream.lastSbn !== void 0)) {
|
|
18804
|
+
stream.lastSbn = frame.meta.fecSbn;
|
|
18805
|
+
}
|
|
18806
|
+
if (frame.meta.recovered !== true) stream.sourced = true;
|
|
18706
18807
|
this.#gate.onReleased?.(frame.data, frame.meta);
|
|
18707
|
-
this.#emit(frame.data, frame.meta);
|
|
18808
|
+
if (!stale) this.#emit(frame.data, frame.meta);
|
|
18708
18809
|
}
|
|
18709
18810
|
};
|
|
18710
18811
|
var FMPU_BOX_TYPES = /* @__PURE__ */ new Set(["ftyp", "moov", "moof"]);
|
|
@@ -18965,11 +19066,12 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
18965
19066
|
/**
|
|
18966
19067
|
* Typed view of the ISO-BMFF timing-sample budget.
|
|
18967
19068
|
*
|
|
18968
|
-
*
|
|
18969
|
-
*
|
|
18970
|
-
*
|
|
18971
|
-
*
|
|
18972
|
-
*
|
|
19069
|
+
* Each stream admits timing against its own window of `capacity` slots
|
|
19070
|
+
* (BLO-52085). A stream at capacity displaces its own oldest timing to
|
|
19071
|
+
* admit the moof in hand, and `evicted` counts the slots so displaced:
|
|
19072
|
+
* timing a stream declared and never delivered shows up there. `pending`
|
|
19073
|
+
* sums every stream, so it can exceed `capacity`. Per repo policy this is
|
|
19074
|
+
* a producer-owned counter -- never infer budget state by parsing logs.
|
|
18973
19075
|
*/
|
|
18974
19076
|
get timingBudgetStats() {
|
|
18975
19077
|
return {
|
|
@@ -19029,6 +19131,14 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
19029
19131
|
fecReleaseRapAbove(packetId, catalogTrackName, ssId) {
|
|
19030
19132
|
return this.#fecSequencer?.rapAbove(packetId, catalogTrackName, ssId) ?? false;
|
|
19031
19133
|
}
|
|
19134
|
+
/** See FecReleaseSequencer.unsource. */
|
|
19135
|
+
unsourceFecRelease(packetId, catalogTrackName) {
|
|
19136
|
+
this.#fecSequencer?.unsource(packetId, catalogTrackName);
|
|
19137
|
+
}
|
|
19138
|
+
/** See FecReleaseSequencer.holdsRebuilt. */
|
|
19139
|
+
fecReleaseHoldsRebuilt(packetId, catalogTrackName) {
|
|
19140
|
+
return this.#fecSequencer?.holdsRebuilt(packetId, catalogTrackName) ?? false;
|
|
19141
|
+
}
|
|
19032
19142
|
/** Re-evaluate held gaps after FEC block state changed. */
|
|
19033
19143
|
pokeFecRelease(packetId, catalogTrackName) {
|
|
19034
19144
|
if (!this.#fecSequencer) return;
|
|
@@ -19282,7 +19392,7 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
19282
19392
|
if (!resolver2?.initialized) return this.#drop("fragment-no-resolver");
|
|
19283
19393
|
const pendingBefore = resolver2.pendingSampleCount;
|
|
19284
19394
|
const evictedBefore = resolver2.evictedSampleCount;
|
|
19285
|
-
const remaining = this.#maxPendingTimingSamples -
|
|
19395
|
+
const remaining = this.#maxPendingTimingSamples - resolver2.pendingSampleCount;
|
|
19286
19396
|
const admitted = resolver2.addMovieFragment(
|
|
19287
19397
|
mpu.mpuSequenceNumber,
|
|
19288
19398
|
data,
|
|
@@ -19355,7 +19465,8 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
19355
19465
|
info,
|
|
19356
19466
|
resolver,
|
|
19357
19467
|
options?.recovered === true,
|
|
19358
|
-
options?.fecSbn
|
|
19468
|
+
options?.fecSbn,
|
|
19469
|
+
options?.fecSbnFirst
|
|
19359
19470
|
);
|
|
19360
19471
|
if (deferred.record === void 0) this.#countDeferredOutcome(deferred.reason);
|
|
19361
19472
|
}
|
|
@@ -19448,7 +19559,8 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
19448
19559
|
info,
|
|
19449
19560
|
resolver,
|
|
19450
19561
|
options?.recovered === true,
|
|
19451
|
-
options?.fecSbn
|
|
19562
|
+
options?.fecSbn,
|
|
19563
|
+
options?.fecSbnFirst
|
|
19452
19564
|
);
|
|
19453
19565
|
if (outcome.record !== void 0) return outcome.record;
|
|
19454
19566
|
return this.#drop(outcome.reason);
|
|
@@ -19468,7 +19580,7 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
19468
19580
|
* attribution exists to keep readable. Leaving the choice at the call site
|
|
19469
19581
|
* is what keeps both true.
|
|
19470
19582
|
*/
|
|
19471
|
-
#emitCombinedSample(combined, info, resolver, recovered, fecSbn) {
|
|
19583
|
+
#emitCombinedSample(combined, info, resolver, recovered, fecSbn, fecSbnFirst) {
|
|
19472
19584
|
const timing = resolver.sampleTiming(
|
|
19473
19585
|
combined.mpuSequenceNumber,
|
|
19474
19586
|
combined.movieFragmentSequenceNumber,
|
|
@@ -19485,6 +19597,7 @@ var MmtpContainerParser = class _MmtpContainerParser {
|
|
|
19485
19597
|
);
|
|
19486
19598
|
if (!meta) return { reason: "combined-meta-build-failed" };
|
|
19487
19599
|
if (fecSbn !== void 0) meta.fecSbn = fecSbn;
|
|
19600
|
+
if (fecSbnFirst !== void 0) meta.fecSbnFirst = fecSbnFirst;
|
|
19488
19601
|
if (!resolver.consumeSample(
|
|
19489
19602
|
combined.mpuSequenceNumber,
|
|
19490
19603
|
combined.movieFragmentSequenceNumber,
|
|
@@ -23001,6 +23114,7 @@ function unstampedBaseSsId(offset, unstampedOffset, headerPsn) {
|
|
|
23001
23114
|
var OVERLAY_ROUTED_LIMIT = 1024;
|
|
23002
23115
|
var OVERLAY_PENDING_LIMIT = 256;
|
|
23003
23116
|
var OVERLAY_OFFSET_MPUS = 16;
|
|
23117
|
+
var OVERLAY_REBUILT_LIMIT = 256;
|
|
23004
23118
|
var OVERLAY_MOQ_HORIZON_BLOCKS = 64;
|
|
23005
23119
|
function assertStreamIdentity(role, stream) {
|
|
23006
23120
|
if (stream === void 0 || !Number.isInteger(stream.packetId) || stream.packetId <= MMTP_SIGNALING_PACKET_ID || typeof stream.catalogTrackName !== "string" || stream.catalogTrackName.length === 0) {
|
|
@@ -23111,6 +23225,7 @@ var MmtpRouter = class {
|
|
|
23111
23225
|
#provenance = /* @__PURE__ */ new Map();
|
|
23112
23226
|
#onFlowProtected = null;
|
|
23113
23227
|
#unadmittedListedDrops = 0;
|
|
23228
|
+
#admittedSourceDatagrams = 0;
|
|
23114
23229
|
#unlistedRepairSetAside = 0;
|
|
23115
23230
|
#assistBlocks = /* @__PURE__ */ new Map();
|
|
23116
23231
|
#assistFailures = /* @__PURE__ */ new Map();
|
|
@@ -23171,10 +23286,22 @@ var MmtpRouter = class {
|
|
|
23171
23286
|
* Per stream, the SS_ID offset at which a base recovery last showed the
|
|
23172
23287
|
* sender's own packet_sequence_number: a recovered packet's header psn
|
|
23173
23288
|
* equal to its SS_ID minus that offset. While it equals the stream's
|
|
23174
|
-
* current offset, no hop re-stamps the stream and a packet's protected psn
|
|
23175
|
-
* names its base SS_ID (joint decoding of
|
|
23289
|
+
* current offset, no hop re-stamps the stream, and a packet's protected psn
|
|
23290
|
+
* names its base SS_ID within unstampedBaseSsId's limits (joint decoding of
|
|
23291
|
+
* an MPU no member of which arrived).
|
|
23176
23292
|
*/
|
|
23177
23293
|
#unstampedSsIdSeqOffsetByStream = /* @__PURE__ */ new Map();
|
|
23294
|
+
/**
|
|
23295
|
+
* The same, shown by the overlay alone, before any base recovery did: a
|
|
23296
|
+
* packet it rebuilt whose base copy carries its protected psn
|
|
23297
|
+
* (#feedOverlaySource), or whose protected psn passes overlayBaseSsId's
|
|
23298
|
+
* test at that offset (#routeOverlayRecovered). A base SS_ID placed by it
|
|
23299
|
+
* anchors the release gate only (BLO-52085 D3): fed to the base, it would
|
|
23300
|
+
* make the base drop a late base copy of a keyframe the overlay never
|
|
23301
|
+
* finished, and lift a block's late-source cut, which nothing before
|
|
23302
|
+
* this offset did.
|
|
23303
|
+
*/
|
|
23304
|
+
#overlayUnstampedSsIdSeqOffsetByStream = /* @__PURE__ */ new Map();
|
|
23178
23305
|
/**
|
|
23179
23306
|
* Streams whose multicast leg delivered a RAP-flagged source packet that was
|
|
23180
23307
|
* not parsed, typically because its overlap copy was parsed first
|
|
@@ -23503,8 +23630,9 @@ var MmtpRouter = class {
|
|
|
23503
23630
|
}
|
|
23504
23631
|
/**
|
|
23505
23632
|
* FEC-recovered source symbols whose reconstructed header named a
|
|
23506
|
-
* packet_sequence_number other than the wire sequence their SS_ID maps to
|
|
23507
|
-
*
|
|
23633
|
+
* packet_sequence_number other than the wire sequence their SS_ID maps to,
|
|
23634
|
+
* or, rebuilt by the overlay, than their base copy carries: a hop
|
|
23635
|
+
* re-stamped the sequence after the sender protected the packet.
|
|
23508
23636
|
*/
|
|
23509
23637
|
get restampedRecoveredSequenceCount() {
|
|
23510
23638
|
return this.#restampedRecoveredSeqs;
|
|
@@ -23683,6 +23811,7 @@ var MmtpRouter = class {
|
|
|
23683
23811
|
enableMseAssembler(packetId, config, catalogTrackName) {
|
|
23684
23812
|
const assemblerKey = this.#mseAssemblerKey(packetId, catalogTrackName);
|
|
23685
23813
|
const previous = this.#mseAssemblers.get(assemblerKey);
|
|
23814
|
+
this.#parser.unsourceFecRelease(packetId, catalogTrackName);
|
|
23686
23815
|
if (previous) {
|
|
23687
23816
|
previous.flush();
|
|
23688
23817
|
previous.dispose();
|
|
@@ -23833,7 +23962,8 @@ var MmtpRouter = class {
|
|
|
23833
23962
|
fec,
|
|
23834
23963
|
k,
|
|
23835
23964
|
offsets: /* @__PURE__ */ new Map(),
|
|
23836
|
-
moqBlocks: /* @__PURE__ */ new Set()
|
|
23965
|
+
moqBlocks: /* @__PURE__ */ new Set(),
|
|
23966
|
+
rebuilt: /* @__PURE__ */ new Map()
|
|
23837
23967
|
};
|
|
23838
23968
|
this.#overlays.set(repairPacketId, inst);
|
|
23839
23969
|
return () => {
|
|
@@ -23874,6 +24004,7 @@ var MmtpRouter = class {
|
|
|
23874
24004
|
inst.last = void 0;
|
|
23875
24005
|
inst.offsets.clear();
|
|
23876
24006
|
inst.moqBlocks.clear();
|
|
24007
|
+
inst.rebuilt.clear();
|
|
23877
24008
|
}
|
|
23878
24009
|
#overlaysForSource(sourcePacketId, catalogTrackName) {
|
|
23879
24010
|
return [...this.#overlays.values()].filter(({ leg }) => leg.sourcePacketId === sourcePacketId && (catalogTrackName === void 0 || leg.sourceCatalogTrackName === void 0 || leg.sourceCatalogTrackName === catalogTrackName));
|
|
@@ -23926,13 +24057,23 @@ var MmtpRouter = class {
|
|
|
23926
24057
|
* base protects: the packet minus its 4-byte SS_ID trailer, extension
|
|
23927
24058
|
* included (7.1, 7.4.3). `baseSsId` is that trailer's SS_ID, when the base
|
|
23928
24059
|
* FEC reads it.
|
|
24060
|
+
*
|
|
24061
|
+
* The base copy of a packet an overlay rebuilt with no base SS_ID shows
|
|
24062
|
+
* what a base recovery of it would (#routeProcessedFecSymbols, BLO-52085):
|
|
24063
|
+
* its wire packet_sequence_number equal to the protected one rebuilt shows
|
|
24064
|
+
* the stream unstamped at the SS_ID offset it states, for the release gate
|
|
24065
|
+
* (#overlayUnstampedSsIdSeqOffsetByStream); any other shows a hop that
|
|
24066
|
+
* re-stamps it, which is counted (restampedRecoveredSequenceCount).
|
|
23929
24067
|
*/
|
|
23930
24068
|
#feedOverlaySource(packetId, catalogTrackName, packet, header, sequenceNumber, rapFlag, source, baseSsId) {
|
|
23931
24069
|
if (this.#overlays.size === 0) return;
|
|
23932
24070
|
const ssId = keyframeOverlaySsId(header);
|
|
23933
24071
|
if (ssId === void 0) return;
|
|
24072
|
+
let rebuiltPsn;
|
|
23934
24073
|
for (const inst of this.#overlaysForSource(packetId, catalogTrackName)) {
|
|
23935
24074
|
this.#noteOverlaySsId(inst, ssId, sequenceNumber);
|
|
24075
|
+
rebuiltPsn ??= inst.rebuilt.get(ssId);
|
|
24076
|
+
inst.rebuilt.delete(ssId);
|
|
23936
24077
|
const identity = MmtpContainerParser.sourcePacketIdentity(packet, header);
|
|
23937
24078
|
if (identity !== null) {
|
|
23938
24079
|
inst.offsets.delete(identity.mpuSequenceNumber);
|
|
@@ -23962,6 +24103,14 @@ var MmtpRouter = class {
|
|
|
23962
24103
|
const recovered = fec.feedSourceSymbol(pid, ssId, symbolData, name);
|
|
23963
24104
|
if (recovered && !alreadyCompleted) this.#routeOverlayRecovered(inst, coords.sbn, recovered);
|
|
23964
24105
|
}
|
|
24106
|
+
if (rebuiltPsn === void 0 || this.#classifyPacketId(packetId) === null) return;
|
|
24107
|
+
const streamKey = this.#mediaStreamKey(packetId, catalogTrackName);
|
|
24108
|
+
if (rebuiltPsn !== sequenceNumber) {
|
|
24109
|
+
this.#restampedRecoveredSeqs++;
|
|
24110
|
+
} else if (baseSsId !== void 0) {
|
|
24111
|
+
const offset = this.#ssIdSeqOffsetByStream.get(streamKey);
|
|
24112
|
+
if (offset === baseSsId - sequenceNumber >>> 0) this.#overlayUnstampedSsIdSeqOffsetByStream.set(streamKey, offset);
|
|
24113
|
+
}
|
|
23965
24114
|
}
|
|
23966
24115
|
#noteOverlayMoqBlock(inst, blockStart) {
|
|
23967
24116
|
inst.moqBlocks.add(blockStart);
|
|
@@ -23995,11 +24144,16 @@ var MmtpRouter = class {
|
|
|
23995
24144
|
}
|
|
23996
24145
|
/**
|
|
23997
24146
|
* Route an overlay-recovered block's packets as source media of the
|
|
23998
|
-
* overlay's source (7.2: an overlay coordinate yields no base SS_ID).
|
|
23999
|
-
*
|
|
24000
|
-
*
|
|
24001
|
-
*
|
|
24002
|
-
*
|
|
24147
|
+
* overlay's source (7.2: an overlay coordinate yields no base SS_ID). A
|
|
24148
|
+
* packet whose base SS_ID is determined independently (overlayBaseSsId,
|
|
24149
|
+
* unstampedBaseSsId) enters the release gate at that SS_ID, as a packet
|
|
24150
|
+
* base FEC recovered does, so it waits behind base frames still in flight,
|
|
24151
|
+
* though not for its own MPU's packets (FrameMeta.fecSbnFirst) and no
|
|
24152
|
+
* longer than unanchored; one whose base SS_ID is undetermined has no
|
|
24153
|
+
* release-gate anchor. No parse ledger, no base re-stamp, no block
|
|
24154
|
+
* advance. Each packet's wire sequence is restored from its keyframe's own
|
|
24155
|
+
* offset; without one, a stream the base never re-stamped keeps the
|
|
24156
|
+
* header's sequence and any other drops the packet.
|
|
24003
24157
|
*/
|
|
24004
24158
|
#routeOverlayRecovered(inst, blockStart, recovered) {
|
|
24005
24159
|
const { fec, repairPacketId: pid, streamName: name } = inst;
|
|
@@ -24020,40 +24174,65 @@ var MmtpRouter = class {
|
|
|
24020
24174
|
const restamped = this.#restampedStreams.has(streamKey);
|
|
24021
24175
|
const restored = /* @__PURE__ */ new Set();
|
|
24022
24176
|
const baseSsIds = /* @__PURE__ */ new Map();
|
|
24177
|
+
const gateOnly = /* @__PURE__ */ new Set();
|
|
24023
24178
|
const symbols = result.symbols.flatMap((sym) => {
|
|
24179
|
+
const overlaySsId = serial32Add(blockStart, sym.index);
|
|
24024
24180
|
const anchor = inst.offsets.get(sym.fragment.mpuSequenceNumber);
|
|
24025
24181
|
if (anchor !== void 0) {
|
|
24026
|
-
const overlaySsId = serial32Add(blockStart, sym.index);
|
|
24027
24182
|
const packetSequenceNumber = overlaySsId - anchor.psnOffset >>> 0;
|
|
24028
24183
|
restored.add(packetSequenceNumber);
|
|
24029
24184
|
const out = { ...sym, packetSequenceNumber };
|
|
24030
24185
|
const baseSsId = overlayBaseSsId(anchor, overlaySsId, packetSequenceNumber, sym.packetSequenceNumber);
|
|
24031
|
-
if (baseSsId !== void 0)
|
|
24186
|
+
if (baseSsId !== void 0) {
|
|
24187
|
+
baseSsIds.set(sym.index, baseSsId);
|
|
24188
|
+
const offset = this.#ssIdSeqOffsetByStream.get(streamKey);
|
|
24189
|
+
if (!this.#sourceSeqReceived(sourcePacketId, packetSequenceNumber, sourceName) && offset === baseSsId - packetSequenceNumber >>> 0) {
|
|
24190
|
+
this.#overlayUnstampedSsIdSeqOffsetByStream.set(streamKey, offset);
|
|
24191
|
+
}
|
|
24192
|
+
}
|
|
24032
24193
|
return [out];
|
|
24033
24194
|
}
|
|
24034
24195
|
if (!restamped) {
|
|
24035
|
-
const
|
|
24036
|
-
|
|
24037
|
-
|
|
24038
|
-
|
|
24039
|
-
|
|
24040
|
-
|
|
24196
|
+
const offset = this.#ssIdSeqOffsetByStream.get(streamKey);
|
|
24197
|
+
const fedSsId = unstampedBaseSsId(offset, this.#unstampedSsIdSeqOffsetByStream.get(streamKey), sym.packetSequenceNumber);
|
|
24198
|
+
const baseSsId = fedSsId ?? unstampedBaseSsId(offset, this.#overlayUnstampedSsIdSeqOffsetByStream.get(streamKey), sym.packetSequenceNumber);
|
|
24199
|
+
if (baseSsId !== void 0) {
|
|
24200
|
+
baseSsIds.set(sym.index, baseSsId);
|
|
24201
|
+
if (fedSsId === void 0) gateOnly.add(sym.index);
|
|
24202
|
+
} else {
|
|
24203
|
+
inst.rebuilt.set(overlaySsId, sym.packetSequenceNumber);
|
|
24204
|
+
if (inst.rebuilt.size > OVERLAY_REBUILT_LIMIT) inst.rebuilt.delete(inst.rebuilt.keys().next().value);
|
|
24205
|
+
}
|
|
24041
24206
|
return [sym];
|
|
24042
24207
|
}
|
|
24043
24208
|
this.#overlayStats.unsequencedDropped++;
|
|
24044
24209
|
return [];
|
|
24045
24210
|
});
|
|
24046
24211
|
this.#overlayStats.recovered++;
|
|
24212
|
+
const mpuFirst = /* @__PURE__ */ new Map();
|
|
24213
|
+
for (const sym of symbols) {
|
|
24214
|
+
const ssId = baseSsIds.get(sym.index);
|
|
24215
|
+
const mpu = sym.fragment.mpuSequenceNumber;
|
|
24216
|
+
const first = mpuFirst.get(mpu);
|
|
24217
|
+
if (ssId !== void 0 && (first === void 0 || serial32Precedes(ssId, first))) mpuFirst.set(mpu, ssId);
|
|
24218
|
+
}
|
|
24219
|
+
const firstSsIds = /* @__PURE__ */ new Map();
|
|
24220
|
+
for (const sym of symbols) {
|
|
24221
|
+
if (baseSsIds.has(sym.index)) firstSsIds.set(sym.index, mpuFirst.get(sym.fragment.mpuSequenceNumber));
|
|
24222
|
+
}
|
|
24047
24223
|
this.#routeProcessedFecSymbols(blockStart, { ...result, symbols }, sourcePacketId, sourceName, {
|
|
24048
|
-
deliveryProvenance: inst.moqBlocks.has(blockStart) ? "mixed" : "multicast"
|
|
24224
|
+
deliveryProvenance: inst.moqBlocks.has(blockStart) ? "mixed" : "multicast",
|
|
24225
|
+
baseSsIds,
|
|
24226
|
+
firstSsIds
|
|
24049
24227
|
});
|
|
24050
24228
|
this.#noteOverlayRecoveredRaps(sourcePacketId, sourceName, streamKey, symbols.filter((sym) => restored.has(sym.packetSequenceNumber)));
|
|
24051
|
-
this.#feedOverlayRecoveredToBase(inst, blockStart, symbols, baseSsIds);
|
|
24229
|
+
this.#feedOverlayRecoveredToBase(inst, blockStart, symbols, gateOnly.size === 0 ? baseSsIds : new Map([...baseSsIds].filter(([index]) => !gateOnly.has(index))));
|
|
24052
24230
|
}
|
|
24053
24231
|
/**
|
|
24054
24232
|
* Joint decoding (BLO-52085). A packet the overlay rebuilt is a source of
|
|
24055
24233
|
* its base block too, once its base SS_ID is determined (overlayBaseSsId,
|
|
24056
|
-
* from a received member of its MPU, else unstampedBaseSsId
|
|
24234
|
+
* from a received member of its MPU, else unstampedBaseSsId at an offset a
|
|
24235
|
+
* base recovery showed; `baseSsIds` holds no other),
|
|
24057
24236
|
* so it is fed to the base decoder as a rebuilt source
|
|
24058
24237
|
* (FECManager.feedRebuiltSourceSymbol): the base block has one erasure
|
|
24059
24238
|
* fewer to solve, and its repair can recover the block's other packets.
|
|
@@ -24079,7 +24258,7 @@ var MmtpRouter = class {
|
|
|
24079
24258
|
const feeds = [];
|
|
24080
24259
|
for (const sym of symbols) {
|
|
24081
24260
|
if (duplicates.sourceSeqs.has(sym.packetSequenceNumber)) continue;
|
|
24082
|
-
const ssId = baseSsIds.get(sym);
|
|
24261
|
+
const ssId = baseSsIds.get(sym.index);
|
|
24083
24262
|
if (ssId === void 0) {
|
|
24084
24263
|
this.#overlayStats.baseUndetermined++;
|
|
24085
24264
|
continue;
|
|
@@ -24266,6 +24445,10 @@ var MmtpRouter = class {
|
|
|
24266
24445
|
get unadmittedListedDropCount() {
|
|
24267
24446
|
return this.#unadmittedListedDrops;
|
|
24268
24447
|
}
|
|
24448
|
+
/** Source datagrams (multicast or MoQ) a protected flow's bc-provenance v2 receiver released: admitted at once or held, then admitted by a record. Repair symbols and user-agent-admitted datagrams are not counted. Counted at release, before this router's own track checks: a released datagram those drop, which only a track change between hold and release can cause, still counts, so this is not a count of routed media. */
|
|
24449
|
+
get admittedSourceDatagramCount() {
|
|
24450
|
+
return this.#admittedSourceDatagrams;
|
|
24451
|
+
}
|
|
24269
24452
|
/** MoQ repair symbols of an unlisted track kept out of a governed FEC instance (7.2.7 step 2). */
|
|
24270
24453
|
get unlistedRepairSetAsideCount() {
|
|
24271
24454
|
return this.#unlistedRepairSetAside;
|
|
@@ -24892,6 +25075,7 @@ var MmtpRouter = class {
|
|
|
24892
25075
|
this.#latestVideoSeqByStream.delete(streamKey);
|
|
24893
25076
|
this.#ssIdSeqOffsetByStream.delete(streamKey);
|
|
24894
25077
|
this.#unstampedSsIdSeqOffsetByStream.delete(streamKey);
|
|
25078
|
+
this.#overlayUnstampedSsIdSeqOffsetByStream.delete(streamKey);
|
|
24895
25079
|
this.#multicastRapTwinByStream.delete(streamKey);
|
|
24896
25080
|
this.#lastDirectSourceVideoTsByStream.delete(streamKey);
|
|
24897
25081
|
this.#lastDirectEmittedVideoTsByStream.delete(streamKey);
|
|
@@ -25018,6 +25202,12 @@ var MmtpRouter = class {
|
|
|
25018
25202
|
* the outgoing stream stops. The hold is bounded by the incoming stream's
|
|
25019
25203
|
* own RAP cadence, so no timer is involved.
|
|
25020
25204
|
*
|
|
25205
|
+
* While the switch is staged, the FEC release gate lets a keyframe the
|
|
25206
|
+
* overlay rebuilt reach it, on either side, when the keyframe did before
|
|
25207
|
+
* the gate anchored it (FecReleaseGate.releaseUnanchored): the switch
|
|
25208
|
+
* decides on what each side delivered, and the commit discards the gate's
|
|
25209
|
+
* frames of the outgoing stream.
|
|
25210
|
+
*
|
|
25021
25211
|
* The commit is one synchronous transition inside the frame path: the
|
|
25022
25212
|
* outgoing stream's already-admitted frames are released (its queued FEC
|
|
25023
25213
|
* gap fills only up to the RAP, since recovery can queue a frame ahead of
|
|
@@ -25068,6 +25258,9 @@ var MmtpRouter = class {
|
|
|
25068
25258
|
droppedIncomingFrames: 0
|
|
25069
25259
|
};
|
|
25070
25260
|
this.#staged = state;
|
|
25261
|
+
if (this.#parser.fecReleaseHoldsRebuilt(from.packetId, from.catalogTrackName)) {
|
|
25262
|
+
this.#requestFecPoke(from.packetId, from.catalogTrackName);
|
|
25263
|
+
}
|
|
25071
25264
|
return {
|
|
25072
25265
|
cancel: () => {
|
|
25073
25266
|
if (this.#staged !== state) return false;
|
|
@@ -25150,7 +25343,17 @@ var MmtpRouter = class {
|
|
|
25150
25343
|
*/
|
|
25151
25344
|
#routeParsedFrame(data, meta) {
|
|
25152
25345
|
if (this.#classifyPacketId(meta.packetId) === null) return;
|
|
25153
|
-
if (this.#staged !== null
|
|
25346
|
+
if (this.#staged !== null) {
|
|
25347
|
+
let consumed = false;
|
|
25348
|
+
this.#fecPokeDepth++;
|
|
25349
|
+
try {
|
|
25350
|
+
consumed = this.#interceptSwitchFrame(data, meta);
|
|
25351
|
+
} finally {
|
|
25352
|
+
this.#fecPokeDepth--;
|
|
25353
|
+
this.#flushPendingFecPokes();
|
|
25354
|
+
}
|
|
25355
|
+
if (consumed) return;
|
|
25356
|
+
}
|
|
25154
25357
|
this.#deliverParsedFrame(data, meta);
|
|
25155
25358
|
}
|
|
25156
25359
|
#commitStreamSwitch(state, rap, reason) {
|
|
@@ -25302,12 +25505,16 @@ var MmtpRouter = class {
|
|
|
25302
25505
|
this.#parser.deferFecRelease(work);
|
|
25303
25506
|
} finally {
|
|
25304
25507
|
this.#fecPokeDepth--;
|
|
25305
|
-
|
|
25306
|
-
|
|
25307
|
-
|
|
25308
|
-
|
|
25309
|
-
|
|
25310
|
-
|
|
25508
|
+
this.#flushPendingFecPokes();
|
|
25509
|
+
}
|
|
25510
|
+
}
|
|
25511
|
+
/** Run the pokes requested while #fecPokeDepth was raised, once it is 0. */
|
|
25512
|
+
#flushPendingFecPokes() {
|
|
25513
|
+
if (this.#fecPokeDepth === 0 && this.#pendingFecPokes.size > 0 && !this.#disposed) {
|
|
25514
|
+
const pokes = [...this.#pendingFecPokes.values()];
|
|
25515
|
+
this.#pendingFecPokes.clear();
|
|
25516
|
+
for (const poke of pokes) {
|
|
25517
|
+
this.#parser.pokeFecRelease(poke.packetId, poke.catalogTrackName);
|
|
25311
25518
|
}
|
|
25312
25519
|
}
|
|
25313
25520
|
}
|
|
@@ -25385,6 +25592,14 @@ var MmtpRouter = class {
|
|
|
25385
25592
|
onRap: (packetId, catalogTrackName, ssId) => {
|
|
25386
25593
|
for (const observer of this.#fecRapObservers) observer(packetId, catalogTrackName, ssId);
|
|
25387
25594
|
},
|
|
25595
|
+
// A staged switch commits on when each side's frames reach it
|
|
25596
|
+
// (#interceptSwitchFrame): both sides' overlay keyframes reach it when
|
|
25597
|
+
// they did unanchored.
|
|
25598
|
+
releaseUnanchored: (packetId, catalogTrackName) => {
|
|
25599
|
+
const staged = this.#staged;
|
|
25600
|
+
const stream = { packetId, ...catalogTrackName === void 0 ? {} : { catalogTrackName } };
|
|
25601
|
+
return staged !== null && (isStream(stream, staged.from) || isStream(stream, staged.to));
|
|
25602
|
+
},
|
|
25388
25603
|
onReleased: (data, meta) => {
|
|
25389
25604
|
if (meta.trackType !== "video" || meta.mpuSequenceNumber === void 0) return;
|
|
25390
25605
|
const timing = meta.authoredTiming;
|
|
@@ -25526,6 +25741,7 @@ var MmtpRouter = class {
|
|
|
25526
25741
|
const parsed = this.#parser.parsePacket(packet);
|
|
25527
25742
|
if (!parsed) return;
|
|
25528
25743
|
const info = parsed.info;
|
|
25744
|
+
if (manifestAdmitted && !info.isRepair && ingress?.admittedBy !== USER_AGENT_VERIFIED) this.#admittedSourceDatagrams++;
|
|
25529
25745
|
if (source === "multicast" && !manifestAdmitted) {
|
|
25530
25746
|
this.#fecManager?.noteMulticastArrival?.(info.packetId, info.sequenceNumber);
|
|
25531
25747
|
}
|
|
@@ -25834,7 +26050,8 @@ var MmtpRouter = class {
|
|
|
25834
26050
|
source: parserOptions?.source,
|
|
25835
26051
|
deliveryProvenance: parserOptions?.deliveryProvenance,
|
|
25836
26052
|
catalogTrackName: parserOptions?.catalogTrackName,
|
|
25837
|
-
...parserOptions?.fecSbn === void 0 ? {} : { fecSbn: parserOptions.fecSbn }
|
|
26053
|
+
...parserOptions?.fecSbn === void 0 ? {} : { fecSbn: parserOptions.fecSbn },
|
|
26054
|
+
...parserOptions?.fecSbnFirst === void 0 ? {} : { fecSbnFirst: parserOptions.fecSbnFirst }
|
|
25838
26055
|
};
|
|
25839
26056
|
if (parsed) this.#parser.feedParsed(packet, parsed, feedOptions);
|
|
25840
26057
|
else this.#parser.feed(packet, feedOptions);
|
|
@@ -26300,7 +26517,12 @@ var MmtpRouter = class {
|
|
|
26300
26517
|
#routeProcessedFecSymbols(blockId, result, ownerPacketId, catalogTrackName, overlay) {
|
|
26301
26518
|
if (ownerPacketId == null) return;
|
|
26302
26519
|
if (this.#classifyPacketId(ownerPacketId) === null) return;
|
|
26303
|
-
const fecSbnOf = (index) =>
|
|
26520
|
+
const fecSbnOf = (index) => {
|
|
26521
|
+
if (!overlay) return { fecSbn: this.#fecAnchorForRecovered(blockId, index) };
|
|
26522
|
+
const fecSbn = overlay.baseSsIds.get(index);
|
|
26523
|
+
const fecSbnFirst = overlay.firstSsIds.get(index);
|
|
26524
|
+
return fecSbn === void 0 || fecSbnFirst === void 0 ? {} : { fecSbn, fecSbnFirst };
|
|
26525
|
+
};
|
|
26304
26526
|
const streamKey = this.#mediaStreamKey(ownerPacketId, catalogTrackName);
|
|
26305
26527
|
const ssIdSeqOffset = overlay ? void 0 : this.#ssIdSeqOffsetByStream.get(streamKey);
|
|
26306
26528
|
if (ssIdSeqOffset !== void 0) {
|