client: webcam fixes on v41 constants

This commit is contained in:
Brad Stein 2025-11-30 23:41:29 -03:00
parent 3cdf5c0718
commit b56789d081
5 changed files with 28 additions and 36 deletions

View File

@ -1,13 +1,11 @@
// client/src/input/camera.rs
#![forbid(unsafe_code)]
use anyhow::Result;
use anyhow::Context;
use gstreamer as gst;
use gstreamer_app as gst_app;
use gst::prelude::*;
use lesavka_common::lesavka::VideoPacket;
use v4l::capability::Capabilities;
pub struct CameraCapture {
pipeline: gst::Pipeline,
@ -127,17 +125,18 @@ impl CameraCapture {
}
fn is_capture(dev: &str) -> bool {
match v4l::Device::with_path(dev) {
Ok(d) => d
.query_caps()
.map(|caps| {
let c = caps.capabilities;
c.contains(Capabilities::VIDEO_CAPTURE)
|| c.contains(Capabilities::VIDEO_CAPTURE_MPLANE)
})
.unwrap_or(false),
Err(_) => false,
}
const V4L2_CAP_VIDEO_CAPTURE: u32 = 0x0000_0001;
const V4L2_CAP_VIDEO_CAPTURE_MPLANE: u32 = 0x0000_1000;
v4l::Device::with_path(dev)
.ok()
.and_then(|d| d.query_caps().ok())
.map(|caps| {
let bits = caps.capabilities.bits();
(bits & V4L2_CAP_VIDEO_CAPTURE != 0)
|| (bits & V4L2_CAP_VIDEO_CAPTURE_MPLANE != 0)
})
.unwrap_or(false)
}
/// Cheap stub used when the webcam is disabled

View File

@ -3,7 +3,7 @@
use anyhow::{bail, Context, Result};
use evdev::{Device, EventType, KeyCode, RelativeAxisCode};
use tokio::{sync::broadcast::Sender, time::{interval, Duration}};
use tracing::{debug, info, warn, trace};
use tracing::{debug, info, warn};
use lesavka_common::lesavka::{KeyboardReport, MouseReport};

View File

@ -157,20 +157,16 @@ fn pick_sink_element() -> Result<String> {
}
fn list_pw_sinks() -> Vec<(String, String)> {
let mut out = Vec::new();
if out.is_empty() {
// ── PulseAudio / pactl fallback ────────────────────────────────
if let Ok(info) = std::process::Command::new("pactl")
.args(["info"])
.output()
.map(|o| String::from_utf8_lossy(&o.stdout).to_string())
{
if let Some(line) = info.lines().find(|l| l.starts_with("Default Sink:")) {
let def = line["Default Sink:".len()..].trim();
return vec![(def.to_string(), "UNKNOWN".to_string())];
}
// ── PulseAudio / pactl fallback ────────────────────────────────
if let Ok(info) = std::process::Command::new("pactl")
.args(["info"])
.output()
.map(|o| String::from_utf8_lossy(&o.stdout).to_string())
{
if let Some(line) = info.lines().find(|l| l.starts_with("Default Sink:")) {
let def = line["Default Sink:".len()..].trim();
return vec![(def.to_string(), "UNKNOWN".to_string())];
}
}
out
Vec::new()
}

View File

@ -1,17 +1,14 @@
// client/src/output/video.rs
use std::process::Command;
use std::time::Duration;
use std::thread;
use anyhow::Context;
use gstreamer as gst;
use gst::glib::{Cast, ObjectExt};
use gstreamer_app as gst_app;
use gstreamer_video::{prelude::*, VideoOverlay};
use gst::prelude::*;
use gstreamer_video::VideoOverlay;
use gstreamer_video::prelude::VideoOverlayExtManual;
use lesavka_common::lesavka::VideoPacket;
use tracing::{error, info, warn, debug};
use gstreamer_video as gst_video;
use gstreamer_video::glib::Type;
use crate::output::{display, layout};
@ -63,7 +60,7 @@ impl MonitorWindow {
/* -------- move/resize overlay ---------------------------------- */
if let Some(sink_elem) = pipeline.by_name("sink") {
// give the native window a predictable title for wmctrl/placement
sink_elem.set_property("window-title", &format!("Lesavka-eye-{id}")).ok();
let _ = sink_elem.set_property("window-title", &format!("Lesavka-eye-{id}"));
if let Ok(overlay) = sink_elem.dynamic_cast::<VideoOverlay>() {
if let Some(r) = rects.get(id as usize) {

View File

@ -6,7 +6,7 @@ ORIG_USER=${SUDO_USER:-$(id -un)}
# 1. packages (Arch)
sudo pacman -Syq --needed --noconfirm \
git rustup protobuf gcc evtest base-devel \
git rustup protobuf gcc clang evtest base-devel \
gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav \
pipewire pipewire-pulse \
wmctrl qt6-tools