Client library (Client.js): new onmultimonlayout callback + a multimon-layout
layerPropertyHandler (mirrors multi-touch), and sendSize extended to carry the
optional per-monitor x_position/top_offset.
rustguac: SpiceParams.secondary_monitors + a secondary-monitors connect arg so
guacd advertises the allowed monitor count; CreateSessionRequest.max_monitors
(secondary = max-1) wired through both SPICE branches.
client.html: onargv reads the secondary-monitors count and onmultimonlayout
parses the layout JSON (logging for now; per-monitor windows are A2).
Verified on the canary vs VMID 300: client logs 'server allows 2 monitors' and
receives a multimon-layout. The layout is request-driven (guacd activates a
second guest head only when the client sends a size for monitor 1), so the
second monitor appears in A2.
Frame dropping at queue depth 5 triggered during normal operation and
broke the H.264 reference chain, corrupting output until the next
keyframe. Remove frame dropping entirely — sync gating alone provides
sufficient flow control by delaying the sync response until decodes
complete, giving guacd accurate backpressure.
The H.264 decode path bypassed the Guacamole sync mechanism — the sync
response fired immediately without waiting for WebCodecs to finish
decoding. guacd thought the client was keeping up and sent at full rate,
causing the decode queue to grow without bound (30+ seconds of lag
observed over time).
Fix: gate the sync response on H.264 decode completion so guacd gets
real backpressure. Also drop delta frames when the decode queue exceeds
5 frames as a safety valve for transient overload (tab backgrounding).
- Add pending-decode tracking and per-frame position capture to
H264Decoder.js (fixes shared mutable state race)
- Add waitForPending() with 1s safety timeout for sync gating
- Add frame dropping when decodeQueueSize > 5 (never drops keyframes)
- Add stats() method for console debugging (__guac_client._h264Decoder.stats())
- Gate sync response in Client.js on H.264 decode completion
Closes#93
Phase 1-3 of H.264 passthrough for premium RDP video performance.
guacamole-server patch (patches/004-h264-passthrough.patch):
- Enable GfxH264 and GfxAVC444 in FreeRDP settings when GFX is on
- Intercept AVC420/AVC444 SurfaceCommand before GDI decode
- Extract raw H.264 NAL units and send as new "h264" instruction
- Keyframe detection via Annex B start code + NAL type parsing
- Original GDI decode path still runs as fallback
Browser-side (static/guac/):
- H264Decoder.js: WebCodecs VideoDecoder, hardware-accelerated decode
- Client.js: "h264" instruction handler, base64→ArrayBuffer→decode
- Feature detection: falls back gracefully if WebCodecs unavailable
rustguac:
- Advertise video/h264 in guacd handshake