Files
v10/dist/dev/playback/behaviors/derive-cdn-priority.js
T

68 lines
3.2 KiB
JavaScript

import { computed, peek } from "../../core/signals/primitives.js";
import { defineBehavior } from "../../core/composition/create-composition.js";
import { createMachineReactor } from "../../core/reactors/create-machine-reactor.js";
import { isResolvedPresentation } from "../../media/types/index.js";
import { getCdnId, getOrderedCdnIds } from "../../media/utils/cdn.js";
//#region src/playback/behaviors/derive-cdn-priority.ts
/**
* **Session-level CDN priority.** While a presentation is resolved, owns the
* `cdnPriority` signal: the distinct CDNs the source is served from (origin of
* each track's URL), in manifest priority order — most-preferred first. Cleared
* on src unload. The name mirrors HLS content steering's `PATHWAY-PRIORITY`.
*
* Redundant-stream sources (e.g. Mux's `?redundant_streams=true`) list the same
* content on multiple hosts, so the candidate tracks already include one variant
* per CDN. This behavior publishes *which* CDNs exist and their priority; the
* `preferActiveCdn` scope rule in `track-switching` reads `cdnPriority` and
* narrows each type's candidates to the first CDN with surviving tracks — so
* video / audio / text all resolve from one host (the shared list is the
* per-presentation coherence guarantee).
*
* The "active" CDN is not stored — it's derived by the scope as the
* highest-priority entry in `cdnPriority` that still has tracks after the
* constraints pre-pass. That makes failover a pure consequence of the (future)
* failed-CDN constraint: when the primary's tracks are pruned during cooldown,
* the scope falls to the next CDN; when the primary recovers, it snaps back.
* Content steering, when it lands, reorders `cdnPriority` (pathway priority as a
* sort key).
*
* Lifecycle: `'presentation-unresolved'` ↔ `'presentation-resolved'`, mirroring
* `setupTrackSwitching`. The resolved state owns the signal; its entry-returned
* cleanup clears it on exit (canonical cleanup-binds-to-setup per `reactors.md`).
*/
const samePriority = (a, b) => !!a && a.length === b.length && a.every((cdn, i) => cdn === b[i]);
/**
* Manage `cdnPriority`: publish the manifest-ordered CDN list on src load, clear
* on src unload.
*
* @example
* const reactor = deriveCdnPriority.setup({ state });
*/
const deriveCdnPriority = defineBehavior({
stateKeys: ["presentation", "cdnPriority"],
contextKeys: [],
setup: ({ state, config = {} }) => {
const getCdnId$1 = config.getCdnId ?? getCdnId;
const derivedStateSignal = computed(() => isResolvedPresentation(state.presentation.get()) ? "presentation-resolved" : "presentation-unresolved");
return createMachineReactor({
initial: "presentation-unresolved",
monitor: () => derivedStateSignal.get(),
states: {
"presentation-unresolved": {},
"presentation-resolved": {
entry: () => () => state.cdnPriority.set(void 0),
effects: [() => {
const presentation = state.presentation.get();
if (!isResolvedPresentation(presentation)) return;
const next = getOrderedCdnIds(presentation, getCdnId$1);
if (!samePriority(peek(state.cdnPriority), next)) state.cdnPriority.set(next);
}]
}
}
});
}
});
//#endregion
export { deriveCdnPriority };
//# sourceMappingURL=derive-cdn-priority.js.map