@videojs/spf 10.0.0-beta.28 → 10.0.0-beta.29
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/default/hls.js +2 -1
- package/dist/default/media/dom/screen.js +129 -0
- package/dist/default/media/dom/screen.js.map +1 -0
- package/dist/default/media/errors.js +9 -2
- package/dist/default/media/errors.js.map +1 -1
- package/dist/default/media/primitives/select-tracks.js +31 -47
- package/dist/default/media/primitives/select-tracks.js.map +1 -1
- package/dist/default/playback/adapters/hls-background-video/adapter.js +99 -11
- package/dist/default/playback/adapters/hls-background-video/adapter.js.map +1 -1
- package/dist/default/playback/adapters/hls-video/error-surface.js.map +1 -1
- package/dist/default/playback/adapters/mux-video/adapter.js +16 -3
- package/dist/default/playback/adapters/mux-video/adapter.js.map +1 -1
- package/dist/default/playback/behaviors/collect-errors.js +36 -2
- package/dist/default/playback/behaviors/collect-errors.js.map +1 -1
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js +29 -0
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/default/playback/behaviors/select-tracks.js +143 -28
- package/dist/default/playback/behaviors/select-tracks.js.map +1 -1
- package/dist/default/playback/behaviors/track-switching.js +5 -68
- package/dist/default/playback/behaviors/track-switching.js.map +1 -1
- package/dist/default/playback/engines/hls/engine-background-video.js +22 -5
- package/dist/default/playback/engines/hls/engine-background-video.js.map +1 -1
- package/dist/default/playback/primitives/error-messages.js +13 -1
- package/dist/default/playback/primitives/error-messages.js.map +1 -1
- package/dist/default/playback/primitives/selection-rules.js +85 -0
- package/dist/default/playback/primitives/selection-rules.js.map +1 -0
- package/dist/dev/hls-background-video.d.ts +2 -1
- package/dist/dev/hls.d.ts +2 -1
- package/dist/dev/hls.js +2 -1
- package/dist/dev/media/dom/screen.d.ts +26 -0
- package/dist/dev/media/dom/screen.d.ts.map +1 -0
- package/dist/dev/media/dom/screen.js +129 -0
- package/dist/dev/media/dom/screen.js.map +1 -0
- package/dist/dev/media/errors.d.ts.map +1 -1
- package/dist/dev/media/errors.js +9 -2
- package/dist/dev/media/errors.js.map +1 -1
- package/dist/dev/media/primitives/select-tracks.js +31 -47
- package/dist/dev/media/primitives/select-tracks.js.map +1 -1
- package/dist/dev/mux-background-video.d.ts +2 -1
- package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts +25 -7
- package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts.map +1 -1
- package/dist/dev/playback/adapters/hls-background-video/adapter.js +99 -11
- package/dist/dev/playback/adapters/hls-background-video/adapter.js.map +1 -1
- package/dist/dev/playback/adapters/hls-video/error-surface.d.ts.map +1 -1
- package/dist/dev/playback/adapters/hls-video/error-surface.js.map +1 -1
- package/dist/dev/playback/adapters/mux-video/adapter.d.ts +1 -0
- package/dist/dev/playback/adapters/mux-video/adapter.d.ts.map +1 -1
- package/dist/dev/playback/adapters/mux-video/adapter.js +16 -3
- package/dist/dev/playback/adapters/mux-video/adapter.js.map +1 -1
- package/dist/dev/playback/behaviors/collect-errors.js +36 -2
- package/dist/dev/playback/behaviors/collect-errors.js.map +1 -1
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js +29 -0
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.d.ts +64 -6
- package/dist/dev/playback/behaviors/select-tracks.d.ts.map +1 -1
- package/dist/dev/playback/behaviors/select-tracks.js +143 -28
- package/dist/dev/playback/behaviors/select-tracks.js.map +1 -1
- package/dist/dev/playback/behaviors/track-switching.js +5 -68
- package/dist/dev/playback/behaviors/track-switching.js.map +1 -1
- package/dist/dev/playback/engines/hls/engine-background-video.d.ts +63 -11
- package/dist/dev/playback/engines/hls/engine-background-video.d.ts.map +1 -1
- package/dist/dev/playback/engines/hls/engine-background-video.js +22 -5
- package/dist/dev/playback/engines/hls/engine-background-video.js.map +1 -1
- package/dist/dev/playback/primitives/error-messages.js +13 -1
- package/dist/dev/playback/primitives/error-messages.js.map +1 -1
- package/dist/dev/playback/primitives/selection-rules.d.ts +38 -0
- package/dist/dev/playback/primitives/selection-rules.d.ts.map +1 -0
- package/dist/dev/playback/primitives/selection-rules.js +85 -0
- package/dist/dev/playback/primitives/selection-rules.js.map +1 -0
- package/package.json +3 -3
- package/dist/dev/media/primitives/select-tracks.d.ts +0 -35
- package/dist/dev/media/primitives/select-tracks.d.ts.map +0 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//#region src/playback/primitives/selection-rules.ts
|
|
2
|
+
/**
|
|
3
|
+
* Apply rules to a candidate list in order; the pick is the first survivor.
|
|
4
|
+
* Two responsibilities the rules don't carry: a rule that returns nothing is
|
|
5
|
+
* skipped (fall-through — a preference never empties the set), and once one
|
|
6
|
+
* survivor remains the chain stops (early-bail — later rules, including the
|
|
7
|
+
* bandwidth ranker, never run, so the effect doesn't subscribe to their
|
|
8
|
+
* signals while the choice is fixed).
|
|
9
|
+
*
|
|
10
|
+
* @param rules - Rules to apply, most authoritative first
|
|
11
|
+
* @param tracks - Candidate tracks
|
|
12
|
+
* @param deps - The behavior's `{ state, context, config }`, passed through to each rule
|
|
13
|
+
* @returns The surviving candidates, pick first
|
|
14
|
+
*/
|
|
15
|
+
function applyRules(rules, tracks, deps) {
|
|
16
|
+
let current = tracks;
|
|
17
|
+
for (const rule of rules) {
|
|
18
|
+
const remaining = rule(current, deps);
|
|
19
|
+
if (remaining.length === 0) continue;
|
|
20
|
+
current = remaining;
|
|
21
|
+
if (current.length === 1) break;
|
|
22
|
+
}
|
|
23
|
+
return current;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Apply hard constraints to a candidate list — the pre-pass that runs before the
|
|
27
|
+
* rule chain. A constraint shares a rule's signature but its exclusion is
|
|
28
|
+
* *hard*: it removes the unplayable (a codec the environment can't decode, a CDN
|
|
29
|
+
* in failover cooldown) and a removed track is never attempted. Unlike
|
|
30
|
+
* `applyRules`, this never skips an empty result and never early-bails — every
|
|
31
|
+
* constraint always applies, and an empty survivor set is a real outcome
|
|
32
|
+
* ("nothing playable here"), not a fall-through. Because each constraint only
|
|
33
|
+
* removes, the order they run in can't change the result.
|
|
34
|
+
*
|
|
35
|
+
* @param constraints - Constraints to apply (pooled, order-independent)
|
|
36
|
+
* @param tracks - Candidate tracks
|
|
37
|
+
* @param deps - The behavior's `{ state, context, config }`, passed to each constraint
|
|
38
|
+
* @returns The playable survivors (possibly empty)
|
|
39
|
+
*/
|
|
40
|
+
function applyConstraints(constraints, tracks, deps) {
|
|
41
|
+
let current = tracks;
|
|
42
|
+
for (const constraint of constraints) current = constraint(current, deps);
|
|
43
|
+
return current;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether two candidate sets hold the same tracks, by id.
|
|
47
|
+
*
|
|
48
|
+
* The `equals` both selection behaviors give their candidate-set `computed`. A
|
|
49
|
+
* live playlist refresh swaps in a new presentation object carrying the same
|
|
50
|
+
* variants, and a constraint's own inputs can churn without changing which
|
|
51
|
+
* tracks survive; in both cases the set is unchanged and the reaction must not
|
|
52
|
+
* re-fire. Compares by id rather than array identity for exactly that.
|
|
53
|
+
*/
|
|
54
|
+
function sameCandidateSet(a, b) {
|
|
55
|
+
return a.length === b.length && a.every((track) => b.some((other) => other.id === track.id));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Capability constraint — a *hard* filter for the {@link applyConstraints}
|
|
59
|
+
* pre-pass. Removes renditions this environment can't decode, probed via the
|
|
60
|
+
* injected `canPlayTrack` (codec → `MediaSource.isTypeSupported`, plus the
|
|
61
|
+
* container and encryption assertions that probe can't make). Constraining here
|
|
62
|
+
* — before selection — means an unplayable variant is pruned upstream and never
|
|
63
|
+
* picked, instead of surviving into the pipeline to fail late at
|
|
64
|
+
* `createSourceBuffer`. That late throw stays as a defensive structural
|
|
65
|
+
* guarantee; with this constraint it should rarely fire.
|
|
66
|
+
*
|
|
67
|
+
* Lives here rather than beside `switchVideoTrack` for the reason this module
|
|
68
|
+
* exists: both the re-evaluating variant and the pinned `selectVideoTrack` apply
|
|
69
|
+
* it, and reaching it through `behaviors/track-switching.ts` would drag the ABR
|
|
70
|
+
* path into a composition that deliberately omits it.
|
|
71
|
+
*
|
|
72
|
+
* Passes everything through when there's no probe (a composition that didn't
|
|
73
|
+
* wire one, or DOM-free tests). When it prunes *every* track, the empty result is
|
|
74
|
+
* preserved (per `applyConstraints`) — "nothing playable" — which each consuming
|
|
75
|
+
* behavior answers by clearing its selection and reporting the type's verdict.
|
|
76
|
+
*/
|
|
77
|
+
function excludeUnplayableTracks(tracks, { config }) {
|
|
78
|
+
const canPlay = config?.canPlayTrack;
|
|
79
|
+
if (!canPlay) return tracks;
|
|
80
|
+
return tracks.filter((track) => canPlay(track));
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { applyConstraints, applyRules, excludeUnplayableTracks, sameCandidateSet };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=selection-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection-rules.js","names":[],"sources":["../../../../src/playback/primitives/selection-rules.ts"],"sourcesContent":["/**\n * The selection-rule substrate: the shape of a rule, and the two composers that\n * turn a list of them into a pick.\n *\n * Lives here rather than beside `switchVideoTrack` so both track-selection\n * behaviors can share rules. The simple `selectVideoTrack` variant exists\n * specifically to tree-shake the ABR path out, so importing a composer from\n * `behaviors/track-switching.ts` would drag the bandwidth estimator and quality\n * selection back in with it. These four have no dependencies at all — pure\n * generics over a candidate list — so either side can reach them freely.\n *\n * See `internal/design/spf/track-switching-model.md` for the model these\n * implement: a hard constraints pre-pass, then an ordered chain of soft\n * narrowing rules and rankers, with the pick as the first survivor.\n */\n\nimport type { CanPlayTrack } from '../../media/types';\n\n/**\n * Deps handed to each rule and to `applyRules`, mirroring a behavior's setup\n * deps so a rule reads from the same surfaces a behavior does. `context` is\n * optional — it's threaded through but absent on direct setup calls (and\n * unread by today's rules), so the whole deps object can pass straight through.\n */\nexport interface SelectionRuleDeps<State = unknown, Context = unknown, Config = unknown> {\n state: State;\n context?: Context;\n config: Config;\n}\n\n/**\n * A selection rule narrows or reorders the candidate list. It reads the state,\n * context, and config it needs at apply time (tightly-coupled reads), so a\n * rule's `.get()`s subscribe the running effect to exactly what it consulted.\n * Returning an empty list means \"no match\" — the composer skips it, so a soft\n * filter never narrows the set to nothing. A ranker returns the list with its\n * pick at the head.\n */\nexport type SelectionRule<T, State = unknown, Context = unknown, Config = unknown> = (\n tracks: readonly T[],\n deps: SelectionRuleDeps<State, Context, Config>\n) => readonly T[];\n\n/**\n * Apply rules to a candidate list in order; the pick is the first survivor.\n * Two responsibilities the rules don't carry: a rule that returns nothing is\n * skipped (fall-through — a preference never empties the set), and once one\n * survivor remains the chain stops (early-bail — later rules, including the\n * bandwidth ranker, never run, so the effect doesn't subscribe to their\n * signals while the choice is fixed).\n *\n * @param rules - Rules to apply, most authoritative first\n * @param tracks - Candidate tracks\n * @param deps - The behavior's `{ state, context, config }`, passed through to each rule\n * @returns The surviving candidates, pick first\n */\nexport function applyRules<T, State, Context, Config>(\n rules: readonly SelectionRule<T, State, Context, Config>[],\n tracks: readonly T[],\n deps: SelectionRuleDeps<State, Context, Config>\n): readonly T[] {\n let current = tracks;\n for (const rule of rules) {\n const remaining = rule(current, deps);\n if (remaining.length === 0) continue;\n current = remaining;\n if (current.length === 1) break;\n }\n return current;\n}\n\n/**\n * Apply hard constraints to a candidate list — the pre-pass that runs before the\n * rule chain. A constraint shares a rule's signature but its exclusion is\n * *hard*: it removes the unplayable (a codec the environment can't decode, a CDN\n * in failover cooldown) and a removed track is never attempted. Unlike\n * `applyRules`, this never skips an empty result and never early-bails — every\n * constraint always applies, and an empty survivor set is a real outcome\n * (\"nothing playable here\"), not a fall-through. Because each constraint only\n * removes, the order they run in can't change the result.\n *\n * @param constraints - Constraints to apply (pooled, order-independent)\n * @param tracks - Candidate tracks\n * @param deps - The behavior's `{ state, context, config }`, passed to each constraint\n * @returns The playable survivors (possibly empty)\n */\nexport function applyConstraints<T, State, Context, Config>(\n constraints: readonly SelectionRule<T, State, Context, Config>[],\n tracks: readonly T[],\n deps: SelectionRuleDeps<State, Context, Config>\n): readonly T[] {\n let current = tracks;\n for (const constraint of constraints) current = constraint(current, deps);\n return current;\n}\n\n/**\n * Whether two candidate sets hold the same tracks, by id.\n *\n * The `equals` both selection behaviors give their candidate-set `computed`. A\n * live playlist refresh swaps in a new presentation object carrying the same\n * variants, and a constraint's own inputs can churn without changing which\n * tracks survive; in both cases the set is unchanged and the reaction must not\n * re-fire. Compares by id rather than array identity for exactly that.\n */\nexport function sameCandidateSet<T extends { id: string }>(a: readonly T[], b: readonly T[]): boolean {\n return a.length === b.length && a.every((track) => b.some((other) => other.id === track.id));\n}\n\n/**\n * What {@link excludeUnplayableTracks} reads off the config it is handed.\n *\n * Read through a cast rather than constraining the rule's `Config` generic, the\n * same way `screenResolutionCap` reads `screenResolution` off its state: a rule\n * composes into chains whose config types have nothing else in common, and\n * constraining the generic would make every one of those a weak-type mismatch.\n * Each engine defaults `canPlayTrack` to the DOM-bound probe; unwired means \"no\n * capability filtering\" and the constraint passes everything through.\n */\nexport interface CapabilityConstraintConfig {\n canPlayTrack?: CanPlayTrack;\n}\n\n/**\n * Capability constraint — a *hard* filter for the {@link applyConstraints}\n * pre-pass. Removes renditions this environment can't decode, probed via the\n * injected `canPlayTrack` (codec → `MediaSource.isTypeSupported`, plus the\n * container and encryption assertions that probe can't make). Constraining here\n * — before selection — means an unplayable variant is pruned upstream and never\n * picked, instead of surviving into the pipeline to fail late at\n * `createSourceBuffer`. That late throw stays as a defensive structural\n * guarantee; with this constraint it should rarely fire.\n *\n * Lives here rather than beside `switchVideoTrack` for the reason this module\n * exists: both the re-evaluating variant and the pinned `selectVideoTrack` apply\n * it, and reaching it through `behaviors/track-switching.ts` would drag the ABR\n * path into a composition that deliberately omits it.\n *\n * Passes everything through when there's no probe (a composition that didn't\n * wire one, or DOM-free tests). When it prunes *every* track, the empty result is\n * preserved (per `applyConstraints`) — \"nothing playable\" — which each consuming\n * behavior answers by clearing its selection and reporting the type's verdict.\n */\nexport function excludeUnplayableTracks<T, State, Context, Config>(\n tracks: readonly T[],\n { config }: SelectionRuleDeps<State, Context, Config>\n): readonly T[] {\n const canPlay = (config as CapabilityConstraintConfig | undefined)?.canPlayTrack;\n if (!canPlay) return tracks;\n return tracks.filter((track) => canPlay(track as Parameters<CanPlayTrack>[0]));\n}\n"],"mappings":";;;;;;;;;;;;;;AAwDA,SAAgB,WACd,OACA,QACA,MACc;CACd,IAAI,UAAU;CACd,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,YAAY,KAAK,SAAS,IAAI;EACpC,IAAI,UAAU,WAAW,GAAG;EAC5B,UAAU;EACV,IAAI,QAAQ,WAAW,GAAG;CAC5B;CACA,OAAO;AACT;;;;;;;;;;;;;;;;AAiBA,SAAgB,iBACd,aACA,QACA,MACc;CACd,IAAI,UAAU;CACd,KAAK,MAAM,cAAc,aAAa,UAAU,WAAW,SAAS,IAAI;CACxE,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,iBAA2C,GAAiB,GAA0B;CACpG,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,UAAU,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM,EAAE,CAAC;AAC7F;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,wBACd,QACA,EAAE,UACY;CACd,MAAM,UAAW,QAAmD;CACpE,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,OAAO,QAAQ,UAAU,QAAQ,KAAoC,CAAC;AAC/E"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@videojs/spf",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "10.0.0-beta.
|
|
4
|
+
"version": "10.0.0-beta.29",
|
|
5
5
|
"description": "Stream Processing Framework for Video.js 10",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -77,8 +77,8 @@
|
|
|
77
77
|
],
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"signal-polyfill": "^0.2.2",
|
|
80
|
-
"@videojs/media": "10.0.0-beta.
|
|
81
|
-
"@videojs/utils": "10.0.0-beta.
|
|
80
|
+
"@videojs/media": "10.0.0-beta.29",
|
|
81
|
+
"@videojs/utils": "10.0.0-beta.29"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@vitest/browser": "^4.1.10",
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { MaybeResolvedPresentation } from "../types/index.js";
|
|
2
|
-
//#region src/media/primitives/select-tracks.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Configuration for video track selection.
|
|
5
|
-
*/
|
|
6
|
-
interface VideoSelectionConfig {
|
|
7
|
-
/**
|
|
8
|
-
* Initial bandwidth estimate for cold start (bits per second).
|
|
9
|
-
* Used to select video quality before we have real measurements.
|
|
10
|
-
* Default: 1 Mbps (conservative).
|
|
11
|
-
*/
|
|
12
|
-
initialBandwidth?: number;
|
|
13
|
-
/**
|
|
14
|
-
* Safety margin for quality selection (0-1).
|
|
15
|
-
* Default: 0.85 (15% headroom).
|
|
16
|
-
*/
|
|
17
|
-
safetyMargin?: number;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Contract for a track picker — a pure function that consults a
|
|
21
|
-
* presentation (and optional config) and returns the id of the track to
|
|
22
|
-
* select, or `undefined` to leave the slot unset.
|
|
23
|
-
*
|
|
24
|
-
* Behaviors that own a track-selection slot (`selectAudioTrack`,
|
|
25
|
-
* `selectVideoTrack`, `switchVideoTrack`) accept a
|
|
26
|
-
* `TrackPicker` via config. The behavior passes its own config straight
|
|
27
|
-
* through as the picker's second argument — pickers that need richer
|
|
28
|
-
* options (language preferences, default-track filtering, bandwidth-aware
|
|
29
|
-
* selection) read from `config`; pickers that don't (e.g., first-track)
|
|
30
|
-
* ignore it.
|
|
31
|
-
*/
|
|
32
|
-
type TrackPicker<Config = unknown> = (presentation: MaybeResolvedPresentation, config?: Config) => string | undefined;
|
|
33
|
-
//#endregion
|
|
34
|
-
export { TrackPicker, VideoSelectionConfig };
|
|
35
|
-
//# sourceMappingURL=select-tracks.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"select-tracks.d.ts","names":[],"sources":["../../../../src/media/primitives/select-tracks.ts"],"mappings":";;;;;UA0CiB;;;;;;EAMf;;;;;EAMA;;;;;;;;;;;;;;;KA8DU,YAAY,qBACtB,cAAc,2BACd,SAAS"}
|