PreviewDriver
Source:
PreviewDriver.h
PreviewDriver¶
src/light/drivers/PreviewDriver.h:70Inherits:
DriverBase,ClientMessageSink
Streams a true-shape 3D preview to the web UI over the binary WebSocket.
The preview is a POINT LIST, not a dense grid: only the real lights are sent, at their real (x,y,z) positions. This is the proven MoonLight model (virtual grid → physical sparse lights; positions sent once at mapping time, channels per frame). Two message types — PreviewDriver owns both wire formats; the HTTP server is a domain-neutral BinaryBroadcaster that just writes the bytes: 0x03 coordinate table (sent ONLY in answer to a client's [0x52] request; the client caches tables per (epoch, stride), so a stride change to a known rung asks nothing): [0x03][count:u32][bx:u8][by:u8][bz:u8][stride:u16][epoch:u8][(x,y,z):u8x3 x count] bx/by/bz = bounding-box extent (for client centring); positions are 1 byte/axis (scaled when an axis exceeds 255). count is u32 so a >65535-light panel isn't capped by the wire format; epoch bumps on every geometry rebuild and keys the client's cache.
0x02 per-frame channels: [0x02][count:u32][stride:u16][epoch:u8][drops:u8][(r,g,b) x count] RGB of every kept light, in the coord table's order. drops = frames discarded at the source since the last delivered one, the congestion signal the client's controller adapts on.
0x04 per-frame AIM, sent only for a rig whose fixtures carry pan/tilt (a moving-head rig); a plain LED wall never emits it and costs nothing for it: [0x04][count:u32][stride:u16][epoch:u8][reserved:u8][(pan,tilt):u8x2 x count] Same order and same (epoch, stride) key as 0x02, so aim[k] belongs to the light the color frame's k-th entry colors. The BROWSER decides how to draw it (today a beam line from the fixture): the wire carries where a head points, never a rendered look, so a richer visual later is a shader change and not a protocol change.
Client requests (masked WS frames, unmasked by core, interpreted only here): [0x51][stride][fps] standing frame request (most conservative across viewers wins; the targetFps control is the ceiling) [0x52][stride] one-shot: send me the coordinate table count is the number of points actually kept after lattice downsampling (the lights whose position satisfies pos ≡ 0 mod stride) — a client sizes its buffer from this count, not from the light total. stride rises above 1 when a client requests it, or when the memory cap forces a floor; with no cap in play every light is sent (stride 1), so a sparse layout streams in full. Its own channel (/wsp), and why. Preview frames are lossy and large; control-plane state is small and latency-sensitive. Sharing one WebSocket made the small messages queue behind the big ones, head-of-line blocking, which users saw as a flickering connection indicator and a UI that stopped responding while a large layout streamed. Separate TCP connections is the standard remedy for that mixed-criticality pairing.
Resolution is client-driven. The browser reads the drops counter each frame carries (the device's own congestion signal) and posts the [0x51][stride][fps] standing request it wants; the device serves the most conservative request across viewers. The memory cap (maxPreviewPoints()) is the only floor a request cannot go finer than.
No request, no work.[tick()] returns immediately when no standing request exists, so a dismissed preview pane (or a hidden tab) costs the device nothing, not merely nothing on the wire.

Public Attributes¶
uint8_t targetFps = 24
: The frame rate the preview aims for (Hz), independent of render FPS.
Public Methods¶
virtual inline bool userEditable() const override
: The 3D preview the web UI renders streams from this driver.
inline void setBroadcaster(BinaryBroadcaster * b)
: Set the sink each message is pushed to (HttpServerModule, as a BinaryBroadcaster).
inline void onClientMessage(int slot, const uint8_t * payload, int len) override
: The pull protocol, this producer's whole request vocabulary: [0x51][stride][fps] standing frame request: serve stride s at rate f (fps 0/absent = the targetFps control's value).
inline void onClientGone(int slot) override
inline nrOfLightsType downscaleForTest() const
: The currently served downsample factor (1 = full resolution).
virtual inline bool hasCorrectionControls() const override
: Preview shows the raw logical buffer, no correction.
virtual inline void defineDriverControls() override
: Bind the controls: targetFps (1-25), the frame rate the preview aims for.
virtual inline void setSourceBuffer(Buffer * buf) override
: Point the driver at the sparse driver buffer the LED/ArtNet drivers also read (the MappingLUT fills it with exactly the real lights).
virtual inline void prepare() override
: A rebuild (layout add/replace/remove, resize, modifier change) ran — the light set / positions may have changed, so rebuild + broadcast the coordinate table (the MoonLight "positions once at mapping time").
virtual inline void release() override
: Clear every shared status string on release — fail buffer, config error, and config warning — so a stopped driver leaves nothing behind (frees the owned failBuf_; retracts the warning the same "clear only MY status" way as the error), then chain to MoonModule::release() so any ScratchBuffer the driver holds frees on disable and children recurse.
virtual inline bool affectsPrepare(const char *) const override
: No control changes the transport structure: targetFps is a plain value edit, so nothing here re-runs prepare.
virtual inline void tick() override
: Per-tick: (re)stream the coordinate table when the geometry or client set changed, then stream one color frame if the previous one finished draining.
inline void buildCoordTable()
: Build (or rebuild) the cached coordinate table from the layout's real lights and broadcast it (the 0x03 message).
inline bool sendCoordTable()
: Answer a [0x52] table request: one 0x03 message for the SERVED stride, through the same resumable slot as everything else.
inline bool sendAim()
: Stream one per-frame 0x02 RGB message straight from the producer buffer — no intermediate copy.
inline bool sendFrame()