Conversation
Adds a platform layer (paths, subprocess flags, opening files, clipboard) and Windows implementations beside the Linux ones: - Capture: ffmpeg ddagrab into a rolling MPEG-TS segment ring, with a probed encoder chain (NVENC/QSV/AMF zero-copy, then any hardware encoder via hwdownload, then x264) and per-run segment directories. - Audio: WASAPI loopback and microphones captured in Python (soundcard) and served to ffmpeg over loopback TCP, padded to the wall clock and anchored to the same epoch as the video timestamps, so clips stay in sync (measured ~0 ms offset, no drift). - Hotkeys: low-level keyboard hook reporting evdev key names, sharing the combo/double-tap dispatcher with the evdev listener. - Daemon IPC over token-authenticated loopback TCP, msvcrt file locks, a shutdown handler instead of self-SIGTERM, psutil tree kills. - Window detection, pointer-follow display, DXGI output enumeration, Discord RPC over named pipes, winsound notifications, Win32 clipboard. Linux code paths are unchanged; Windows branches sit in front of them.
The daemon reports its platform in status. On Windows, Settings offers the ffmpeg and OBS backends, NVENC/QSV/AMF encoders, OBS connection fields and an 'Extra ffmpeg arguments' label, and hides the wf-recorder microphone mode. About, the hotkey banners, the codec-fallback notice and the blocklist help get Windows wording instead of udev, systemd and X11 instructions. Linux keeps every existing string and option. Also fixes tools/check-locales.mjs on Windows (URL.pathname -> fileURLToPath).
verify-custom-accent spawned npx, which Windows only has as a .cmd shim that execFileSync will not start; run vite's entry with this node instead. It also parsed accents.ts assuming LF, which an autocrlf checkout breaks. The accent-parity vite config used URL.pathname, which is /C:/... on Windows; use fileURLToPath.
recording.backend = "obs" drives OBS Studio's replay buffer over obs-websocket v5 (Hello/Identify with SHA-256 auth, SaveReplayBuffer and the ReplayBufferSaved event, StartRecord/StopRecord for sessions). The saved file is moved into the library under Vice's name and goes through the usual trim, volume and watermark steps. A buffer the user started themselves is left running on exit. tests/test_windows_port.py covers key mapping, the wall-clock audio padding and epoch anchoring, encoder plan ordering, capture command building, segment selection, filter-path escaping, the TCP IPC transport, Win32 helpers, and the OBS protocol against a fake obs-websocket server. Screen capture and injected-key tests run with VICE_LIVE_TESTS=1. Also lock a byte far past the content on Windows: byte-range locks there are mandatory, so locking byte 0 made the pid in the lock file unreadable.
install.ps1 installs Python, ffmpeg (with ddagrab) and optionally cloudflared through winget, puts Vice in a private venv under %LOCALAPPDATA%\Vice, adds a Start Menu shortcut and a vice command, and can register recording at login; -Uninstall reverses all of it and never touches clips. It is ASCII-only and routes native programs through a helper, because Windows PowerShell 5.1 aborts on native stderr and eats a loose -- argument. evdev becomes Linux-only and soundcard Windows-only in the dependencies. The README gains Windows install, compatibility and troubleshooting sections. CI adds a windows-latest job that runs the modules covering shared and Windows code; the Linux-mechanics modules stay Linux-only. Settings also hides replay storage, colour depth and hardware decode on Windows, where they do nothing, and doctor prints Windows locations.
A module named platform inside the package shadows the standard library's the moment anything runs a file in vice/ directly, and uuid, among others, imports platform. Also let the Windows port tests load on Linux, where ctypes has no WINFUNCTYPE.
…eding admin soundcard initialises COM only on the thread that first imports it. When the Settings audio-source list imported it on a worker thread first, the capture thread had no COM and every source failed with CO_E_NOTINITIALIZED, leaving the recorder down. Each soundcard thread now initialises COM itself, after the import, since soundcard treats S_FALSE at import as fatal. winget's cloudflared package is a machine-wide MSI that prompts for administrator rights. install.ps1 now downloads Cloudflare's standalone exe into Vice's own bin folder instead, and the share server also looks there, for a daemon started before the PATH change reached it.
Windows does not refuse a loopback connection to a closed port at once; it retries for about two seconds. daemon_is_running() probed a crashed daemon's port with a 0.2 s timeout, which timed out rather than being refused, read as "a daemon may be busy", and so every start after a crash or a kill failed with "Vice is already starting, running, or shutting down" until the temp files were deleted by hand. The endpoint file already names the daemon's pid, so a dead (or reused, non-Python) owner now marks the endpoint stale without any probing, and open_ipc_connection fails fast in the same case. Found by a soak test that kills the daemon outright; the restart now also reaps the orphaned ffmpeg.
- install.ps1: a user PATH with a single entry came back from the pipeline as a string, and the Vice folder was glued onto it with no separator, breaking PATH on a fresh Windows install. Uninstall now also stops anything running from the venv and retries removal instead of aborting. - Audio: a capture thread that dies (device unplugged) now closes its ffmpeg inputs, so the watchdog sees an unhealthy recorder and restarts it instead of ffmpeg waiting forever on a silent input. - Encoders: hevc_qsv/av1_qsv/hevc_amf/av1_amf kept H.264 as the codec family, so the H.264 plan won and the chosen codec was silently ignored. A chosen libx264 no longer raises the CPU-fallback banner. Failed probes are no longer cached (a locked screen made them permanent), nor is a missing ffmpeg. Start-up work that blocks runs off the event loop. - Daemon: the Windows shutdown handler is registered before anything starts, so a stop during start-up is honoured instead of dropped. - Hotkeys: modifiers are read from GetAsyncKeyState at each press, and a keydown long after the last event is a new press, so key-ups lost to the lock screen or a UAC prompt no longer leave Win/Alt stuck or F9 dead. - gpu_vendors() counts every adapter, not only those driving a monitor, so NVENC is found on laptops using only their built-in panel. - Raising the existing window only matches Vice's own window, and follow-the-pointer uses MonitorFromPoint instead of a DXGI walk each tick. - vice uninstall on Windows reads the clips folder before removing the config, deletes only clip files, and never deletes clips under --yes. - tests: stub AutoPlaylistToggleTests' background thumbnailing, which hung the whole suite at teardown on Python 3.12 when ffmpeg is installed (the hang predates the port; main hangs the same way).
Reading them on the event loop (the previous fix for modifiers stuck by key-ups lost to the lock screen) raced a quick Ctrl+F9: by the time the loop ran, Ctrl was already up and the combo read as plain F9. The hook now samples GetAsyncKeyState when the key goes down and hands the set along with the event. Caught by the live injected-key test.
When asyncio.run's teardown cancels a task mid-probe, Python 3.12 can close the subprocess transport before the process exit is reported, and the unbounded await in the cleanup never returned. That hung the Linux test suite on 3.12 whenever ffmpeg was installed (on main too), and could hang the daemon's own exit with a thumbnail or probe in flight.
This reverts commit d2a039a.
Same Python 3.12 teardown hang as AutoPlaylistToggleTests: cancelling a task while asyncio is still spawning ffprobe never returns on 3.12, so the whole suite stalled whenever ffmpeg was installed. The hang is inside CPython's create_subprocess_exec, so it is avoided in the tests rather than worked around in Vice.
…tunnel Share links were built from the public address the daemon had when the library loaded. The app usually loads before cloudflared prints its URL, so every listed clip carried the LAN fallback and only worked on the local network. The store now moves those links onto the tunnel URL when it arrives, and on load when the status already reports one.
pywebview's WinForms backend falls back to the interpreter's icon, and without an AppUserModelID Windows groups the window under pythonw.exe.
8485531 to
60b1ce7
Compare
# Conflicts: # vice/share.py # vice/ui/scripts/app.js
|
Thank you for this, and I mean that. It's a serious piece of work: a ddagrab backend with a segment ring, encoder probing, WASAPI audio, a keyboard hook, and an OBS fallback for exclusive fullscreen. That's the whole shape of a port, not a sketch of one. I'm not going to take it on right now, though, and I'd rather be straight about why than leave it sitting unanswered. Vice is still settling on Linux, and I'm fixing bugs there most weeks. Merging a port means every change from then on has to work on Windows too, and I can't test on Windows, so I'd be shipping a platform I can't stand behind. That wouldn't be fair to the people who'd install it. I may well come back to Windows once Vice is more mature and the Linux side is quieter. I'll leave this open rather than close it, because it's the best starting point there could be for that, and if I do pick it up it'll be through your PR with your name on it. |
Full Windows Port
Adds Windows 10/11 support to Vice. The Linux code paths are unchanged. Windows code lives in new modules or in
if IS_WINDOWSbranches placed in front of the existing Linux code.Recording
recorder_win.pybackend using ffmpeg'sddagrab(Desktop Duplication). The replay buffer is a rolling ring of 2-second segments, and saving a clip joins the newest ones.win_audio.pyrecords desktop audio through WASAPI loopback and the microphone through ffmpeg. Audio and video share a start time, so clips stay in sync.recorder_obs.pydrives OBS's replay buffer over obs-websocket v5. It's for exclusive-fullscreen games thatddagrabcan't see. Clips from OBS go through the normal Vice library pipeline.Desktop integration
hotkey_win.pyuses a low-level keyboard hook that passes keys through. Keys map to the existing evdev names, so configs and the hotkey UI are unchanged. The combo and double-tap logic moved into a sharedhotkey_dispatch.py,.exeentries ingames.jsonmatch.vice autostartturns it on or off.Daemon
oscompat.pyholds the platform paths (%APPDAP%) and the process helpers. On Linux it returns the same paths asbefore.Install and UI
install.ps1installs Python and ffmpeg through winget, downloads cloudflared, sets up a venv under%LOCALAPPDATA%\Vice, and adds a Start Menu shortcut. It doesn't need admin rights and supports-Uninstall.windows-latestjob runs the platform-neutral test modules.Also fixed
test_share_serverhung on Python 3.12 when ffmpeg was installed. The tests now stub the background ffmpeg work that triggered it.