@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.
Files changed (72) hide show
  1. package/dist/default/hls.js +2 -1
  2. package/dist/default/media/dom/screen.js +129 -0
  3. package/dist/default/media/dom/screen.js.map +1 -0
  4. package/dist/default/media/errors.js +9 -2
  5. package/dist/default/media/errors.js.map +1 -1
  6. package/dist/default/media/primitives/select-tracks.js +31 -47
  7. package/dist/default/media/primitives/select-tracks.js.map +1 -1
  8. package/dist/default/playback/adapters/hls-background-video/adapter.js +99 -11
  9. package/dist/default/playback/adapters/hls-background-video/adapter.js.map +1 -1
  10. package/dist/default/playback/adapters/hls-video/error-surface.js.map +1 -1
  11. package/dist/default/playback/adapters/mux-video/adapter.js +16 -3
  12. package/dist/default/playback/adapters/mux-video/adapter.js.map +1 -1
  13. package/dist/default/playback/behaviors/collect-errors.js +36 -2
  14. package/dist/default/playback/behaviors/collect-errors.js.map +1 -1
  15. package/dist/default/playback/behaviors/dom/track-screen-resolution.js +29 -0
  16. package/dist/default/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
  17. package/dist/default/playback/behaviors/select-tracks.js +143 -28
  18. package/dist/default/playback/behaviors/select-tracks.js.map +1 -1
  19. package/dist/default/playback/behaviors/track-switching.js +5 -68
  20. package/dist/default/playback/behaviors/track-switching.js.map +1 -1
  21. package/dist/default/playback/engines/hls/engine-background-video.js +22 -5
  22. package/dist/default/playback/engines/hls/engine-background-video.js.map +1 -1
  23. package/dist/default/playback/primitives/error-messages.js +13 -1
  24. package/dist/default/playback/primitives/error-messages.js.map +1 -1
  25. package/dist/default/playback/primitives/selection-rules.js +85 -0
  26. package/dist/default/playback/primitives/selection-rules.js.map +1 -0
  27. package/dist/dev/hls-background-video.d.ts +2 -1
  28. package/dist/dev/hls.d.ts +2 -1
  29. package/dist/dev/hls.js +2 -1
  30. package/dist/dev/media/dom/screen.d.ts +26 -0
  31. package/dist/dev/media/dom/screen.d.ts.map +1 -0
  32. package/dist/dev/media/dom/screen.js +129 -0
  33. package/dist/dev/media/dom/screen.js.map +1 -0
  34. package/dist/dev/media/errors.d.ts.map +1 -1
  35. package/dist/dev/media/errors.js +9 -2
  36. package/dist/dev/media/errors.js.map +1 -1
  37. package/dist/dev/media/primitives/select-tracks.js +31 -47
  38. package/dist/dev/media/primitives/select-tracks.js.map +1 -1
  39. package/dist/dev/mux-background-video.d.ts +2 -1
  40. package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts +25 -7
  41. package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts.map +1 -1
  42. package/dist/dev/playback/adapters/hls-background-video/adapter.js +99 -11
  43. package/dist/dev/playback/adapters/hls-background-video/adapter.js.map +1 -1
  44. package/dist/dev/playback/adapters/hls-video/error-surface.d.ts.map +1 -1
  45. package/dist/dev/playback/adapters/hls-video/error-surface.js.map +1 -1
  46. package/dist/dev/playback/adapters/mux-video/adapter.d.ts +1 -0
  47. package/dist/dev/playback/adapters/mux-video/adapter.d.ts.map +1 -1
  48. package/dist/dev/playback/adapters/mux-video/adapter.js +16 -3
  49. package/dist/dev/playback/adapters/mux-video/adapter.js.map +1 -1
  50. package/dist/dev/playback/behaviors/collect-errors.js +36 -2
  51. package/dist/dev/playback/behaviors/collect-errors.js.map +1 -1
  52. package/dist/dev/playback/behaviors/dom/track-screen-resolution.js +29 -0
  53. package/dist/dev/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
  54. package/dist/dev/playback/behaviors/select-tracks.d.ts +64 -6
  55. package/dist/dev/playback/behaviors/select-tracks.d.ts.map +1 -1
  56. package/dist/dev/playback/behaviors/select-tracks.js +143 -28
  57. package/dist/dev/playback/behaviors/select-tracks.js.map +1 -1
  58. package/dist/dev/playback/behaviors/track-switching.js +5 -68
  59. package/dist/dev/playback/behaviors/track-switching.js.map +1 -1
  60. package/dist/dev/playback/engines/hls/engine-background-video.d.ts +63 -11
  61. package/dist/dev/playback/engines/hls/engine-background-video.d.ts.map +1 -1
  62. package/dist/dev/playback/engines/hls/engine-background-video.js +22 -5
  63. package/dist/dev/playback/engines/hls/engine-background-video.js.map +1 -1
  64. package/dist/dev/playback/primitives/error-messages.js +13 -1
  65. package/dist/dev/playback/primitives/error-messages.js.map +1 -1
  66. package/dist/dev/playback/primitives/selection-rules.d.ts +38 -0
  67. package/dist/dev/playback/primitives/selection-rules.d.ts.map +1 -0
  68. package/dist/dev/playback/primitives/selection-rules.js +85 -0
  69. package/dist/dev/playback/primitives/selection-rules.js.map +1 -0
  70. package/package.json +3 -3
  71. package/dist/dev/media/primitives/select-tracks.d.ts +0 -35
  72. 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.28",
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.28",
81
- "@videojs/utils": "10.0.0-beta.28"
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"}