Two device-REPORTING fixes from the #134 investigation (the PiP rendering itself was #135). 1) "Device reconnects every ~45s" was a logging artifact, not instability. The player re-emits a full device:register on the SAME socket every ~45-60s (requestPlaylistRefresh) to pull a fresh playlist; the server logged "Device reconnected" for every register of a known device. The attached 4-day log showed 1415 "reconnected" vs 30 real socket connects and 0 heartbeat timeouts — the socket never dropped, so #134's "PiP lost between reconnects" was a misdiagnosis. Fix: only log a genuine reconnect (new socket); a same-socket re-register is a refresh (currentDeviceId === device_id) and stays quiet. The playlist still refreshes. 2) Device reported 720p while the monitor showed a 1080 signal. DeviceInfo reported getRealMetrics() — the UI RENDER SURFACE — but TV boxes render the UI at 720p and upscale to a 1080p HDMI signal. Now report BOTH: screen_width/height = the output mode (Display.Mode.physicalWidth/Height), render_width/height = the render surface (getRealMetrics). Two new nullable devices columns, stored on pairing INSERT + reconnect UPDATE, exposed via the device API, shown on the dashboard as "1920x1080 (UI 1280x720)" when they differ. Backward compatible (required + verified on emulator): a device that omits render_* — or sends no device_info at all — still registers, with render_* = null, on both the INSERT and UPDATE paths. New columns nullable; stores use `?? null` / `|| null`. All 167 server tests pass. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.9 KiB
#134 follow-ups — device reporting fixes
Two issues surfaced while investigating #134 (the PiP bug report). Neither is the PiP rendering itself (that was #135) — both are device reporting problems.
1. "Device reconnects every ~45s" — a logging artifact, not instability
Symptom (#134): the server log shows the device reconnecting every ~45s, read as an unstable WebSocket that could drop PiP commands.
Reality: the connection is stable. The player calls requestPlaylistRefresh()
every ~45–60s, which re-emits a full device:register on the same socket to
pull a fresh playlist. The server's register handler logged Device reconnected
for every register of a known device, so a healthy device that re-registers
~2000×/day looked like it was flapping.
Evidence from the attached 4-day log:
| Signal | Count |
|---|---|
Device reconnected |
1415 |
Device socket connected (real) |
30 |
Device disconnected (real) |
21 |
marked offline (heartbeat timeout) |
0 |
1415 "reconnects" vs 30 real socket connects, and the socket never timed out. So #134's "PiP lost between reconnects / queue TTL-expired" was a misdiagnosis — the socket doesn't drop; the PiP failure was the rendering bugs fixed in #135.
Fix (ws/deviceSocket.js): a re-register on the same socket
(currentDeviceId === device_id) is a playlist refresh, not a reconnect — only
log Device reconnected for a genuinely new socket. The refresh still resends the
playlist; it just no longer spams the log / reads as instability.
Verified on the emulator: a periodic refresh was processed (device received a new
playlist) while the server's Device reconnected count stayed flat; two genuine
reconnects logged exactly twice.
Follow-up (not done here): the full re-register every ~45s is heavier than it needs to be (re-runs fingerprint/token/eviction + resends the playlist). A lightweight
device:request-playlistevent would cut that churn. Left as a separate optimization.
2. Reports 720p while the monitor shows a 1080 signal
Symptom (#134-adjacent): a panel receiving a real 1080p HDMI signal was reported as 720p.
Cause: DeviceInfo reported getRealMetrics() — the UI render surface.
Many Android TV boxes/sticks (YaOS, Fire TV, etc.) render the UI at 1280×720 and
let the hardware scaler upscale to a 1920×1080 (or 4K) HDMI signal. getRealMetrics
honestly reports the 720p render surface; the monitor sees the 1080p output mode.
They are two different numbers.
Fix: report both, so neither is lost:
screen_width/screen_height= the HDMI/panel output mode, fromDisplay.getMode().getPhysicalWidth()/getPhysicalHeight()(orientation-independent; the panel doesn't rotate when the stage is software-rotated). This is the headline resolution and now reads 1080 on those boxes.render_width/render_height= the UI render surface, fromgetRealMetrics().
Wiring: Android DeviceInfo.getDeviceInfo() → two new nullable devices columns
(render_width, render_height, migration) → stored in both the pairing INSERT and
the reconnect UPDATE → exposed via the device API (SELECT d.*) → the dashboard
device detail shows 1920x1080 (UI 1280x720) when they differ.
Backward compatibility
Required and verified: a device that doesn't report the new fields must still be accepted.
- New columns are nullable; the store uses
device_info.render_width ?? null(reconnect) anddevice_info?.render_width || null(pairing);device_infoitself remains optional. - Verified on the emulator: an old-style register with
screen_*but norender_*, and a register with nodevice_infoat all, both succeed withrender_*= null — on both the INSERT (pairing) and UPDATE (reconnect) paths. - The dashboard only appends
(UI …)whenrender_*is present and differs, so legacy devices render as before.