pinray
Cross-platform screen and audio capture for Rust — raw frames, real metadata, native backends.
Getting Started • Platform Support • Troubleshooting • API Docs • Type reference (any platform)
pinray is a capture infrastructure crate: it talks to each OS's native capture API and hands you raw video and audio frames with their metadata intact - stride, pixel format, timestamps, sequence numbers, drop signals. Encoding is deliberately out of scope; pipe frames into ffmpeg, WebRTC, wgpu, image crates, or your own pipeline.
Why pinray
- Native backends, no wrapper crates - XDG Desktop Portal + PipeWire and X11 on Linux, ScreenCaptureKit (via objc2) on macOS, DXGI Desktop Duplication + Windows Graphics Capture + WASAPI (via the
windowscrate) on Windows. - Audio is first-class - system-mix capture on all four backends, timestamped on the same clock as video, no
cpaldetour and no shelling out topactl. - A frame model that doesn't lie - every frame carries width/height/stride, pixel format, color-space hint, a monotonic timestamp, and a per-stream sequence number. Dropped frames surface as explicit
Gapevents. - Inspectable backend selection -
Autopicks the right backend per platform (with fallbacks like DXGI→WGC), andsession.backend_info()tells you exactly what you got and its caveats. - Honest about platform differences - X11 is documented as polling, DXGI as change-driven, Wayland as portal-mediated. No pretending all platforms behave the same.
Platform support
| Video | System audio | Notes | |
|---|---|---|---|
| Linux Wayland | ✅ portal + PipeWire streaming | ✅ PipeWire | restore tokens skip the dialog |
| Linux X11 | ✅ paced polling (GetImage) | ✅ PipeWire | XFixes cursor blend |
| macOS 12.3+ | ✅ ScreenCaptureKit | ✅ ScreenCaptureKit | display + window capture |
| Windows 10+ | ✅ DXGI + WGC | ✅ WASAPI loopback | DXGI→WGC auto-fallback |
Full matrix with per-backend limitations: docs/platforms.md.
Quick start
cargo add pinray
use Duration;
use ;
Pick specific displays/windows with pinray::enumerate_sources(), capture audio-only without any permission dialogs, force a backend with BackendPreference - see Getting started.
Requirements
| Platform | Build | Runtime |
|---|---|---|
| Linux | libpipewire-0.3-dev + clang |
PipeWire; XDG portal for Wayland video |
| macOS | - | macOS 12.3+, Screen Recording permission |
| Windows | - | Windows 10+ (WGC needs 1903+) |
Examples
cargo run --example wayland_smoke # Linux Wayland: video + audio
cargo run --example x11_smoke # Linux X11: polling video + audio
cargo run --example audio_smoke # Linux/Windows: audio only
cargo run --example macos_smoke # macOS
cargo run --example windows_smoke # Windows (PINRAY_BACKEND=wgc|dxgi to force)
Architecture
Cargo workspace: pinray-core defines the frame model and backend traits, one crate per platform owns its native/unsafe code (platform-linux, platform-macos, platform-windows), and pinray is the public facade. A future encoder crate can slot in without touching capture.
Stability
pinray is 0.2 and moving fast: minor versions may break the API while the frame model and builder settle against real-world use. Pin a minor version if you need stability.
Minimum supported Rust version
Rust 1.88 (let-chains). MSRV bumps are minor-version changes during 0.2.
Contributing
Issues and PRs welcome. Please include session.backend_info() output and RUST_LOG=debug logs in bug reports - backend selection differs per machine. CI runs clippy (warnings deny), tests on Linux/macOS/Windows, cross-target checks, and a real Xvfb capture smoke test.
License
MIT - see LICENSE. Contact: rupamgolui@proton.me