w0vncserver: a compositor-closed PipeWire stream is never reported — the session freezes silently and forever
Summary
If the compositor destroys the ScreenCast stream while a client is connected, w0vncserver
does not notice in any actionable way. It keeps serving a stale framebuffer indefinitely: no
error is logged at the default log level, the RFB client is not told, and no attempt is made to
renegotiate. The user sees a frozen desktop and eventually a client-side timeout, with nothing
in the server log to explain it.
Environment
- TigerVNC 1.16.0 (
w0vncserver), built from release tarball - openSUSE Leap 16.0, KDE Plasma / KWin 6.4.2, xdg-desktop-portal-kde 6.4.2
- NVIDIA proprietary driver, single 4K DisplayPort output, Wayland session
How to reproduce
- Start
w0vncserver, connect a client, confirm frames are flowing. - Cause the compositor to destroy the stream. The easy way is to make the output disappear: let an external DisplayPort monitor sleep so it drops the link (many do). KWin then has zero outputs, and an output-bound screencast is closed.
- The output returns a second later and the local session is completely unaffected.
Observed: the client's picture freezes permanently. w0vncserver sits idle in poll();
ss -tni shows Send-Q 0 and no traffic in either direction. The server log says nothing.
Subsequent input calls fail with
GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: Invalid session, which is the only hint
anything is wrong — and only if the client sends input. A reconnect does not help: the portal
session is gone, so it is dead until w0vncserver is restarted.
Expected: the server notices the stream is gone and does something — logs at a visible level, disconnects the client so it can reconnect and renegotiate, or re-requests a stream.
Cause
unix/w0vncserver/pipewire/PipeWireStream.cxx, handleStreamStateChanged():
case PW_STREAM_STATE_UNCONNECTED:
vlog.debug("PipeWire stream disconnected");
break;When the compositor tears the stream down, PipeWire transitions the client stream to
PW_STREAM_STATE_UNCONNECTED. That is logged at debug level — invisible at the default log
level — and then execution simply falls through. Contrast PW_STREAM_STATE_ERROR immediately
above, which calls fatal_error(). An unconnected stream is just as fatal to the session in
practice: no further frame can ever arrive, because nothing re-creates the stream.
Compounding it: in xdg-desktop-portal-kde the RemoteDesktop session and the ScreenCast session are the same object, so when the stream goes the input half dies too. A client therefore loses video and input together while the server reports neither.
Suggested fix
At minimum, treat PW_STREAM_STATE_UNCONNECTED while a session is active as an error worth
surfacing: log at error/notice level, and close client connections so they can reconnect
(reconnecting also re-runs the portal negotiation, which does recover). Better still, attempt to
re-request the ScreenCast stream, since the compositor's output usually returns within a second.
Silently serving a stale framebuffer forever is the worst of the options, because it is indistinguishable from a network stall and leaves no evidence.
Notes
The trigger here was an external monitor dropping its DisplayPort link on power-save — ordinary hardware behaviour, and something a screencast consumer should survive. We worked around it at the DRM layer (forcing the connector so the output never disappears), but that only avoids the trigger; the silent-freeze behaviour would remain for any other cause of stream teardown (compositor restart, user revoking the portal grant, output reconfiguration).
Source: TigerVNC/tigervnc