docs: record automatic session validation and platform gaps
This commit is contained in:
@@ -8,7 +8,9 @@ An open-source game recorder for Windows and Linux, inspired by Plays.tv. Rust a
|
||||
|
||||
The recording foundation is being validated (see [docs/validation.md](docs/validation.md)). `clipbin-obs` records official OBS capture sources through one hardware encoder into keyframe-aligned segments and reports honest status; `clipbin-probe` exercises it. It passes the Linux headless rig and the hardware sign-off on CachyOS/Hyprland/RX 9070 XT; all Windows validation is still to do.
|
||||
|
||||
The desktop interface follows the web Clipbin's look (zinc dark theme, purple accent, Geist Mono): a session library, a session timeline with bookmarks and a clip selection, clips, and settings. It is not yet connected to the recorder, so it shows empty states; `CLIPBIN_SAMPLE_LIBRARY=1` fills it with example sessions for interface work. Steam detection, the recorder in the app, playback, export, persistence, global hotkeys, autostart, and background recording are not implemented yet.
|
||||
The desktop app detects Steam games, owns the recorder on a background thread, persists settings and sessions, and loads recorded sessions from disk. Linux detects Steam’s `reaper` processes and watches their pidfds; Windows reads Steam’s registry state and watches native process handles (cross-checked, not run). Game exit finalises a session; closing the window keeps the current session recording until the game exits, then exits the app. Ctrl+Q or Quit stops the output cleanly.
|
||||
|
||||
The desktop interface follows the web Clipbin's look (zinc dark theme, purple accent, Geist Mono): a session library, a session timeline with bookmarks and a clip selection, clips, and settings. It shows sessions from disk; `CLIPBIN_SAMPLE_LIBRARY=1` fills it with example sessions for interface work. Playback, export, global hotkeys, storage cleanup, autostart and a tray are not implemented yet. After closing the only window, reopening it without a tray is a follow-up.
|
||||
|
||||
Windows is a first-class target. Every change must keep the Windows code paths building (`cargo clippy --target x86_64-pc-windows-msvc`) and list what still needs validating on Windows.
|
||||
|
||||
@@ -16,7 +18,7 @@ Windows is a first-class target. Every change must keep the Windows code paths b
|
||||
|
||||
```text
|
||||
crates/
|
||||
clipbin-core/ Settings and recorder state; independent of GPUI and native OBS.
|
||||
clipbin-core/ Settings, Steam detection and session storage; independent of GPUI and OBS.
|
||||
clipbin-obs/ Recording engine over the pinned libobs runtime; all unsafe code is in src/ffi.rs.
|
||||
clipbin-probe/ Validation probe for capture, encoders, segments and status.
|
||||
clipbin-desktop/ GPUI application and initial session-library view.
|
||||
@@ -28,7 +30,7 @@ docs/validation.md Validation status and findings.
|
||||
SPEC.md Product requirements and acceptance checks.
|
||||
```
|
||||
|
||||
The core has no external dependencies. Keep capture and session operations out of the UI thread.
|
||||
Keep capture and session operations out of the UI thread. Core uses serde/JSON, dirs, tempfile, rustix on Linux and winreg/windows-sys on Windows. Raw OBS calls live in `clipbin-obs/src/ffi.rs`; raw Windows process calls live in the small `clipbin-core/src/windows_process.rs` bridge.
|
||||
|
||||
## Development
|
||||
|
||||
@@ -85,7 +87,7 @@ cargo test --locked --workspace
|
||||
cargo clippy --locked --target x86_64-pc-windows-msvc -p clipbin-core -p clipbin-obs -p clipbin-probe --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
Recording validation on Linux, headless: `scripts/validate/linux-rig.sh`. Interface screenshots, headless: `scripts/rig/screenshot-ui.sh` (screens: sessions, session, clips, settings, failed, empty). The rig has no input devices; `rig-pointer` drives a virtual pointer (`move`, `click`, `down`/`up`, `scroll`, `sleep` on stdin) and `wtype` types. `CLIPBIN_TRACE_FRAMES=1` logs frame times.
|
||||
Recording validation on Linux, headless: `scripts/validate/linux-rig.sh`. Automatic desktop sessions: `scripts/validate/linux-session.sh` (fake Steam reaper, recording and library screenshots, close-window survival, game exit and explicit Quit). Interface screenshots, headless: `scripts/rig/screenshot-ui.sh` (screens: sessions, session, clips, settings, failed, empty). The rig has no input devices; `rig-pointer` drives a virtual pointer (`move`, `click`, `down`/`up`, `scroll`, `sleep` on stdin) and `wtype` types. `CLIPBIN_TRACE_FRAMES=1` logs frame times.
|
||||
|
||||
Development builds optimise dependencies (`[profile.dev.package."*"]`): unoptimised GPUI made screens noticeably slow, with first frames of 200–300 ms.
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ pass/fail results.
|
||||
| --- | --- | --- |
|
||||
| Linux, headless rig (Wayland portal + Xwayland) | `scripts/validate/linux-rig.sh` | All 9 scenarios pass on devbox (Intel UHD 770, VA-API) |
|
||||
| Linux, real session (CachyOS, Hyprland, RX 9070 XT, 1440p60) | `scripts/validate/linux-hardware.sh` | Passed 2026-10-08 (run 4, dc9cbd6) |
|
||||
| Linux desktop automatic sessions (headless Wayland) | `scripts/validate/linux-session.sh` | Passed 2026-10-08: Recording sidebar, game exit, library reload, window close and active Quit |
|
||||
| Windows (Game Capture, NVENC/AMF/QSV) | `scripts/validate/windows.ps1` | Not run yet; script untested |
|
||||
|
||||
## Probe commands
|
||||
@@ -119,6 +120,8 @@ Windows status:
|
||||
- The assembled runtime keeps the six Game Capture hook binaries byte-identical
|
||||
to the release, with their Authenticode signatures present; signature
|
||||
validity has not been checked on Windows.
|
||||
- The native Steam process bridge (`clipbin-core/src/windows_process.rs`) uses Toolhelp enumeration, limited process queries and a dedicated thread waiting on the process handle. Registry discovery uses `RunningAppID` and `Apps\<id>\Running`; executable paths are matched beneath the app manifest’s installation directory. This code is cross-checked but unvalidated on Windows, including launcher/child-process identity, handle access permissions and exit ordering.
|
||||
- Unvalidated: atomic metadata replacement and recovery on Windows, settings/data directory paths, desktop close-window survival and clean Quit. GPUI desktop integration cannot be cross-checked from Linux.
|
||||
- Unvalidated: encoder ids and settings for NVENC, AMF and QSV; Game Capture
|
||||
hooking and its loss detection (the engine expects the source size to drop
|
||||
to 0); WASAPI audio; `obs-ffmpeg-mux.exe` beside the executable; linking
|
||||
@@ -184,3 +187,69 @@ Windows status:
|
||||
- **Plugin configuration.** libobs is started without a module config path;
|
||||
set one under the app's config directory before plugins that save settings
|
||||
are added.
|
||||
|
||||
## Automatic desktop sessions
|
||||
|
||||
`scripts/validate/linux-session.sh [output-dir]` runs the desktop and a fake
|
||||
Steam reaper (`argv[0]=reaper`, `SteamLaunch`, `AppId=480`) inside the headless
|
||||
Wayland rig. It verifies Recording status, non-empty segment files and metadata,
|
||||
closes the only window while recording continues, kills the game process,
|
||||
checks finalisation, reopens the app to load its library from disk, captures
|
||||
screenshots and uses Ctrl+Q during a second recording for clean shutdown.
|
||||
The recording and library screenshots were inspected; storage totals came from
|
||||
real Matroska file sizes. The existing Linux rig also passed all nine scenarios
|
||||
after integration (2026-10-08). Its unwritable-output assertion accepts both
|
||||
OBS Error and EncodeError: the muxer can report either for a permission error.
|
||||
|
||||
Session metadata is `session.json` inside each data-directory session folder;
|
||||
recovery attempts use separate `run-NNN` folders. Each segment stores its exact
|
||||
start using `(total_frames_at_file_changed - 1) / fps`. The keyframe triggering
|
||||
the split is already included in OBS’s count but belongs to the new segment:
|
||||
the rig observed 121, 241, 361 at the boundaries of 120-frame segments. The
|
||||
initial file starts at zero. Raw callback counts are preserved in events; the
|
||||
e2e script checks placements exactly against cumulative earlier ffprobe video
|
||||
packet counts within each run. Dropped output frames could make this count
|
||||
drift: each segment records the run’s cumulative dropped-frame count at its
|
||||
completion, and a nonzero count logs an explicit warning. Placement with
|
||||
actual dropped frames still needs validation.
|
||||
|
||||
Stopping exactly as a split fires can leave a header-only final Matroska file
|
||||
(the rig observed 747 bytes, no Cluster and no video packets), despite a counted
|
||||
split keyframe and zero reported drops. Finalisation checks the small header
|
||||
prefix for the Cluster ID and deletes an empty tail after output stop. If deletion
|
||||
fails (including a still-open file on Windows), it is marked unavailable in
|
||||
metadata. Footage ends at the last real segment’s end and the remainder is
|
||||
Missing. The offset check verifies every retained segment and explicitly
|
||||
checks any unavailable marker, without treating an empty file as playable. Wall-clock time places each run inside the session and
|
||||
marks capture waiting/recovery as Missing spans. Containers are never summed
|
||||
to derive segment offsets. Metadata is replaced atomically from a synced
|
||||
same-directory temporary file; startup finalises previously active metadata.
|
||||
|
||||
Run `CLIPBIN_VALIDATE_RECOVERY=1 scripts/validate/linux-session.sh` to also
|
||||
kill the portal capture stream and check that bounded automatic recovery
|
||||
resumes into the same session, with a Missing span and a second run directory.
|
||||
This passed in the headless Wayland rig. A deliberately missing runtime path
|
||||
also opened the interface with a persistent failure banner and honoured Quit.
|
||||
|
||||
Settings are saved under the config directory, including the portal restore
|
||||
token. Capture selection clears that token and restarts the current session’s
|
||||
capture; automatic recovery retries at five-second intervals, at most three
|
||||
consecutive attempts. A failure stays visible until footage is proven again.
|
||||
|
||||
One game is recorded at a time. Startup discovery also records a game already
|
||||
running; simultaneous games are selected by PID order and the next still-live
|
||||
game is detected after the current session ends. Linux Steam names come from
|
||||
library manifests, with `App <id>` as the fallback. Windows requires a manifest
|
||||
installation path to identify candidate processes and fails honestly if none
|
||||
can be found. Real Steam/Proton lifecycle validation, X11 desktop session
|
||||
integration and Windows runtime validation remain follow-ups. Audio-source
|
||||
failure detection remains limited as described above.
|
||||
|
||||
GPUI 0.2.2 ends its Linux event loop when the last window is removed, even
|
||||
without an application close callback. Main keeps the recorder worker alive
|
||||
after that return. Closing the window continues the current game session;
|
||||
when that game exits, it finalises and the process exits. If no session is
|
||||
active, it exits immediately. It stops discovering new games once closed,
|
||||
so there is no indefinitely running invisible app. Reopening the window and
|
||||
persistent background discovery need the future tray integration. Explicit
|
||||
Quit/Ctrl+Q stops and finalises the current recording immediately.
|
||||
|
||||
Reference in New Issue
Block a user