@vestra-player/sdk 1.5.33 → 1.5.35

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.
@@ -293,6 +293,8 @@ export interface Scope extends Disposable {
293
293
  readonly window: MainWindow;
294
294
  /** The player's version and components, and the system it runs on. */
295
295
  readonly app: App;
296
+ /** GPU or software rendering: read the choice, change it (`rendering.manage`). */
297
+ readonly rendering: Rendering;
296
298
  /** Every command's bindings and the user's overrides (`bindings.manage`). */
297
299
  readonly bindings: Bindings;
298
300
  /** Runtime images for Slint `image` properties. */
@@ -3991,8 +3993,9 @@ export interface AppInfo {
3991
3993
  */
3992
3994
  export interface App extends AppInfo {
3993
3995
  /**
3994
- * The operating system and the displays, read when called (displays come
3995
- * and go). No capability. CPU and memory: Node's `os` module.
3996
+ * The operating system, the displays and the renderer, read when called
3997
+ * (displays come and go; the renderer can fall back from GPU to software
3998
+ * once). No capability. CPU and memory: Node's `os` module.
3996
3999
  *
3997
4000
  * @capability None.
3998
4001
  * @throws `busy` (rejects) The player could not start the request (no
@@ -4034,6 +4037,71 @@ export interface SystemInfo {
4034
4037
  readonly arch: string;
4035
4038
  /** Primary display first; empty without a user interface. */
4036
4039
  readonly displays: readonly DisplayInfo[];
4040
+ /**
4041
+ * Which renderer draws the video now: `"gpu"` (the GPU renderer, so
4042
+ * {@link RenderOptions | render options} apply) or `"software"` (they
4043
+ * fail with `unsupported`). Read at each call. It changes at most once
4044
+ * while the player runs, from `"gpu"` to `"software"` when a window
4045
+ * cannot show GPU frames; the owner of the render options hears that
4046
+ * switch through {@link RenderOptions.onStatus}.
4047
+ *
4048
+ * Absent (`undefined`) on players before 0.5.12, which do not report it:
4049
+ * the renderer is then unknown, not software.
4050
+ *
4051
+ * Today the player renders on the GPU on macOS and in software on
4052
+ * Windows, Linux and without a user interface (see
4053
+ * [Platforms](../../docs/reference/platforms.md)); test this field
4054
+ * rather than {@link SystemInfo.os}.
4055
+ *
4056
+ * @example Offer the HDR menu only where render options work
4057
+ * The plugin adds its HDR command only when the player renders on the
4058
+ * GPU, instead of creating the render options just to find out from a
4059
+ * failed status. `system()` asks the player, which reports the renderer
4060
+ * drawing at that moment; no capability is needed to ask. A player before
4061
+ * 0.5.12 leaves the field out, so the test is for `"gpu"` exactly (an
4062
+ * older player gets no HDR command).
4063
+ * ```ts
4064
+ * const { rendering } = await plugin.app.system();
4065
+ * if (rendering === "gpu") {
4066
+ * const render = plugin.video.render(); // one handle, kept
4067
+ * plugin.commands.add({
4068
+ * id: "hdr",
4069
+ * path: ["@video", "HDR Tone Mapping"],
4070
+ * run: () => render.set({ toneMapping: "bt.2390", targetPeak: 250 }),
4071
+ * });
4072
+ * }
4073
+ * ```
4074
+ *
4075
+ * @player 0.5.12; older players leave it out (declare
4076
+ * `"minPlayerVersion": "0.5.12"` when the plugin relies on it).
4077
+ * @since 1.5.34
4078
+ */
4079
+ readonly rendering?: "gpu" | "software";
4080
+ /**
4081
+ * Why {@link SystemInfo.rendering} is what it is now: the same reason as
4082
+ * {@link RenderingState.reason} (`default`, `no-gpu-backend`,
4083
+ * `preference`, `denylist`, `window-fallback`…, see
4084
+ * {@link RenderingReasonCode}). Read at each call, like `rendering`.
4085
+ *
4086
+ * Absent (`undefined`) on players before 0.5.13.
4087
+ *
4088
+ * @example Say why the video is drawn in software
4089
+ * An About page explains a software renderer with the player's own words,
4090
+ * for example that the graphics driver is on the player's denylist.
4091
+ * `system()` reports the renderer and its reason together, with no
4092
+ * capability; the message is English text that may name the adapter and
4093
+ * the driver version.
4094
+ * ```ts
4095
+ * const { rendering, renderingReason } = await plugin.app.system();
4096
+ * if (rendering === "software" && renderingReason)
4097
+ * console.log(`Rendering: software (${renderingReason.message})`);
4098
+ * ```
4099
+ *
4100
+ * @player 0.5.13; older players leave it out (declare
4101
+ * `"minPlayerVersion": "0.5.13"` when the plugin relies on it).
4102
+ * @since 1.5.35
4103
+ */
4104
+ readonly renderingReason?: RenderingReason;
4037
4105
  }
4038
4106
  /**
4039
4107
  * One display in {@link SystemInfo.displays}.
@@ -6294,8 +6362,10 @@ export interface RenderSettings {
6294
6362
  *
6295
6363
  * Platforms: only macOS renders on the GPU. Under software rendering
6296
6364
  * (Windows, Linux, headless, fallback) every `set` fails with
6297
- * `unsupported`. macOS OpenGL 4.1 has no compute shaders, so `peakDetect`
6298
- * is accepted but has no effect; output is always SDR.
6365
+ * `unsupported`; {@link SystemInfo.rendering} tells which renderer draws
6366
+ * without creating the handle. macOS OpenGL 4.1 has no
6367
+ * compute shaders, so `peakDetect` is accepted but has no effect; output
6368
+ * is always SDR.
6299
6369
  *
6300
6370
  * @example Tone-map HDR video and hide the menu where it cannot work
6301
6371
  * On a GPU-rendering player HDR video is tone-mapped with BT.2390 for a
@@ -6591,7 +6661,10 @@ export interface Subtitles {
6591
6661
  *
6592
6662
  * Limits: SRT ≤ 2 MiB and ≤ 10,000 cues; ASS ≤ 2 MiB with `[Script Info]`
6593
6663
  * and `[Events]` and 1–20,000 `Dialogue:` lines. Convert other formats
6594
- * (VTT, SAMI) to SRT first.
6664
+ * (VTT, SAMI) to SRT first. Per source, a plugin has at most 4 loaded
6665
+ * tracks at once and loads at most 16 files (removed ones count), and
6666
+ * every plugin together at most 16 tracks; see `SUBTITLE_LIMITS` in
6667
+ * `@vestra-player/sdk/testing`.
6595
6668
  *
6596
6669
  * @capability subtitles.control and subtitles.read
6597
6670
  * @throws `invalid` (rejects) A bad `format` or `title`, or a file over the
@@ -6602,7 +6675,10 @@ export interface Subtitles {
6602
6675
  * loading.
6603
6676
  * @throws `aborted` (rejects) `signal` aborted before the commit (an
6604
6677
  * `AbortError`); the upload is discarded.
6605
- * @throws `busy` (rejects) Too many subtitle operations at once.
6678
+ * @throws `busy` (rejects) Too many subtitle operations at once, or a
6679
+ * limit of `SUBTITLE_LIMITS` is reached (4 tracks of this plugin, 16
6680
+ * loads of this plugin or 16 tracks in the source, or another of its
6681
+ * limits); nothing is loaded.
6606
6682
  * @throws `capability` (rejects) The manifest does not declare
6607
6683
  * `subtitles.control` and `subtitles.read`.
6608
6684
  *
@@ -8885,3 +8961,329 @@ export interface Secrets {
8885
8961
  */
8886
8962
  delete(name: string): Promise<void>;
8887
8963
  }
8964
+ /**
8965
+ * Which renderer draws the video: `"gpu"` (the GPU renderer, where
8966
+ * {@link RenderOptions | render options} apply) or `"software"` (they fail
8967
+ * with `unsupported`). The same values as {@link SystemInfo.rendering}.
8968
+ *
8969
+ * @example Tell the user which renderer draws the video
8970
+ * The plugin shows "Rendering: GPU" or "Rendering: software" on the
8971
+ * video. `state()` asks the player; `mode` is the renderer drawing now,
8972
+ * which can differ from the saved choice until the next start.
8973
+ * ```ts
8974
+ * const { mode } = await plugin.rendering.state();
8975
+ * const label: Record<RenderingMode, string> = { gpu: "GPU", software: "software" };
8976
+ * await plugin.osd.show("Rendering: {}", [label[mode]]);
8977
+ * ```
8978
+ *
8979
+ * @player 0.5.13
8980
+ * @since 1.5.35
8981
+ * @category Services
8982
+ */
8983
+ export type RenderingMode = "gpu" | "software";
8984
+ /**
8985
+ * The user's saved rendering choice: `"auto"` (the player decides: the GPU
8986
+ * where this system has a GPU renderer that is not ruled out, software
8987
+ * elsewhere), `"gpu"` or `"software"`. It applies from the next start.
8988
+ *
8989
+ * @example Describe the saved choice on a settings page
8990
+ * The plugin turns the saved choice into the words its settings page
8991
+ * shows. `preference` is what the user chose, not what draws now:
8992
+ * {@link RenderingState.nextMode} says what the next start will use.
8993
+ * ```ts
8994
+ * const { preference } = await plugin.rendering.state();
8995
+ * // One word per choice; the Record type makes sure none is missing.
8996
+ * const words: Record<RenderingPreference, string> = {
8997
+ * auto: "Automatic",
8998
+ * gpu: "GPU",
8999
+ * software: "Software",
9000
+ * };
9001
+ * console.log(words[preference]);
9002
+ * ```
9003
+ *
9004
+ * @player 0.5.13
9005
+ * @since 1.5.35
9006
+ * @category Services
9007
+ */
9008
+ export type RenderingPreference = "auto" | "gpu" | "software";
9009
+ /**
9010
+ * Why the player renders the way it does, as a stable kebab-case code. A
9011
+ * newer player may add codes: compare with the ones you handle and show
9012
+ * {@link RenderingReason.message} for the rest. The codes of player 0.5.13:
9013
+ *
9014
+ * | Code | Meaning |
9015
+ * | --- | --- |
9016
+ * | `default` | Nothing ruled the GPU out; the platform's default. |
9017
+ * | `pending` | GPU rendering is starting. |
9018
+ * | `headless` | The player runs without a user interface. |
9019
+ * | `no-gpu-backend` | This player has no GPU renderer on this system (Windows today). |
9020
+ * | `env` | The environment chose it (`VESTRA_RENDER`, `VESTRA_SOFTWARE_RENDER`). |
9021
+ * | `preference` | The user chose software rendering ({@link Rendering.setPreference}); GPU chosen and available reports `default`. |
9022
+ * | `denylist` | The graphics driver is on the player's denylist. |
9023
+ * | `previous-crash` | GPU rendering crashed at an earlier start; it is tried again after a driver or player update, or after 7 days. |
9024
+ * | `init-failed` | GPU rendering could not start. |
9025
+ * | `window-fallback` | A window could not show GPU frames; the player switched to software during the run. |
9026
+ *
9027
+ * @example Explain a driver problem differently from a user choice
9028
+ * The plugin adds advice only when the graphics driver is the cause.
9029
+ * `reason.code` is looked up among the codes the plugin knows; an unknown
9030
+ * code from a newer player falls through to the player's own message.
9031
+ * ```ts
9032
+ * const { reason } = await plugin.rendering.state();
9033
+ * // Advice for the codes this plugin knows; any other code shows the message.
9034
+ * const advice: Partial<Record<RenderingReasonCode, string>> = {
9035
+ * denylist: "Update the graphics driver to use the GPU.",
9036
+ * "previous-crash": "The GPU renderer crashed earlier; it is retried after an update.",
9037
+ * };
9038
+ * console.log(advice[reason.code] ?? reason.message);
9039
+ * ```
9040
+ *
9041
+ * @player 0.5.13
9042
+ * @since 1.5.35
9043
+ * @category Services
9044
+ */
9045
+ export type RenderingReasonCode = "default" | "pending" | "headless" | "no-gpu-backend" | "env" | "preference" | "denylist" | "previous-crash" | "init-failed" | "window-fallback" | (string & {});
9046
+ /**
9047
+ * Why the player renders, or will render, the way it does: a stable
9048
+ * {@link RenderingReasonCode} to branch on and a sentence to show.
9049
+ *
9050
+ * @example Show why GPU rendering is off
9051
+ * The plugin logs the player's explanation when the video is drawn in
9052
+ * software. `message` is the player's English text and may name the
9053
+ * graphics adapter and driver version; `code` is for decisions.
9054
+ * ```ts
9055
+ * const { mode, reason } = await plugin.rendering.state();
9056
+ * if (mode === "software") console.log(`${reason.code}: ${reason.message}`);
9057
+ * ```
9058
+ *
9059
+ * @player 0.5.13
9060
+ * @since 1.5.35
9061
+ * @category Services
9062
+ */
9063
+ export interface RenderingReason {
9064
+ /** The reason as a stable kebab-case code; branch on this. */
9065
+ readonly code: RenderingReasonCode;
9066
+ /**
9067
+ * The reason as English text for people, for example with the graphics
9068
+ * adapter's name and driver version; never branch on it.
9069
+ */
9070
+ readonly message: string;
9071
+ }
9072
+ /**
9073
+ * What {@link Rendering.state} and {@link Rendering.setPreference} report:
9074
+ * the renderer drawing now and why, the saved choice, what the next start
9075
+ * will use, and whether `"gpu"` can be chosen.
9076
+ *
9077
+ * @example Label a menu item while a change waits for a restart
9078
+ * The plugin adds "(Restart to Apply)" to its GPU item after the user
9079
+ * changed the choice. `restartPending` compares the mode the next start
9080
+ * will use with the mode this run started with, so it turns false again
9081
+ * when the user changes the choice back.
9082
+ * ```ts
9083
+ * const state = await plugin.rendering.state();
9084
+ * const title = state.restartPending
9085
+ * ? "GPU Rendering (Experimental) (Restart to Apply)"
9086
+ * : "GPU Rendering (Experimental)";
9087
+ * console.log(title, state.nextMode, state.nextReason.message);
9088
+ * ```
9089
+ *
9090
+ * @player 0.5.13
9091
+ * @since 1.5.35
9092
+ * @category Services
9093
+ */
9094
+ export interface RenderingState {
9095
+ /** The renderer drawing the video now; the same as {@link SystemInfo.rendering}. */
9096
+ readonly mode: RenderingMode;
9097
+ /** Why {@link RenderingState.mode} is what it is now. */
9098
+ readonly reason: RenderingReason;
9099
+ /** The saved choice; it applies from the next start. */
9100
+ readonly preference: RenderingPreference;
9101
+ /**
9102
+ * The renderer the next start will use, as far as the player knows now:
9103
+ * from the saved choice, the environment, the driver denylist and an
9104
+ * earlier GPU crash.
9105
+ */
9106
+ readonly nextMode: RenderingMode;
9107
+ /** Why the next start will use {@link RenderingState.nextMode}. */
9108
+ readonly nextReason: RenderingReason;
9109
+ /**
9110
+ * `true` while {@link RenderingState.nextMode} differs from the mode this
9111
+ * run started with, so a restart would change the renderer; `false` again
9112
+ * when the user changes the choice back.
9113
+ */
9114
+ readonly restartPending: boolean;
9115
+ /** Whether the user can choose `"gpu"` now. */
9116
+ readonly gpu: {
9117
+ /** `true` when `setPreference("gpu")` would be accepted. */
9118
+ readonly available: boolean;
9119
+ /**
9120
+ * Why `"gpu"` cannot be chosen (`no-gpu-backend`, `headless`,
9121
+ * `denylist`, `previous-crash`…); `null` while it is available.
9122
+ */
9123
+ readonly reason: RenderingReason | null;
9124
+ };
9125
+ }
9126
+ /**
9127
+ * `plugin.rendering`: the player's rendering choice, GPU or software.
9128
+ * Reading it needs no capability; changing the saved choice and restarting
9129
+ * the player need `rendering.manage`.
9130
+ *
9131
+ * @remarks
9132
+ * The choice works like a browser's hardware acceleration switch: the
9133
+ * player saves it in its own settings at once, and the running player
9134
+ * keeps its renderer. The next start uses it, whether the user restarts
9135
+ * now through {@link Rendering.restartPlayer} or quits and starts the
9136
+ * player later. The player can still rule the GPU out at a start (an
9137
+ * environment variable, a graphics driver on its denylist, a GPU crash at
9138
+ * an earlier start); {@link RenderingState.nextMode} and
9139
+ * {@link RenderingState.nextReason} say what the next start will do.
9140
+ *
9141
+ * The renderer is a choice for the whole player and a restart stops every
9142
+ * plugin, so change it only when the user asks. A plugin that only needs
9143
+ * to know whether render options work reads {@link SystemInfo.rendering}.
9144
+ *
9145
+ * Players before 0.5.13 do not know these requests: `state()` rejects with
9146
+ * `unsupported`, and they do not load a plugin that declares
9147
+ * `rendering.manage` (an unknown capability). Declare
9148
+ * `"minPlayerVersion": "0.5.13"` when the plugin needs this.
9149
+ *
9150
+ * @example Offer GPU rendering as a menu item
9151
+ * Settings ▸ GPU Rendering (Experimental) carries a check mark while the
9152
+ * next start will draw on the GPU, is greyed out with the player's reason
9153
+ * where the GPU cannot be chosen, and saves the other choice when picked.
9154
+ * `state()` reads the player's view once; `setPreference` saves the choice
9155
+ * and resolves with the new state, which the item's bound values read
9156
+ * again after the handler. The how-to guide adds the restart.
9157
+ * ```ts
9158
+ * let state = await plugin.rendering.state();
9159
+ * plugin.commands.add({
9160
+ * id: "gpu-rendering",
9161
+ * path: ["@settings", "GPU Rendering (Experimental)"],
9162
+ * checked: () => state.nextMode === "gpu", // also for "auto" on a GPU system
9163
+ * enabled: () => state.gpu.available,
9164
+ * reason: () => state.gpu.reason?.message ?? null, // shown while disabled
9165
+ * run: async () => {
9166
+ * const choice = state.nextMode === "gpu" ? "software" : "gpu";
9167
+ * state = await plugin.rendering.setPreference(choice);
9168
+ * },
9169
+ * });
9170
+ * ```
9171
+ *
9172
+ * @capability None to read the state; `rendering.manage` to change the
9173
+ * choice or restart the player.
9174
+ * @see [Offer a GPU rendering switch](../../docs/how-to/gpu-rendering.md)
9175
+ * @player 0.5.13; older players reject the requests as unknown
9176
+ * (`unsupported`).
9177
+ * @since 1.5.35
9178
+ * @category Services
9179
+ */
9180
+ export interface Rendering {
9181
+ /**
9182
+ * Read the renderer drawing now, the saved choice, what the next start
9183
+ * will use and whether `"gpu"` can be chosen. No capability.
9184
+ *
9185
+ * @capability None.
9186
+ * @throws `unsupported` (rejects) A player before 0.5.13, which does not
9187
+ * know the request.
9188
+ *
9189
+ * @example Find out whether the GPU can be chosen
9190
+ * The plugin reads the state once while it starts and keeps it for its
9191
+ * menu. Each call asks the player; `gpu.available` is false, with a
9192
+ * reason, where this player has no GPU renderer, without a user
9193
+ * interface, or when the driver is ruled out. An older player rejects
9194
+ * with `unsupported`, and the plugin then offers nothing.
9195
+ * ```ts
9196
+ * const state = await plugin.rendering.state().catch((error: PluginError) => {
9197
+ * if (error.code === "unsupported") return null; // a player before 0.5.13
9198
+ * throw error;
9199
+ * });
9200
+ * if (state && !state.gpu.available) console.log(state.gpu.reason?.message);
9201
+ * ```
9202
+ *
9203
+ * @since 1.5.35
9204
+ */
9205
+ state(): Promise<RenderingState>;
9206
+ /**
9207
+ * Save the user's rendering choice. The player writes it to its settings
9208
+ * at once; the running player keeps its renderer, and the next start
9209
+ * uses the choice whether or not the user restarts now. `"auto"` and
9210
+ * `"software"` are always accepted.
9211
+ *
9212
+ * @param preference - `"auto"`, `"gpu"` or `"software"`.
9213
+ * @returns The new state; {@link RenderingState.restartPending} tells
9214
+ * whether a restart would change the renderer.
9215
+ *
9216
+ * @capability rendering.manage
9217
+ * @throws `invalid` (rejects) `preference` is not `"auto"`, `"gpu"` or
9218
+ * `"software"`.
9219
+ * @throws `unsupported` (rejects) `"gpu"` where this player has no GPU
9220
+ * renderer on this system, or runs without a user interface; also any
9221
+ * value on a player before 0.5.13.
9222
+ * @throws `unavailable` (rejects) `"gpu"` while it is ruled out: the
9223
+ * graphics driver is on the player's denylist, or GPU rendering crashed
9224
+ * at an earlier start. The message says which, with the adapter's name
9225
+ * and the driver version.
9226
+ * @throws `failed` (rejects) The player could not write its settings file.
9227
+ * @throws `capability` (rejects) The manifest does not declare
9228
+ * `rendering.manage`.
9229
+ *
9230
+ * @example Switch back to the automatic choice
9231
+ * A Reset item returns the renderer to the player's own choice and tells
9232
+ * the user when it takes effect. `setPreference` saves the choice and
9233
+ * resolves with the new state; `restartPending` is true when the next
9234
+ * start will draw differently from this run. A refused save leaves the
9235
+ * old choice in place.
9236
+ * ```ts
9237
+ * try {
9238
+ * const state = await plugin.rendering.setPreference("auto");
9239
+ * if (state.restartPending) await plugin.osd.show("Applies after a restart");
9240
+ * } catch (error) {
9241
+ * // `failed`: the player's settings file could not be written.
9242
+ * await plugin.osd.show("Not saved ({})", [(error as PluginError).code]);
9243
+ * }
9244
+ * ```
9245
+ *
9246
+ * @since 1.5.35
9247
+ */
9248
+ setPreference(preference: RenderingPreference): Promise<RenderingState>;
9249
+ /**
9250
+ * Restart the player so that a changed choice applies now. Resolves once
9251
+ * the player has accepted; the player then quits normally, which stops
9252
+ * every plugin (this one included), and starts again with the same
9253
+ * plugins. A local file that was open continues at its position, paused
9254
+ * or playing as it was; a stream or another source that is not a file is
9255
+ * not reopened.
9256
+ *
9257
+ * @capability rendering.manage
9258
+ * @throws `unsupported` (rejects) The player runs without a user
9259
+ * interface; also a player before 0.5.13.
9260
+ * @throws `busy` (rejects) A restart is already under way, or this player
9261
+ * was itself started by a restart less than 30 seconds ago (so a plugin
9262
+ * that restarts on activation cannot make a loop).
9263
+ * @throws `failed` (rejects) The new player process could not be started;
9264
+ * the player keeps running.
9265
+ * @throws `capability` (rejects) The manifest does not declare
9266
+ * `rendering.manage`.
9267
+ *
9268
+ * @example Restart after asking the user
9269
+ * After the user changed the renderer, the plugin offers to restart now.
9270
+ * `confirm` asks first, because a restart closes every window (it needs
9271
+ * `ui.dialog`); once `restartPlayer` resolves, the player is quitting and
9272
+ * will stop this plugin, so nothing else is started after it.
9273
+ * ```ts
9274
+ * const { confirmed } = await plugin.dialogs.confirm({
9275
+ * message: "Restart the player now?",
9276
+ * detail: "The new renderer is used from the restart on. The video continues where it is.",
9277
+ * confirm: "Restart",
9278
+ * });
9279
+ * if (confirmed)
9280
+ * await plugin.rendering.restartPlayer().catch((error: PluginError) => {
9281
+ * // `failed`: the new player could not start; this one keeps running.
9282
+ * void plugin.osd.show("Could not restart ({})", [error.code]);
9283
+ * });
9284
+ * ```
9285
+ *
9286
+ * @since 1.5.35
9287
+ */
9288
+ restartPlayer(): Promise<void>;
9289
+ }
package/dist/wire.d.ts CHANGED
@@ -297,7 +297,7 @@ export interface LocalServices {
297
297
  signal: AbortSignal;
298
298
  }): Promise<Uint8Array>;
299
299
  }
300
- /** `app.system`: the operating system and the displays. */
300
+ /** `app.system`: the operating system, the displays and the renderer. */
301
301
  export interface WireSystemInfo {
302
302
  os: "macos" | "windows" | "linux" | "other";
303
303
  name: string;
@@ -313,6 +313,28 @@ export interface WireSystemInfo {
313
313
  refreshRate: number | null;
314
314
  primary: boolean;
315
315
  }[];
316
+ /** Player 0.5.12; older players leave it out. */
317
+ rendering?: "gpu" | "software";
318
+ /** Why `rendering` is what it is (player 0.5.13; older players leave it out). */
319
+ renderingReason?: WireRenderingReason;
320
+ }
321
+ /** A rendering reason: a stable kebab-case `code` and English text. */
322
+ export interface WireRenderingReason {
323
+ code: string;
324
+ message: string;
325
+ }
326
+ /** `rendering.state` and `rendering.setPreference` (player 0.5.13). */
327
+ export interface WireRenderingState {
328
+ mode: "gpu" | "software";
329
+ reason: WireRenderingReason;
330
+ preference: "auto" | "gpu" | "software";
331
+ nextMode: "gpu" | "software";
332
+ nextReason: WireRenderingReason;
333
+ restartPending: boolean;
334
+ gpu: {
335
+ available: boolean;
336
+ reason: WireRenderingReason | null;
337
+ };
316
338
  }
317
339
  /**
318
340
  * Template arguments on the wire (`osd.show`, `osd.panel`, `dialogs.confirm`,
@@ -525,6 +547,15 @@ export declare function createWire(transport: Transport): {
525
547
  app: {
526
548
  system: () => Promise<WireSystemInfo>;
527
549
  };
550
+ /**
551
+ * The rendering choice (player 0.5.13): `state` needs no capability,
552
+ * `setPreference` and `restart` need `rendering.manage`.
553
+ */
554
+ rendering: {
555
+ state: () => Promise<WireRenderingState>;
556
+ setPreference: (preference: string) => Promise<WireRenderingState>;
557
+ restart: () => Promise<null>;
558
+ };
528
559
  power: {
529
560
  preventSleep: (mode: "off" | "playing") => Promise<void>;
530
561
  };
package/dist/wire.js CHANGED
@@ -214,6 +214,17 @@ export function createWire(transport) {
214
214
  app: {
215
215
  system: () => transport.request("app.system"),
216
216
  },
217
+ /**
218
+ * The rendering choice (player 0.5.13): `state` needs no capability,
219
+ * `setPreference` and `restart` need `rendering.manage`.
220
+ */
221
+ rendering: {
222
+ state: () => transport.request("rendering.state"),
223
+ setPreference: (preference) => transport.request("rendering.setPreference", {
224
+ preference,
225
+ }),
226
+ restart: () => transport.request("rendering.restart"),
227
+ },
217
228
  power: {
218
229
  preventSleep: (mode) => transport.request("power.preventSleep", { mode }),
219
230
  },