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 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.
|
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
|
```text
|
||||||
crates/
|
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-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-probe/ Validation probe for capture, encoders, segments and status.
|
||||||
clipbin-desktop/ GPUI application and initial session-library view.
|
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.
|
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
|
## 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
|
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.
|
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, 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, 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 |
|
| Windows (Game Capture, NVENC/AMF/QSV) | `scripts/validate/windows.ps1` | Not run yet; script untested |
|
||||||
|
|
||||||
## Probe commands
|
## Probe commands
|
||||||
@@ -119,6 +120,8 @@ Windows status:
|
|||||||
- The assembled runtime keeps the six Game Capture hook binaries byte-identical
|
- The assembled runtime keeps the six Game Capture hook binaries byte-identical
|
||||||
to the release, with their Authenticode signatures present; signature
|
to the release, with their Authenticode signatures present; signature
|
||||||
validity has not been checked on Windows.
|
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
|
- 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
|
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
|
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;
|
- **Plugin configuration.** libobs is started without a module config path;
|
||||||
set one under the app's config directory before plugins that save settings
|
set one under the app's config directory before plugins that save settings
|
||||||
are added.
|
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