@blockcast/mmt-container 0.1.0-main.f2d8d03d6809 → 0.1.0-main.f8328f38cfb6
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 +231 -48
- package/dist/browser-runtime.js.map +2 -2
- package/dist/catalog-fec-params.d.ts +15 -0
- package/dist/catalog-fec-params.d.ts.map +1 -1
- package/dist/catalog-fec-params.js +11 -0
- package/dist/catalog-fec-params.js.map +2 -2
- package/dist/cmaf-block-assembler.js.map +1 -1
- package/dist/cmaf-group-batcher.js.map +1 -1
- package/dist/cmcd-producer.d.ts.map +1 -1
- package/dist/cmcd-producer.js.map +2 -2
- package/dist/fec-manager.d.ts +1 -5
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +7 -19
- package/dist/fec-manager.js.map +2 -2
- package/dist/fec-worker-setup.d.ts +8 -0
- package/dist/fec-worker-setup.d.ts.map +1 -1
- package/dist/fec-worker-setup.js +5 -3
- package/dist/fec-worker-setup.js.map +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +2 -2
- package/dist/manifest-auth-plan.js +29 -11
- package/dist/manifest-auth-plan.js.map +2 -2
- package/dist/media-router.js.map +2 -2
- package/dist/mfu-reassembler.js +56 -0
- package/dist/mfu-reassembler.js.map +2 -2
- package/dist/mmtp-container-parser.js +56 -0
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +100 -15
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/mmtp-decode-pipeline.js +56 -0
- package/dist/mmtp-decode-pipeline.js.map +2 -2
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +72 -9
- package/dist/mmtp-router.js.map +2 -2
- package/dist/mmtp-to-cmaf.d.ts +11 -2
- package/dist/mmtp-to-cmaf.d.ts.map +1 -1
- package/dist/mmtp-to-cmaf.js +15 -4
- package/dist/mmtp-to-cmaf.js.map +2 -2
- package/dist/multicast-manager.d.ts +12 -0
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +117 -39
- package/dist/multicast-manager.js.map +2 -2
- package/dist/multicast-transport.js +9 -5
- package/dist/multicast-transport.js.map +2 -2
- package/dist/multicast-unwrap.js.map +2 -2
- package/dist/no-modules.js +100 -15
- package/dist/no-modules.js.map +2 -2
- package/dist/signaling.js.map +2 -2
- package/dist/source-auth.js +29 -11
- package/dist/source-auth.js.map +2 -2
- package/dist/timestamp-codec.js.map +1 -1
- package/dist/track-session.d.ts +74 -1
- package/dist/track-session.d.ts.map +1 -1
- package/dist/track-session.js +83 -2
- package/dist/track-session.js.map +2 -2
- package/dist/wasm-mfu-reassembler.js +56 -0
- package/dist/wasm-mfu-reassembler.js.map +2 -2
- package/dist/wasm-mmtp-container-parser.js +56 -0
- package/dist/wasm-mmtp-container-parser.js.map +2 -2
- package/node_modules/@blockcast/fec-worker/README.md +1 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts +2 -2
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js +2 -2
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts +4 -4
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts.map +1 -1
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.js +3 -3
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.js.map +2 -2
- package/node_modules/@blockcast/fec-worker/src/fec-worker-client.ts +2 -2
- package/node_modules/@blockcast/fec-worker/src/fec-worker-types.ts +4 -4
- package/node_modules/@blockcast/fec-worker/src/fec-worker.ts +6 -6
- package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +6 -5
- package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-base/dist/mmtp.js +5 -4
- package/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -1
- package/node_modules/@blockcast/mmt-base/src/mmtp.ts +6 -5
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts +3 -1
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.js +3 -1
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.js.map +1 -1
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts +2 -2
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js +2 -2
- package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts +5 -7
- package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-fec/dist/oti.js +4 -6
- package/node_modules/@blockcast/mmt-fec/dist/oti.js.map +1 -1
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +6 -5
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js +5 -4
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -1
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/mmtp.ts +6 -5
- package/node_modules/@blockcast/mmt-fec/src/block-manager.ts +3 -1
- package/node_modules/@blockcast/mmt-fec/src/fec-block-mapper.ts +2 -2
- package/node_modules/@blockcast/mmt-fec/src/oti.ts +5 -7
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts +10 -1
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts.map +1 -1
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js +40 -10
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js.map +1 -1
- package/node_modules/@blockcast/mmt-manifest-verify/src/verifier.ts +41 -8
- package/package.json +6 -6
- package/src/catalog-fec-params.ts +28 -0
- package/src/cmcd-producer.ts +5 -0
- package/src/fec-manager.ts +17 -25
- package/src/fec-worker-setup.ts +11 -1
- package/src/index.ts +2 -0
- package/src/mfu-reassembler.ts +95 -0
- package/src/mmtp-router.ts +18 -20
- package/src/mmtp-to-cmaf.ts +24 -2
- package/src/multicast-manager.ts +74 -10
- package/src/track-session.ts +120 -2
- package/test-vectors/source-contiguity-v1.json +131 -0
package/dist/browser-runtime.js
CHANGED
|
@@ -143,8 +143,8 @@ var init_fec_worker_client = __esm({
|
|
|
143
143
|
* Caller must not access data after this call — it is detached.
|
|
144
144
|
*
|
|
145
145
|
* Carries the wire-level Repair FEC Payload ID fields (ISO 23008-1 §C.5.3):
|
|
146
|
-
* - ssStart: SS_ID of first source symbol in the block (= SBN *
|
|
147
|
-
* - ssbLength:
|
|
146
|
+
* - ssStart: SS_ID of first source symbol in the block (= SBN * configured K)
|
|
147
|
+
* - ssbLength: authored source-symbol count (1..configured K)
|
|
148
148
|
* - rsId: repair symbol index within the block
|
|
149
149
|
*/
|
|
150
150
|
feedRepair(ssStart, ssbLength, rsId, data, ts) {
|
|
@@ -1936,6 +1936,62 @@ if (void 0) {
|
|
|
1936
1936
|
expect(out?.data).toEqual(new Uint8Array([161, 162]));
|
|
1937
1937
|
expect(out?.sampleOffset).toBe(4);
|
|
1938
1938
|
});
|
|
1939
|
+
test("a mid-data-unit packet sequence gap strands the data unit", () => {
|
|
1940
|
+
const reassembler = new MFUReassembler({ timeoutMs: null, maxBuffered: 10 });
|
|
1941
|
+
expect(
|
|
1942
|
+
reassembler.addFragment({
|
|
1943
|
+
fragmentationIndicator: 1,
|
|
1944
|
+
mpuSequenceNumber: 7,
|
|
1945
|
+
fragmentCounter: 2,
|
|
1946
|
+
movieFragmentSequenceNumber: 9,
|
|
1947
|
+
sampleNumber: 17,
|
|
1948
|
+
sampleOffset: 0,
|
|
1949
|
+
packetSequenceNumber: 100,
|
|
1950
|
+
data: new Uint8Array([161]),
|
|
1951
|
+
timestamp: 1100n,
|
|
1952
|
+
rapFlag: true
|
|
1953
|
+
})
|
|
1954
|
+
).toBeNull();
|
|
1955
|
+
const interleaved = reassembler.addFragment({
|
|
1956
|
+
fragmentationIndicator: 0,
|
|
1957
|
+
mpuSequenceNumber: 7,
|
|
1958
|
+
fragmentCounter: 0,
|
|
1959
|
+
movieFragmentSequenceNumber: 9,
|
|
1960
|
+
sampleNumber: 18,
|
|
1961
|
+
sampleOffset: 0,
|
|
1962
|
+
packetSequenceNumber: 101,
|
|
1963
|
+
data: new Uint8Array([255]),
|
|
1964
|
+
timestamp: 1101n,
|
|
1965
|
+
rapFlag: true
|
|
1966
|
+
});
|
|
1967
|
+
expect(interleaved?.data).toEqual(new Uint8Array([255]));
|
|
1968
|
+
expect(
|
|
1969
|
+
reassembler.addFragment({
|
|
1970
|
+
fragmentationIndicator: 2,
|
|
1971
|
+
mpuSequenceNumber: 7,
|
|
1972
|
+
fragmentCounter: 1,
|
|
1973
|
+
packetSequenceNumber: 102,
|
|
1974
|
+
data: new Uint8Array([162]),
|
|
1975
|
+
timestamp: 1102n,
|
|
1976
|
+
rapFlag: false
|
|
1977
|
+
})
|
|
1978
|
+
).toBeNull();
|
|
1979
|
+
const output = reassembler.addFragment({
|
|
1980
|
+
fragmentationIndicator: 3,
|
|
1981
|
+
mpuSequenceNumber: 7,
|
|
1982
|
+
fragmentCounter: 0,
|
|
1983
|
+
packetSequenceNumber: 103,
|
|
1984
|
+
data: new Uint8Array([163]),
|
|
1985
|
+
timestamp: 1103n,
|
|
1986
|
+
rapFlag: false
|
|
1987
|
+
});
|
|
1988
|
+
expect(output).toBeNull();
|
|
1989
|
+
expect(reassembler.stats.reassembledMFUs).toBe(1);
|
|
1990
|
+
expect(reassembler.stats.rejectedFragments).toBe(0);
|
|
1991
|
+
expect(reassembler.stats.evictedMemoryLimit).toBe(0);
|
|
1992
|
+
expect(reassembler.getStatus().bufferedMFUs).toBe(2);
|
|
1993
|
+
expect(reassembler.getStatus().pendingFragments).toBe(3);
|
|
1994
|
+
});
|
|
1939
1995
|
test("sibling subsample DUs of one sample reassemble independently by offset", () => {
|
|
1940
1996
|
const reassembler = new MFUReassembler({ timeoutMs: 1e3 });
|
|
1941
1997
|
expect(
|
|
@@ -7719,16 +7775,26 @@ var MmtpToCmaf = class {
|
|
|
7719
7775
|
return __privateGet(this, _audioInitSegment);
|
|
7720
7776
|
}
|
|
7721
7777
|
/** Convert a raw video sample to an fMP4 moof+mdat segment. */
|
|
7722
|
-
wrapVideoSample(data, timestamp, keyframe, duration) {
|
|
7723
|
-
return this.wrapVideoSampleWithTiming(data, timestamp, keyframe, duration).segment;
|
|
7778
|
+
wrapVideoSample(data, timestamp, keyframe, duration, compositionTimeOffset) {
|
|
7779
|
+
return this.wrapVideoSampleWithTiming(data, timestamp, keyframe, duration, compositionTimeOffset).segment;
|
|
7724
7780
|
}
|
|
7725
7781
|
/**
|
|
7726
7782
|
* Convert a raw video sample and return the exact browser media interval
|
|
7727
7783
|
* encoded into tfdt/trun. Consumers that correlate SourceBuffer appends with
|
|
7728
7784
|
* requestVideoFrameCallback must use this rebased timestamp, not the wire or
|
|
7729
7785
|
* caller-owned timestamp passed above.
|
|
7786
|
+
*
|
|
7787
|
+
* `compositionTimeOffset` is the signed authored PTS-DTS delta, in the same
|
|
7788
|
+
* #videoTimescale units as `timestamp` and `duration` — unlike wrapAudioSample,
|
|
7789
|
+
* which takes microseconds and rescales, because every other quantity on this
|
|
7790
|
+
* path is already denominated in #videoTimescale (see setVideoTrackParams).
|
|
7791
|
+
* Passing it therefore needs no conversion here; rescaling would double-convert.
|
|
7792
|
+
* Absent leaves the trun at version 0 with no offset field; a declared 0 is an
|
|
7793
|
+
* authored value and still promotes to version 1. Never reconstruct it from
|
|
7794
|
+
* arrival time.
|
|
7730
7795
|
*/
|
|
7731
|
-
wrapVideoSampleWithTiming(data, timestamp, keyframe, duration) {
|
|
7796
|
+
wrapVideoSampleWithTiming(data, timestamp, keyframe, duration, compositionTimeOffset) {
|
|
7797
|
+
assertCompositionTimeOffsets([{ compositionTimeOffset }]);
|
|
7732
7798
|
if (duration !== void 0 && Number.isFinite(duration) && duration > 0) {
|
|
7733
7799
|
__privateSet(this, _frameDuration, Math.round(duration));
|
|
7734
7800
|
} else if (__privateGet(this, _lastVideoTimestamp) > 0 && timestamp > __privateGet(this, _lastVideoTimestamp)) {
|
|
@@ -7746,7 +7812,8 @@ var MmtpToCmaf = class {
|
|
|
7746
7812
|
frameDuration,
|
|
7747
7813
|
keyframe,
|
|
7748
7814
|
__privateWrapper(this, _videoSeq)._++,
|
|
7749
|
-
__privateGet(this, _videoTrackId)
|
|
7815
|
+
__privateGet(this, _videoTrackId),
|
|
7816
|
+
compositionTimeOffset
|
|
7750
7817
|
),
|
|
7751
7818
|
mediaTimestamp: relTs,
|
|
7752
7819
|
duration: frameDuration
|
|
@@ -9255,6 +9322,24 @@ var TrackSession = class {
|
|
|
9255
9322
|
get isFecArmed() {
|
|
9256
9323
|
return __privateGet(this, _fecArmed);
|
|
9257
9324
|
}
|
|
9325
|
+
/**
|
|
9326
|
+
* Start the deadline a `joining` entry deferred while the join was inactive
|
|
9327
|
+
* (SessionManager.joinActive). The track gets the FULL deadline from here,
|
|
9328
|
+
* because that is when media can first arrive. No-op outside `joining` and
|
|
9329
|
+
* when a deadline is already running, so it never shortens or restarts one.
|
|
9330
|
+
*
|
|
9331
|
+
* The `joinActive` guard is what makes this safe to call from anywhere: a
|
|
9332
|
+
* track parked in `joining` with a deferred (null) timer satisfies the other
|
|
9333
|
+
* two, so without it a host calling this while the join is still inactive
|
|
9334
|
+
* would arm the exact deadline the gate exists to defer -- silently
|
|
9335
|
+
* reinstating BLO-34289. It is a no-op for the internal caller, which writes
|
|
9336
|
+
* `#joinActive = true` before iterating the sessions.
|
|
9337
|
+
*/
|
|
9338
|
+
armDeferredJoinDeadline() {
|
|
9339
|
+
if (__privateGet(this, _state) !== "joining" || __privateGet(this, _joinDeadlineTimer) !== null) return;
|
|
9340
|
+
if (!__privateGet(this, _manager).joinActive) return;
|
|
9341
|
+
__privateMethod(this, _TrackSession_instances, armJoinDeadline_fn).call(this, __privateGet(this, _manager).takeoverDeadlineMs);
|
|
9342
|
+
}
|
|
9258
9343
|
dispose() {
|
|
9259
9344
|
__privateMethod(this, _TrackSession_instances, clearHysteresis_fn).call(this);
|
|
9260
9345
|
__privateMethod(this, _TrackSession_instances, clearJoinDeadline_fn).call(this);
|
|
@@ -9281,7 +9366,9 @@ transition_fn = function(to, opts) {
|
|
|
9281
9366
|
const joinDeadlineMs = to === "joining" ? __privateGet(this, _manager).takeoverDeadlineMs : void 0;
|
|
9282
9367
|
__privateSet(this, _state, to);
|
|
9283
9368
|
if (from === "joining") __privateMethod(this, _TrackSession_instances, clearJoinDeadline_fn).call(this);
|
|
9284
|
-
if (joinDeadlineMs !== void 0
|
|
9369
|
+
if (joinDeadlineMs !== void 0 && __privateGet(this, _manager).joinActive) {
|
|
9370
|
+
__privateMethod(this, _TrackSession_instances, armJoinDeadline_fn).call(this, joinDeadlineMs);
|
|
9371
|
+
}
|
|
9285
9372
|
const fecActive = (s) => s === "joining" || s === "multicast" || s === "amt" || s === "failing" || s === "unicast-fallback";
|
|
9286
9373
|
if (!fecActive(to) && !opts?.retainFec) __privateMethod(this, _TrackSession_instances, disarmFec_fn).call(this);
|
|
9287
9374
|
__privateGet(this, _manager).callbacks?.onStateChange?.(this.config.trackName, from, to);
|
|
@@ -9333,13 +9420,16 @@ unsuppress_fn = function() {
|
|
|
9333
9420
|
__privateGet(this, _manager).callbacks?.onSuppress?.(this.config.trackName, false);
|
|
9334
9421
|
};
|
|
9335
9422
|
var MAX_TAKEOVER_DEADLINE_MS = 2147483647;
|
|
9336
|
-
var
|
|
9423
|
+
var JOIN_DEFER_WARN_MS = 3e4;
|
|
9424
|
+
var _takeoverDeadlineMs, _joinActive, _joinDeferWarnTimer, _SessionManager_instances, armJoinDeferWarn_fn, clearJoinDeferWarn_fn, requireTakeoverDeadlineMs_fn;
|
|
9337
9425
|
var SessionManager = class {
|
|
9338
9426
|
constructor(poolOptions) {
|
|
9339
9427
|
__privateAdd(this, _SessionManager_instances);
|
|
9340
9428
|
this.sessions = /* @__PURE__ */ new Map();
|
|
9341
9429
|
this.callbacks = null;
|
|
9342
9430
|
__privateAdd(this, _takeoverDeadlineMs);
|
|
9431
|
+
__privateAdd(this, _joinActive, true);
|
|
9432
|
+
__privateAdd(this, _joinDeferWarnTimer, null);
|
|
9343
9433
|
this.pool = new TransportPool(poolOptions);
|
|
9344
9434
|
this.pool.onSubscriptionFailed((sub) => {
|
|
9345
9435
|
for (const trackName of sub.consumers) {
|
|
@@ -9388,6 +9478,46 @@ var SessionManager = class {
|
|
|
9388
9478
|
get hasTakeoverDeadline() {
|
|
9389
9479
|
return __privateGet(this, _takeoverDeadlineMs) !== void 0;
|
|
9390
9480
|
}
|
|
9481
|
+
/**
|
|
9482
|
+
* Whether the transport the joining tracks are waiting on is actually
|
|
9483
|
+
* subscribed. The takeover deadline is a media-arrival budget and media
|
|
9484
|
+
* cannot arrive before the join exists, so while this is false, entering
|
|
9485
|
+
* `joining` arms no deadline; flipping it true starts the FULL deadline for
|
|
9486
|
+
* every track already parked there.
|
|
9487
|
+
*
|
|
9488
|
+
* Default true, which is the arm-on-`joining` behaviour every host had
|
|
9489
|
+
* before: a host that only calls joinStarted() after its own join resolves
|
|
9490
|
+
* (moqtail-private's player, post-BLO-33339) is already at the right edge and
|
|
9491
|
+
* needs no gate. A host that arms joinStarted() up front — to have FEC
|
|
9492
|
+
* decoders ready before the first datagram — sets this false before addTrack()
|
|
9493
|
+
* and true when its subscribe settles. Charging a slow subscribe (bridge
|
|
9494
|
+
* reconnect, AMT relay handshake) against the media budget expired the
|
|
9495
|
+
* deadline before the subscription existed and abandoned the join on the
|
|
9496
|
+
* happy path. BLO-34289.
|
|
9497
|
+
*
|
|
9498
|
+
* The flag tracks the host's primary join, not per-track transport state. A
|
|
9499
|
+
* track that fails over to the next transport in its own chain while this is
|
|
9500
|
+
* false (transportFailed's failover branch also enters `joining`) has that
|
|
9501
|
+
* deadline gated on the primary join activating, not on its own transport.
|
|
9502
|
+
* Under the documented usage -- false once at setup, true once the subscribe
|
|
9503
|
+
* settles -- the two coincide.
|
|
9504
|
+
*
|
|
9505
|
+
* Leaving this false is not free: see JOIN_DEFER_WARN_MS.
|
|
9506
|
+
*/
|
|
9507
|
+
get joinActive() {
|
|
9508
|
+
return __privateGet(this, _joinActive);
|
|
9509
|
+
}
|
|
9510
|
+
set joinActive(active) {
|
|
9511
|
+
const wasActive = __privateGet(this, _joinActive);
|
|
9512
|
+
__privateSet(this, _joinActive, active);
|
|
9513
|
+
if (!active) {
|
|
9514
|
+
if (wasActive) __privateMethod(this, _SessionManager_instances, armJoinDeferWarn_fn).call(this);
|
|
9515
|
+
return;
|
|
9516
|
+
}
|
|
9517
|
+
__privateMethod(this, _SessionManager_instances, clearJoinDeferWarn_fn).call(this);
|
|
9518
|
+
if (wasActive) return;
|
|
9519
|
+
for (const [, session] of this.sessions) session.armDeferredJoinDeadline();
|
|
9520
|
+
}
|
|
9391
9521
|
/** Narrow to MMTP callbacks (onTrackEvent). Safe — optional chaining handles PIM-only consumers. */
|
|
9392
9522
|
get mmtp() {
|
|
9393
9523
|
return this.callbacks;
|
|
@@ -9541,6 +9671,7 @@ var SessionManager = class {
|
|
|
9541
9671
|
// Cleanup
|
|
9542
9672
|
// -----------------------------------------------------------------------
|
|
9543
9673
|
dispose() {
|
|
9674
|
+
__privateMethod(this, _SessionManager_instances, clearJoinDeferWarn_fn).call(this);
|
|
9544
9675
|
for (const [, session] of this.sessions) {
|
|
9545
9676
|
session.dispose();
|
|
9546
9677
|
}
|
|
@@ -9550,7 +9681,23 @@ var SessionManager = class {
|
|
|
9550
9681
|
}
|
|
9551
9682
|
};
|
|
9552
9683
|
_takeoverDeadlineMs = new WeakMap();
|
|
9684
|
+
_joinActive = new WeakMap();
|
|
9685
|
+
_joinDeferWarnTimer = new WeakMap();
|
|
9553
9686
|
_SessionManager_instances = new WeakSet();
|
|
9687
|
+
armJoinDeferWarn_fn = function() {
|
|
9688
|
+
__privateSet(this, _joinDeferWarnTimer, setTimeout(() => {
|
|
9689
|
+
__privateSet(this, _joinDeferWarnTimer, null);
|
|
9690
|
+
const deferred = [...this.sessions.values()].filter((s) => s.state === "joining").length;
|
|
9691
|
+
console.warn(
|
|
9692
|
+
`[SessionManager] joinActive has been false for ${JOIN_DEFER_WARN_MS} ms and ${deferred} track(s) sit in 'joining' with no takeover deadline. Set joinActive = true when the subscribe settles, on every exit path including failures, or these tracks never time out, never release their FEC decoders, and never advance to the next transport.`
|
|
9693
|
+
);
|
|
9694
|
+
}, JOIN_DEFER_WARN_MS));
|
|
9695
|
+
};
|
|
9696
|
+
clearJoinDeferWarn_fn = function() {
|
|
9697
|
+
if (__privateGet(this, _joinDeferWarnTimer) === null) return;
|
|
9698
|
+
clearTimeout(__privateGet(this, _joinDeferWarnTimer));
|
|
9699
|
+
__privateSet(this, _joinDeferWarnTimer, null);
|
|
9700
|
+
};
|
|
9554
9701
|
// -----------------------------------------------------------------------
|
|
9555
9702
|
// Track management
|
|
9556
9703
|
// -----------------------------------------------------------------------
|
|
@@ -9898,6 +10045,7 @@ var FECManager = class {
|
|
|
9898
10045
|
const k = this.kForPacket(packetId);
|
|
9899
10046
|
const isSourceSymbol = esi >= 0 && esi < k;
|
|
9900
10047
|
const isStartupPartial = __privateGet(this, _startupPartialBlocks).has(blockKey);
|
|
10048
|
+
const isReadyMulticastRepair = __privateGet(this, _startupRequireRepairReady) && source === "multicast" && !isSourceSymbol && __privateGet(this, _startupRepairReadyPackets).has(streamKey);
|
|
9901
10049
|
const awaitingMulticastRepair = __privateGet(this, _startupRequireRepairReady) && source === "multicast" && !__privateGet(this, _startupRepairReadyPackets).has(streamKey) && !__privateGet(this, _startupRepairFailOpenPackets).has(streamKey);
|
|
9902
10050
|
if (awaitingMulticastRepair) {
|
|
9903
10051
|
if (!isSourceSymbol) {
|
|
@@ -9924,7 +10072,7 @@ var FECManager = class {
|
|
|
9924
10072
|
if (isSourceSymbol && esi === 0) {
|
|
9925
10073
|
__privateGet(this, _startupPartialBlocks).delete(blockKey);
|
|
9926
10074
|
__privateGet(this, _startupAlignedPackets).add(streamKey);
|
|
9927
|
-
} else if (isStartupPartial || !__privateGet(this, _startupAlignedPackets).has(streamKey)) {
|
|
10075
|
+
} else if (isStartupPartial && !isReadyMulticastRepair || !__privateGet(this, _startupAlignedPackets).has(streamKey) && !isReadyMulticastRepair) {
|
|
9928
10076
|
__privateMethod(this, _FECManager_instances, markStartupPartial_fn).call(this, blockKey);
|
|
9929
10077
|
return false;
|
|
9930
10078
|
}
|
|
@@ -10017,7 +10165,7 @@ var FECManager = class {
|
|
|
10017
10165
|
symbolSizeForPacket(packetId) {
|
|
10018
10166
|
return __privateMethod(this, _FECManager_instances, resolveTrackConfig_fn).call(this, packetId).symbolSize;
|
|
10019
10167
|
}
|
|
10020
|
-
/** FEC
|
|
10168
|
+
/** FEC block span in milliseconds (0 = no interleaving). */
|
|
10021
10169
|
get interleaveDepthMs() {
|
|
10022
10170
|
return __privateGet(this, _fecInterleaveDepthMs);
|
|
10023
10171
|
}
|
|
@@ -10339,14 +10487,10 @@ var FECManager = class {
|
|
|
10339
10487
|
return null;
|
|
10340
10488
|
}
|
|
10341
10489
|
const fecData = repairData;
|
|
10342
|
-
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
catalogTrackName
|
|
10347
|
-
);
|
|
10348
|
-
}
|
|
10349
|
-
const sbn = ssbLength > 0 ? Math.floor(ssStart / ssbLength) : 0;
|
|
10490
|
+
const k = this.kForPacket(packetId);
|
|
10491
|
+
if (ssbLength <= 0 || ssbLength > k || ssStart % k !== 0) return null;
|
|
10492
|
+
const sbn = Math.floor(ssStart / k);
|
|
10493
|
+
this.noteBlockActivity(sbn, packetId, catalogTrackName);
|
|
10350
10494
|
const blockKey = __privateMethod(this, _FECManager_instances, blockKey_fn).call(this, sbn, packetId, catalogTrackName);
|
|
10351
10495
|
if (__privateGet(this, _completedBlocks).has(blockKey)) return null;
|
|
10352
10496
|
const syncBlockOwner = __privateGet(this, _syncDecoderBlockOwners).get(blockKey);
|
|
@@ -10382,15 +10526,6 @@ var FECManager = class {
|
|
|
10382
10526
|
if (recovered) __privateGet(this, _syncDecoderBlockOwners).delete(blockKey);
|
|
10383
10527
|
return recovered;
|
|
10384
10528
|
}
|
|
10385
|
-
/**
|
|
10386
|
-
* Unified symbol feeder. Dispatches to feedSourceSymbol or feedRepairSymbol.
|
|
10387
|
-
*/
|
|
10388
|
-
feedSymbol(packetId, symbolId, data, isRepair) {
|
|
10389
|
-
if (isRepair) {
|
|
10390
|
-
return this.feedRepairSymbol(packetId, symbolId, 1, symbolId, data);
|
|
10391
|
-
}
|
|
10392
|
-
return this.feedSourceSymbol(packetId, symbolId, data);
|
|
10393
|
-
}
|
|
10394
10529
|
// -----------------------------------------------------------------------
|
|
10395
10530
|
// Block lifecycle
|
|
10396
10531
|
// -----------------------------------------------------------------------
|
|
@@ -13497,6 +13632,7 @@ var MmtpRouter = class {
|
|
|
13497
13632
|
);
|
|
13498
13633
|
}
|
|
13499
13634
|
const repairSbn = __privateMethod(this, _MmtpRouter_instances, deriveRepairSbn_fn).call(this, parsed.ssStart, parsed.ssbLength, ownerPacketId);
|
|
13635
|
+
if (repairSbn === null) return;
|
|
13500
13636
|
const repairEsi = __privateMethod(this, _MmtpRouter_instances, kForPacket_fn).call(this, ownerPacketId) + parsed.rsId;
|
|
13501
13637
|
if (!__privateMethod(this, _MmtpRouter_instances, feedFecTransportSymbol_fn).call(this, ownerPacketId, repairSbn, repairEsi, parsed.repairData, "moq", catalogTrackName)) return;
|
|
13502
13638
|
const recovered = catalogTrackName === void 0 ? __privateGet(this, _fecManager).feedRepairSymbol(
|
|
@@ -13527,7 +13663,7 @@ var MmtpRouter = class {
|
|
|
13527
13663
|
} else {
|
|
13528
13664
|
__privateGet(this, _fecManager).markBlockCompleted(repairSbn, ownerPacketId, catalogTrackName);
|
|
13529
13665
|
}
|
|
13530
|
-
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, repairSbn, recovered, ownerPacketId,
|
|
13666
|
+
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, repairSbn, recovered, ownerPacketId, catalogTrackName);
|
|
13531
13667
|
}
|
|
13532
13668
|
}
|
|
13533
13669
|
}
|
|
@@ -13535,7 +13671,7 @@ var MmtpRouter = class {
|
|
|
13535
13671
|
/** Route a recovered FEC block through the parser + dedup pipeline.
|
|
13536
13672
|
* Sync WASM decoders return K fixed-width source symbols concatenated. */
|
|
13537
13673
|
routeRecoveredBlock(blockId, data, packetId, catalogTrackName) {
|
|
13538
|
-
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, blockId, data, packetId,
|
|
13674
|
+
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, blockId, data, packetId, catalogTrackName);
|
|
13539
13675
|
}
|
|
13540
13676
|
/** Route a single recovered source symbol through the parser + dedup pipeline.
|
|
13541
13677
|
* Worker-backed decoders emit one padded source symbol per frame event. */
|
|
@@ -13694,8 +13830,9 @@ deriveSbnEsi_fn = function(ssId, packetId) {
|
|
|
13694
13830
|
return { sbn: Math.floor(ssId / k), esi: ssId % k };
|
|
13695
13831
|
};
|
|
13696
13832
|
deriveRepairSbn_fn = function(ssStart, ssbLength, packetId) {
|
|
13697
|
-
|
|
13698
|
-
|
|
13833
|
+
const k = __privateMethod(this, _MmtpRouter_instances, kForPacket_fn).call(this, packetId);
|
|
13834
|
+
if (ssbLength <= 0 || ssbLength > k || ssStart % k !== 0) return null;
|
|
13835
|
+
return Math.floor(ssStart / k);
|
|
13699
13836
|
};
|
|
13700
13837
|
resolveRepairOwnerPacketId_fn = function(packetId, ingress) {
|
|
13701
13838
|
if (__privateMethod(this, _MmtpRouter_instances, classifyPacketId_fn).call(this, packetId) !== null) return packetId;
|
|
@@ -13854,6 +13991,7 @@ processMMTP_fn = function(packet, source, manifestIdentity, manifestAdmitted = f
|
|
|
13854
13991
|
);
|
|
13855
13992
|
}
|
|
13856
13993
|
const repairSbn = __privateMethod(this, _MmtpRouter_instances, deriveRepairSbn_fn).call(this, parsed.ssStart, parsed.ssbLength, ownerPacketId);
|
|
13994
|
+
if (repairSbn === null) return;
|
|
13857
13995
|
const repairEsi = __privateMethod(this, _MmtpRouter_instances, kForPacket_fn).call(this, ownerPacketId) + parsed.rsId;
|
|
13858
13996
|
if (!__privateMethod(this, _MmtpRouter_instances, feedFecTransportSymbol_fn).call(this, ownerPacketId, repairSbn, repairEsi, parsed.repairData, source, catalogTrackNameForPacket(ingress, ownerPacketId))) return;
|
|
13859
13997
|
const repairCatalogTrackName = catalogTrackNameForPacket(ingress, ownerPacketId);
|
|
@@ -13906,7 +14044,7 @@ processMMTP_fn = function(packet, source, manifestIdentity, manifestAdmitted = f
|
|
|
13906
14044
|
repairCatalogTrackName
|
|
13907
14045
|
);
|
|
13908
14046
|
}
|
|
13909
|
-
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, repairSbn, recovered, ownerPacketId,
|
|
14047
|
+
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, repairSbn, recovered, ownerPacketId, catalogTrackNameForPacket(ingress, ownerPacketId));
|
|
13910
14048
|
}
|
|
13911
14049
|
}
|
|
13912
14050
|
}
|
|
@@ -14022,7 +14160,7 @@ processMMTP_fn = function(packet, source, manifestIdentity, manifestAdmitted = f
|
|
|
14022
14160
|
catalogTrackName
|
|
14023
14161
|
);
|
|
14024
14162
|
}
|
|
14025
|
-
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, sourceFec.sbn, recovered, info.packetId,
|
|
14163
|
+
__privateMethod(this, _MmtpRouter_instances, routeRecoveredBlock_fn).call(this, sourceFec.sbn, recovered, info.packetId, catalogTrackName);
|
|
14026
14164
|
}
|
|
14027
14165
|
}
|
|
14028
14166
|
}
|
|
@@ -14370,8 +14508,8 @@ routeDirectRecoveredAudio_fn = function(packetId, data, meta, cb) {
|
|
|
14370
14508
|
};
|
|
14371
14509
|
// ── Private: FEC recovery routing ───────────────────────────────
|
|
14372
14510
|
/** Route WASM-recovered block through appropriate path based on container kind. */
|
|
14373
|
-
routeRecoveredBlock_fn = function(blockId, recovered, ownerPacketId,
|
|
14374
|
-
const k =
|
|
14511
|
+
routeRecoveredBlock_fn = function(blockId, recovered, ownerPacketId, catalogTrackName) {
|
|
14512
|
+
const k = __privateMethod(this, _MmtpRouter_instances, kForPacket_fn).call(this, ownerPacketId);
|
|
14375
14513
|
const packetSymbolSize = __privateMethod(this, _MmtpRouter_instances, symbolSizeForPacket_fn).call(this, ownerPacketId);
|
|
14376
14514
|
const symbolSize = packetSymbolSize > 0 ? packetSymbolSize : void 0;
|
|
14377
14515
|
const result = processFecBlock(recovered, {
|
|
@@ -14452,7 +14590,11 @@ admitRecoveredResult_fn = function(blockId, result, ownerPacketId, catalogTrackN
|
|
|
14452
14590
|
__privateMethod(this, _MmtpRouter_instances, routeProcessedFecSymbols_fn).call(this, blockId, { ...result, symbols: [symbol] }, ownerPacketId, catalogTrackName);
|
|
14453
14591
|
}
|
|
14454
14592
|
admitNext(index + 1);
|
|
14455
|
-
}
|
|
14593
|
+
},
|
|
14594
|
+
// A stalled symbol that is later discarded instead of played must still
|
|
14595
|
+
// advance this loop; enforce mode never calls the release callback for
|
|
14596
|
+
// it (BLO-30095).
|
|
14597
|
+
() => admitNext(index + 1)
|
|
14456
14598
|
);
|
|
14457
14599
|
if (admission.action === "drop") admitNext(index + 1);
|
|
14458
14600
|
};
|
|
@@ -15225,12 +15367,16 @@ var driadDiscovery = new DRIADDiscovery();
|
|
|
15225
15367
|
function endpointKey(endpoint) {
|
|
15226
15368
|
return `${endpoint.sourceAddress ?? ""}|${endpoint.groupAddress}|${endpoint.port}`;
|
|
15227
15369
|
}
|
|
15370
|
+
function carriesMedia(endpoint) {
|
|
15371
|
+
return endpoint.carriesMedia !== false;
|
|
15372
|
+
}
|
|
15228
15373
|
function selectMulticastTier(endpoints, estimate) {
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15374
|
+
const media = endpoints.filter(carriesMedia);
|
|
15375
|
+
if (media.length <= 1)
|
|
15376
|
+
return media[0];
|
|
15377
|
+
const ranked = media.filter((endpoint) => typeof endpoint.bandwidth === "number" && endpoint.bandwidth > 0).sort((a, b) => a.bandwidth - b.bandwidth);
|
|
15232
15378
|
if (ranked.length < 2)
|
|
15233
|
-
return
|
|
15379
|
+
return media[0];
|
|
15234
15380
|
if (estimate === void 0)
|
|
15235
15381
|
return ranked[0];
|
|
15236
15382
|
const budget = estimate * 0.8;
|
|
@@ -15479,7 +15625,7 @@ var MulticastOrchestrator = class {
|
|
|
15479
15625
|
const currentBandwidth = __privateGet(this, _current).bandwidth;
|
|
15480
15626
|
if (typeof currentBandwidth !== "number")
|
|
15481
15627
|
return void 0;
|
|
15482
|
-
const desired = this.options.endpoints.filter((endpoint) => typeof endpoint.bandwidth === "number" && endpoint.bandwidth > currentBandwidth).sort((a, b) => a.bandwidth - b.bandwidth)[0];
|
|
15628
|
+
const desired = this.options.endpoints.filter((endpoint) => carriesMedia(endpoint) && typeof endpoint.bandwidth === "number" && endpoint.bandwidth > currentBandwidth).sort((a, b) => a.bandwidth - b.bandwidth)[0];
|
|
15483
15629
|
if (!desired) {
|
|
15484
15630
|
__privateSet(this, _favored, void 0);
|
|
15485
15631
|
return void 0;
|
|
@@ -16785,6 +16931,24 @@ function publishFecDiagnostics(packetId, stats) {
|
|
|
16785
16931
|
function altGroupKey(track) {
|
|
16786
16932
|
return track.altGroup === void 0 ? DEFAULT_ALT_GROUP : String(track.altGroup);
|
|
16787
16933
|
}
|
|
16934
|
+
function repairTrackNamesBySource(tracks) {
|
|
16935
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
16936
|
+
const add = (source, repair) => {
|
|
16937
|
+
if (!source || !repair) return;
|
|
16938
|
+
const names = bySource.get(source) ?? /* @__PURE__ */ new Set();
|
|
16939
|
+
names.add(repair);
|
|
16940
|
+
bySource.set(source, names);
|
|
16941
|
+
};
|
|
16942
|
+
for (const track of tracks) {
|
|
16943
|
+
if (track.fec !== void 0 && isFecCatalogConfig(track.fec) && track.fec.repairTrack) {
|
|
16944
|
+
add(track.name, track.fec.repairTrack);
|
|
16945
|
+
}
|
|
16946
|
+
if (track.packaging === "fec-repair" && Array.isArray(track.depends) && track.depends.length === 1) {
|
|
16947
|
+
add(track.depends[0], track.name);
|
|
16948
|
+
}
|
|
16949
|
+
}
|
|
16950
|
+
return bySource;
|
|
16951
|
+
}
|
|
16788
16952
|
var _fec, _router, _transport, _reportedFecDiagnosticsFailure, _streamFecBaseline, _trackFecTiming, _switchingSets, _repairPacketIds, _repairInFlight, _repairLifecycleObservers, _trackResetObservers, _onRepairSubscribeCb, _MulticastManager_instances, configureTrackMapper_fn, applyStreamGlobalFecTiming_fn, _onTrackTypeDiscovered, emitRepairLifecycle_fn;
|
|
16789
16953
|
var MulticastManager = class {
|
|
16790
16954
|
constructor(options) {
|
|
@@ -17245,12 +17409,13 @@ var MulticastManager = class {
|
|
|
17245
17409
|
* a factory returning a distinct decoder per stream.
|
|
17246
17410
|
*/
|
|
17247
17411
|
configureMultiTrack(catalog, wasmDecoderSource) {
|
|
17412
|
+
const repairNamesBySource = repairTrackNamesBySource(catalog.tracks);
|
|
17248
17413
|
const repairOwnerGroup = /* @__PURE__ */ new Map();
|
|
17249
17414
|
const repairOwnerAltGroup = /* @__PURE__ */ new Map();
|
|
17250
17415
|
for (const track of catalog.tracks) {
|
|
17251
|
-
|
|
17252
|
-
repairOwnerGroup.set(
|
|
17253
|
-
repairOwnerAltGroup.set(
|
|
17416
|
+
for (const repairName of repairNamesBySource.get(track.name) ?? []) {
|
|
17417
|
+
repairOwnerGroup.set(repairName, altGroupKey(track));
|
|
17418
|
+
repairOwnerAltGroup.set(repairName, track.altGroup);
|
|
17254
17419
|
}
|
|
17255
17420
|
}
|
|
17256
17421
|
const groupKeyFor = (track) => repairOwnerGroup.get(track.name) ?? altGroupKey(track);
|
|
@@ -17353,9 +17518,13 @@ var MulticastManager = class {
|
|
|
17353
17518
|
}
|
|
17354
17519
|
if (track.fec !== void 0) {
|
|
17355
17520
|
const fecCfg = track.fec;
|
|
17356
|
-
|
|
17357
|
-
|
|
17358
|
-
|
|
17521
|
+
if (track.packetId !== void 0) {
|
|
17522
|
+
for (const repairName of repairNamesBySource.get(track.name) ?? []) {
|
|
17523
|
+
const repairTrack = catalogTracksByName.get(repairName);
|
|
17524
|
+
if (repairTrack?.packetId !== void 0) {
|
|
17525
|
+
__privateGet(this, _router).setRepairPacketIdOwner(repairTrack.packetId, track.packetId);
|
|
17526
|
+
}
|
|
17527
|
+
}
|
|
17359
17528
|
}
|
|
17360
17529
|
const wasmDecoder = fecDecoders.get(i);
|
|
17361
17530
|
if (track.packetId !== void 0 && wasmDecoder !== void 0) {
|
|
@@ -17645,7 +17814,9 @@ async function setupFecWorkerForTrack(opts) {
|
|
|
17645
17814
|
sampleRate: opts.sampleRate,
|
|
17646
17815
|
algorithm: "raptor",
|
|
17647
17816
|
k: opts.fecK,
|
|
17648
|
-
|
|
17817
|
+
// P as this receiver joined it, not the catalog total: the worker snapshot
|
|
17818
|
+
// and CMCD `x-bc-fec-p` are read from this. Identity on a single layer.
|
|
17819
|
+
repairCount: opts.joinedRepairCount ?? opts.fecRepairCount,
|
|
17649
17820
|
symbolSize: opts.fecSymbolSize,
|
|
17650
17821
|
interleaveDepth: interleaveDepthBlocks,
|
|
17651
17822
|
interleaveMs: opts.fecInterleaveMs,
|
|
@@ -19507,6 +19678,16 @@ var NO_FEC = {
|
|
|
19507
19678
|
fecSymbolSize: 0,
|
|
19508
19679
|
fecInterleaveMs: 0
|
|
19509
19680
|
};
|
|
19681
|
+
function joinedRepairSymbolCount(params, joinedRepairTrackNames) {
|
|
19682
|
+
const layers = params.repairLayers;
|
|
19683
|
+
if (layers === void 0 || layers.length === 0) return params.fecRepairCount;
|
|
19684
|
+
const joined = new Set(joinedRepairTrackNames);
|
|
19685
|
+
let total = 0;
|
|
19686
|
+
for (const layer of layers) {
|
|
19687
|
+
if (joined.has(layer.repairTrackName)) total += layer.repairSymbols;
|
|
19688
|
+
}
|
|
19689
|
+
return total;
|
|
19690
|
+
}
|
|
19510
19691
|
function recordOf(value) {
|
|
19511
19692
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
19512
19693
|
}
|
|
@@ -19836,6 +20017,7 @@ export {
|
|
|
19836
20017
|
FEC_SBN_MAX,
|
|
19837
20018
|
FecSourceInfo,
|
|
19838
20019
|
FecStarvationDetector,
|
|
20020
|
+
JOIN_DEFER_WARN_MS,
|
|
19839
20021
|
KEYFRAME_LOST_TIMEOUT_SLACK,
|
|
19840
20022
|
LOCHeaderExtensionId,
|
|
19841
20023
|
MAX_ENCODING_SYMBOL_ID,
|
|
@@ -19936,6 +20118,7 @@ export {
|
|
|
19936
20118
|
isSignalingPacket,
|
|
19937
20119
|
isSourcePacket,
|
|
19938
20120
|
isTrackTimingConfig,
|
|
20121
|
+
joinedRepairSymbolCount,
|
|
19939
20122
|
mergeOverrideIntoCmsfTracks,
|
|
19940
20123
|
mergeOverrideIntoHangRenditions,
|
|
19941
20124
|
mfuReassemblyTimeoutMs,
|