uu-remote status
scripts/verify.sh --quick
uu-remote logsRuntime logs are under ~/.local/state/uu-remote-bridge. UU's proprietary logs
remain inside its Wine prefix. Do not post either set without removing account
and device metadata.
Persistent runtime choices are in
~/.config/uu-remote-bridge/environment. Change them by rerunning the
installer, for example:
./install.sh --skip-packages --skip-account-login \
--rdp-port 3391 --resolution 2560x1440 --display auto \
--grd-fd-restart-threshold 4096Keep the relay resolution and Wine DPI unchanged. The process-local cursor
guard is an opt-in compatibility extension, so hosts with a working cursor do
not load it. Enable it when the controller loses the cursor, renders it too
small, or the UU server records ERROR_INVALID_CURSOR_HANDLE:
./install.sh --skip-packages --skip-account-login \
--cursor-guard on --cursor-size autoauto reads the physical GNOME Xcursor size and creates the same-sized
fallback arrow for UU's independent cursor channel. For a controller that
still renders the cursor too small, use a fixed size:
./install.sh --skip-packages --skip-account-login \
--cursor-guard on --cursor-size 64Accepted values are 24 through 128. Disable the extension with
--cursor-guard off when it is unnecessary. It does not change XRDP, VNC,
TeamViewer, the physical desktop resolution, or Wine's global DPI.
This message can be misleading: the controller may be waiting for the host to
finish local startup before any transport route can be selected. On the
affected workstation, GameViewerServer.exe used about two CPU cores and its
newest log stopped at:
update_gvinput start
The dedicated Wine registry had accumulated 527 failed gvinput devices and
21,894 Bluetooth observations while Ubuntu's Bluetooth scanner was active.
UU enumerated those records synchronously before joining its signaling room.
This was not an Ethernet, DNS, firewall, XRDP, or controller-route failure.
Current installations make the audited devcon.exe unavailable while keeping
its exact vendor binary as devcon.exe.uu-original, disable Bluetooth only
inside UU's dedicated Wine prefix, and remove only recognized stale device
records. Existing installations can apply the same transactional repair:
uu-remote repair-registry
./scripts/verify.sh --quickThe command stops and restarts only uu-remote-bridge.service. It keeps a
mode-0600 system.reg.before-device-hygiene-* backup under
$WINEPREFIX/compat/registry-backups, refuses a root-device subtree containing
an unrelated device, and does not change Ubuntu Bluetooth or XRDP.
On 2026-09-19, an audited UU 4.39.2.1561 installation stalled again with
roughly 55,557 Bluetooth device records and an 80 MB system.reg. The UU
server consumed approximately one CPU core for several minutes. The Wine
Bluetooth service already had Start=4, but the UU-owned winedevice.exe
processes still mapped both winebth.sys and winebth.so. Cleaning the
registry alone allowed about 95 device records to return immediately.
The launcher and transactional cleaner now include winebth.sys=d in
WINEDLLOVERRIDES before starting Wine. This blocks the Bluetooth driver
inside the dedicated UU process tree in both audio modes; it does not disable
Ubuntu Bluetooth. Retain the other overrides, including the optional audio
isolation, when applying this narrow fix to an existing installation.
After deploying those two script changes, run uu-remote repair-registry
once. This removes already accumulated entries and restarts only UU. On the
affected host, the registry fell to 3,979,849 bytes, device counts stayed zero,
and the UU-owned device processes no longer mapped the Bluetooth driver.
The existing account, desktop relay, and input patches were retained. The
service is enabled at login/boot through the existing unattended setup; no
new periodic repair loop is needed.
Inspect the actual runtime as well as the registry: a Start=4 value or one
clean snapshot alone does not prove the driver cannot load. Use /proc/PID/maps
for only the winedevice.exe processes whose WINEPREFIX is this UU prefix;
neither winebth.sys nor winebth.so should be present. Recheck registry counts
after several minutes. Do not stop unrelated Wine applications.
UU 4.39.x uses structured .slog files, so the plaintext milestones below
apply to older releases. The current verifier checks a fresh structured-log
signature, exact local version IPC, patched binaries, relay/input helpers,
and one stable server PID. These are host checks, not proof of a successful
remote controller connection; reconnect from a real client to confirm video,
mouse, typing, and dictation.
A healthy cold start records update_gvinput end within milliseconds and then
room_state_changed: created. Inspect without publishing account metadata:
server_logs="$HOME/.local/share/wineprefixes/uu-remote/drive_c/Program Files/Netease/GameViewer/log/server/log"
latest="$(find "$server_logs" -type f -name 'log_*.txt' -printf '%T@ %p\n' |
sort -nr | head -n 1 | cut -d' ' -f2-)"
rg 'update_gvinput|input_device_count|room_state_changed: created' "$latest"Do not copy this cleanup to a shared Wine prefix or delete arbitrary
ROOT\HIDCLASS entries. Its preflight assumptions are valid because this
project owns a dedicated UU-only prefix.
Inspect the unattended boot chain without displaying either password:
./scripts/configure-unattended.sh status
journalctl --user -b \
-u uu-keyring-unlock.service \
-u gnome-remote-desktop.service \
-u uu-remote-bridge.serviceAfter the first configured reboot, both Account in tss group and
tss active in this login must be yes. A keyring unlock failure usually
means the GNOME keyring password changed. Replace the encrypted credential:
./scripts/configure-unattended.sh enable --replace-credential
sudo rebootDo not place the password in the unit or command line. See
unattended-startup.md for the boot sequence, controlled verification, and
rollback.
First inspect the broker metadata:
broker="$HOME/.local/share/wineprefixes/uu-remote/drive_c/users/$USER/Temp/uu-input-broker.log"
tail -80 "$broker"Repeated focus=timeout result=0 error=21 immediately after opening the local
UU app means one Wine prefix was split across two X displays. Wine's foreground
window state is shared across that prefix, so a physical-display
GameViewer.exe can prevent the private Ubuntu-Desktop-Relay from becoming
the Win32 foreground window even when X11 says it is active.
Update and reinstall this launcher, then restart the bridge once:
git pull --ff-only
./install.sh --skip-packages --skip-account-login
uu-remote restartuu-remote open must present a UU Remote - TigerVNC window while
GameViewer.exe, GameViewerServer.exe, uu-input-broker.exe, and
sdl-freerdp.exe all retain the same private DISPLAY. Do not launch the
prefix's GameViewer.exe directly on DISPLAY=:0. A healthy fresh input call
reports focus=ready, a matching result count, and error=0.
Then check the compatibility hook log:
log="$HOME/.local/share/wineprefixes/uu-remote/drive_c/users/$USER/AppData/Local/Temp/uu-input-bridge.log"
tail -80 "$log"A working click contains:
route=broker result=1 error=0
result=0 error=5 without route=broker means the server was not injected.
Restart the service and inspect input-injector.log:
uu-remote restart
tail -80 ~/.local/state/uu-remote-bridge/input-injector.logIf UU was updated, run the patch verifier. Do not force a new version through the patcher:
scripts/patch-gameviewer.py verify \
"$HOME/.local/share/wineprefixes/uu-remote/drive_c/Program Files/Netease/GameViewer/bin/GameViewerServer.exe"An unsupported executable result is intentional. Stage and audit the new
release with scripts/stage-uu-release.sh and
scripts/audit-gameviewer.py; follow docs/upstream-maintenance.md. Do not
add only the new hash to an old manifest.
Do not connect a second RDP client to the bridge's desktop-sharing port. The internal SDL FreeRDP process already owns that GNOME session. Port 3389 is GNOME remote login and opens a separate desktop.
An SSH tunnel to ::1:5900 can also be wrong even though it connects. On the
validated host that socket belonged to x11vnc on an unrelated Xvfb display
:42, so the Mac received a black or stale desktop.
Use the maintained launcher and its default Current Desktop action:
~/.local/bin/uu-remote-console relay-portOn the Mac, the launcher forwards local localhost:15922 to that loopback
port over the glassagent-ubuntu SSH alias. The first connection asks for the
bridge password; select Remember password. A healthy connection leaves no
LAN VNC listener:
ss -ltnp | grep 5922The Ubuntu address must be 127.0.0.1:5922. The Mac may expose both
127.0.0.1:15922 and [::1]:15922, but only while the SSH tunnel is active.
If Ubuntu is simultaneously viewing the Mac during a test, the two remote
windows form a recursive image. Close the Ubuntu-to-Mac viewer; this is not a
black-screen fault.
This was the original symptom of Wine rejecting SendInput from UU's service
token. Verify that both lines appear in the bridge log:
UU SendInput bridge active
UU Wine event-log compatibility active
Then verify that uu-input-broker.exe is running. A service restart normally
restores both components.
These controls use different paths. The computer-keyboard panel sends physical
key events through SendInput; the phone's native IME sends batches marked
KEYEVENTF_UNICODE. SDL FreeRDP expects physical scancodes, so an old broker
can turn every letter into one repeated key and numbers into punctuation.
Confirm the broker log reports text=normalized for a phone text commit:
log="$HOME/.local/share/wineprefixes/uu-remote/drive_c/users/$USER/Temp/uu-input-broker.log"
tail -80 "$log"If Unicode calls appear in uu-input-bridge.log with flag 0x00000004 but the
broker does not report normalization, reinstall or update the bridge and
restart the service. A Windows UU host followed by RDP appears to fix the issue
because native Windows converts the Unicode input before RDP handles it.
On the default RDP route, current builds keep routine keys and mouse events on the proven RDP path but route non-representable phone text through the physical desktop clipboard. Verify both halves without reading clipboard content:
uu-remote verify --quick
tail -80 "$log" | rg 'semantic-clipboard|rdp-clipboard-text'The startup line should report keyboard-route=rdp and
semantic-clipboard=relay; a successful Chinese or multiline commit reports
route=rdp-clipboard-text with the full requested count and error=0. Run
./scripts/test-rdp-semantic-text.sh before a live deployment when either
marker is missing. The test uses two disposable X displays and a disposable
Wine prefix, so it does not type into the operator's desktop.
If the checkout contains the fix but the verifier says the installed runtime differs, pulling was not followed by installation:
./install.sh --skip-packages --skip-account-loginUse the mobile-keyboard parity handoff when this path works on one Ubuntu host but not another. It records the known-good 7090 baseline, phone/controller variables, exact acceptance matrix, and bounded diagnostics without exposing typed content or UU identity data.
The direct X11 path follows the target Ubuntu desktop's XKB layout; it does not hardcode JIS inside the bridge. Check the selected desktop explicitly:
DISPLAY=:11 XAUTHORITY="$HOME/.Xauthority" setxkbmap -queryWith layout: jp, Shift+6 produces &, Shift+7 produces ', and the
other symbol positions follow Japanese JIS. A US layout produces different
shift-number symbols. RealVNC can feel more controller-dependent because its
client protocol sends already interpreted key symbols, while UU's physical
path supplies Windows virtual keys/scancodes that the direct helper places on
the target XKB key positions.
UU does not expose a reliable controller-layout identity to this bridge.
Automatically guessing jp versus us from one symbol would make mixed Mac,
Windows, and phone controllers unstable. Keep the intended Ubuntu layout
explicit and change it only as an operator choice; resolution following never
changes keyboard settings.
Run the quick verifier and inspect only descriptor metadata:
scripts/verify.sh --quick
pid="$(pgrep -o -f 'gnome-remote-desktop-daemon --rdp-port')"
find "/proc/$pid/fd" -maxdepth 1 -type l | wc -l
sed -n '/Max open files/p' "/proc/$pid/limits"Repeated Failed to dup keymap fd: Too many open files messages mean GNOME
RDP can no longer allocate the descriptor required by libei input. On the
validated Ubuntu 24.04 stack, libei 1.2.1 duplicated every received keymap FD
without closing the original. Current installations load a bridge-local
backport of upstream commit ee27dd5c92e4e9496a36ca2d4112049fe02d2269 into
GNOME RDP only. scripts/verify.sh confirms the running process mapped that
library, and a timed verifier rejects renewed descriptor growth.
The 65536 soft limit and 4096-descriptor relay rebuild remain as defense in
depth. The launcher raises its own soft limit after any runuser/PAM boundary,
because that boundary can replace a system unit's 65536 limit with 1024. The
quick verifier also recognizes the supported application-profile service and
checks GNOME RDP's listener inside its network namespace. Rerun the installer
if the verifier still reports a 1024 limit, a missing backport, or
installed-source drift. The threshold is configurable with
--grd-fd-restart-threshold; 0 disables only the fallback guard, not the
backport.
Run:
uu-remote networkThe output includes the completed session time. A stale note means it is
historical evidence and does not describe the current idle or newly restarted
bridge. controller/host relay geography: cross-region means the controlling
device's VPN, proxy, or internet exit may have sent the two ends to distant
relay regions. The command reports only the match status, not either location.
This distinction matters. Direct RDP bypasses UU's controller-to-host network
path, while the UU route adds its own P2P or relay transport before the local
Wine-to-RDP bridge. If the report says relay (forced by controller) and its
delay approaches 300 ms, compare that with any key watchdog line. UU may
release a key after its own 300 ms safety interval before a delayed key-up
arrives.
Do not compensate by replaying keys in the host bridge. A late original event would then create duplicate text. Prefer Automatic/P2P in the controlling UU client when it is available, but compare the measured result: NAT or firewall rules can block P2P and make automatic relay fallback slower. The host bridge must retain its proven original-call-then-broker fallback for ordinary input. Do not select that route from service-side relay-window visibility: Wine may hide the window from that token even while the relay is healthy.
On a multi-homed host, also compare Ubuntu's defaults with the address UU chose:
ip -4 route show default
./scripts/verify.sh --quickUU under Wine can bind the first enumerated adapter rather than the interface on Ubuntu's lowest-metric default route. If logs and a controlled comparison confirm that mismatch, enable the opt-in process-local filter:
./install.sh --skip-packages --skip-account-login \
--network-interface defaultThe verifier must report default -> INTERFACE. The setting is resolved at
service start and the existing supervisor compares it with Ubuntu's preferred
interface about every ten seconds. Three consecutive checks must agree on the
same replacement interface before a complete relay restart on the new route;
an absent route or return to the original interface clears the pending change.
This reduces restarts from brief route fluctuations; no second loop or service
is added. It is fail-open
if no usable default exists, and it does not modify host routes or other
applications. To restore UU's original all-adapter view:
./install.sh --skip-packages --skip-account-login \
--network-interface allIf the transport and relay are responsive, deliberate slow typing works, and fast physical-key input still omits events, test bounded physical-key pacing:
./install.sh --skip-packages --skip-account-login \
--physical-key-delay-ms 8
./scripts/verify.sh --quickThe default is 0. The broker waits only after an accepted physical-key
segment; it does not retry or synthesize a key. Confirm the accepted test with
privacy-safe metadata:
broker="$HOME/.local/share/wineprefixes/uu-remote/drive_c/users/$USER/Temp/uu-input-broker.log"
rg 'category=keyboard' "$broker" | tail -n 30Look for focus=ready, paced-physical=1, the configured
physical-delay-ms, a matching result count, and error=0. Restore the
original behavior with --physical-key-delay-ms 0. After changing the value,
reconnect the UU controller and verify that fresh keyboard records appear after
the broker startup line for that value. A subjective test made through RDP or
an unreconnected UU client does not measure the new bridge process.
If 8-12 ms pacing improves but does not solve the symptom, and fresh broker
records still show matching counts with error=0, do not keep increasing the
delay. On a verified Xorg/XRDP target, select the native physical-key route:
./install.sh --skip-packages --skip-account-login \
--keyboard-route x11 --physical-key-delay-ms 0
./scripts/verify.sh --quickThe verifier must report direct X11 physical-key helper is active. A fresh
UU computer-keyboard event must report category=keyboard route=x11, while a
representable normal-phone-keyboard commit reports
category=text route=x11-text; both require a matching result and error=0.
A fresh pointer or click event reports category=mouse route=x11-mouse with
the same success boundary. Video and clipboard remain on the selected local
relay. If explicit X11 preflight cannot verify the target display, the service
remains usable on RDP but verification fails so the fallback is not mistaken
for the requested test. Restore the baseline with:
./install.sh --skip-packages --skip-account-login \
--keyboard-route rdp --physical-key-delay-ms 0First determine whether the newest XRDP attempt stops immediately after
TLS connection established:
ss -H -tnp 'sport = :3389'
journalctl -u xrdp.service -u xrdp-sesman.service \
--since '-15 min' --no-pager
tail -n 80 /var/log/xrdp.logIf no capability, authentication, or session-selection line follows, reset Windows App on the controlling Mac before touching Ubuntu:
osascript -e 'tell application "Windows App" to quit'
open -a "Windows App"A localhost VNC mirror on a different RFB port does not conflict with XRDP's
TCP 3389 listener. Restart xrdp.service only if the listener remains unhealthy
after the client closes. Ubuntu's unit dependencies can restart
xrdp-sesman.service too; the replacement manager may create a new display and
end the prior XRDP/VNC desktop. The complete evidence and safest ordering are
in XRDP Client Stall and UU Keyboard Recovery.
Compare the active XRDP display with the UU relay setting:
DISPLAY=:11 XAUTHORITY="$HOME/.Xauthority" xdotool getdisplaygeometry
sed -n 's/^UURB_RESOLUTION=//p' \
~/.config/uu-remote-bridge/environmentWindows App can dynamically resize the XRDP desktop when its window changes. When XRDP is smaller than UU's private relay, the unused region appears as white space. When XRDP is larger, FreeRDP can clip the right or bottom edge instead of scaling it. The GNOME top bar may still look plausible, so inspect the dimensions rather than judging only from the header.
On an active direct-X11 bridge, the quick verifier performs this comparison too and fails with both dimensions when they differ:
./scripts/verify.sh --quickDo not shrink UU to a very small window-derived size unless that low resolution
is intentional. Restore a useful XRDP size first, then match UU. For example,
if both should be 1920x1080:
./install.sh --skip-packages --skip-account-login \
--resolution 1920x1080This restarts only the supervised UU bridge; it does not restart or reconfigure XRDP. If XRDP itself must be resized, do that as a separate operator-controlled step because changing the XRDP geometry may disconnect its attached viewer. See the recovery note for the FreeRDP 3 compatibility correction and persistence behavior.
If Windows RDP and UU regularly take turns on the same X11/XRDP desktop, the VNC relay can follow a stable source size automatically:
./install.sh --skip-packages --skip-account-login \
--follow-desktop-resolution onThe bridge aligns immediately at startup. While running, it ignores the first
minute, rejects sizes below 1024x720, and requires three matching five-second
checks before atomically saving the new size and restarting only UU. This
debounce prevents a dragged or minimized RDP window from causing a restart
loop. It never resizes or restarts XRDP, GNOME, or the shared applications.
Check for Wine's unimplemented event-log abort:
rg 'EvtOpenPublisherMetadata, aborting' \
~/.local/state/uu-remote-bridge/winlogon.logOld occurrences can remain because logs append. Record the server PID, wait 270 seconds, and compare it, or run:
scripts/verify.shIf the PID still changes, confirm the event-log compatibility hook initialized for the current PID. The launcher re-injects automatically after a UU restart.
Check each hop:
systemctl --user status uu-remote-bridge.service
/usr/bin/grdctl status
rdp_port="$(sed -n 's/^UURB_RDP_PORT=//p' \
~/.config/uu-remote-bridge/environment)"
ss -ltnp | rg ":${rdp_port:-3390}\\b"
tail -80 ~/.local/state/uu-remote-bridge/gnome-remote-desktop.log
tail -80 ~/.local/state/uu-remote-bridge/freerdp.log
tail -80 ~/.local/state/uu-remote-bridge/openbox.logGNOME RDP must mirror the primary desktop, allow input, and own the configured
port. The daemon is a child of uu-remote-bridge.service; an idle
gnome-remote-desktop.service on a different D-Bus is not sufficient. The
relay window must be named Ubuntu-Desktop-Relay:
pgrep -af '/usr/bin/Xvfb :[0-9]+'Automatic display selection starts at :20 and skips occupied X sockets and
lock files. If a fixed display is configured and occupied, the service fails
clearly instead of attaching to or disrupting that display.
The Windows FreeRDP client requires SDL_RENDER_DRIVER=software under Xvfb.
OPENSSL_MODULES points to the copied provider directory, while the pinned
WinPR build uses internal MD4/MD5/RC4 for NTLM if Wine cannot load the legacy
provider.
On XRDP, confirm the journal says which private desktop was selected:
GNOME Desktop Sharing is relaying x11 :10.0.
The launcher reads this from the live gnome-shell process. Do not hard-code
an old /tmp/dbus-* address; it changes after logout or reboot.
Two GNOME sessions are alive and automatic discovery selected the physical/GDM
session (commonly :0) while the useful windows remain in an XRDP session
(commonly :10 or :11). Confirm their identities without restarting either
desktop:
loginctl list-sessions
pgrep -a gnome-shell
journalctl --user -u uu-remote-bridge.service -n 30 --no-pagerPin the session by type rather than by its temporary display number:
./install.sh --skip-packages --skip-account-login \
--desktop-target xrdpThe journal must identify xrdp-sesman and the current XRDP display. When no
XRDP desktop exists, the bridge waits; it does not fall back to the physical
desktop. This operation restarts only the UU bridge. It must not restart
xrdp, xrdp-sesman, GDM, GNOME Shell, or the applications being shared.
Restore historical automatic selection with --desktop-target auto, or
select the physical seat with --desktop-target physical.
Do not assume that every sound heard during a UU session belongs to UU. The
bridge's internal SDL FreeRDP command includes /audio-mode:2, so the nested
desktop relay does not intentionally play the shared desktop back into the
host speakers. Identify the live PipeWire stream first:
wpctl status
wpctl inspect STREAM_OR_CLIENT_ID
pgrep -a -u "$UID" -f 'sdl-freerdp|GameViewer|SHI'During the first 2026-08-09 inspection, UU and FreeRDP owned no playback stream. The only continuous output was an Unreal packaged build:
application.name = SDL Application
application.process.binary = SHI
media.class = Stream/Output/Audio
target.object = ...USB_Audio_2...sink
Its own log confirmed that SDL3 opened the physical USB S/PDIF output with a six-channel 48 kHz stream. Mute only the identified node while preserving the game and desktop:
wpctl set-mute STREAM_NODE_ID 1
wpctl get-volume STREAM_NODE_IDIf the hardware still remains active, disconnect that application's two
links from the physical sink and connect them to the existing XRDP virtual
sink with pw-link. Use the exact names from pw-link -l; never change the
system default sink merely to repair one application. On the affected host,
this changed the physical S/PDIF node from running to idle while SHI, UU,
XRDP, GNOME Shell, and every window remained running.
The durable Unreal-side fix is to launch remote previews with its supported
-nosound option. Keep -enablesound as an explicit listening override. A
single launcher edit is not sufficient when a build pipeline regenerates new
review directories: identify every live SHI stream, and make the generated
launch command carry -NoSound. Do not add a polling daemon or a global
WirePlumber mute rule for this symptom.
That first diagnosis was valid for that stream graph, but it was not the whole
incident. After the UU bridge restarted at 22:58, wpctl status showed two
new streams owned by GameViewerServer.exe through Wine:
Output/Audio 网易UU远程服务 -> physical USB S/PDIF
Input/Audio 网易UU远程服务 <- C922 webcam microphone
The capture stream was active and pipewire-pulse repeatedly logged
[网易UU远程服务] overrun recover. This was the remaining sound path. Mute
both dynamically discovered UU stream nodes, then move only their exact links
from physical devices to the existing XRDP virtual endpoints:
wpctl set-mute UU_OUTPUT_NODE 1
wpctl set-mute UU_INPUT_NODE 1
# Use IDs from `pw-link -I -l`; they are examples, not stable identifiers.
pw-link -d UU_OUTPUT_FL PHYSICAL_PLAYBACK_FL
pw-link -d UU_OUTPUT_FR PHYSICAL_PLAYBACK_FR
pw-link -d PHYSICAL_CAPTURE_FL UU_INPUT_FL
pw-link -d PHYSICAL_CAPTURE_FR UU_INPUT_FR
pw-link UU_OUTPUT_FL XRDP_SINK_FL
pw-link UU_OUTPUT_FR XRDP_SINK_FR
pw-link XRDP_SOURCE_FL UU_INPUT_FL
pw-link XRDP_SOURCE_FR UU_INPUT_FRwpctl set-mute records the per-application input and output mute through
WirePlumber's normal stream-restore mechanism. Do not edit WirePlumber's state
file directly. A live link reroute can be useful for diagnosis, but do not make
PULSE_SINK=xrdp-sink or PULSE_SOURCE=xrdp-source a service environment
override. On the validated multi-session host, many stale XRDP modules exported
the same node names. Wine connected to PipeWire but then hung forever while
enumerating Windows Core Audio. The HTTP room request still returned success,
which made the service look healthy, but signaling never started and
LACHLANSERVER disappeared from every other UU client.
Digital mute is not the same as closing the device. Two subsequently generated
SHI review builds remained linked to the S/PDIF endpoint while their restored
stream mute was on, leaving ALSA pcm2p in RUNNING. Route those exact
streams away from the physical sink. On hardware that keeps an idle USB S/PDIF
clock active, an exact-device WirePlumber rule may set node.pause-on-idle to
true and a short session.suspend-timeout-seconds; do not apply that rule to
all sound devices. The acceptance check is:
cat /proc/asound/card*/pcm*p/sub*/status
fuser -v /dev/snd/*The affected playback PCM must say closed, not merely SUSPENDED, muted, or
idle in a desktop mixer.
Finally, UU's own log showed that every controller connection still invoked
startAudioCapture, even after its stream was muted and the physical PCM was
closed. Disabling Wine PulseAudio only in this dedicated prefix prevents UU
from opening PipeWire or a physical ALSA device:
# ~/.config/systemd/user/uu-remote-bridge.service.d/20-audio-isolation.conf
[Service]
Environment="UURB_UU_AUDIO=off"The bridge maps off to winepulse.drv=d in its own Wine process. It does not
disable normal Ubuntu, browser, XRDP, or other Wine-prefix audio.
Do not stop at device visibility. In the 2026-08-10 incident, off alone let
the host advertise itself and accept a controller participant, but the
controller waited forever. The streamer stopped at
AudioDeviceModuleImpl::InitPlayout; ICE and video capture never started. UU
therefore requires a usable audio abstraction even when the operator wants no
sound.
Give only this Wine prefix a silent ALSA namespace. The repository includes a reviewed template:
install -d -m 0700 ~/.config/uu-remote-bridge
install -m 0600 config/alsa-null.conf \
~/.config/uu-remote-bridge/alsa-null.conf
WINEPREFIX="$HOME/.local/share/wineprefixes/uu-remote" \
/opt/wine-stable/bin/wine reg add \
'HKCU\Software\Wine\Drivers' /v Audio /t REG_SZ /d alsa /fExtend the same service drop-in without adding global ALSA or PipeWire state:
[Service]
Environment="UURB_UU_AUDIO=off"
Environment="ALSA_CONFIG_PATH=/home/USER/.config/uu-remote-bridge/alsa-null.conf"Run systemctl --user daemon-reload, then restart only
uu-remote-bridge.service during a disconnected UU window. The validated cold
start completed both peer-connection factories in milliseconds, connected
signaling, reached room_state_changed: created, advertised the device as
CONNECTED, and left no GameViewer stream in wpctl status or physical PCM
in /proc/asound. The exact acceptance sequence for a new controller includes
peer states 1 through 3, successful media initialization, and video capture;
room creation alone is not sufficient.
UURB_UU_AUDIO=system is the compatibility default. To undo the silent
fallback, remove the drop-in and delete only this prefix's explicit audio
driver value, then restart only the bridge:
WINEPREFIX="$HOME/.local/share/wineprefixes/uu-remote" \
/opt/wine-stable/bin/wine reg delete \
'HKCU\Software\Wine\Drivers' /v Audio /fDo not restart PipeWire, WirePlumber, XRDP, GDM, or GNOME for this repair.
Current versions treat a missing GameViewerServer.exe lasting ten seconds,
or a failed DLL re-injection after a server PID change, as a bridge failure.
Systemd then restarts the complete relay. Confirm the journal contains the
recovery reason rather than an indefinitely idle service:
uu-remote logsIf shutdown previously waited for winedevice.exe, rerun the current
installer. It installs a bounded prefix-scoped cleanup helper. The helper
matches both the current UID and exact UU WINEPREFIX; it does not terminate
Wine programs from other prefixes.
First distinguish signaling from capture. A successful account login, room creation, and controller join prove only that the device is visible to UU. Inspect the private canvas separately:
uu-agent status
uu-agent snapshot ~/.local/state/uu-remote-bridge/private-canvas.pngIf the real target display has content but the private screenshot is uniformly
black or white, test the source through a localhost-only VNC mirror. On the
validated dual-NVIDIA/XRDP host, GNOME Remote Desktop 46.3 accepted the local
FreeRDP client but delivered a blank nested surface; disabling CUDA merely
changed black to white. The same X11 desktop rendered immediately through
x11vnc, and pointer motion crossed the viewer back to the original display.
Enable the scoped fallback without changing XRDP or logging out:
./install.sh --skip-packages --skip-account-login \
--desktop-target xrdp --desktop-relay vncThe fallback owns a dynamically selected loopback port, disables IPv6 and the
VNC bell, keeps the native viewer full-screen on UU's private display, and is
supervised in the same service cgroup. It does not reuse or restart the user's
normal VNC viewer. rdp remains the default for other hosts. Switch back with
--desktop-relay rdp.
For UU media compatibility, keep UURB_UU_AUDIO=system only if completely
disabling Wine PulseAudio makes a particular controller disconnect. Do not
force XRDP sink/source names through the service environment. Disable the VNC
bell independently; it does not participate in UU's WebRTC negotiation.
The UU GUI sends the account login IPC message after the service starts. The launcher performs this automatically and again after a server PID change. Confirm the account has been authenticated once:
uu-remote loginThis temporarily stops the hidden relay, opens the official UU client on the current visible desktop, and restores the bridge when the client closes. Complete sign-in, then close the GUI normally. Forcibly terminating it during its bootstrap handshake can ask the background server to exit; the supervisor will recover, but the device can be briefly offline.
On an unpatched Wine host, UU successfully opens its terminal channel and then
launches Wine's placeholder powershell.exe. That executable returns success
without creating an interactive shell, so exit code 0 is the symptom—not a UU
account or network failure.
Install the current bridge and verify the native broker:
./install.sh --skip-packages --skip-account-login
./scripts/verify.sh --quick
./scripts/test-terminal-bridge.shIn UU, choose the PowerShell shell even though the resulting PTY is the
native Ubuntu login shell. If verification reports a missing or stale terminal
bridge, do not copy an arbitrary executable over
GameViewer/bin/powershell.exe; rerun the installer so its byte-identity guard
can repair a known installation or refuse unknown vendor drift.
If the proxy instead says UU Ubuntu terminal bridge is not configured, UU
has launched it through a reconstructed user environment. Current releases
handle that normal vendor boundary with an atomic mode-0600 sibling runtime
file. Rerun the current installer; verify.sh checks that the file has exactly
three fields, belongs to the current UID, has mode 600, matches the live
broker/server token and port, and points to the owning loopback listener.
Inspect only metadata when diagnosing:
tail -n 30 ~/.local/state/uu-remote-bridge/terminal-bridge.logDo not add an SSH password or expose another listening port as a workaround. The intended listener is ephemeral, token-authenticated, and localhost-only.
If $ starts on a separate row but typed commands follow the active cursor,
the terminal is working. UU can count non-printing login-prompt bytes toward
its row width. Do not change TERM, .bashrc, or .inputrc merely to remove
that cosmetic wrap: real-controller tests showed that prompt sanitization can
make UU draw otherwise correct input at column zero.
If typed text instead appears at the upper-left or beginning of the row,
install the current bridge and open a genuinely new UU terminal session. The
current release deliberately restores TERM=xterm-256color and the configured
login shell's normal startup stream. The isolated test proves PTY transport,
but visual cursor placement must be checked in the real UU controller because
its input echo is client-side.
The UU bridge uses a separate local RDP credential from the login keyring:
/usr/bin/secret-tool lookup service uu-desktop-bridge username "$USER" >/dev/null
/usr/bin/grdctl statusClear only the bridge's keyring item, then rerun the installer to prompt for and store a replacement credential:
secret-tool clear service uu-desktop-bridge username "$USER"
./install.sh --skip-packages --skip-account-loginDo not place the credential in the systemd unit or launcher.
Confirm these files exist together:
libwinpr3.dll
libcrypto-3-x64.dll
libssl-3-x64.dll
libcjson-1.dll
liburiparser-1.dll
winpr-sspi-shim.dll
ossl-modules/legacy.dll
sdl-freerdp.exe
Rebuild them with scripts/build-winpr.sh and scripts/build-compat.sh; do
not mix a different major WinPR DLL into the runtime directory.
./uninstall.shThis restores the audited backups and removes the bridge while preserving the
dedicated UU Wine prefix. --purge removes the prefix and its account state.