@ksp-gonogo/kerbcast 1.4.0
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/CHANGELOG.md +186 -0
- package/LICENSE +369 -0
- package/README.md +112 -0
- package/dist/__generated__/types.d.ts +529 -0
- package/dist/__generated__/types.js +50 -0
- package/dist/client.d.ts +433 -0
- package/dist/client.js +821 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/noise.d.ts +34 -0
- package/dist/noise.js +274 -0
- package/dist/panZoom.d.ts +190 -0
- package/dist/panZoom.js +302 -0
- package/dist/testing/index.d.ts +217 -0
- package/dist/testing/index.js +606 -0
- package/package.json +57 -0
- package/src/__generated__/types.ts +488 -0
- package/src/client.test.ts +1673 -0
- package/src/client.ts +1219 -0
- package/src/domStubs.test.ts +49 -0
- package/src/index.ts +29 -0
- package/src/noise.test.ts +340 -0
- package/src/noise.ts +317 -0
- package/src/panZoom.test.ts +404 -0
- package/src/panZoom.ts +405 -0
- package/src/testing/index.ts +689 -0
- package/src/testing.test.ts +156 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Generated by typeshare 1.13.4
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface AdaptiveShedPayload {
|
|
6
|
+
level: number;
|
|
7
|
+
kspFps: number;
|
|
8
|
+
reason: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Lifecycle state of a camera. Transmitted in `CameraState` so clients
|
|
13
|
+
* can react to part destruction without a new message type.
|
|
14
|
+
*
|
|
15
|
+
* Destroyed is a terminal state — the sidecar never transitions a camera
|
|
16
|
+
* back to Active after writing the tombstone.
|
|
17
|
+
*/
|
|
18
|
+
export enum CameraLifecycle {
|
|
19
|
+
Active = "active",
|
|
20
|
+
Destroyed = "destroyed",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Layer mask. Mirrors `Kerbcast.CameraLayers` on the plugin side.
|
|
25
|
+
* Receiving clients use this for both the rendered-layer status reports
|
|
26
|
+
* and per-camera layer requests.
|
|
27
|
+
*/
|
|
28
|
+
export enum Layer {
|
|
29
|
+
Near = "NEAR",
|
|
30
|
+
Scaled = "SCALED",
|
|
31
|
+
Far = "FAR",
|
|
32
|
+
Galaxy = "GALAXY",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Viewer-selectable resolution preset. Each maps to a fraction of the
|
|
37
|
+
* operator-configured render size (the settings.cfg Width/Height ceiling):
|
|
38
|
+
* full = 1.0, threeQuarter = 0.75, half = 0.5, quarter = 0.25. The steps
|
|
39
|
+
* mirror the plugin's shed-table resolution ladder so the viewer clamp and
|
|
40
|
+
* the adaptive controller move on the same grid, and a preset can never
|
|
41
|
+
* exceed the ring's allocated max (every scale is <= 1.0 of the ceiling).
|
|
42
|
+
*
|
|
43
|
+
* Presets, not freeform WxH: a fixed menu keeps the unauthenticated
|
|
44
|
+
* viewer-writable surface tiny and aspect-correct by construction.
|
|
45
|
+
*/
|
|
46
|
+
export enum QualityPreset {
|
|
47
|
+
Full = "full",
|
|
48
|
+
ThreeQuarter = "threeQuarter",
|
|
49
|
+
Half = "half",
|
|
50
|
+
Quarter = "quarter",
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Per-camera snapshot pushed by the sidecar on every state change
|
|
55
|
+
* (operator API call, adaptive shed, vessel change). Same shape served
|
|
56
|
+
* by `GET /cameras` so client UIs can treat the two interchangeably.
|
|
57
|
+
*
|
|
58
|
+
* Capability fields (`supports_zoom`, `supports_pan`) let clients
|
|
59
|
+
* render controls only for features each part actually offers — a
|
|
60
|
+
* fixed-FoV camera shouldn't get a zoom slider, a non-steerable one
|
|
61
|
+
* shouldn't get a pan stick.
|
|
62
|
+
*/
|
|
63
|
+
export interface CameraState {
|
|
64
|
+
flightId: number;
|
|
65
|
+
/**
|
|
66
|
+
* Part-destruction lifecycle. `Active` for live cameras. `Destroyed`
|
|
67
|
+
* when the plugin reports the Hullcam part was destroyed in-flight
|
|
68
|
+
* (collision, overheating, decoupling beyond physics range). Once
|
|
69
|
+
* destroyed the sidecar stops forwarding frames; the client should
|
|
70
|
+
* surface a "SIGNAL LOST" overlay and keep the last frame visible.
|
|
71
|
+
*/
|
|
72
|
+
lifecycle?: CameraLifecycle;
|
|
73
|
+
partName: string;
|
|
74
|
+
partTitle: string;
|
|
75
|
+
cameraName: string;
|
|
76
|
+
vesselName: string;
|
|
77
|
+
/** Currently-rendered layers (effective after adaptive shedding). */
|
|
78
|
+
layers: Layer[];
|
|
79
|
+
/**
|
|
80
|
+
* Operator-requested layer mask — the ceiling adaptive shedding
|
|
81
|
+
* can reduce below. UIs use this to show "scaled is *requested* but
|
|
82
|
+
* not *active* right now due to fps".
|
|
83
|
+
*/
|
|
84
|
+
operatorLayers: Layer[];
|
|
85
|
+
/**
|
|
86
|
+
* Currently-rendered dimensions (effective after adaptive
|
|
87
|
+
* resolution downscale). Equal to `operatorWidth` × `operatorHeight`
|
|
88
|
+
* when no auto-shed is in effect.
|
|
89
|
+
*/
|
|
90
|
+
renderWidth: number;
|
|
91
|
+
renderHeight: number;
|
|
92
|
+
/**
|
|
93
|
+
* Operator-requested render size — ceiling adaptive downscale can
|
|
94
|
+
* reduce below.
|
|
95
|
+
*/
|
|
96
|
+
operatorWidth: number;
|
|
97
|
+
operatorHeight: number;
|
|
98
|
+
/**
|
|
99
|
+
* Whether the part's Hullcam module supports runtime FoV changes
|
|
100
|
+
* (i.e. it's a `MuMechModuleHullCameraZoom`, not the fixed base
|
|
101
|
+
* `MuMechModuleHullCamera`). 19 of 21 stock parts do.
|
|
102
|
+
*/
|
|
103
|
+
supportsZoom: boolean;
|
|
104
|
+
/** Current effective FoV in degrees. */
|
|
105
|
+
fov: number;
|
|
106
|
+
/**
|
|
107
|
+
* FoV bounds the operator can choose between. Wider than the
|
|
108
|
+
* camera's "default" — these come from the Hullcam part config.
|
|
109
|
+
* Equal to `fov` when `supports_zoom == false`.
|
|
110
|
+
*/
|
|
111
|
+
fovMin: number;
|
|
112
|
+
fovMax: number;
|
|
113
|
+
/**
|
|
114
|
+
* Whether the part supports pan/tilt (kerbcast-side mod extension —
|
|
115
|
+
* no stock Hullcam parts are steerable, but the extended mod adds
|
|
116
|
+
* pan to specific parts). False on every shipping part today;
|
|
117
|
+
* clients should hide pan controls until this flips true.
|
|
118
|
+
*/
|
|
119
|
+
supportsPan: boolean;
|
|
120
|
+
panYaw: number;
|
|
121
|
+
panPitch: number;
|
|
122
|
+
panYawMin: number;
|
|
123
|
+
panYawMax: number;
|
|
124
|
+
panPitchMin: number;
|
|
125
|
+
panPitchMax: number;
|
|
126
|
+
/**
|
|
127
|
+
* Current encoder bitrate target in bits per second. Equals
|
|
128
|
+
* `target_bitrate_bps` after the consume loop applies receiver
|
|
129
|
+
* feedback; the two diverge briefly between a REMB arriving and
|
|
130
|
+
* the consume loop's next tick. Zero when no encoder is running
|
|
131
|
+
* yet (no subscribers).
|
|
132
|
+
*/
|
|
133
|
+
encoderBitrateBps: number;
|
|
134
|
+
/**
|
|
135
|
+
* Bandwidth target derived from receivers' REMB feedback (min
|
|
136
|
+
* across active subscribers). Drives the encoder when
|
|
137
|
+
* significantly diverged. Zero until the first REMB packet
|
|
138
|
+
* arrives — encoder falls back to the sidecar's CLI default.
|
|
139
|
+
*/
|
|
140
|
+
targetBitrateBps: number;
|
|
141
|
+
/**
|
|
142
|
+
* Effective degrade level (max across subscribers' SetDegrade
|
|
143
|
+
* requests). 0.0 = perfect, 1.0 = max degradation. Applied
|
|
144
|
+
* alongside operator render-size + adaptive shed; the encoder
|
|
145
|
+
* multiplies its effective bitrate by `(1 - 0.7 * level)` and
|
|
146
|
+
* skips fan-out for a fraction of frames at high levels.
|
|
147
|
+
*/
|
|
148
|
+
degradeLevel: number;
|
|
149
|
+
/**
|
|
150
|
+
* Viewer-requested resolution preset for this camera. Last write
|
|
151
|
+
* wins across all connected peers; this broadcast is what keeps
|
|
152
|
+
* every UI consistent. Absent/None = auto: no viewer clamp, the
|
|
153
|
+
* operator ceiling and the adaptive controller alone decide.
|
|
154
|
+
*/
|
|
155
|
+
viewerQuality?: QualityPreset;
|
|
156
|
+
/**
|
|
157
|
+
* Why the effective resolution sits below what the viewer asked
|
|
158
|
+
* for (or below the operator ceiling when no preset is set).
|
|
159
|
+
* `"throttled"` = the adaptive perf machinery is holding the
|
|
160
|
+
* camera down; the viewer target is honored again on recovery.
|
|
161
|
+
* Absent/None = the request is fully honored.
|
|
162
|
+
*/
|
|
163
|
+
qualityLimitedBy?: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface CameraSnapshotPayload {
|
|
167
|
+
cameras: CameraState[];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface CameraStateChangedPayload {
|
|
171
|
+
state: CameraState;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export enum ErrorSource {
|
|
175
|
+
Sidecar = "sidecar",
|
|
176
|
+
Client = "client",
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface ErrorPayload {
|
|
180
|
+
message: string;
|
|
181
|
+
source?: ErrorSource;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface FlightIdPayload {
|
|
185
|
+
flightId: number;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export interface HelloPayload {
|
|
189
|
+
sidecarVersion: string;
|
|
190
|
+
encoderBackend: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface SetDegradePayload {
|
|
194
|
+
flightId: number;
|
|
195
|
+
/**
|
|
196
|
+
* 0.0 = perfect quality, 1.0 = maximum degradation. Caps and
|
|
197
|
+
* is per-subscriber: the sidecar applies max across active
|
|
198
|
+
* subscribers so the noisiest consumer's request wins (same
|
|
199
|
+
* pattern as REMB picking the min bandwidth).
|
|
200
|
+
*/
|
|
201
|
+
level: number;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface SetFovPayload {
|
|
205
|
+
flightId: number;
|
|
206
|
+
fov: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface SetLayersPayload {
|
|
210
|
+
flightId: number;
|
|
211
|
+
layers: Layer[];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface SetPanPayload {
|
|
215
|
+
flightId: number;
|
|
216
|
+
yaw: number;
|
|
217
|
+
pitch: number;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface SetPanRatePayload {
|
|
221
|
+
flightId: number;
|
|
222
|
+
/**
|
|
223
|
+
* Normalised yaw velocity, -1..=1. +1 = pan right at the part's
|
|
224
|
+
* full `PanRateDegPerSec`. Persistent until superseded (a new rate,
|
|
225
|
+
* including zero, replaces it); the plugin integrates it into the
|
|
226
|
+
* pan target every frame.
|
|
227
|
+
*/
|
|
228
|
+
yawRate: number;
|
|
229
|
+
/**
|
|
230
|
+
* Normalised pitch velocity, -1..=1. +1 = pan up. Persistent until
|
|
231
|
+
* superseded.
|
|
232
|
+
*/
|
|
233
|
+
pitchRate: number;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface SetQualityPayload {
|
|
237
|
+
flightId: number;
|
|
238
|
+
/**
|
|
239
|
+
* Requested resolution preset, or absent/null for auto (clear the
|
|
240
|
+
* viewer clamp). Future viewer-quality knobs are added here as
|
|
241
|
+
* optional fields with serde defaults, so older clients keep
|
|
242
|
+
* parsing; richer controls (bitrate, ladder toggles) stay
|
|
243
|
+
* operator-only until deliberately opened up.
|
|
244
|
+
*/
|
|
245
|
+
preset?: QualityPreset;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface SetRenderSizePayload {
|
|
249
|
+
flightId: number;
|
|
250
|
+
width: number;
|
|
251
|
+
height: number;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface SetThrottleMainScreenPayload {
|
|
255
|
+
/**
|
|
256
|
+
* When `true`, disable the KSP main flight cameras to free GPU for
|
|
257
|
+
* kerbcast streams. Persists via the per-save difficulty parameter,
|
|
258
|
+
* matching the in-game Difficulty Settings toggle.
|
|
259
|
+
*/
|
|
260
|
+
enabled: boolean;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface SetZoomRatePayload {
|
|
264
|
+
flightId: number;
|
|
265
|
+
/**
|
|
266
|
+
* Normalised zoom velocity, -1..=1. +1 = zoom IN (FoV decreasing)
|
|
267
|
+
* at the part's full `ZoomRateDegPerSec`. Persistent until
|
|
268
|
+
* superseded; the plugin integrates it into the FoV target every
|
|
269
|
+
* frame.
|
|
270
|
+
*/
|
|
271
|
+
rate: number;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export interface SettingsStatePayload {
|
|
275
|
+
/**
|
|
276
|
+
* Effective value of the "Throttle KSP main render" setting as last
|
|
277
|
+
* reported by the plugin's `global.status.json`. Reflects what the
|
|
278
|
+
* plugin has *applied*, not just what was last requested.
|
|
279
|
+
*/
|
|
280
|
+
throttleMainScreen: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* KSP mission time (`Planetarium.GetUniversalTime()`, seconds) at
|
|
283
|
+
* which the video currently being produced was captured. `None` =
|
|
284
|
+
* no clock yet (old plugin/sidecar, or first status not seen); a
|
|
285
|
+
* consumer treats that as "unknown" and keeps a live passthrough.
|
|
286
|
+
*/
|
|
287
|
+
captureUt?: number;
|
|
288
|
+
/**
|
|
289
|
+
* Monotonic counter bumped only on a non-monotonic UT jump (revert,
|
|
290
|
+
* quickload, scene reload). Consumers resynchronise on any change;
|
|
291
|
+
* the absolute value is meaningless.
|
|
292
|
+
*/
|
|
293
|
+
captureEpoch?: number;
|
|
294
|
+
/**
|
|
295
|
+
* Current KSP time-warp multiplier, so a consumer can interpolate
|
|
296
|
+
* `capture_ut` between ~1Hz samples. `None` => treat as 1.0.
|
|
297
|
+
*/
|
|
298
|
+
timeWarpRate?: number;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Slot↔camera assignment for the dynamic-subscription model. The sidecar
|
|
303
|
+
* negotiates a pool of recv-only video transceivers up front; `Subscribe`
|
|
304
|
+
* binds a camera to a free one and the sidecar announces the binding here.
|
|
305
|
+
*/
|
|
306
|
+
export interface SlotMapPayload {
|
|
307
|
+
/**
|
|
308
|
+
* Transceiver `mid` carrying this slot's track. Stable for the
|
|
309
|
+
* connection's life, so the client keys off it rather than the
|
|
310
|
+
* fragile `onTrack` arrival order — match against
|
|
311
|
+
* `RTCTrackEvent.transceiver.mid`.
|
|
312
|
+
*/
|
|
313
|
+
mid: string;
|
|
314
|
+
/**
|
|
315
|
+
* Camera now carried by the slot, or `None` when the slot was freed
|
|
316
|
+
* by `Unsubscribe`. Serialised as `null` (not omitted) so "freed" is
|
|
317
|
+
* unambiguous on the wire.
|
|
318
|
+
*/
|
|
319
|
+
flightId?: number;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Messages sent FROM the client TO the sidecar. */
|
|
323
|
+
export type ClientMessage =
|
|
324
|
+
/**
|
|
325
|
+
* First message on a new data channel. Sidecar replies with `Hello`
|
|
326
|
+
* + a `CameraSnapshot` so the client gets server version + every
|
|
327
|
+
* camera's full state on one round-trip.
|
|
328
|
+
*/
|
|
329
|
+
| { type: "hello", content?: undefined }
|
|
330
|
+
/**
|
|
331
|
+
* Override the operator layer mask for one camera. Server-wide
|
|
332
|
+
* state — all consumers see the change.
|
|
333
|
+
*/
|
|
334
|
+
| { type: "set-layers", content: SetLayersPayload }
|
|
335
|
+
/**
|
|
336
|
+
* Override the operator render size for one camera. Even pixels
|
|
337
|
+
* only (H.264 chroma); server caps at the ring's allocated max.
|
|
338
|
+
*/
|
|
339
|
+
| { type: "set-render-size", content: SetRenderSizePayload }
|
|
340
|
+
/**
|
|
341
|
+
* Set the camera's field-of-view (degrees). Silently ignored for
|
|
342
|
+
* parts whose Hullcam module is the fixed base (`supportsZoom ==
|
|
343
|
+
* false`); clients are expected to clamp to `fovMin / fovMax`
|
|
344
|
+
* from the camera's `CameraState` before sending.
|
|
345
|
+
*/
|
|
346
|
+
| { type: "set-fov", content: SetFovPayload }
|
|
347
|
+
/**
|
|
348
|
+
* Pan/tilt the camera (yaw and pitch, both degrees from the
|
|
349
|
+
* part's resting forward). No stock Hullcam parts support this
|
|
350
|
+
* yet — the message is ignored until the planned mod extension
|
|
351
|
+
* adds steerable mounts to specific parts. Clients should hide
|
|
352
|
+
* pan controls until `supportsPan == true` for the camera.
|
|
353
|
+
*/
|
|
354
|
+
| { type: "set-pan", content: SetPanPayload }
|
|
355
|
+
/**
|
|
356
|
+
* Set a *persistent* pan/tilt velocity (normalised yaw + pitch,
|
|
357
|
+
* -1..=1). Unlike `SetPan` (a one-shot absolute target), the rate
|
|
358
|
+
* holds until a new rate — including zero, which stops — supersedes
|
|
359
|
+
* it; the plugin integrates it into the pan target every frame so
|
|
360
|
+
* smoothness lives in KSP's frame loop rather than the control-poll
|
|
361
|
+
* cadence. +yaw = pan right, +pitch = pan up. Ignored (sidecar
|
|
362
|
+
* replies `Error`) when `supportsPan == false`. Composes with
|
|
363
|
+
* `SetPan`: an absolute command jumps the target, integration then
|
|
364
|
+
* continues from there.
|
|
365
|
+
*/
|
|
366
|
+
| { type: "set-pan-rate", content: SetPanRatePayload }
|
|
367
|
+
/**
|
|
368
|
+
* Set a *persistent* zoom velocity (normalised, -1..=1). +1 = zoom
|
|
369
|
+
* IN (FoV decreasing). Holds until a new rate — including zero —
|
|
370
|
+
* supersedes it; the plugin integrates it into the FoV target every
|
|
371
|
+
* frame. Ignored (sidecar replies `Error`) when `supportsZoom ==
|
|
372
|
+
* false`. Composes with the absolute `SetFov` the same way
|
|
373
|
+
* `SetPanRate` composes with `SetPan`.
|
|
374
|
+
*/
|
|
375
|
+
| { type: "set-zoom-rate", content: SetZoomRatePayload }
|
|
376
|
+
/**
|
|
377
|
+
* Request artificial signal degradation. 0.0 = perfect quality,
|
|
378
|
+
* 1.0 = maximum degradation. Per-subscriber: the sidecar
|
|
379
|
+
* applies max across active subscribers (slowest consumer
|
|
380
|
+
* wins, same pattern as REMB bandwidth). Lets consumers signal
|
|
381
|
+
* to the sidecar "I want to look like the in-game CommNet
|
|
382
|
+
* antenna is struggling"; sidecar takes the opportunity to
|
|
383
|
+
* reduce bitrate + skip frames, which both creates the
|
|
384
|
+
* signal-loss aesthetic AND saves encoder CPU.
|
|
385
|
+
*/
|
|
386
|
+
| { type: "set-degrade", content: SetDegradePayload }
|
|
387
|
+
/**
|
|
388
|
+
* Set (or clear, with `preset: null`) a camera's viewer-requested
|
|
389
|
+
* resolution preset. Server-wide, last write wins across peers; the
|
|
390
|
+
* resulting `CameraStateChanged` broadcast keeps every UI
|
|
391
|
+
* consistent. The effective resolution is always
|
|
392
|
+
* min(operator ceiling, adaptive level, viewer preset): a preset
|
|
393
|
+
* can never raise quality past the operator's settings.cfg
|
|
394
|
+
* Width/Height, and the adaptive controller's demotes keep
|
|
395
|
+
* winning until it recovers. Viewers can NOT change bitrate or
|
|
396
|
+
* toggle the adaptive machinery through this message.
|
|
397
|
+
*/
|
|
398
|
+
| { type: "set-quality", content: SetQualityPayload }
|
|
399
|
+
/**
|
|
400
|
+
* Request an IDR (keyframe) on the next encode tick. Browsers send
|
|
401
|
+
* this when they've dropped enough frames to be unable to decode
|
|
402
|
+
* the current P-frame chain. Sidecar forwards to the camera's
|
|
403
|
+
* encoder.
|
|
404
|
+
*/
|
|
405
|
+
| { type: "request-keyframe", content: FlightIdPayload }
|
|
406
|
+
/**
|
|
407
|
+
* Dynamically subscribe to a camera on an already-connected peer. The
|
|
408
|
+
* sidecar binds it to a free pre-negotiated slot (one of the recv-only
|
|
409
|
+
* video transceivers from the offer), starts encoding it, forces a
|
|
410
|
+
* keyframe, and replies with `SlotMap` naming the transceiver `mid` now
|
|
411
|
+
* carrying it — no renegotiation. Replies with `Error` if no slot is
|
|
412
|
+
* free (the client should have negotiated enough transceivers up front).
|
|
413
|
+
*/
|
|
414
|
+
| { type: "subscribe", content: FlightIdPayload }
|
|
415
|
+
/**
|
|
416
|
+
* Release a camera's slot. The sidecar stops feeding that slot (the
|
|
417
|
+
* camera sleeps if it has no other subscribers) and replies with
|
|
418
|
+
* `SlotMap { flightId: null }` for the freed transceiver `mid`.
|
|
419
|
+
*/
|
|
420
|
+
| { type: "unsubscribe", content: FlightIdPayload }
|
|
421
|
+
/** Response to `Ping`. Browser sends this immediately on receiving each Ping. */
|
|
422
|
+
| { type: "pong", content?: undefined }
|
|
423
|
+
/**
|
|
424
|
+
* Graceful teardown. The canonical way for a client to leave: the sidecar
|
|
425
|
+
* immediately releases every camera this peer is feeding (so they sleep
|
|
426
|
+
* without waiting for ICE to time out), after which the client may close
|
|
427
|
+
* the connection. The drop-detection reaper remains the fallback for
|
|
428
|
+
* ungraceful exits (crash / tab close / network loss) that can't send this.
|
|
429
|
+
*/
|
|
430
|
+
| { type: "disconnect", content?: undefined }
|
|
431
|
+
/**
|
|
432
|
+
* Enable or disable the KSP main render throttle globally. Persists
|
|
433
|
+
* across saves (writes the per-save difficulty parameter). Server-wide:
|
|
434
|
+
* all peers see the resulting `SettingsState` broadcast.
|
|
435
|
+
*/
|
|
436
|
+
| { type: "set-throttle-main-screen", content: SetThrottleMainScreenPayload };
|
|
437
|
+
|
|
438
|
+
/** Messages sent FROM the sidecar TO the client. */
|
|
439
|
+
export type ServerMessage =
|
|
440
|
+
/**
|
|
441
|
+
* Reply to `Hello`. Carries server version + the active encoder
|
|
442
|
+
* backend's name.
|
|
443
|
+
*/
|
|
444
|
+
| { type: "hello", content: HelloPayload }
|
|
445
|
+
/**
|
|
446
|
+
* Full snapshot of every currently-attached camera. Sent in reply
|
|
447
|
+
* to `Hello` and on any structural change (vessel switch, ring
|
|
448
|
+
* added/removed).
|
|
449
|
+
*/
|
|
450
|
+
| { type: "camera-snapshot", content: CameraSnapshotPayload }
|
|
451
|
+
/**
|
|
452
|
+
* Single-camera state change. Sent when an operator request applies
|
|
453
|
+
* or adaptive shedding kicks in. Lets clients update their UI
|
|
454
|
+
* without re-fetching the whole snapshot.
|
|
455
|
+
*/
|
|
456
|
+
| { type: "camera-state-changed", content: CameraStateChangedPayload }
|
|
457
|
+
/**
|
|
458
|
+
* Slot↔camera assignment for the dynamic-subscription model. Sent in
|
|
459
|
+
* reply to `Subscribe`/`Unsubscribe`: `flightId` is the camera now
|
|
460
|
+
* carried by transceiver `mid`, or `null` when the slot was freed. The
|
|
461
|
+
* client maps `mid` to the track it received via `onTrack` and routes
|
|
462
|
+
* that track to (or away from) the camera's stream — no renegotiation.
|
|
463
|
+
*/
|
|
464
|
+
| { type: "slot-map", content: SlotMapPayload }
|
|
465
|
+
/**
|
|
466
|
+
* Adaptive shedding level changed. Reason is human-readable
|
|
467
|
+
* ("ksp-fps-low", "ksp-fps-recovered") so client UIs can show
|
|
468
|
+
* *why* quality changed rather than just *that* it did.
|
|
469
|
+
*/
|
|
470
|
+
| { type: "adaptive-shed", content: AdaptiveShedPayload }
|
|
471
|
+
/**
|
|
472
|
+
* Malformed / unknown client message. Includes the offending
|
|
473
|
+
* payload so the client can log it.
|
|
474
|
+
*/
|
|
475
|
+
| { type: "error", content: ErrorPayload }
|
|
476
|
+
/**
|
|
477
|
+
* Keepalive probe sent by the sidecar every 5 seconds. Browser responds
|
|
478
|
+
* with `Pong`; if no Ping arrives within 15s the browser tears down
|
|
479
|
+
* the connection.
|
|
480
|
+
*/
|
|
481
|
+
| { type: "ping", content?: undefined }
|
|
482
|
+
/**
|
|
483
|
+
* Current value of global settings (throttle state). Sent after `Hello`
|
|
484
|
+
* so a freshly-connected client shows correct state immediately, and
|
|
485
|
+
* re-broadcast whenever the polled plugin status shows a change.
|
|
486
|
+
*/
|
|
487
|
+
| { type: "settings-state", content: SettingsStatePayload };
|
|
488
|
+
|