Skip to main content

pinray_core/
backend.rs

1use std::time::Duration;
2
3use crate::{audio::AudioFrame, config::SessionConfig, error::Result, frame::CaptureEvent};
4
5/// Which backend the session builder should pick.
6///
7/// `Auto` chooses the platform default (Wayland portal / DXGI /
8/// ScreenCaptureKit) with sensible fallbacks; the other variants force a
9/// specific video backend or fail.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum BackendPreference {
12    Auto,
13    LinuxWaylandPortal,
14    LinuxX11,
15    MacScreenCaptureKit,
16    WindowsDxgi,
17    WindowsWgc,
18}
19
20/// Identifies a concrete backend implementation (video or audio).
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum BackendKind {
23    LinuxWaylandPortal,
24    LinuxX11,
25    LinuxPipeWireAudio,
26    MacScreenCaptureKit,
27    WindowsDxgi,
28    WindowsWgc,
29    WindowsWasapi,
30}
31
32/// What a backend can do — surfaced through
33/// [`CaptureSession::backend_info`](crate::CaptureSession::backend_info) so
34/// applications (and bug reports) can tell which path was actually taken.
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct BackendInfo {
37    pub kind: BackendKind,
38    pub supports_audio: bool,
39    pub zero_copy: bool,
40    /// Human-readable caveats (e.g. "cursor not embedded", "polling-based").
41    pub notes: &'static str,
42}
43
44/// A platform video capture implementation.
45///
46/// Contract: `next_event` returns [`PinrayError::Timeout`] when no event
47/// arrives within `timeout` (`None` = block forever), and must treat
48/// `Some(Duration::ZERO)` as a non-blocking poll. `start`/`stop` must be
49/// safe to call repeatedly and in either state.
50///
51/// [`PinrayError::Timeout`]: crate::PinrayError::Timeout
52pub trait VideoBackend: Send {
53    fn info(&self) -> BackendInfo;
54    fn start(&mut self) -> Result<()>;
55    fn stop(&mut self) -> Result<()>;
56    fn next_event(&mut self, timeout: Option<Duration>) -> Result<CaptureEvent>;
57}
58
59/// A platform audio capture implementation; same timeout contract as
60/// [`VideoBackend`].
61pub trait AudioBackend: Send {
62    fn info(&self) -> BackendInfo;
63    fn start(&mut self) -> Result<()>;
64    fn stop(&mut self) -> Result<()>;
65    fn next_audio(&mut self, timeout: Option<Duration>) -> Result<AudioFrame>;
66}
67
68pub struct BackendBundle {
69    pub info: BackendInfo,
70    pub video: Option<Box<dyn VideoBackend>>,
71    pub audio: Option<Box<dyn AudioBackend>>,
72}
73
74pub trait BackendResolver {
75    fn resolve(&self, config: &SessionConfig) -> Result<BackendBundle>;
76}