@blockcast/mmt-container 2.2.0-main.2c4d96d3ffc2 → 2.2.0-main.34e6f78a7088
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 +271 -50
- 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 +258 -46
- package/dist/mmtp-router.js.map +2 -2
- package/dist/multicast-manager.js +271 -50
- 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 +207 -21
- package/src/mmtp-router.ts +222 -53
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();
|
|
@@ -23176,6 +23291,17 @@ var MmtpRouter = class {
|
|
|
23176
23291
|
* an MPU no member of which arrived).
|
|
23177
23292
|
*/
|
|
23178
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();
|
|
23179
23305
|
/**
|
|
23180
23306
|
* Streams whose multicast leg delivered a RAP-flagged source packet that was
|
|
23181
23307
|
* not parsed, typically because its overlap copy was parsed first
|
|
@@ -23504,8 +23630,9 @@ var MmtpRouter = class {
|
|
|
23504
23630
|
}
|
|
23505
23631
|
/**
|
|
23506
23632
|
* FEC-recovered source symbols whose reconstructed header named a
|
|
23507
|
-
* packet_sequence_number other than the wire sequence their SS_ID maps to
|
|
23508
|
-
*
|
|
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.
|
|
23509
23636
|
*/
|
|
23510
23637
|
get restampedRecoveredSequenceCount() {
|
|
23511
23638
|
return this.#restampedRecoveredSeqs;
|
|
@@ -23684,6 +23811,7 @@ var MmtpRouter = class {
|
|
|
23684
23811
|
enableMseAssembler(packetId, config, catalogTrackName) {
|
|
23685
23812
|
const assemblerKey = this.#mseAssemblerKey(packetId, catalogTrackName);
|
|
23686
23813
|
const previous = this.#mseAssemblers.get(assemblerKey);
|
|
23814
|
+
this.#parser.unsourceFecRelease(packetId, catalogTrackName);
|
|
23687
23815
|
if (previous) {
|
|
23688
23816
|
previous.flush();
|
|
23689
23817
|
previous.dispose();
|
|
@@ -23834,7 +23962,8 @@ var MmtpRouter = class {
|
|
|
23834
23962
|
fec,
|
|
23835
23963
|
k,
|
|
23836
23964
|
offsets: /* @__PURE__ */ new Map(),
|
|
23837
|
-
moqBlocks: /* @__PURE__ */ new Set()
|
|
23965
|
+
moqBlocks: /* @__PURE__ */ new Set(),
|
|
23966
|
+
rebuilt: /* @__PURE__ */ new Map()
|
|
23838
23967
|
};
|
|
23839
23968
|
this.#overlays.set(repairPacketId, inst);
|
|
23840
23969
|
return () => {
|
|
@@ -23875,6 +24004,7 @@ var MmtpRouter = class {
|
|
|
23875
24004
|
inst.last = void 0;
|
|
23876
24005
|
inst.offsets.clear();
|
|
23877
24006
|
inst.moqBlocks.clear();
|
|
24007
|
+
inst.rebuilt.clear();
|
|
23878
24008
|
}
|
|
23879
24009
|
#overlaysForSource(sourcePacketId, catalogTrackName) {
|
|
23880
24010
|
return [...this.#overlays.values()].filter(({ leg }) => leg.sourcePacketId === sourcePacketId && (catalogTrackName === void 0 || leg.sourceCatalogTrackName === void 0 || leg.sourceCatalogTrackName === catalogTrackName));
|
|
@@ -23927,13 +24057,23 @@ var MmtpRouter = class {
|
|
|
23927
24057
|
* base protects: the packet minus its 4-byte SS_ID trailer, extension
|
|
23928
24058
|
* included (7.1, 7.4.3). `baseSsId` is that trailer's SS_ID, when the base
|
|
23929
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).
|
|
23930
24067
|
*/
|
|
23931
24068
|
#feedOverlaySource(packetId, catalogTrackName, packet, header, sequenceNumber, rapFlag, source, baseSsId) {
|
|
23932
24069
|
if (this.#overlays.size === 0) return;
|
|
23933
24070
|
const ssId = keyframeOverlaySsId(header);
|
|
23934
24071
|
if (ssId === void 0) return;
|
|
24072
|
+
let rebuiltPsn;
|
|
23935
24073
|
for (const inst of this.#overlaysForSource(packetId, catalogTrackName)) {
|
|
23936
24074
|
this.#noteOverlaySsId(inst, ssId, sequenceNumber);
|
|
24075
|
+
rebuiltPsn ??= inst.rebuilt.get(ssId);
|
|
24076
|
+
inst.rebuilt.delete(ssId);
|
|
23937
24077
|
const identity = MmtpContainerParser.sourcePacketIdentity(packet, header);
|
|
23938
24078
|
if (identity !== null) {
|
|
23939
24079
|
inst.offsets.delete(identity.mpuSequenceNumber);
|
|
@@ -23963,6 +24103,14 @@ var MmtpRouter = class {
|
|
|
23963
24103
|
const recovered = fec.feedSourceSymbol(pid, ssId, symbolData, name);
|
|
23964
24104
|
if (recovered && !alreadyCompleted) this.#routeOverlayRecovered(inst, coords.sbn, recovered);
|
|
23965
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
|
+
}
|
|
23966
24114
|
}
|
|
23967
24115
|
#noteOverlayMoqBlock(inst, blockStart) {
|
|
23968
24116
|
inst.moqBlocks.add(blockStart);
|
|
@@ -23996,11 +24144,16 @@ var MmtpRouter = class {
|
|
|
23996
24144
|
}
|
|
23997
24145
|
/**
|
|
23998
24146
|
* Route an overlay-recovered block's packets as source media of the
|
|
23999
|
-
* overlay's source (7.2: an overlay coordinate yields no base SS_ID).
|
|
24000
|
-
*
|
|
24001
|
-
*
|
|
24002
|
-
*
|
|
24003
|
-
*
|
|
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.
|
|
24004
24157
|
*/
|
|
24005
24158
|
#routeOverlayRecovered(inst, blockStart, recovered) {
|
|
24006
24159
|
const { fec, repairPacketId: pid, streamName: name } = inst;
|
|
@@ -24021,40 +24174,65 @@ var MmtpRouter = class {
|
|
|
24021
24174
|
const restamped = this.#restampedStreams.has(streamKey);
|
|
24022
24175
|
const restored = /* @__PURE__ */ new Set();
|
|
24023
24176
|
const baseSsIds = /* @__PURE__ */ new Map();
|
|
24177
|
+
const gateOnly = /* @__PURE__ */ new Set();
|
|
24024
24178
|
const symbols = result.symbols.flatMap((sym) => {
|
|
24179
|
+
const overlaySsId = serial32Add(blockStart, sym.index);
|
|
24025
24180
|
const anchor = inst.offsets.get(sym.fragment.mpuSequenceNumber);
|
|
24026
24181
|
if (anchor !== void 0) {
|
|
24027
|
-
const overlaySsId = serial32Add(blockStart, sym.index);
|
|
24028
24182
|
const packetSequenceNumber = overlaySsId - anchor.psnOffset >>> 0;
|
|
24029
24183
|
restored.add(packetSequenceNumber);
|
|
24030
24184
|
const out = { ...sym, packetSequenceNumber };
|
|
24031
24185
|
const baseSsId = overlayBaseSsId(anchor, overlaySsId, packetSequenceNumber, sym.packetSequenceNumber);
|
|
24032
|
-
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
|
+
}
|
|
24033
24193
|
return [out];
|
|
24034
24194
|
}
|
|
24035
24195
|
if (!restamped) {
|
|
24036
|
-
const
|
|
24037
|
-
|
|
24038
|
-
|
|
24039
|
-
|
|
24040
|
-
|
|
24041
|
-
|
|
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
|
+
}
|
|
24042
24206
|
return [sym];
|
|
24043
24207
|
}
|
|
24044
24208
|
this.#overlayStats.unsequencedDropped++;
|
|
24045
24209
|
return [];
|
|
24046
24210
|
});
|
|
24047
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
|
+
}
|
|
24048
24223
|
this.#routeProcessedFecSymbols(blockStart, { ...result, symbols }, sourcePacketId, sourceName, {
|
|
24049
|
-
deliveryProvenance: inst.moqBlocks.has(blockStart) ? "mixed" : "multicast"
|
|
24224
|
+
deliveryProvenance: inst.moqBlocks.has(blockStart) ? "mixed" : "multicast",
|
|
24225
|
+
baseSsIds,
|
|
24226
|
+
firstSsIds
|
|
24050
24227
|
});
|
|
24051
24228
|
this.#noteOverlayRecoveredRaps(sourcePacketId, sourceName, streamKey, symbols.filter((sym) => restored.has(sym.packetSequenceNumber)));
|
|
24052
|
-
this.#feedOverlayRecoveredToBase(inst, blockStart, symbols, baseSsIds);
|
|
24229
|
+
this.#feedOverlayRecoveredToBase(inst, blockStart, symbols, gateOnly.size === 0 ? baseSsIds : new Map([...baseSsIds].filter(([index]) => !gateOnly.has(index))));
|
|
24053
24230
|
}
|
|
24054
24231
|
/**
|
|
24055
24232
|
* Joint decoding (BLO-52085). A packet the overlay rebuilt is a source of
|
|
24056
24233
|
* its base block too, once its base SS_ID is determined (overlayBaseSsId,
|
|
24057
|
-
* 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),
|
|
24058
24236
|
* so it is fed to the base decoder as a rebuilt source
|
|
24059
24237
|
* (FECManager.feedRebuiltSourceSymbol): the base block has one erasure
|
|
24060
24238
|
* fewer to solve, and its repair can recover the block's other packets.
|
|
@@ -24080,7 +24258,7 @@ var MmtpRouter = class {
|
|
|
24080
24258
|
const feeds = [];
|
|
24081
24259
|
for (const sym of symbols) {
|
|
24082
24260
|
if (duplicates.sourceSeqs.has(sym.packetSequenceNumber)) continue;
|
|
24083
|
-
const ssId = baseSsIds.get(sym);
|
|
24261
|
+
const ssId = baseSsIds.get(sym.index);
|
|
24084
24262
|
if (ssId === void 0) {
|
|
24085
24263
|
this.#overlayStats.baseUndetermined++;
|
|
24086
24264
|
continue;
|
|
@@ -24267,6 +24445,10 @@ var MmtpRouter = class {
|
|
|
24267
24445
|
get unadmittedListedDropCount() {
|
|
24268
24446
|
return this.#unadmittedListedDrops;
|
|
24269
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
|
+
}
|
|
24270
24452
|
/** MoQ repair symbols of an unlisted track kept out of a governed FEC instance (7.2.7 step 2). */
|
|
24271
24453
|
get unlistedRepairSetAsideCount() {
|
|
24272
24454
|
return this.#unlistedRepairSetAside;
|
|
@@ -24893,6 +25075,7 @@ var MmtpRouter = class {
|
|
|
24893
25075
|
this.#latestVideoSeqByStream.delete(streamKey);
|
|
24894
25076
|
this.#ssIdSeqOffsetByStream.delete(streamKey);
|
|
24895
25077
|
this.#unstampedSsIdSeqOffsetByStream.delete(streamKey);
|
|
25078
|
+
this.#overlayUnstampedSsIdSeqOffsetByStream.delete(streamKey);
|
|
24896
25079
|
this.#multicastRapTwinByStream.delete(streamKey);
|
|
24897
25080
|
this.#lastDirectSourceVideoTsByStream.delete(streamKey);
|
|
24898
25081
|
this.#lastDirectEmittedVideoTsByStream.delete(streamKey);
|
|
@@ -25019,6 +25202,12 @@ var MmtpRouter = class {
|
|
|
25019
25202
|
* the outgoing stream stops. The hold is bounded by the incoming stream's
|
|
25020
25203
|
* own RAP cadence, so no timer is involved.
|
|
25021
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
|
+
*
|
|
25022
25211
|
* The commit is one synchronous transition inside the frame path: the
|
|
25023
25212
|
* outgoing stream's already-admitted frames are released (its queued FEC
|
|
25024
25213
|
* gap fills only up to the RAP, since recovery can queue a frame ahead of
|
|
@@ -25069,6 +25258,9 @@ var MmtpRouter = class {
|
|
|
25069
25258
|
droppedIncomingFrames: 0
|
|
25070
25259
|
};
|
|
25071
25260
|
this.#staged = state;
|
|
25261
|
+
if (this.#parser.fecReleaseHoldsRebuilt(from.packetId, from.catalogTrackName)) {
|
|
25262
|
+
this.#requestFecPoke(from.packetId, from.catalogTrackName);
|
|
25263
|
+
}
|
|
25072
25264
|
return {
|
|
25073
25265
|
cancel: () => {
|
|
25074
25266
|
if (this.#staged !== state) return false;
|
|
@@ -25151,7 +25343,17 @@ var MmtpRouter = class {
|
|
|
25151
25343
|
*/
|
|
25152
25344
|
#routeParsedFrame(data, meta) {
|
|
25153
25345
|
if (this.#classifyPacketId(meta.packetId) === null) return;
|
|
25154
|
-
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
|
+
}
|
|
25155
25357
|
this.#deliverParsedFrame(data, meta);
|
|
25156
25358
|
}
|
|
25157
25359
|
#commitStreamSwitch(state, rap, reason) {
|
|
@@ -25303,12 +25505,16 @@ var MmtpRouter = class {
|
|
|
25303
25505
|
this.#parser.deferFecRelease(work);
|
|
25304
25506
|
} finally {
|
|
25305
25507
|
this.#fecPokeDepth--;
|
|
25306
|
-
|
|
25307
|
-
|
|
25308
|
-
|
|
25309
|
-
|
|
25310
|
-
|
|
25311
|
-
|
|
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);
|
|
25312
25518
|
}
|
|
25313
25519
|
}
|
|
25314
25520
|
}
|
|
@@ -25386,6 +25592,14 @@ var MmtpRouter = class {
|
|
|
25386
25592
|
onRap: (packetId, catalogTrackName, ssId) => {
|
|
25387
25593
|
for (const observer of this.#fecRapObservers) observer(packetId, catalogTrackName, ssId);
|
|
25388
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
|
+
},
|
|
25389
25603
|
onReleased: (data, meta) => {
|
|
25390
25604
|
if (meta.trackType !== "video" || meta.mpuSequenceNumber === void 0) return;
|
|
25391
25605
|
const timing = meta.authoredTiming;
|
|
@@ -25527,6 +25741,7 @@ var MmtpRouter = class {
|
|
|
25527
25741
|
const parsed = this.#parser.parsePacket(packet);
|
|
25528
25742
|
if (!parsed) return;
|
|
25529
25743
|
const info = parsed.info;
|
|
25744
|
+
if (manifestAdmitted && !info.isRepair && ingress?.admittedBy !== USER_AGENT_VERIFIED) this.#admittedSourceDatagrams++;
|
|
25530
25745
|
if (source === "multicast" && !manifestAdmitted) {
|
|
25531
25746
|
this.#fecManager?.noteMulticastArrival?.(info.packetId, info.sequenceNumber);
|
|
25532
25747
|
}
|
|
@@ -25835,7 +26050,8 @@ var MmtpRouter = class {
|
|
|
25835
26050
|
source: parserOptions?.source,
|
|
25836
26051
|
deliveryProvenance: parserOptions?.deliveryProvenance,
|
|
25837
26052
|
catalogTrackName: parserOptions?.catalogTrackName,
|
|
25838
|
-
...parserOptions?.fecSbn === void 0 ? {} : { fecSbn: parserOptions.fecSbn }
|
|
26053
|
+
...parserOptions?.fecSbn === void 0 ? {} : { fecSbn: parserOptions.fecSbn },
|
|
26054
|
+
...parserOptions?.fecSbnFirst === void 0 ? {} : { fecSbnFirst: parserOptions.fecSbnFirst }
|
|
25839
26055
|
};
|
|
25840
26056
|
if (parsed) this.#parser.feedParsed(packet, parsed, feedOptions);
|
|
25841
26057
|
else this.#parser.feed(packet, feedOptions);
|
|
@@ -26301,7 +26517,12 @@ var MmtpRouter = class {
|
|
|
26301
26517
|
#routeProcessedFecSymbols(blockId, result, ownerPacketId, catalogTrackName, overlay) {
|
|
26302
26518
|
if (ownerPacketId == null) return;
|
|
26303
26519
|
if (this.#classifyPacketId(ownerPacketId) === null) return;
|
|
26304
|
-
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
|
+
};
|
|
26305
26526
|
const streamKey = this.#mediaStreamKey(ownerPacketId, catalogTrackName);
|
|
26306
26527
|
const ssIdSeqOffset = overlay ? void 0 : this.#ssIdSeqOffsetByStream.get(streamKey);
|
|
26307
26528
|
if (ssIdSeqOffset !== void 0) {
|