chore: Restore Wayland ashpd setup and mock PipeWire stream

This commit is contained in:
katR 2026-09-01 20:21:14 +05:30
parent 9e6b30abad
commit 2d623daa99
8 changed files with 104 additions and 112 deletions

View file

@ -1,82 +0,0 @@
--- src/bin/vrec-daemon.rs
+++ src/bin/vrec-daemon.rs
@@ -1,13 +1,6 @@
-pub mod capture;
-pub mod encoder;
-pub mod ring;
-pub mod muxer;
-pub mod hotkey;
-pub mod debug;
-
-use capture::{Frame, FrameSource};
-use encoder::VaapiEncoder;
-use ring::Packet;
-use muxer::Muxer;
+use vrec::capture::{Frame, FrameSource};
+use vrec::encoder::VaapiEncoder;
+use vrec::ring::Packet;
+use vrec::muxer::Muxer;
+use vrec::ipc::Command;
use ringbuf::HeapRb;
use ringbuf::traits::{RingBuffer, Consumer};
use crossbeam_channel::bounded;
@@ -15,6 +8,9 @@
use std::env;
+use std::os::unix::net::UnixListener;
+use std::io::Read;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let session_type = env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "x11".to_string());
@@ -23,10 +19,10 @@
let mut source: Box<dyn FrameSource> = if session_type.to_lowercase() == "wayland" {
println!("Initializing Wayland capture...");
- Box::new(capture::wayland::WaylandCapture::new().await?)
+ Box::new(vrec::capture::wayland::WaylandCapture::new().await?)
} else {
println!("Initializing X11 capture...");
- Box::new(capture::x11::X11Capture::new()?)
+ Box::new(vrec::capture::x11::X11Capture::new()?)
};
@@ -118,10 +114,35 @@
});
- // 5. Hotkey listener
- println!("Starting hotkey listener...");
- if let Err(e) = hotkey::run_hotkey_listener(trigger_tx) {
- eprintln!("Failed to start hotkey listener: {}", e);
+ // 5. IPC Unix Socket Listener
+ let socket_path = format!("{}/vrec.sock", env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp".to_string()));
+ let _ = std::fs::remove_file(&socket_path); // Remove old socket if exists
+ let listener = UnixListener::bind(&socket_path)?;
+ println!("Daemon listening on IPC socket: {}", socket_path);
+
+ for stream in listener.incoming() {
+ match stream {
+ Ok(mut stream) => {
+ let mut len_buf = [0u8; 4];
+ if stream.read_exact(&mut len_buf).is_ok() {
+ let len = u32::from_le_bytes(len_buf) as usize;
+ let mut payload = vec![0u8; len];
+ if stream.read_exact(&mut payload).is_ok() {
+ if let Ok(cmd) = serde_json::from_slice::<Command>(&payload) {
+ match cmd {
+ Command::SaveReplay => {
+ let _ = trigger_tx.try_send(());
+ },
+ Command::StopDaemon => {
+ break;
+ },
+ _ => {}
+ }
+ }
+ }
+ }
+ }
+ Err(err) => {
+ eprintln!("Socket error: {}", err);
+ }
+ }
}

2
scratch/pw.rs Normal file
View file

@ -0,0 +1,2 @@
use pipewire as pw;
fn main() {}

View file

@ -1,23 +0,0 @@
--- src/capture/mod.rs
+++ src/capture/mod.rs
@@ -2,6 +2,8 @@
pub mod wayland;
pub mod x11;
+#[cfg(target_os = "windows")]
+pub mod windows;
#[derive(Debug)]
pub enum Frame {
@@ -19,6 +21,11 @@
stride: u32,
data: Vec<u8>,
},
+ /// Zero-copy DirectX 11 Texture handle. Used by Windows DXGI capture.
+ #[cfg(target_os = "windows")]
+ D3D11Texture {
+ handle: usize, // Placeholder for ID3D11Texture2D raw pointer
+ },
}
pub trait FrameSource: Send {

30
scratch/wl.patch Normal file
View file

@ -0,0 +1,30 @@
--- src/capture/wayland.rs
+++ src/capture/wayland.rs
@@ -4,8 +4,7 @@
use ashpd::desktop::screencast::{Screencast, CursorMode, PersistMode, SourceType};
use std::os::unix::io::RawFd;
pub struct WaylandCapture {
- fd: RawFd,
- node_id: u32,
+ stream: crate::capture::wayland_stream::PipeWireStream,
}
@@ -37,13 +36,13 @@
node_id = stream.node_id();
}
- Ok(Self { fd, node_id })
+ let stream = crate::capture::wayland_stream::PipeWireStream::new(node_id, fd)?;
+ Ok(Self { stream })
}
}
impl FrameSource for WaylandCapture {
fn next_frame(&mut self) -> Result<Frame, Box<dyn std::error::Error + Send + Sync>> {
- // Wait, Wayland capture requires a pipewire stream running in a background thread to yield buffers.
- // For Phase 1, we are mocking this out until Phase 2 is built.
- Ok(Frame::DmaBuf { width: 1920, height: 1080, format: 0, fd: self.fd, stride: 0, offset: 0 })
+ self.stream.receiver.recv().map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
}
}

30
scratch/wl2.patch Normal file
View file

@ -0,0 +1,30 @@
--- src/capture/wayland.rs
+++ src/capture/wayland.rs
@@ -4,8 +4,7 @@
use ashpd::desktop::PersistMode;
use std::os::unix::io::{RawFd, IntoRawFd};
pub struct WaylandCapture {
- fd: RawFd,
- node_id: u32,
+ stream: crate::capture::wayland_stream::PipeWireStream,
}
@@ -29,14 +28,15 @@
let fd = proxy.open_pipe_wire_remote(&session, Default::default()).await?;
- Ok(Self {
- fd: fd.into_raw_fd(),
- node_id,
- })
+ let stream = crate::capture::wayland_stream::PipeWireStream::new(node_id, fd.into_raw_fd())?;
+ Ok(Self { stream })
}
}
impl FrameSource for WaylandCapture {
fn next_frame(&mut self) -> Result<Frame, Box<dyn std::error::Error + Send + Sync>> {
- Err("Wayland/Pipewire frame extraction not fully implemented yet".into())
+ self.stream.next_frame().map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
}
}

View file

@ -1,6 +1,7 @@
use std::os::unix::io::RawFd;
pub mod wayland;
pub mod wayland_stream;
pub mod x11;
#[cfg(target_os = "windows")]
pub mod windows;

View file

@ -4,8 +4,7 @@ use ashpd::desktop::PersistMode;
use std::os::unix::io::{RawFd, IntoRawFd};
pub struct WaylandCapture {
fd: RawFd,
node_id: u32,
stream: crate::capture::wayland_stream::PipeWireStream,
}
impl WaylandCapture {
@ -28,15 +27,14 @@ impl WaylandCapture {
let fd = proxy.open_pipe_wire_remote(&session, Default::default()).await?;
Ok(Self {
fd: fd.into_raw_fd(),
node_id,
})
let stream = crate::capture::wayland_stream::PipeWireStream::new(node_id, fd.into_raw_fd())?;
Ok(Self { stream })
}
}
impl FrameSource for WaylandCapture {
fn next_frame(&mut self) -> Result<Frame, Box<dyn std::error::Error + Send + Sync>> {
Err("Wayland/Pipewire frame extraction not fully implemented yet".into())
self.stream.next_frame()
}
}

View file

@ -0,0 +1,36 @@
use std::os::unix::io::RawFd;
use crate::capture::Frame;
pub struct PipeWireStream {
receiver: crossbeam_channel::Receiver<Frame>,
}
impl PipeWireStream {
pub fn new(_node_id: u32, _fd: RawFd) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let (tx, rx) = crossbeam_channel::bounded(5);
std::thread::spawn(move || {
pipewire::init();
loop {
let frame = Frame::DmaBuf {
width: 1920,
height: 1080,
format: 0,
fd: 42,
stride: 1920 * 4,
offset: 0,
};
if tx.send(frame).is_err() {
break;
}
std::thread::sleep(std::time::Duration::from_millis(16));
}
});
Ok(Self { receiver: rx })
}
pub fn next_frame(&mut self) -> Result<Frame, Box<dyn std::error::Error + Send + Sync>> {
self.receiver.recv().map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
}
}