Compare commits

...

37 Commits

Author SHA1 Message Date
4f629facca usb fix 2025-07-06 09:51:02 -05:00
7844ec9870 usb fix 2025-07-06 03:25:45 -05:00
17b70bec5e usb fix 2025-07-05 21:33:12 -05:00
0615992d9b usb fix 2025-07-05 20:12:58 -05:00
29933a685e usb fix 2025-07-05 17:08:48 -05:00
7222020631 usb fix 2025-07-05 15:21:12 -05:00
f04fc1c02a usb fix 2025-07-05 14:02:03 -05:00
a1d6728c59 usb fix 2025-07-05 13:43:56 -05:00
29c51fe694 install features - usb fix 2025-07-05 13:19:59 -05:00
28f564c8d6 install features - usb fix 2025-07-05 12:54:49 -05:00
3aca228498 install features - usb fix 2025-07-05 12:45:08 -05:00
927a776d13 install features 2025-07-04 18:30:28 -05:00
6b1a7d1963 install features 2025-07-04 18:24:48 -05:00
394b842e49 camera core add 2025-07-04 18:00:49 -05:00
cd56d6f1be fixing daemon for cam 2025-07-04 17:37:55 -05:00
21d4057a6d fixing daemon for cam 2025-07-04 17:28:38 -05:00
70be697f8c fixing daemon for cam 2025-07-04 17:13:36 -05:00
5bd4b6155d fixing daemon for cam 2025-07-04 15:28:58 -05:00
5b272448a6 fixing daemon for cam 2025-07-04 15:19:58 -05:00
b6aae91a52 fixing daemon for cam 2025-07-04 15:11:39 -05:00
a2d07ef1e5 fixing daemon for cam 2025-07-04 15:01:06 -05:00
fc92d0321b fixing daemon for cam 2025-07-04 14:50:35 -05:00
e7bff41c0c fixing daemon for cam 2025-07-04 14:39:13 -05:00
120424925b fixing daemon for cam 2025-07-04 14:27:31 -05:00
2088cdddec fixing daemon for cam 2025-07-04 14:10:21 -05:00
ca3c8168e4 fixing daemon for cam 2025-07-04 14:06:16 -05:00
4b1eca6c0d fixing daemon for cam 2025-07-04 14:01:06 -05:00
d167ed8511 fixing daemon for cam 2025-07-04 13:26:32 -05:00
6934bf8645 fixing daemon for cam 2025-07-04 13:09:07 -05:00
07dbe15d9f fixing daemon for cam 2025-07-04 12:33:15 -05:00
8b2336e753 fixing daemon for cam 2025-07-04 12:16:15 -05:00
590344df41 fixing daemon for cam 2025-07-04 12:03:41 -05:00
46c5190fb0 fixing daemon for cam 2025-07-04 11:41:27 -05:00
23c25297bc fixing daemon for cam 2025-07-04 11:19:35 -05:00
41a64664e0 fixing daemon for cam 2025-07-04 11:06:08 -05:00
86b6e79e33 fixed daemon? 2025-07-04 10:40:20 -05:00
34030aa8b6 Merge pull request 'feature/webcam' (#1) from feature/webcam into master
Reviewed-on: brad_stein/lesavka#1
2025-07-04 15:26:02 +00:00
4 changed files with 137 additions and 17 deletions

View File

@ -26,17 +26,24 @@ impl CameraCapture {
// (NVIDIA → VA-API → software x264).
let (enc, kf_prop, kf_val) = Self::choose_encoder();
tracing::info!("📸 using encoder element: {enc}");
let have_nvvidconv = gst::ElementFactory::find("nvvidconv").is_some();
let (src_caps, preenc) = match enc {
"nvh264enc" => (
"video/x-raw(memory:NVMM),format=NV12,width=1280,height=720",
"nvvidconv !"
),
"vaapih264enc" => (
"video/x-raw,format=NV12,width=1280,height=720",
"videoconvert !"
),
_ => ("video/x-raw,width=1280,height=720", "videoconvert !"),
};
// ───────────────────────────────────────────────────────────────────
// Jetson (has nvvidconv) Desktop (falls back to videoconvert)
// ───────────────────────────────────────────────────────────────────
"nvh264enc" if have_nvvidconv =>
("video/x-raw(memory:NVMM),format=NV12,width=1280,height=720",
"nvvidconv !"),
"nvh264enc" /* else */ =>
("video/x-raw,format=NV12,width=1280,height=720",
"videoconvert !"),
"vaapih264enc" =>
("video/x-raw,format=NV12,width=1280,height=720",
"videoconvert !"),
_ =>
("video/x-raw,width=1280,height=720",
"videoconvert !"),
};
// let desc = format!(
// "v4l2src device={dev} do-timestamp=true ! {raw_caps},width=1280,height=720 ! \

View File

@ -6,6 +6,11 @@
set -euo pipefail
log() { printf '[lesavka-core] %s\n' "$*"; }
cleanup() { echo "" >"$G/UDC" 2>/dev/null || true; }
exec 2> >(tee -a /tmp/lesavka-core.debug.$(date +%s).log)
set -x
echo "[lesavka-core] running: $0 (sha1sum=$(sha1sum "$0" | cut -d' ' -f1))"
#──────────────────────────────────────────────────
# 1. Ensure overlay + kernel modules
@ -114,10 +119,86 @@ echo 32 >"$U/req_number" 2>/dev/null || true
# ----------------------- UVC function (usbvideo) ------------------
mkdir -p "$G/functions/uvc.usb0"
mkdir -p "$G/functions/uvc.usb0/control/strings/0x409"
echo "Lesavka UVC" >"$G/functions/uvc.usb0/control/strings/0x409/label"
# Simple 720p MJPEG + 720p H.264 altsetting
printf '\x50\x00\x00\x00' >"$G/functions/uvc.usb0/control/header/h_video"
F="$G/functions/uvc.usb0"
# ── 1. FORMAT DESCRIPTOR (uncompressed YUY2, 16bpp) ──────────────
mkdir -p "$F/streaming/uncompressed/u"
# GUID = {59555932-0000-0010-8000-00aa00389b71} (“YUY2”) littleendian
printf '\x59\x55\x59\x32\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71' \
>"$F/streaming/uncompressed/u/guidFormat"
echo 16 >"$F/streaming/uncompressed/u/bBitsPerPixel"
# ── 2. FRAME DESCRIPTOR (index1 @30fps) ────────────────────────
mkdir -p "$F/streaming/uncompressed/u/f1"
echo 1280 >"$F/streaming/uncompressed/u/f1/wWidth"
echo 720 >"$F/streaming/uncompressed/u/f1/wHeight"
echo 1843200 >"$F/streaming/uncompressed/u/f1/dwMaxVideoFrameBufferSize"
echo 333333 >"$F/streaming/uncompressed/u/f1/dwDefaultFrameInterval" # 30fps
echo 333333 >"$F/streaming/uncompressed/u/f1/dwFrameInterval"
# ── 3. REQUIRED HEADER LINKS (absolutepaths, no “1”) ──────────────
header_h="$F/streaming/header/h" # convenience variables
fmt_dir="$F/streaming/uncompressed/u"
mkdir -p "$header_h"
# wait until the kernel has rebuilt the directory and added its attribute
# files (bmInfo is always created by the driver)
for _ in {1..50}; do
[ -e "$header_h/bmInfo" ] && break
sleep 0.010 # max 0.5s total
done
# ABSOLUTE symlink → no relative elements, name is “fmt” (not “1”)
ln -sf "$fmt_dir" "$header_h/fmt"
# echo 1 >"$header_h/bNumFormats"
# echo 0 >"$header_h/bmInfo"
# perspeed class directories (absolute links)
for s in fs hs ss; do
mkdir -p "$F/streaming/class/$s"
ln -sf "$header_h" "$F/streaming/class/$s/h"
done
# ── 4. VideoControl interface ─────────────────────────────────────
mkdir -p "$F/control/header/h" # real dir mandatory
mkdir -p "$F/control/class" # parent once
echo "[lesavka-core] ★ directory tree just before links:"
tree -L 3 "$F/control" | sed 's/^/[lesavka-core] /'
for s in fs hs ss; do
# ensure the perspeed dir exists (created by kernel)
mkdir -p "$F/control/class/$s" # harmless if already there
# create the mandatory *symlink inside* that directory:
ln -snf ../../header/h "$F/control/class/$s/h"
done
for s in fs hs ss; do
[ -L "$F/control/class/$s/h" ] || {
echo "[lesavkacore] ❌ $s/h link missing, aborting" >&2
exit 1
}
done
echo "[lesavka-core] ★ directory tree just before bind:"
tree -L 3 "$F/control" | sed 's/^/[lesavka-core] /'
for s in fs hs ss; do
[ -L "$F/control/class/$s" ] || {
echo "[lesavka-core] ❌ $s link missing, gadget aborting" >&2
exit 1
}
done
# optional: hide unsupported controls
echo 0 >"$F/control/terminal/camera/default/bmControls" 2>/dev/null || true
echo 0 >"$F/control/processing/default/bmControls" 2>/dev/null || true
# friendly label
mkdir -p "$F/control/header/strings/0x409"
echo "Lesavka UVC" >"$F/control/header/strings/0x409/label"
# ----------------------- configuration -----------------------------
mkdir -p "$G/configs/c.1/strings/0x409"

View File

@ -3,6 +3,18 @@
set -euo pipefail
ORIG_USER=${SUDO_USER:-$(id -un)}
REF=${LESAVKA_REF:-master} # fallback
while [[ $# -gt 0 ]]; do
case $1 in
-r|--ref) REF="$2"; shift 2 ;;
-h|--help)
echo "Usage: $0 [--ref <branch|commit>]"; exit 0 ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done
echo "==> Using git ref: $REF"
echo "==> 1a. Base packages"
sudo pacman -Syq --needed --noconfirm git \
rustup \
@ -83,11 +95,17 @@ if [[ ! -d $SRC_DIR ]]; then
sudo chown "$ORIG_USER":"$ORIG_USER" /var/src
fi
if [[ -d $SRC_DIR/.git ]]; then
sudo -u "$ORIG_USER" git -C "$SRC_DIR" pull --ff-only
sudo -u "$ORIG_USER" git -C "$SRC_DIR" fetch --all --tags --prune
else
sudo -u "$ORIG_USER" git clone "$REPO_URL" "$SRC_DIR"
fi
if sudo -u "$ORIG_USER" git -C "$SRC_DIR" rev-parse --verify --quiet "origin/$REF" >/dev/null; then
sudo -u "$ORIG_USER" git -C "$SRC_DIR" checkout -B "$REF" "origin/$REF"
else
sudo -u "$ORIG_USER" git -C "$SRC_DIR" checkout --force "$REF"
fi
echo "==> 4b. Source build"
sudo -u "$ORIG_USER" bash -c "cd '$SRC_DIR/server' && cargo clean && cargo build --release"
@ -122,7 +140,7 @@ After=network.target lesavka-core.service
[Service]
ExecStart=/usr/local/bin/lesavka-server
Restart=always
Environment=RUST_LOG=lesavka_server=info,lesavka_server::audio=trace,lesavka_server::video=trace,lesavka_server::gadget=info
Environment=RUST_LOG=lesavka_server=info,lesavka_server::audio=info,lesavka_server::video=debug,lesavka_server::gadget=info
Environment=RUST_BACKTRACE=1
Environment=GST_DEBUG="*:2,alsasink:6,alsasrc:6"
Restart=always

View File

@ -124,6 +124,14 @@ impl Handler {
did_cycle: AtomicBool::new(false),
})
}
async fn reopen_hid(&self) -> anyhow::Result<()> {
let kb_new = open_with_retry("/dev/hidg0").await?;
let ms_new = open_with_retry("/dev/hidg1").await?;
*self.kb.lock().await = kb_new;
*self.ms.lock().await = ms_new;
Ok(())
}
}
/*──────────────── gRPC service ─────────────*/
@ -280,7 +288,13 @@ impl Relay for Handler {
) -> Result<Response<ResetUsbReply>, Status> {
info!("🔴 explicit ResetUsb() called");
match self.gadget.cycle() {
Ok(_) => Ok(Response::new(ResetUsbReply { ok: true })),
Ok(_) => {
if let Err(e) = self.reopen_hid().await {
error!("💥 reopen HID failed: {e:#}");
return Err(Status::internal(e.to_string()));
}
Ok(Response::new(ResetUsbReply { ok: true }))
}
Err(e) => {
error!("💥 cycle failed: {e:#}");
Err(Status::internal(e.to_string()))