@blockcast/mmt-container 2.1.0 → 2.2.0-main.050b52fb9b00
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 +1949 -374
- 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 +70 -12
- package/dist/fec-manager.d.ts.map +1 -1
- package/dist/fec-manager.js +403 -58
- 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 +6 -5
- 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 +48 -13
- package/dist/iso-block-locator.d.ts.map +1 -1
- package/dist/iso-block-locator.js +97 -25
- 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 +79 -10
- package/dist/mmtp-container-parser.d.ts.map +1 -1
- package/dist/mmtp-container-parser.js +219 -45
- package/dist/mmtp-container-parser.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +342 -63
- package/dist/mmtp-container-parser.no-modules.js.map +3 -3
- package/dist/mmtp-decode-pipeline.js +218 -45
- 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 +43 -9
- package/dist/mmtp-router.d.ts.map +1 -1
- package/dist/mmtp-router.js +2006 -95
- 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 +28 -5
- package/dist/multicast-manager.d.ts.map +1 -1
- package/dist/multicast-manager.js +16116 -15005
- 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 +336 -59
- package/dist/no-modules.js.map +3 -3
- package/dist/repair-fetch.d.ts +36 -8
- package/dist/repair-fetch.d.ts.map +1 -1
- package/dist/repair-fetch.js +285 -26
- package/dist/repair-fetch.js.map +3 -3
- 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.d.ts.map +1 -1
- package/dist/track-session.js +1 -0
- package/dist/track-session.js.map +2 -2
- package/dist/wasm-mfu-reassembler.js.map +1 -1
- package/dist/wasm-mmtp-container-parser.js +218 -45
- 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 +433 -32
- package/src/fec-worker-setup.ts +2 -2
- package/src/index.ts +20 -2
- package/src/iso-block-locator.ts +133 -31
- package/src/iso-bmff-timing.ts +40 -1
- package/src/mmtp-container-parser.ts +306 -29
- package/src/mmtp-fec-session.ts +115 -15
- package/src/mmtp-router.ts +629 -54
- package/src/multicast-manager.ts +70 -11
- package/src/multicast-transport.ts +44 -20
- package/src/repair-fetch.ts +363 -49
- package/src/repair-layer-subscriptions.ts +261 -0
- package/src/track-session.ts +4 -1
package/src/multicast-manager.ts
CHANGED
|
@@ -18,8 +18,10 @@ import {
|
|
|
18
18
|
type FecFallbackDecoder,
|
|
19
19
|
type MulticastSymbolDelivery,
|
|
20
20
|
type RepairVia,
|
|
21
|
+
type ExpiredIsoHole,
|
|
21
22
|
type UndelimitedIsoLoss,
|
|
22
23
|
type FecFailClosedEvent,
|
|
24
|
+
type IsoSpanFailure,
|
|
23
25
|
} from "./fec-manager.js";
|
|
24
26
|
import {
|
|
25
27
|
deriveBlockClassifierGeometry,
|
|
@@ -50,7 +52,11 @@ import {
|
|
|
50
52
|
type StreamSwitchCommit,
|
|
51
53
|
type TrackPacketCallback,
|
|
52
54
|
} from "./mmtp-router.js";
|
|
53
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
isMulticastTrackPacketId,
|
|
57
|
+
userAgentVerifiedIngress,
|
|
58
|
+
type WindowMulticastGateway,
|
|
59
|
+
} from "@blockcast/mmt-transport";
|
|
54
60
|
import {
|
|
55
61
|
MulticastTransport,
|
|
56
62
|
type MulticastFailbackReason,
|
|
@@ -94,6 +100,8 @@ export interface MulticastRepairEndpoint {
|
|
|
94
100
|
mode?: string;
|
|
95
101
|
amtRelay?: string;
|
|
96
102
|
amtRelayPort?: number;
|
|
103
|
+
/** The media join's `'driad'` discovery (no relay pinned), carried so the repair group rides the same relay. */
|
|
104
|
+
amtDiscovery?: 'driad';
|
|
97
105
|
/** The repair packet IDs this group carries. */
|
|
98
106
|
packetIds: number[];
|
|
99
107
|
/** Each repair packet ID bound to the media packet ID it repairs. */
|
|
@@ -401,6 +409,14 @@ export type RepairLifecycleEvent =
|
|
|
401
409
|
readonly block: RepairBlockIdentity;
|
|
402
410
|
readonly blockClass: BlockClass;
|
|
403
411
|
readonly symbols: RepairSymbolCounts;
|
|
412
|
+
/**
|
|
413
|
+
* Set when what failed is an iso-ssbg1-v1 repair-less span starting at
|
|
414
|
+
* `block.sbn`: `length` SS_IDs between two stated blocks, `sources` of
|
|
415
|
+
* them received. No repair stated the blocks inside it, so the receiver
|
|
416
|
+
* cannot tell which of them lost a source; it is not the failure of the
|
|
417
|
+
* block at `block.sbn` alone.
|
|
418
|
+
*/
|
|
419
|
+
readonly span?: IsoSpanFailure;
|
|
404
420
|
}
|
|
405
421
|
| {
|
|
406
422
|
readonly version: 2;
|
|
@@ -785,6 +801,19 @@ function isSymbolCounts(value: unknown): boolean {
|
|
|
785
801
|
);
|
|
786
802
|
}
|
|
787
803
|
|
|
804
|
+
/** A failed repair-less span: `sources` of its `length` SS_IDs arrived, never all. */
|
|
805
|
+
function isSpanFailure(value: unknown): boolean {
|
|
806
|
+
if (!isRecord(value) || !hasExactKeys(value, ["length", "sources"])) return false;
|
|
807
|
+
const length = value["length"];
|
|
808
|
+
const sources = value["sources"];
|
|
809
|
+
return (
|
|
810
|
+
Number.isSafeInteger(length) &&
|
|
811
|
+
(length as number) > 0 &&
|
|
812
|
+
isNonNegativeSafeInteger(sources) &&
|
|
813
|
+
(sources as number) < (length as number)
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
|
|
788
817
|
function isNullableNonNegative(value: unknown): boolean {
|
|
789
818
|
return value === null || (typeof value === "number" && Number.isFinite(value) && value >= 0);
|
|
790
819
|
}
|
|
@@ -827,10 +856,16 @@ export function isRepairLifecycleEvent(
|
|
|
827
856
|
);
|
|
828
857
|
case "failed":
|
|
829
858
|
return (
|
|
830
|
-
hasExactKeys(
|
|
859
|
+
hasExactKeys(
|
|
860
|
+
value,
|
|
861
|
+
"span" in value
|
|
862
|
+
? ["version", "type", "block", "blockClass", "symbols", "span"]
|
|
863
|
+
: ["version", "type", "block", "blockClass", "symbols"],
|
|
864
|
+
) &&
|
|
831
865
|
isRepairBlockIdentity(block) &&
|
|
832
866
|
BLOCK_CLASSES.has(value["blockClass"]) &&
|
|
833
|
-
isSymbolCounts(value["symbols"])
|
|
867
|
+
isSymbolCounts(value["symbols"]) &&
|
|
868
|
+
(!("span" in value) || isSpanFailure(value["span"]))
|
|
834
869
|
);
|
|
835
870
|
case "repair-preempted":
|
|
836
871
|
case "repair-deferred":
|
|
@@ -1360,7 +1395,7 @@ export class MulticastManager {
|
|
|
1360
1395
|
onPublisherRestart: (packetId, catalogTrackName) => {
|
|
1361
1396
|
this.#resetStreamOutsideRouter(packetId, catalogTrackName);
|
|
1362
1397
|
},
|
|
1363
|
-
onBlockFailed: (sbn, packetId, catalogTrackName, blockClass) => {
|
|
1398
|
+
onBlockFailed: (sbn, packetId, catalogTrackName, blockClass, span) => {
|
|
1364
1399
|
const pathCount = this.#fec.blockPathCount(
|
|
1365
1400
|
sbn,
|
|
1366
1401
|
packetId,
|
|
@@ -1379,6 +1414,7 @@ export class MulticastManager {
|
|
|
1379
1414
|
multicast: pathCount?.multicastSymbols ?? 0,
|
|
1380
1415
|
moq: pathCount?.moqSymbols ?? 0,
|
|
1381
1416
|
},
|
|
1417
|
+
...(span === undefined ? {} : { span }),
|
|
1382
1418
|
});
|
|
1383
1419
|
},
|
|
1384
1420
|
onFrameGap: (decision) => {
|
|
@@ -2353,10 +2389,20 @@ export class MulticastManager {
|
|
|
2353
2389
|
* repair roles and owners are registered here; in-band owners stay the
|
|
2354
2390
|
* caller's. Joining is best effort: a group that fails to join is logged
|
|
2355
2391
|
* and leaves the media join as it was.
|
|
2392
|
+
*
|
|
2393
|
+
* `options.gateway` names the gateway a subscribe callback reads through.
|
|
2394
|
+
* When it is the browser's own MulticastReceiver provider, the callback's
|
|
2395
|
+
* packets are fed as admitted by the user agent
|
|
2396
|
+
* (`userAgentVerifiedIngress`); nothing the callback passes can mark them.
|
|
2397
|
+
* The mark rests on this statement, not on the data path: every packet the
|
|
2398
|
+
* callback delivers must come from a subscription opened on
|
|
2399
|
+
* `options.gateway`. A callback that also merges another source (a MoQ or
|
|
2400
|
+
* WebSocket repair feed) must not name a native provider here.
|
|
2356
2401
|
*/
|
|
2357
2402
|
joinRepairEndpoints(
|
|
2358
2403
|
endpoints: readonly MulticastRepairEndpoint[],
|
|
2359
2404
|
provider?: WindowMulticastGateway | MulticastRepairSubscribe,
|
|
2405
|
+
options?: { gateway?: WindowMulticastGateway },
|
|
2360
2406
|
): () => void {
|
|
2361
2407
|
const releases: Array<() => void> = [];
|
|
2362
2408
|
let released = false;
|
|
@@ -2382,22 +2428,26 @@ export class MulticastManager {
|
|
|
2382
2428
|
...(endpoint.flow === undefined ? {} : { flow: endpoint.flow }),
|
|
2383
2429
|
};
|
|
2384
2430
|
let sender: string | undefined;
|
|
2385
|
-
const
|
|
2431
|
+
const feed = (packet: Uint8Array, sourceAddress: string | undefined, ingressToFeed: MmtpIngressContext) => {
|
|
2386
2432
|
if (released) return;
|
|
2387
2433
|
// The media join's sender owns the repair too; this group's own first
|
|
2388
2434
|
// sender stands in only until the media join has one.
|
|
2389
2435
|
if (sourceAddress !== undefined && !sameDatagramSource(sourceAddress, this.#transport.sender ?? (sender ??= sourceAddress))) return;
|
|
2390
|
-
this.#router.feedPacket(packet, "multicast",
|
|
2436
|
+
this.#router.feedPacket(packet, "multicast", ingressToFeed);
|
|
2391
2437
|
};
|
|
2392
2438
|
const fail = (error: unknown) =>
|
|
2393
2439
|
console.warn(`[MulticastManager] repair group ${endpoint.group}:${endpoint.port} not joined`, error);
|
|
2394
2440
|
if (typeof provider === "function") {
|
|
2441
|
+
const marked = userAgentVerifiedIngress(ingress, options?.gateway);
|
|
2442
|
+
const onPacket = (packet: Uint8Array, sourceAddress?: string) => feed(packet, sourceAddress, marked);
|
|
2395
2443
|
Promise.resolve()
|
|
2396
2444
|
.then(() => provider(endpoint, onPacket))
|
|
2397
2445
|
.then((release) => (released ? safely(release) : releases.push(release)), fail);
|
|
2398
2446
|
continue;
|
|
2399
2447
|
}
|
|
2400
|
-
|
|
2448
|
+
// The transport marks what it delivers when its gateway is the user
|
|
2449
|
+
// agent's MulticastReceiver provider; feedPacket would not.
|
|
2450
|
+
const transport = new MulticastTransport<MmtpIngressContext>((packet, delivered) => feed(packet, undefined, delivered ?? ingress), {
|
|
2401
2451
|
gateway: provider,
|
|
2402
2452
|
lockedTo: () => this.#transport.sender,
|
|
2403
2453
|
});
|
|
@@ -2409,11 +2459,12 @@ export class MulticastManager {
|
|
|
2409
2459
|
mode: endpoint.mode as MulticastEndpointConfig["mode"],
|
|
2410
2460
|
amtRelay: endpoint.amtRelay,
|
|
2411
2461
|
amtRelayPort: endpoint.amtRelayPort ?? (endpoint.amtRelay?.trim() ? DEFAULT_AMT_RELAY_PORT : undefined),
|
|
2462
|
+
amtDiscovery: endpoint.amtDiscovery,
|
|
2412
2463
|
packetIds: endpoint.packetIds,
|
|
2413
2464
|
tracks: endpoint.tracks.map(({ name, packetId }) => ({ name, packetId })),
|
|
2414
2465
|
// A protected repair group's records ride in band on its port (7.2.3).
|
|
2415
2466
|
...(endpoint.flow === undefined ? {} : { protected: true }),
|
|
2416
|
-
}).then((joined) => {
|
|
2467
|
+
}, ingress).then((joined) => {
|
|
2417
2468
|
if (!joined && !released) fail(transport.lastJoinOutcome);
|
|
2418
2469
|
});
|
|
2419
2470
|
}
|
|
@@ -3172,10 +3223,15 @@ export class MulticastManager {
|
|
|
3172
3223
|
* Register the range repair scheduler (draft-ramadan-moq-fec §7.5): from now
|
|
3173
3224
|
* on an iso-ssbg1-v1 gap missing a source and every repair is kept as a
|
|
3174
3225
|
* pending hole and reported here, and `closeIsoHoles` must be called for it
|
|
3175
|
-
* once its range FETCH ends (or none is sent).
|
|
3226
|
+
* once its range FETCH ends (or none is sent). `onExpired` is told of a
|
|
3227
|
+
* pending hole the stream runs past the locator's horizon: returning true,
|
|
3228
|
+
* the caller closes it (`closeIsoHoles`); otherwise it is discarded.
|
|
3176
3229
|
*/
|
|
3177
|
-
onUndelimitedLoss(
|
|
3178
|
-
|
|
3230
|
+
onUndelimitedLoss(
|
|
3231
|
+
cb: (loss: UndelimitedIsoLoss) => void,
|
|
3232
|
+
onExpired?: (hole: ExpiredIsoHole) => boolean,
|
|
3233
|
+
): void {
|
|
3234
|
+
this.#fec.setUndelimitedLossHandler(cb, onExpired ?? null);
|
|
3179
3235
|
}
|
|
3180
3236
|
|
|
3181
3237
|
/**
|
|
@@ -3494,6 +3550,9 @@ export class MulticastManager {
|
|
|
3494
3550
|
...("symbols" in event
|
|
3495
3551
|
? { symbols: Object.freeze({ ...event.symbols }) }
|
|
3496
3552
|
: {}),
|
|
3553
|
+
...("span" in event && event.span !== undefined
|
|
3554
|
+
? { span: Object.freeze({ ...event.span }) }
|
|
3555
|
+
: {}),
|
|
3497
3556
|
},
|
|
3498
3557
|
) as RepairLifecycleEvent);
|
|
3499
3558
|
// Serialize before invoking observers so a re-entrant observer cannot log
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
isMulticastTrackPacketId,
|
|
9
|
+
isUserAgentVerifiedGateway,
|
|
10
|
+
resolveMulticastGateway,
|
|
9
11
|
subscriptionDeliversPacketBatches,
|
|
12
|
+
userAgentVerifiedIngress,
|
|
10
13
|
toWindowMulticastSubscribeConfig,
|
|
11
14
|
type WindowMulticastDelivery,
|
|
12
15
|
type WindowMulticastGateway,
|
|
@@ -52,7 +55,13 @@ export interface MulticastTransportConfig {
|
|
|
52
55
|
protected?: boolean
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
/**
|
|
59
|
+
* The leg a join resolved to. `'user-agent'`: the browser's own
|
|
60
|
+
* `MulticastReceiver` delivers it, which picks native or AMT itself and does
|
|
61
|
+
* not say which. CMCD has no user-agent value, so a caller reports a
|
|
62
|
+
* `'user-agent'` join as `'native'` (`TransportSnapshot.transport`).
|
|
63
|
+
*/
|
|
64
|
+
export type ResolvedMulticastTransport = 'native' | 'amt' | 'user-agent'
|
|
56
65
|
|
|
57
66
|
/**
|
|
58
67
|
* Why a joined transport handed control back to MoQ.
|
|
@@ -211,16 +220,8 @@ function providerErrorOf(error: unknown): MulticastJoinProviderError | undefined
|
|
|
211
220
|
*/
|
|
212
221
|
const MAX_TRACKED_DROPPED_PIDS = 16
|
|
213
222
|
|
|
214
|
-
type MulticastGlobals = typeof globalThis & {
|
|
215
|
-
multicast?: WindowMulticastGateway
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function getMulticastGlobals(): MulticastGlobals {
|
|
219
|
-
return globalThis as MulticastGlobals
|
|
220
|
-
}
|
|
221
|
-
|
|
222
223
|
function hasMulticastGateway(): boolean {
|
|
223
|
-
return typeof
|
|
224
|
+
return typeof resolveMulticastGateway()?.subscribe === 'function'
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
/**
|
|
@@ -371,6 +372,9 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
371
372
|
// listener closure, so an in-place admission change (setContext) applies
|
|
372
373
|
// from the next packet on without rejoining.
|
|
373
374
|
#context: TPacketContext | undefined = undefined
|
|
375
|
+
#deliveredContext: TPacketContext | undefined = undefined
|
|
376
|
+
/** The live join's gateway, when it is the user agent's MulticastReceiver provider. */
|
|
377
|
+
#userAgentGateway: WindowMulticastGateway | undefined = undefined
|
|
374
378
|
// The live join's provider-side filter. An in-place widening must reach it,
|
|
375
379
|
// or the provider never delivers the new ID; null without a live join.
|
|
376
380
|
#providerFilter: ProviderFilter | null = null
|
|
@@ -415,7 +419,7 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
415
419
|
this.#sender = undefined
|
|
416
420
|
|
|
417
421
|
if (this.#disposed) return this.#declined(generation, 'disposed')
|
|
418
|
-
const gateway = this.#gateway ??
|
|
422
|
+
const gateway = this.#gateway ?? resolveMulticastGateway()
|
|
419
423
|
if (typeof gateway?.subscribe !== 'function') {
|
|
420
424
|
console.warn('[MulticastTransport] Multicast API not available')
|
|
421
425
|
return this.#declined(generation, 'unavailable')
|
|
@@ -435,15 +439,18 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
435
439
|
console.log(
|
|
436
440
|
`[MulticastTransport] window.multicast.subscribe(${config.sourceAddress ?? config.senderAddress ?? '*'}, ${config.groupAddress}, ${config.port})`,
|
|
437
441
|
)
|
|
442
|
+
// The browser's MulticastReceiver picks native or AMT, and the relay,
|
|
443
|
+
// itself: ask it for the group only.
|
|
444
|
+
const userAgent = isUserAgentVerifiedGateway(gateway)
|
|
438
445
|
const subscribeConfig = toWindowMulticastSubscribeConfig({
|
|
439
446
|
source: config.sourceAddress,
|
|
440
447
|
senderAddress: config.senderAddress,
|
|
441
448
|
group: config.groupAddress,
|
|
442
449
|
port: config.port,
|
|
443
|
-
mode: config.mode,
|
|
444
|
-
amtRelay: config.amtRelay,
|
|
445
|
-
amtRelayPort: config.amtRelayPort,
|
|
446
|
-
amtDiscovery: config.amtDiscovery,
|
|
450
|
+
mode: userAgent ? 'native' : config.mode,
|
|
451
|
+
amtRelay: userAgent ? undefined : config.amtRelay,
|
|
452
|
+
amtRelayPort: userAgent ? undefined : config.amtRelayPort,
|
|
453
|
+
amtDiscovery: userAgent ? undefined : config.amtDiscovery,
|
|
447
454
|
packetIds: config.packetIds,
|
|
448
455
|
tracks: config.tracks,
|
|
449
456
|
atsc3: config.atsc3,
|
|
@@ -506,7 +513,8 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
506
513
|
acknowledgedUpdate: 0,
|
|
507
514
|
inFlight: 0,
|
|
508
515
|
}
|
|
509
|
-
this.#
|
|
516
|
+
this.#userAgentGateway = userAgent ? gateway : undefined
|
|
517
|
+
this.#setContext(context)
|
|
510
518
|
// Seed the allow-list's counters so accepted packets never insert. An
|
|
511
519
|
// id already counted by an earlier join keeps its count: the counters
|
|
512
520
|
// are cumulative across rejoins, as bytesReceived is.
|
|
@@ -521,7 +529,7 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
521
529
|
// gateway no longer exposes a mutable transport/transportchange
|
|
522
530
|
// surface, so assign this only after subscribe() has resolved and the
|
|
523
531
|
// returned subscription has passed the event-surface check above.
|
|
524
|
-
this.#resolvedTransport = subscribeConfig.origin === 'amt' ? 'amt' : 'native'
|
|
532
|
+
this.#resolvedTransport = userAgent ? 'user-agent' : subscribeConfig.origin === 'amt' ? 'amt' : 'native'
|
|
525
533
|
// The provider alone knows whether its packets are independent
|
|
526
534
|
// datagrams or an ordered relay of one socket; undeclared promises no
|
|
527
535
|
// ordering. Announce it before the listener can deliver a packet. A
|
|
@@ -630,7 +638,7 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
630
638
|
// Read per packet: a callback that changes the admission (an in-place
|
|
631
639
|
// rendition switch committing on this very packet) takes effect from the
|
|
632
640
|
// next packet, including the rest of a batch.
|
|
633
|
-
this.#onPacket(packet, this.#
|
|
641
|
+
this.#onPacket(packet, this.#deliveredContext)
|
|
634
642
|
return liveness
|
|
635
643
|
}
|
|
636
644
|
|
|
@@ -872,8 +880,10 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
872
880
|
}
|
|
873
881
|
|
|
874
882
|
/**
|
|
875
|
-
*
|
|
876
|
-
*
|
|
883
|
+
* The live join's context as the caller gave it (the join's `context`, or
|
|
884
|
+
* the last setContext), or undefined without a live join. On a native
|
|
885
|
+
* provider each accepted packet is delivered with a marked copy of it
|
|
886
|
+
* (`userAgentVerifiedIngress`); this getter never carries the mark.
|
|
877
887
|
*/
|
|
878
888
|
get context(): TPacketContext | undefined {
|
|
879
889
|
return this.#context
|
|
@@ -899,7 +909,19 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
899
909
|
'[MulticastTransport] setContext needs a live join; join() carries the first context',
|
|
900
910
|
)
|
|
901
911
|
}
|
|
912
|
+
this.#setContext(context)
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* The join's context, and what the subscription delivers with each packet:
|
|
917
|
+
* marked admitted by the user agent when the gateway is its native
|
|
918
|
+
* MulticastReceiver provider. feedPacket never marks.
|
|
919
|
+
*/
|
|
920
|
+
#setContext(context: TPacketContext | undefined): void {
|
|
902
921
|
this.#context = context
|
|
922
|
+
this.#deliveredContext = this.#userAgentGateway !== undefined && typeof context === 'object' && context !== null
|
|
923
|
+
? userAgentVerifiedIngress(context, this.#userAgentGateway)
|
|
924
|
+
: context
|
|
903
925
|
}
|
|
904
926
|
|
|
905
927
|
/**
|
|
@@ -1040,6 +1062,8 @@ export class MulticastTransport<TPacketContext = never> {
|
|
|
1040
1062
|
this.#matchedSource = undefined
|
|
1041
1063
|
this.#providerFilter = null
|
|
1042
1064
|
this.#context = undefined
|
|
1065
|
+
this.#deliveredContext = undefined
|
|
1066
|
+
this.#userAgentGateway = undefined
|
|
1043
1067
|
this.#withdrawnPacketIds.clear()
|
|
1044
1068
|
}
|
|
1045
1069
|
|