@blockcast/mmt-container 2.1.0 → 2.2.0-main.02321582f1ca
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -17
- package/dist/browser-runtime.js +1302 -249
- package/dist/browser-runtime.js.map +4 -4
- package/dist/carp-catalog.js.map +1 -1
- package/dist/catalog-fec-params.d.ts +17 -1
- package/dist/catalog-fec-params.d.ts.map +1 -1
- package/dist/catalog-fec-params.js +15 -0
- package/dist/catalog-fec-params.js.map +2 -2
- package/dist/catalog-network-source.js.map +1 -1
- package/dist/cmcd-producer.d.ts +65 -47
- package/dist/cmcd-producer.d.ts.map +1 -1
- package/dist/cmcd-producer.js +138 -109
- package/dist/cmcd-producer.js.map +2 -2
- package/dist/delivery-catalog.js +26 -16
- package/dist/delivery-catalog.js.map +2 -2
- package/dist/delta-fallback-config.js.map +1 -1
- package/dist/fec-manager.d.ts +33 -1
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +213 -6
- package/dist/fec-manager.js.map +2 -2
- package/dist/fec-state.js.map +1 -1
- package/dist/fec-worker-setup.d.ts +1 -1
- package/dist/fec-worker-setup.js +1 -1
- package/dist/fec-worker-setup.js.map +1 -1
- package/dist/held-layer-admission.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +2 -2
- package/dist/iso-block-locator.d.ts +9 -0
- package/dist/iso-block-locator.d.ts.map +1 -1
- package/dist/iso-block-locator.js +17 -0
- package/dist/iso-block-locator.js.map +2 -2
- package/dist/iso-bmff-timing.d.ts +10 -1
- package/dist/iso-bmff-timing.d.ts.map +1 -1
- package/dist/iso-bmff-timing.js +36 -2
- package/dist/iso-bmff-timing.js.map +2 -2
- package/dist/media-router.js.map +1 -1
- package/dist/mfu-reassembler.js +12 -19
- package/dist/mfu-reassembler.js.map +2 -2
- package/dist/mmtp-container-parser.d.ts +37 -2
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +98 -28
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +222 -45
- package/dist/mmtp-container-parser.no-modules.js.map +3 -3
- package/dist/mmtp-decode-pipeline.js +97 -28
- package/dist/mmtp-decode-pipeline.js.map +2 -2
- package/dist/mmtp-fec-session.d.ts +41 -3
- package/dist/mmtp-fec-session.d.ts.map +1 -1
- package/dist/mmtp-fec-session.js +118 -13
- package/dist/mmtp-fec-session.js.map +3 -3
- package/dist/mmtp-router.d.ts +25 -2
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +1749 -56
- package/dist/mmtp-router.js.map +4 -4
- package/dist/multicast-auth-catalog.js.map +1 -1
- package/dist/multicast-input.js.map +1 -1
- package/dist/multicast-manager.d.ts +15 -2
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +15683 -14941
- package/dist/multicast-manager.js.map +4 -4
- package/dist/multicast-transport.d.ts +11 -3
- package/dist/multicast-transport.d.ts.map +1 -1
- package/dist/multicast-transport.js +281 -35
- package/dist/multicast-transport.js.map +4 -4
- package/dist/multicast-unwrap.js +12 -19
- package/dist/multicast-unwrap.js.map +2 -2
- package/dist/no-modules.js +215 -42
- package/dist/no-modules.js.map +3 -3
- package/dist/repair-fetch.js.map +1 -1
- package/dist/repair-layer-subscriptions.d.ts +82 -0
- package/dist/repair-layer-subscriptions.d.ts.map +1 -0
- package/dist/repair-layer-subscriptions.js +192 -0
- package/dist/repair-layer-subscriptions.js.map +7 -0
- package/dist/signaling.js.map +2 -2
- package/dist/timestamp-codec.js +12 -19
- package/dist/timestamp-codec.js.map +2 -2
- package/dist/track-session.d.ts +1 -1
- package/dist/track-session.js.map +1 -1
- package/dist/wasm-mfu-reassembler.js.map +1 -1
- package/dist/wasm-mmtp-container-parser.js +97 -28
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/package.json +8 -5
- package/schemas/catalog.schema.json +4 -0
- package/src/catalog-fec-params.ts +36 -1
- package/src/cmcd-producer.ts +194 -179
- package/src/fec-manager.ts +256 -6
- package/src/fec-worker-setup.ts +2 -2
- package/src/index.ts +18 -2
- package/src/iso-block-locator.ts +19 -0
- package/src/iso-bmff-timing.ts +40 -1
- package/src/mmtp-container-parser.ts +96 -8
- package/src/mmtp-fec-session.ts +115 -15
- package/src/mmtp-router.ts +414 -29
- package/src/multicast-manager.ts +26 -5
- package/src/multicast-transport.ts +44 -20
- package/src/repair-layer-subscriptions.ts +261 -0
- package/src/track-session.ts +1 -1
|
@@ -73,6 +73,8 @@ var BlockcastMmt = (() => {
|
|
|
73
73
|
var PACKET_TYPE_REPAIR = 3;
|
|
74
74
|
var MMTP_SIGNALING_PACKET_ID = 0;
|
|
75
75
|
var MMTP_PACKET_ID_MAX = 65535;
|
|
76
|
+
var FEC_CODE_REED_SOLOMON = 1;
|
|
77
|
+
var FEC_CODE_RAPTORQ = 3;
|
|
76
78
|
function parseMMTPHeader(buffer) {
|
|
77
79
|
if (buffer.length < MMTP_HEADER_SIZE) {
|
|
78
80
|
throw new Error(`MMTP packet too small: ${buffer.length} bytes`);
|
|
@@ -213,30 +215,26 @@ var BlockcastMmt = (() => {
|
|
|
213
215
|
const authLength = view2.getUint16(2, false);
|
|
214
216
|
return start + LEGACY_TRAILER_HEADER_SIZE + authLength === end;
|
|
215
217
|
}
|
|
216
|
-
function resolveDeclaredTrailers(payload, declaredEnd, fecType, options
|
|
218
|
+
function resolveDeclaredTrailers(payload, declaredEnd, fecType, options) {
|
|
217
219
|
if (declaredEnd > payload.length)
|
|
218
220
|
return null;
|
|
219
221
|
if (options?.skipFecId) {
|
|
220
|
-
return isEmptyOrExactLegacyTrailer(payload, declaredEnd, payload.length) ? { hasFecId: false
|
|
222
|
+
return isEmptyOrExactLegacyTrailer(payload, declaredEnd, payload.length) ? { hasFecId: false } : null;
|
|
221
223
|
}
|
|
222
|
-
const overlay = options?.overlayDeclared === true && rapFlag;
|
|
223
224
|
if (fecType === 1) {
|
|
224
|
-
const fecStart = payload.length -
|
|
225
|
+
const fecStart = payload.length - SOURCE_FEC_PAYLOAD_ID_SIZE;
|
|
225
226
|
if (fecStart < declaredEnd || !isEmptyOrExactLegacyTrailer(payload, declaredEnd, fecStart)) {
|
|
226
227
|
return null;
|
|
227
228
|
}
|
|
228
|
-
return { hasFecId: true
|
|
229
|
+
return { hasFecId: true };
|
|
229
230
|
}
|
|
230
|
-
if (fecType !== 0
|
|
231
|
+
if (fecType !== 0)
|
|
231
232
|
return null;
|
|
232
233
|
if (isEmptyOrExactLegacyTrailer(payload, declaredEnd, payload.length)) {
|
|
233
|
-
return { hasFecId: false
|
|
234
|
+
return { hasFecId: false };
|
|
234
235
|
}
|
|
235
236
|
return null;
|
|
236
237
|
}
|
|
237
|
-
function sourceFecTrailerSize(overlay) {
|
|
238
|
-
return overlay ? 2 * SOURCE_FEC_PAYLOAD_ID_SIZE : SOURCE_FEC_PAYLOAD_ID_SIZE;
|
|
239
|
-
}
|
|
240
238
|
function planMfuExtraction(mmtpPacket, options, parsedHeader) {
|
|
241
239
|
if (mmtpPacket.length < MMTP_HEADER_SIZE + MPU_HEADER_SIZE) {
|
|
242
240
|
return {
|
|
@@ -289,11 +287,11 @@ var BlockcastMmt = (() => {
|
|
|
289
287
|
if ("rejection" in layoutResult)
|
|
290
288
|
return layoutResult;
|
|
291
289
|
const { layout } = layoutResult;
|
|
292
|
-
const trailerLayout = resolveDeclaredTrailers(payload, layout.dataEnd, header.fecType, options
|
|
290
|
+
const trailerLayout = resolveDeclaredTrailers(payload, layout.dataEnd, header.fecType, options);
|
|
293
291
|
if (!trailerLayout) {
|
|
294
292
|
if (!options?.skipFecId && header.fecType === 1) {
|
|
295
293
|
const observed = payload.length - layout.dataEnd;
|
|
296
|
-
const expected =
|
|
294
|
+
const expected = SOURCE_FEC_PAYLOAD_ID_SIZE;
|
|
297
295
|
if (observed !== expected) {
|
|
298
296
|
return {
|
|
299
297
|
rejection: {
|
|
@@ -325,13 +323,10 @@ var BlockcastMmt = (() => {
|
|
|
325
323
|
const mfuDuHeader = mfuDuHeaderPresent && mpu.timedFlag === 1 ? parseTimedMfuDuHeader(payload, MPU_HEADER_SIZE) : null;
|
|
326
324
|
const itemId = mfuDuHeaderPresent && mpu.timedFlag === 0 ? new DataView(payload.buffer, payload.byteOffset + MPU_HEADER_SIZE, 4).getUint32(0, false) : null;
|
|
327
325
|
const data = payload.subarray(mfuOffset, dataEnd);
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
const fecPayloadId = trailerLayout.hasFecId ? ssIdAt(trailerStart) : null;
|
|
333
|
-
const overlayFecPayloadId = trailerLayout.hasOverlayFecId ? ssIdAt(trailerStart + SOURCE_FEC_PAYLOAD_ID_SIZE) : null;
|
|
334
|
-
return { header, mpu, fragmentType, data, mfuDuHeader, itemId, fecPayloadId, overlayFecPayloadId };
|
|
326
|
+
const fecPayloadId = trailerLayout.hasFecId ? {
|
|
327
|
+
ssId: new DataView(mmtpPacket.buffer, mmtpPacket.byteOffset + mmtpPacket.length - SOURCE_FEC_PAYLOAD_ID_SIZE, 4).getUint32(0, false)
|
|
328
|
+
} : null;
|
|
329
|
+
return { header, mpu, fragmentType, data, mfuDuHeader, itemId, fecPayloadId };
|
|
335
330
|
}
|
|
336
331
|
function sourceFecPayloadIdOf(mmtpPacket, header) {
|
|
337
332
|
if (mmtpPacket.length < MMTP_HEADER_SIZE + MPU_HEADER_SIZE)
|
|
@@ -423,6 +418,50 @@ var BlockcastMmt = (() => {
|
|
|
423
418
|
var NTP_SHORT_MODULUS = 2 ** NTP_SHORT_BITS;
|
|
424
419
|
var NTP_SHORT_HALF_RANGE = 2 ** (NTP_SHORT_BITS - 1);
|
|
425
420
|
|
|
421
|
+
// ../mmt-base/dist/signalling.js
|
|
422
|
+
var FEC_CODING_STRUCTURE_ONE_STAGE = 1;
|
|
423
|
+
var SSBG_MODE_1 = 1;
|
|
424
|
+
var RAPTORQ_MAX_SOURCE_SYMBOLS = 56403;
|
|
425
|
+
var REPAIR_SYMBOL_ID_MAX = 16777215;
|
|
426
|
+
var MIN_REPAIR_SYMBOL_SIZE = 14;
|
|
427
|
+
var REED_SOLOMON_MAX_BLOCK = 255;
|
|
428
|
+
function alFecRaptorQFlowConfig(flow) {
|
|
429
|
+
if (flow.fecCodingStructure !== FEC_CODING_STRUCTURE_ONE_STAGE || flow.repairFlows.length !== 1)
|
|
430
|
+
return null;
|
|
431
|
+
if (flow.ssbgMode !== SSBG_MODE_1 || flow.ffsrptsFlag !== 0 || flow.fecPayloadIdMode !== 0)
|
|
432
|
+
return null;
|
|
433
|
+
if (flow.packetIds.length !== 1)
|
|
434
|
+
return null;
|
|
435
|
+
const repair = flow.repairFlows[0];
|
|
436
|
+
const { fecCodeId, maximumK: k, maximumP: p } = repair;
|
|
437
|
+
const t = flow.repairSymbolSize;
|
|
438
|
+
if (t < MIN_REPAIR_SYMBOL_SIZE || k < 1 || p < 1 || k + p - 1 > REPAIR_SYMBOL_ID_MAX)
|
|
439
|
+
return null;
|
|
440
|
+
if (fecCodeId === FEC_CODE_RAPTORQ) {
|
|
441
|
+
if (t % 8 !== 0 || k > RAPTORQ_MAX_SOURCE_SYMBOLS)
|
|
442
|
+
return null;
|
|
443
|
+
} else if (fecCodeId === FEC_CODE_REED_SOLOMON) {
|
|
444
|
+
if (k + p > REED_SOLOMON_MAX_BLOCK)
|
|
445
|
+
return null;
|
|
446
|
+
} else {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
if (repair.repairFlowId === MMTP_SIGNALING_PACKET_ID || repair.repairFlowId === flow.packetIds[0])
|
|
450
|
+
return null;
|
|
451
|
+
return {
|
|
452
|
+
sourcePacketIds: [...flow.packetIds],
|
|
453
|
+
repairFlowId: repair.repairFlowId,
|
|
454
|
+
fecCodeId,
|
|
455
|
+
ssbgMode: flow.ssbgMode,
|
|
456
|
+
fecPayloadIdMode: flow.fecPayloadIdMode,
|
|
457
|
+
repairSymbolSize: t,
|
|
458
|
+
maximumK: k,
|
|
459
|
+
maximumP: p,
|
|
460
|
+
protectionWindowTime: repair.protectionWindowTime,
|
|
461
|
+
protectionWindowSize: repair.protectionWindowSize
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
426
465
|
// ../mmt-base/dist/serial-number.js
|
|
427
466
|
var SERIAL32_SPAN = 4294967296;
|
|
428
467
|
var SERIAL32_HALF = 2147483648;
|
|
@@ -5594,13 +5633,21 @@ var BlockcastMmt = (() => {
|
|
|
5594
5633
|
function sameSample(a, b) {
|
|
5595
5634
|
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;
|
|
5596
5635
|
}
|
|
5597
|
-
var _track, _fragments, _pendingSamples, _evictedSamples, _lastMovieFragmentRejection, _IsoBmffTimingResolver_instances, evictOldestFragment_fn, clearSlot_fn;
|
|
5636
|
+
var _track, _fragments, _firstSamples, _delivered, _pendingSamples, _evictedSamples, _lastMovieFragmentRejection, _IsoBmffTimingResolver_instances, evictOldestFragment_fn, clearSlot_fn;
|
|
5598
5637
|
var IsoBmffTimingResolver = class {
|
|
5599
5638
|
constructor(maxPendingSamples) {
|
|
5600
5639
|
this.maxPendingSamples = maxPendingSamples;
|
|
5601
5640
|
__privateAdd(this, _IsoBmffTimingResolver_instances);
|
|
5602
5641
|
__privateAdd(this, _track, null);
|
|
5603
5642
|
__privateAdd(this, _fragments, /* @__PURE__ */ new Map());
|
|
5643
|
+
/** First sample of each pending fragment, kept in `#delivered` with its sample count. */
|
|
5644
|
+
__privateAdd(this, _firstSamples, /* @__PURE__ */ new Map());
|
|
5645
|
+
/**
|
|
5646
|
+
* First sample and sample count of the newest fragments whose every slot was
|
|
5647
|
+
* cleared. Abandonment counts: `releaseSample` clears a slot too, which
|
|
5648
|
+
* matches the combiner, since it retires an abandoned sample as well.
|
|
5649
|
+
*/
|
|
5650
|
+
__privateAdd(this, _delivered, /* @__PURE__ */ new Map());
|
|
5604
5651
|
__privateAdd(this, _pendingSamples, 0);
|
|
5605
5652
|
__privateAdd(this, _evictedSamples, 0);
|
|
5606
5653
|
__privateAdd(this, _lastMovieFragmentRejection, null);
|
|
@@ -5608,6 +5655,10 @@ var BlockcastMmt = (() => {
|
|
|
5608
5655
|
throw new Error("[IsoBmffTimingResolver] maxPendingSamples must be a positive integer");
|
|
5609
5656
|
}
|
|
5610
5657
|
}
|
|
5658
|
+
/** True once an FT=0 has bound the track that FT=1 timing is read against. */
|
|
5659
|
+
get initialized() {
|
|
5660
|
+
return __privateGet(this, _track) !== null;
|
|
5661
|
+
}
|
|
5611
5662
|
get pendingSampleCount() {
|
|
5612
5663
|
return __privateGet(this, _pendingSamples);
|
|
5613
5664
|
}
|
|
@@ -5631,7 +5682,14 @@ var BlockcastMmt = (() => {
|
|
|
5631
5682
|
__privateSet(this, _track, timing);
|
|
5632
5683
|
return true;
|
|
5633
5684
|
}
|
|
5634
|
-
|
|
5685
|
+
/**
|
|
5686
|
+
* `recovered` marks an FEC-recovered copy. A recovered block hands back
|
|
5687
|
+
* every FT=1 it holds, the received ones included, so a recovered copy of a
|
|
5688
|
+
* fragment whose samples are all done is a duplicate: admitting it again
|
|
5689
|
+
* would charge stale timing and could displace the live MPU's. A source
|
|
5690
|
+
* copy is still admitted again (a rendition switch re-arms timing that way).
|
|
5691
|
+
*/
|
|
5692
|
+
addMovieFragment(mpuSequenceNumber, data, additionalSampleLimit = this.maxPendingSamples, recovered = false) {
|
|
5635
5693
|
__privateSet(this, _lastMovieFragmentRejection, null);
|
|
5636
5694
|
if (!Number.isInteger(additionalSampleLimit) || additionalSampleLimit < 0) {
|
|
5637
5695
|
__privateSet(this, _lastMovieFragmentRejection, "invalid");
|
|
@@ -5657,6 +5715,8 @@ var BlockcastMmt = (() => {
|
|
|
5657
5715
|
(sample, index) => sample !== null && sameSample(sample, parsed.samples[index])
|
|
5658
5716
|
);
|
|
5659
5717
|
}
|
|
5718
|
+
const delivered = recovered ? __privateGet(this, _delivered).get(key) : void 0;
|
|
5719
|
+
if (delivered && delivered.sampleCount === parsed.samples.length && sameSample(delivered.first, parsed.samples[0])) return true;
|
|
5660
5720
|
let freed = 0;
|
|
5661
5721
|
while (__privateGet(this, _fragments).size > 0 && (__privateGet(this, _pendingSamples) + parsed.samples.length > this.maxPendingSamples || parsed.samples.length - freed > additionalSampleLimit)) {
|
|
5662
5722
|
freed += __privateMethod(this, _IsoBmffTimingResolver_instances, evictOldestFragment_fn).call(this);
|
|
@@ -5670,6 +5730,7 @@ var BlockcastMmt = (() => {
|
|
|
5670
5730
|
return false;
|
|
5671
5731
|
}
|
|
5672
5732
|
__privateGet(this, _fragments).set(key, [...parsed.samples]);
|
|
5733
|
+
__privateGet(this, _firstSamples).set(key, parsed.samples[0]);
|
|
5673
5734
|
__privateSet(this, _pendingSamples, __privateGet(this, _pendingSamples) + parsed.samples.length);
|
|
5674
5735
|
return true;
|
|
5675
5736
|
}
|
|
@@ -5716,11 +5777,15 @@ var BlockcastMmt = (() => {
|
|
|
5716
5777
|
reset() {
|
|
5717
5778
|
__privateSet(this, _track, null);
|
|
5718
5779
|
__privateGet(this, _fragments).clear();
|
|
5780
|
+
__privateGet(this, _firstSamples).clear();
|
|
5781
|
+
__privateGet(this, _delivered).clear();
|
|
5719
5782
|
__privateSet(this, _pendingSamples, 0);
|
|
5720
5783
|
}
|
|
5721
5784
|
};
|
|
5722
5785
|
_track = new WeakMap();
|
|
5723
5786
|
_fragments = new WeakMap();
|
|
5787
|
+
_firstSamples = new WeakMap();
|
|
5788
|
+
_delivered = new WeakMap();
|
|
5724
5789
|
_pendingSamples = new WeakMap();
|
|
5725
5790
|
_evictedSamples = new WeakMap();
|
|
5726
5791
|
_lastMovieFragmentRejection = new WeakMap();
|
|
@@ -5739,6 +5804,7 @@ var BlockcastMmt = (() => {
|
|
|
5739
5804
|
let live = 0;
|
|
5740
5805
|
for (const sample of samples) if (sample !== null) live++;
|
|
5741
5806
|
__privateGet(this, _fragments).delete(oldest);
|
|
5807
|
+
__privateGet(this, _firstSamples).delete(oldest);
|
|
5742
5808
|
__privateSet(this, _pendingSamples, __privateGet(this, _pendingSamples) - live);
|
|
5743
5809
|
__privateSet(this, _evictedSamples, __privateGet(this, _evictedSamples) + live);
|
|
5744
5810
|
return live;
|
|
@@ -5754,7 +5820,16 @@ var BlockcastMmt = (() => {
|
|
|
5754
5820
|
if (!samples || !samples[index]) return false;
|
|
5755
5821
|
samples[index] = null;
|
|
5756
5822
|
__privateWrapper(this, _pendingSamples)._--;
|
|
5757
|
-
if (samples.every((value) => value === null))
|
|
5823
|
+
if (samples.every((value) => value === null)) {
|
|
5824
|
+
__privateGet(this, _fragments).delete(key);
|
|
5825
|
+
const first = __privateGet(this, _firstSamples).get(key);
|
|
5826
|
+
__privateGet(this, _firstSamples).delete(key);
|
|
5827
|
+
__privateGet(this, _delivered).delete(key);
|
|
5828
|
+
__privateGet(this, _delivered).set(key, { first, sampleCount: samples.length });
|
|
5829
|
+
if (__privateGet(this, _delivered).size > this.maxPendingSamples) {
|
|
5830
|
+
__privateGet(this, _delivered).delete(__privateGet(this, _delivered).keys().next().value);
|
|
5831
|
+
}
|
|
5832
|
+
}
|
|
5758
5833
|
return true;
|
|
5759
5834
|
};
|
|
5760
5835
|
function fragmentKey(mpuSequenceNumber, movieFragmentSequenceNumber) {
|
|
@@ -6216,7 +6291,7 @@ var BlockcastMmt = (() => {
|
|
|
6216
6291
|
return FMPU_BOX_TYPES.has(type);
|
|
6217
6292
|
}
|
|
6218
6293
|
var MAX_AWAITING_TIMING_HEADS = 8;
|
|
6219
|
-
var _tracks, _defaultTrack, _reassembler, _sampleCombiners, _sampleCombinerOptions, _retiredSampleCombinerStats, _timingStreams, _maxPendingTimingSamples, _pendingTimingSamples, _reclaimedTimingSamples, _evictedTimingSamples, _rejectedMovieFragments, _sequencers, _fecGate, _fecSequencer, _reorderWindow, _reassemblyPolicy, _frameCb, _initCb, _sourceSymbolCb, _trackFrameCbs, _reorderStats, _reliableMoqStartupGate, _disposed, _replayingAwaitingTiming, _fedObjects, _reassemblerFragmentsFed, _reassemblerDataUnitsReturned, _feedOutcomes, _deferredFeedOutcomes, _lastOutcome, _lastOutcomeCount, _MmtpContainerParser_instances, streamKey_fn, sampleCombinerFor_fn, releaseTimingSlot_fn, dropSampleCombiner_fn, countOutcome_fn, countDeferredOutcome_fn, drop_fn, feedCounted_fn, feed_fn, emitCombinedSample_fn, passReliableMoqStartupGate_fn, timingResolver_fn, awaitTiming_fn, replayAwaitingTiming_fn, dropTimingStream_fn, validateReassemblyPolicy_fn, buildFrameMeta_fn, sequencerFor_fn, flushSequencers_fn, emitFrame_fn2, _MmtpContainerParser_static, scanForKeyframe_fn, scanLengthPrefixedHevcForKeyframe_fn, scanAnnexBForKeyframe_fn;
|
|
6294
|
+
var _tracks, _defaultTrack, _reassembler, _sampleCombiners, _sampleCombinerOptions, _retiredSampleCombinerStats, _timingStreams, _maxPendingTimingSamples, _pendingTimingSamples, _reclaimedTimingSamples, _evictedTimingSamples, _rejectedMovieFragments, _recoveredHeadsAwaitingTiming, _sequencers, _fecGate, _fecSequencer, _reorderWindow, _reassemblyPolicy, _frameCb, _initCb, _sourceSymbolCb, _trackFrameCbs, _reorderStats, _reliableMoqStartupGate, _disposed, _replayingAwaitingTiming, _fedObjects, _reassemblerFragmentsFed, _reassemblerDataUnitsReturned, _feedOutcomes, _deferredFeedOutcomes, _lastOutcome, _lastOutcomeCount, _MmtpContainerParser_instances, streamKey_fn, sampleCombinerFor_fn, releaseTimingSlot_fn, dropSampleCombiner_fn, countOutcome_fn, countDeferredOutcome_fn, drop_fn, feedCounted_fn, feed_fn, emitCombinedSample_fn, passReliableMoqStartupGate_fn, timingResolver_fn, awaitTiming_fn, leaveAwaitingTiming_fn, replayAwaitingTiming_fn, dropTimingStream_fn, validateReassemblyPolicy_fn, buildFrameMeta_fn, sequencerFor_fn, flushSequencers_fn, emitFrame_fn2, _MmtpContainerParser_static, scanForKeyframe_fn, scanLengthPrefixedHevcForKeyframe_fn, scanAnnexBForKeyframe_fn;
|
|
6220
6295
|
var _MmtpContainerParser = class _MmtpContainerParser {
|
|
6221
6296
|
constructor(config) {
|
|
6222
6297
|
__privateAdd(this, _MmtpContainerParser_instances);
|
|
@@ -6252,6 +6327,12 @@ var BlockcastMmt = (() => {
|
|
|
6252
6327
|
__privateAdd(this, _reclaimedTimingSamples, 0);
|
|
6253
6328
|
__privateAdd(this, _evictedTimingSamples, 0);
|
|
6254
6329
|
__privateAdd(this, _rejectedMovieFragments, 0);
|
|
6330
|
+
__privateAdd(this, _recoveredHeadsAwaitingTiming, {
|
|
6331
|
+
held: 0,
|
|
6332
|
+
expired: 0,
|
|
6333
|
+
discarded: 0,
|
|
6334
|
+
superseded: 0
|
|
6335
|
+
});
|
|
6255
6336
|
__privateAdd(this, _sequencers, /* @__PURE__ */ new Map());
|
|
6256
6337
|
__privateAdd(this, _fecGate, null);
|
|
6257
6338
|
__privateAdd(this, _fecSequencer, null);
|
|
@@ -6394,6 +6475,14 @@ var BlockcastMmt = (() => {
|
|
|
6394
6475
|
rejectedMovieFragments: __privateGet(this, _rejectedMovieFragments)
|
|
6395
6476
|
};
|
|
6396
6477
|
}
|
|
6478
|
+
/** Recovered heads parked for FT=1 timing (BLO-53369). Survives dispose(). */
|
|
6479
|
+
get recoveredHeadsAwaitingTiming() {
|
|
6480
|
+
let pending = 0;
|
|
6481
|
+
for (const { awaitingTiming } of __privateGet(this, _timingStreams).values()) {
|
|
6482
|
+
for (const head of awaitingTiming) if (head.options?.recovered) pending++;
|
|
6483
|
+
}
|
|
6484
|
+
return { ...__privateGet(this, _recoveredHeadsAwaitingTiming), pending };
|
|
6485
|
+
}
|
|
6397
6486
|
get reorderStats() {
|
|
6398
6487
|
let bufferedFrames = __privateGet(this, _fecSequencer)?.buffered ?? 0;
|
|
6399
6488
|
for (const { sequencer } of __privateGet(this, _sequencers).values()) bufferedFrames += sequencer.buffered;
|
|
@@ -6545,7 +6634,7 @@ var BlockcastMmt = (() => {
|
|
|
6545
6634
|
const now = Date.now();
|
|
6546
6635
|
for (const { awaitingTiming } of __privateGet(this, _timingStreams).values()) {
|
|
6547
6636
|
while (awaitingTiming.length > 0 && now - awaitingTiming[0].arrivedAt > timeoutMs) {
|
|
6548
|
-
awaitingTiming.shift();
|
|
6637
|
+
__privateMethod(this, _MmtpContainerParser_instances, leaveAwaitingTiming_fn).call(this, awaitingTiming.shift(), "expired");
|
|
6549
6638
|
}
|
|
6550
6639
|
}
|
|
6551
6640
|
}
|
|
@@ -6750,6 +6839,10 @@ var BlockcastMmt = (() => {
|
|
|
6750
6839
|
}
|
|
6751
6840
|
__privateMethod(this, _MmtpContainerParser_instances, emitFrame_fn2).call(this, data, meta);
|
|
6752
6841
|
}
|
|
6842
|
+
/** Whether FT=1 metadata already names this sample, without claiming it. */
|
|
6843
|
+
hasAuthoredTimingFor(packetId, mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber, catalogTrackName) {
|
|
6844
|
+
return __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, __privateMethod(this, _MmtpContainerParser_instances, streamKey_fn).call(this, packetId, catalogTrackName), packetId, false)?.sampleTiming(mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber) != null;
|
|
6845
|
+
}
|
|
6753
6846
|
/**
|
|
6754
6847
|
* Claim and return the authored timing for a recovered sample. Recovery does
|
|
6755
6848
|
* not pass through the ordinary `feed()` completion path, so it must retire
|
|
@@ -6794,6 +6887,9 @@ var BlockcastMmt = (() => {
|
|
|
6794
6887
|
for (const { sequencer } of __privateGet(this, _sequencers).values()) sequencer.discard();
|
|
6795
6888
|
__privateGet(this, _sequencers).clear();
|
|
6796
6889
|
__privateGet(this, _fecSequencer)?.discard();
|
|
6890
|
+
for (const { awaitingTiming } of __privateGet(this, _timingStreams).values()) {
|
|
6891
|
+
for (const head of awaitingTiming) __privateMethod(this, _MmtpContainerParser_instances, leaveAwaitingTiming_fn).call(this, head, "discarded");
|
|
6892
|
+
}
|
|
6797
6893
|
__privateGet(this, _timingStreams).clear();
|
|
6798
6894
|
__privateSet(this, _pendingTimingSamples, 0);
|
|
6799
6895
|
__privateGet(this, _reliableMoqStartupGate).clear();
|
|
@@ -6822,6 +6918,7 @@ var BlockcastMmt = (() => {
|
|
|
6822
6918
|
_reclaimedTimingSamples = new WeakMap();
|
|
6823
6919
|
_evictedTimingSamples = new WeakMap();
|
|
6824
6920
|
_rejectedMovieFragments = new WeakMap();
|
|
6921
|
+
_recoveredHeadsAwaitingTiming = new WeakMap();
|
|
6825
6922
|
_sequencers = new WeakMap();
|
|
6826
6923
|
_fecGate = new WeakMap();
|
|
6827
6924
|
_fecSequencer = new WeakMap();
|
|
@@ -6980,11 +7077,16 @@ var BlockcastMmt = (() => {
|
|
|
6980
7077
|
if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0)
|
|
6981
7078
|
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-unexpected-fragmentation");
|
|
6982
7079
|
const resolver2 = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, false);
|
|
6983
|
-
if (!resolver2) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-no-resolver");
|
|
7080
|
+
if (!resolver2?.initialized) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "fragment-no-resolver");
|
|
6984
7081
|
const pendingBefore = resolver2.pendingSampleCount;
|
|
6985
7082
|
const evictedBefore = resolver2.evictedSampleCount;
|
|
6986
7083
|
const remaining = __privateGet(this, _maxPendingTimingSamples) - __privateGet(this, _pendingTimingSamples);
|
|
6987
|
-
const admitted = resolver2.addMovieFragment(
|
|
7084
|
+
const admitted = resolver2.addMovieFragment(
|
|
7085
|
+
mpu.mpuSequenceNumber,
|
|
7086
|
+
data,
|
|
7087
|
+
remaining,
|
|
7088
|
+
options?.recovered === true
|
|
7089
|
+
);
|
|
6988
7090
|
__privateSet(this, _pendingTimingSamples, __privateGet(this, _pendingTimingSamples) + (resolver2.pendingSampleCount - pendingBefore));
|
|
6989
7091
|
__privateSet(this, _evictedTimingSamples, __privateGet(this, _evictedTimingSamples) + (resolver2.evictedSampleCount - evictedBefore));
|
|
6990
7092
|
if (!admitted) {
|
|
@@ -7004,7 +7106,7 @@ var BlockcastMmt = (() => {
|
|
|
7004
7106
|
};
|
|
7005
7107
|
}
|
|
7006
7108
|
if (fragmentType !== 2) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "unknown-fragment-type");
|
|
7007
|
-
const resolver = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId,
|
|
7109
|
+
const resolver = __privateMethod(this, _MmtpContainerParser_instances, timingResolver_fn).call(this, streamKey, info.packetId, true);
|
|
7008
7110
|
if (!resolver) return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-no-resolver");
|
|
7009
7111
|
if (!Number.isSafeInteger(data.byteLength) || data.byteLength <= 0)
|
|
7010
7112
|
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-empty-payload");
|
|
@@ -7025,6 +7127,7 @@ var BlockcastMmt = (() => {
|
|
|
7025
7127
|
mpuSequenceNumber: mpu.mpuSequenceNumber,
|
|
7026
7128
|
movieFragmentSequenceNumber: mfuDuHeader.movieFragmentSequenceNumber,
|
|
7027
7129
|
sampleNumber: mfuDuHeader.sampleNumber,
|
|
7130
|
+
sequenceNumber: info.sequenceNumber,
|
|
7028
7131
|
arrivedAt: Date.now()
|
|
7029
7132
|
});
|
|
7030
7133
|
return __privateMethod(this, _MmtpContainerParser_instances, drop_fn).call(this, "mfu-sample-timing-missing");
|
|
@@ -7206,10 +7309,23 @@ var BlockcastMmt = (() => {
|
|
|
7206
7309
|
return resolver;
|
|
7207
7310
|
};
|
|
7208
7311
|
awaitTiming_fn = function(streamKey, head) {
|
|
7209
|
-
const
|
|
7210
|
-
if (!
|
|
7312
|
+
const state = __privateGet(this, _timingStreams).get(streamKey);
|
|
7313
|
+
if (!state) return;
|
|
7314
|
+
if (!head.options?.recovered) {
|
|
7315
|
+
const kept = state.awaitingTiming.filter((queued) => !queued.options?.recovered || queued.sequenceNumber !== head.sequenceNumber);
|
|
7316
|
+
__privateGet(this, _recoveredHeadsAwaitingTiming).superseded += state.awaitingTiming.length - kept.length;
|
|
7317
|
+
state.awaitingTiming = kept;
|
|
7318
|
+
}
|
|
7319
|
+
const awaitingTiming = state.awaitingTiming;
|
|
7211
7320
|
awaitingTiming.push(head);
|
|
7212
|
-
if (
|
|
7321
|
+
if (head.options?.recovered) __privateGet(this, _recoveredHeadsAwaitingTiming).held++;
|
|
7322
|
+
if (awaitingTiming.length > MAX_AWAITING_TIMING_HEADS) {
|
|
7323
|
+
__privateMethod(this, _MmtpContainerParser_instances, leaveAwaitingTiming_fn).call(this, awaitingTiming.shift(), "expired");
|
|
7324
|
+
}
|
|
7325
|
+
};
|
|
7326
|
+
/** Count a recovered head leaving the queue other than by replay or its source copy. */
|
|
7327
|
+
leaveAwaitingTiming_fn = function(head, outcome) {
|
|
7328
|
+
if (head.options?.recovered) __privateGet(this, _recoveredHeadsAwaitingTiming)[outcome]++;
|
|
7213
7329
|
};
|
|
7214
7330
|
/**
|
|
7215
7331
|
* Feed again the heads whose timing the FT=1 just admitted declares. That
|
|
@@ -7237,6 +7353,7 @@ var BlockcastMmt = (() => {
|
|
|
7237
7353
|
const state = __privateGet(this, _timingStreams).get(streamKey);
|
|
7238
7354
|
if (!state) return;
|
|
7239
7355
|
__privateGet(this, _timingStreams).delete(streamKey);
|
|
7356
|
+
for (const head of state.awaitingTiming) __privateMethod(this, _MmtpContainerParser_instances, leaveAwaitingTiming_fn).call(this, head, "discarded");
|
|
7240
7357
|
__privateSet(this, _pendingTimingSamples, __privateGet(this, _pendingTimingSamples) - state.resolver.pendingSampleCount);
|
|
7241
7358
|
if (__privateGet(this, _pendingTimingSamples) < 0) {
|
|
7242
7359
|
throw new Error("[MmtpContainerParser] pending timing sample accounting underflow");
|
|
@@ -8217,7 +8334,7 @@ var BlockcastMmt = (() => {
|
|
|
8217
8334
|
// src/mmtp-fec-session.ts
|
|
8218
8335
|
var PATH_BITS = { moq: 1, multicast: 2 };
|
|
8219
8336
|
var MIXED_PATHS = PATH_BITS.moq | PATH_BITS.multicast;
|
|
8220
|
-
var _decoder, _blocks, _settled, _have, _newest, _prunedAt, _repairPacketId, _newestSource, _heldLayers, _anchorHorizon, _stats3, _MmtpFecSession_instances, drop_fn2, noteNewest_fn, blockStartOf_fn, countHeld_fn, noteMixed_fn, behindHorizon_fn, settle_fn, settleClean_fn, settleDecoded_fn, retireBehindHorizon_fn;
|
|
8337
|
+
var _decoder, _repairSymbols, _message, _blocks, _settled, _have, _newest, _prunedAt, _repairPacketId, _newestSource, _heldLayers, _anchorHorizon, _stats3, _MmtpFecSession_instances, trackFor_fn, drop_fn2, noteNewest_fn, blockStartOf_fn, countHeld_fn, noteMixed_fn, behindHorizon_fn, settle_fn, settleClean_fn, settleDecoded_fn, retireBehindHorizon_fn;
|
|
8221
8338
|
var MmtpFecSession = class {
|
|
8222
8339
|
/**
|
|
8223
8340
|
* @throws when the instance lacks or misstates a field the session needs:
|
|
@@ -8227,6 +8344,9 @@ var BlockcastMmt = (() => {
|
|
|
8227
8344
|
constructor(config) {
|
|
8228
8345
|
__privateAdd(this, _MmtpFecSession_instances);
|
|
8229
8346
|
__privateAdd(this, _decoder);
|
|
8347
|
+
__privateAdd(this, _repairSymbols);
|
|
8348
|
+
/** The message entry a catalog-less session was built from; undefined under a catalog. */
|
|
8349
|
+
__privateAdd(this, _message);
|
|
8230
8350
|
/** Blocks a repair has defined and that are not settled yet, by SS_Start. */
|
|
8231
8351
|
__privateAdd(this, _blocks, /* @__PURE__ */ new Map());
|
|
8232
8352
|
/** SS_Starts of settled blocks, so a later repair for one is refused. */
|
|
@@ -8258,6 +8378,24 @@ var BlockcastMmt = (() => {
|
|
|
8258
8378
|
mixedPath: { clean: 0, recovered: 0, failed: 0, released: 0 },
|
|
8259
8379
|
failClosed: null
|
|
8260
8380
|
});
|
|
8381
|
+
if (config && "alFecFlow" in config) {
|
|
8382
|
+
const message = alFecRaptorQFlowConfig(config.alFecFlow);
|
|
8383
|
+
if (!message) {
|
|
8384
|
+
throw new Error("MmtpFecSession: the AL-FEC entry is outside draft-ramadan-moq-mmt-02 8.3 (iso-ssbg1-v1)");
|
|
8385
|
+
}
|
|
8386
|
+
__privateSet(this, _message, message);
|
|
8387
|
+
this.blockProfile = parseFecBlockProfile("iso-ssbg1-v1", "alFecFlow");
|
|
8388
|
+
this.algorithm = message.fecCodeId === FEC_CODE_RAPTORQ ? "raptorq" : "reed-solomon";
|
|
8389
|
+
this.sourceSymbols = message.maximumK;
|
|
8390
|
+
__privateSet(this, _repairSymbols, message.maximumP);
|
|
8391
|
+
this.symbolSize = message.repairSymbolSize;
|
|
8392
|
+
this.retentionBlocks = requirePositiveInteger(config.retentionBlocks, "retentionBlocks");
|
|
8393
|
+
__privateSet(this, _repairPacketId, message.repairFlowId);
|
|
8394
|
+
__privateSet(this, _heldLayers, layerZero(message.maximumP));
|
|
8395
|
+
__privateSet(this, _anchorHorizon, heldLayerAnchorHorizon(this.retentionBlocks, this.sourceSymbols));
|
|
8396
|
+
__privateSet(this, _decoder, buildDecoder(config.Decoder, this));
|
|
8397
|
+
return;
|
|
8398
|
+
}
|
|
8261
8399
|
const fec = config?.fec;
|
|
8262
8400
|
if (!fec || typeof fec !== "object") {
|
|
8263
8401
|
throw new Error("MmtpFecSession: the catalog fec instance is required");
|
|
@@ -8268,7 +8406,7 @@ var BlockcastMmt = (() => {
|
|
|
8268
8406
|
}
|
|
8269
8407
|
this.algorithm = fec.scheme;
|
|
8270
8408
|
this.sourceSymbols = requirePositiveInteger(fec.sourceSymbols, "fec.sourceSymbols");
|
|
8271
|
-
this
|
|
8409
|
+
__privateSet(this, _repairSymbols, requirePositiveInteger(fec.repairSymbols, "fec.repairSymbols"));
|
|
8272
8410
|
this.symbolSize = requirePositiveInteger(fec.symbolSize, "fec.symbolSize");
|
|
8273
8411
|
const interleaveDepthMs = requireNumber(fec.interleaveDepthMs, "fec.interleaveDepthMs");
|
|
8274
8412
|
const reorderToleranceMs = requireNumber(fec.reorderToleranceMs, "fec.reorderToleranceMs");
|
|
@@ -8288,17 +8426,34 @@ var BlockcastMmt = (() => {
|
|
|
8288
8426
|
config.heldLayers
|
|
8289
8427
|
));
|
|
8290
8428
|
__privateSet(this, _anchorHorizon, heldLayerAnchorHorizon(this.retentionBlocks, this.sourceSymbols));
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8429
|
+
__privateSet(this, _decoder, buildDecoder(config.Decoder, this));
|
|
8430
|
+
}
|
|
8431
|
+
/** P_0 = B_0, the held total every repair packet is checked against. */
|
|
8432
|
+
get repairSymbols() {
|
|
8433
|
+
return __privateGet(this, _repairSymbols);
|
|
8434
|
+
}
|
|
8435
|
+
/**
|
|
8436
|
+
* A later version of the AL-FEC message, catalog-less sessions only. A
|
|
8437
|
+
* maximum_p_for_repair_flow above the held total raises it (`raised`): the
|
|
8438
|
+
* anchored check restarts at the new total, so a block generated under the
|
|
8439
|
+
* previous one stays valid before the first block carrying the new total
|
|
8440
|
+
* (fec-core-00 7.3.2, mmt-02 8.3). A field at or below it changes nothing
|
|
8441
|
+
* (`unchanged`): no publisher lowers it, and the check catches a wire that
|
|
8442
|
+
* does. An entry with another asset, repair flow, code point, K or T, or
|
|
8443
|
+
* one outside 8.3, is `refused`: that is a new source encoding, which needs
|
|
8444
|
+
* a new session. A latched fail-closed stays latched either way.
|
|
8445
|
+
*/
|
|
8446
|
+
updateAlFecFlow(flow) {
|
|
8447
|
+
const held = __privateGet(this, _message);
|
|
8448
|
+
if (!held) throw new Error("MmtpFecSession: updateAlFecFlow() needs a session built from an AL-FEC entry");
|
|
8449
|
+
const next = alFecRaptorQFlowConfig(flow);
|
|
8450
|
+
if (!next || next.sourcePacketIds[0] !== held.sourcePacketIds[0] || next.repairFlowId !== held.repairFlowId || next.fecCodeId !== held.fecCodeId || next.maximumK !== held.maximumK || next.repairSymbolSize !== held.repairSymbolSize) {
|
|
8451
|
+
return "refused";
|
|
8452
|
+
}
|
|
8453
|
+
if (next.maximumP <= __privateGet(this, _repairSymbols)) return "unchanged";
|
|
8454
|
+
__privateSet(this, _repairSymbols, next.maximumP);
|
|
8455
|
+
__privateSet(this, _heldLayers, layerZero(next.maximumP));
|
|
8456
|
+
return "raised";
|
|
8302
8457
|
}
|
|
8303
8458
|
/** True once release() ran. */
|
|
8304
8459
|
get released() {
|
|
@@ -8393,7 +8548,7 @@ var BlockcastMmt = (() => {
|
|
|
8393
8548
|
}
|
|
8394
8549
|
if (admission.reject) {
|
|
8395
8550
|
const verdict2 = __privateGet(this, _heldLayers).failsClosed(
|
|
8396
|
-
repairTrackName,
|
|
8551
|
+
__privateMethod(this, _MmtpFecSession_instances, trackFor_fn).call(this, repairTrackName),
|
|
8397
8552
|
frame.ssStart,
|
|
8398
8553
|
frame.rsbLength,
|
|
8399
8554
|
__privateGet(this, _anchorHorizon),
|
|
@@ -8408,7 +8563,7 @@ var BlockcastMmt = (() => {
|
|
|
8408
8563
|
__privateGet(this, _repairPacketId) ?? __privateSet(this, _repairPacketId, frame.packetId);
|
|
8409
8564
|
if (frame.ssbLength > this.sourceSymbols) return __privateMethod(this, _MmtpFecSession_instances, drop_fn2).call(this, "repair:ssb-length");
|
|
8410
8565
|
const verdict = __privateGet(this, _heldLayers).admit(
|
|
8411
|
-
repairTrackName,
|
|
8566
|
+
__privateMethod(this, _MmtpFecSession_instances, trackFor_fn).call(this, repairTrackName),
|
|
8412
8567
|
frame.ssStart,
|
|
8413
8568
|
frame.rsbLength,
|
|
8414
8569
|
__privateGet(this, _anchorHorizon),
|
|
@@ -8469,6 +8624,8 @@ var BlockcastMmt = (() => {
|
|
|
8469
8624
|
}
|
|
8470
8625
|
};
|
|
8471
8626
|
_decoder = new WeakMap();
|
|
8627
|
+
_repairSymbols = new WeakMap();
|
|
8628
|
+
_message = new WeakMap();
|
|
8472
8629
|
_blocks = new WeakMap();
|
|
8473
8630
|
_settled = new WeakMap();
|
|
8474
8631
|
_have = new WeakMap();
|
|
@@ -8480,6 +8637,10 @@ var BlockcastMmt = (() => {
|
|
|
8480
8637
|
_anchorHorizon = new WeakMap();
|
|
8481
8638
|
_stats3 = new WeakMap();
|
|
8482
8639
|
_MmtpFecSession_instances = new WeakSet();
|
|
8640
|
+
/** Catalog-less: layer 0 has no own-track clause (mmt-02 8.3), so no track name is judged. */
|
|
8641
|
+
trackFor_fn = function(repairTrackName) {
|
|
8642
|
+
return __privateGet(this, _message) ? void 0 : repairTrackName;
|
|
8643
|
+
};
|
|
8483
8644
|
drop_fn2 = function(reason) {
|
|
8484
8645
|
__privateGet(this, _stats3).dropped[reason] = (__privateGet(this, _stats3).dropped[reason] ?? 0) + 1;
|
|
8485
8646
|
return [];
|
|
@@ -8600,6 +8761,22 @@ var BlockcastMmt = (() => {
|
|
|
8600
8761
|
if (__privateMethod(this, _MmtpFecSession_instances, behindHorizon_fn).call(this, start)) __privateGet(this, _settled).delete(start);
|
|
8601
8762
|
}
|
|
8602
8763
|
};
|
|
8764
|
+
function layerZero(total) {
|
|
8765
|
+
return new HeldLayerAdmission([{ layer: 0, repairTrackName: "", rsIdOffset: 0, repairSymbols: total }]);
|
|
8766
|
+
}
|
|
8767
|
+
function buildDecoder(Decoder, session) {
|
|
8768
|
+
if (typeof Decoder !== "function") {
|
|
8769
|
+
throw new Error("MmtpFecSession: a decoder constructor (wasm_bindgen.MmtFecDecoder) is required");
|
|
8770
|
+
}
|
|
8771
|
+
const decoder = new Decoder(session.retentionBlocks, session.blockProfile, session.algorithm);
|
|
8772
|
+
try {
|
|
8773
|
+
decoder.configure_params(session.sourceSymbols, session.symbolSize);
|
|
8774
|
+
} catch (error) {
|
|
8775
|
+
decoder.free();
|
|
8776
|
+
throw error;
|
|
8777
|
+
}
|
|
8778
|
+
return decoder;
|
|
8779
|
+
}
|
|
8603
8780
|
function requirePositiveInteger(value, path) {
|
|
8604
8781
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
|
|
8605
8782
|
throw new Error(`MmtpFecSession: ${path} must be a positive integer (got ${String(value)})`);
|