@solidrt/flux-types 0.0.59 → 0.0.60

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/gui/audio.d.ts CHANGED
@@ -144,9 +144,10 @@ declare module "flux:audio" {
144
144
  /**
145
145
  * Open a clip for streaming: it is decoded on demand instead of loaded fully
146
146
  * into memory, so a large track needs little RAM. Takes a `file()` from
147
- * `flux:fs` (not a path), so the source rides the `file()` proxy override - a
148
- * dev-server-proxied file streams from the server. Play the result as a single
149
- * playback; do not overlap a stream with itself. Call `unload()` when done.
147
+ * `flux:fs` (not a path), read from local storage like any `file()` (the
148
+ * app's assets in a packed app); there is no network streaming. Play the
149
+ * result as a single playback; do not overlap a stream with itself. Call
150
+ * `unload()` when done.
150
151
  */
151
152
  export function stream(source: ReturnType<typeof import("flux:fs").file>): Clip
152
153
  /**
package/gui/video.d.ts CHANGED
@@ -1,49 +1,154 @@
1
1
  // Video playback (gui-enabled runtime only). The imperative primitive;
2
2
  // @solidrt/core wraps it with SolidJS reactivity. There is no video element:
3
- // the player's `texture` id is displayed with <texture>/<d-texture>, and a
4
- // richer Video component composes in a higher layer.
3
+ // a texture player's `texture` id is displayed with <texture>/<d-texture>,
4
+ // and a richer Video component composes in a higher layer. A plane player
5
+ // (Android) has no texture at all: the platform composites the decoded
6
+ // picture fullscreen beneath the UI, off the frame loop entirely, and it
7
+ // streams: its source may be a URL, read as it plays.
5
8
 
6
9
  declare module "flux:video" {
10
+ import type { FluxFile } from "flux:fs"
7
11
  import type { TextureId } from "flux:gpu"
8
12
 
9
- /** An opened video: the frame texture plus controls bound to it. */
10
- type VideoPlayer = {
11
- /**
12
- * GPU texture id decoded frames are uploaded into (use as a texture
13
- * source). Holds the current frame; black until playback starts.
14
- */
15
- texture: TextureId
16
- /** Frame width in pixels. */
13
+ /**
14
+ * What went wrong with a stream, for the app to key on:
15
+ * - "network": the source could not be opened or stopped delivering (an
16
+ * unreachable or failing server, an unreadable file, a truncated body);
17
+ * - "decode": the bytes are not a stream the decoders can follow;
18
+ * - "unsupported": a stream, codec or feature this player does not play;
19
+ * - "no-plane": no video plane (not on this platform, or one is open).
20
+ * An app falling back from a plane to a texture keys on "no-plane" only:
21
+ * a network error would fail the texture the same way.
22
+ */
23
+ export type VideoErrorKind = "network" | "decode" | "unsupported" | "no-plane"
24
+
25
+ /** The Error `open` rejects with and `error()` returns. */
26
+ export interface VideoError extends Error {
27
+ kind: VideoErrorKind
28
+ }
29
+
30
+ /** Controls and facts shared by both kinds of player. */
31
+ export type VideoTransport = {
32
+ /** Frame width in pixels, at open. */
17
33
  width: number
18
- /** Frame height in pixels. */
34
+ /** Frame height in pixels, at open. */
19
35
  height: number
20
- /** Duration in seconds. */
21
- duration: number
36
+ /**
37
+ * Duration in seconds; undefined when the source has no known end (a
38
+ * live stream, a container written to a pipe).
39
+ */
40
+ duration: number | undefined
22
41
  /** Whether the file has a playable audio track. */
23
42
  hasAudio: boolean
43
+ /**
44
+ * Whether `seek` does anything. False for a texture player, and for a
45
+ * source that cannot be read at an offset (an HTTP response without
46
+ * Range support); `seek` is then a no-op.
47
+ */
48
+ seekable: boolean
24
49
  /** Start or resume playback. */
25
50
  play(): void
26
51
  /** Pause playback (the current frame stays displayed). */
27
52
  pause(): void
53
+ /**
54
+ * Seek to a time in seconds. Lands on the frame at that time (decoding
55
+ * from the preceding keyframe); while paused the target frame is shown.
56
+ * A no-op when `seekable` is false.
57
+ */
58
+ seek(seconds: number): void
28
59
  /** Whether playback is running. */
29
60
  playing(): boolean
30
61
  /** Presentation time of the displayed frame, in seconds. */
31
62
  currentTime(): number
32
- /** Whether the last frame has been displayed. */
63
+ /**
64
+ * Whether the last frame has been displayed. A failure does not set
65
+ * it: see `error`.
66
+ */
33
67
  finished(): boolean
34
- /** Stop playback and release the decoder, texture, and audio sink. */
68
+ /**
69
+ * Whether playback is held for the source to catch up: playing, with
70
+ * the picture and the sound paused until enough is read ahead. Never
71
+ * true for a texture player.
72
+ */
73
+ buffering(): boolean
74
+ /**
75
+ * The failure that stopped playback, if one did: the reader could not
76
+ * read on, or the decoder gave up. Playback stops where it was
77
+ * (`playing()` goes false, the last frame stays up); a `seek` retries
78
+ * the source. The same object `failed` resolves with.
79
+ */
80
+ error(): VideoError | undefined
81
+ /**
82
+ * Resolves with the failure that stops playback, once, or with
83
+ * undefined when the player closes without one. What a reactive layer
84
+ * watches instead of polling `error()`.
85
+ */
86
+ failed: Promise<VideoError | undefined>
87
+ /** Stop playback and release everything the player holds. */
35
88
  close(): void
36
89
  }
37
90
 
91
+ /** A texture player: frames land in a GPU texture on the UI's clock. */
92
+ export type VideoPlayer = VideoTransport & {
93
+ /**
94
+ * GPU texture id decoded frames are uploaded into (use as a texture
95
+ * source). Holds the current frame; black until playback starts.
96
+ */
97
+ texture: TextureId
98
+ }
99
+
100
+ /**
101
+ * A plane player: the decoder renders into the platform's own video
102
+ * surface, fullscreen beneath the UI, on the video's clock. Exists from
103
+ * open until close; one at a time. The UI draws over it wherever it
104
+ * paints, and the window's uncovered pixels show the video. Its audio
105
+ * track plays on the default output, in sync with the picture.
106
+ */
107
+ export type VideoPlane = VideoTransport
108
+
109
+ /**
110
+ * A video source: a path resolved like file() paths (through the app's
111
+ * assets in a packed app), an http: or https: URL, or a file() from
112
+ * flux:fs (a packed asset is read out of the exe). Any other scheme
113
+ * throws. A URL plays on a plane only, and is read by the runtime
114
+ * directly: no disk cache, no dev-server proxying, so the device must
115
+ * reach the host itself.
116
+ */
117
+ export type VideoSource = string | FluxFile
118
+
119
+ export type VideoOpenOptions = {
120
+ /** Where the picture goes: a texture (default) or the platform's video plane. */
121
+ present?: "texture"
122
+ /**
123
+ * Aborting it abandons the open: the promise rejects with the signal's
124
+ * reason and the source is closed. (A texture player opens at once;
125
+ * the signal matters for a plane's streamed open.)
126
+ */
127
+ signal?: AbortSignal
128
+ }
129
+
130
+ export type VideoPlaneOptions = {
131
+ present: "plane"
132
+ /** How the picture fits the window: letterboxed (default) or cropped to fill. */
133
+ fit?: "contain" | "cover"
134
+ /** Aborting it abandons the open (see VideoOpenOptions). */
135
+ signal?: AbortSignal
136
+ }
137
+
38
138
  /**
39
- * Open a video file (MP4 with 8-bit 4:2:0 VP9 video, i.e. profile 0;
40
- * AAC audio plays, other audio tracks are ignored). The path resolves
41
- * like file() paths (through the app's assets in a packed app). Playback
42
- * starts paused; call `play()`. Rejects when the file is unreadable or
43
- * its codec unsupported.
139
+ * Open a video (WebM with 8-bit 4:2:0 VP9 video, i.e. profile 0; Opus
140
+ * audio plays, other audio tracks are ignored). Playback starts paused;
141
+ * call `play()`. Rejects with a VideoError: "network" when the source
142
+ * cannot be opened (or does not answer within the open timeout),
143
+ * "unsupported" when its codec is not played or a URL is given to a
144
+ * texture player, "no-plane" for `present: "plane"` on a platform without
145
+ * a video plane (Android only) or while another plane is open or opening.
146
+ * A plane open reads the header off the JS thread and resolves once the
147
+ * plane exists; a texture player opens at once.
44
148
  *
45
- * Encode with `ffmpeg -c:v libvpx-vp9 -c:a aac out.mp4`; VP9 is
46
- * royalty-free, so the decoder ships on every platform.
149
+ * Encode with `ffmpeg -c:v libvpx-vp9 -c:a libopus out.webm`; VP9 and
150
+ * Opus are royalty-free, so both decoders ship on every platform.
47
151
  */
48
- export function open(path: string): Promise<VideoPlayer>
152
+ export function open(source: VideoSource, options?: VideoOpenOptions): Promise<VideoPlayer>
153
+ export function open(source: VideoSource, options: VideoPlaneOptions): Promise<VideoPlane>
49
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidrt/flux-types",
3
- "version": "0.0.59",
3
+ "version": "0.0.60",
4
4
  "license": "MIT",
5
5
  "funding": "https://github.com/sponsors/wellawaretech",
6
6
  "author": "Antoine van Wel",