Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
RELAY_COLOR_FILTER="videoflip method=rotate-180"
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-License-Identifier: CC0-1.0
%YAML 1.1
---
version: 1
algorithms:
- BlackLevel:
- Awb:
- Ccm:
ccms:
- ct: 6500
ccm: [ 1, 0, 0,
0, 0.7, 0,
0, 0, 1]
- Lut:
- Agc:
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v4l2loopback
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Tag media controller video nodes for the samsung-camera-relay group.
ACTION=="remove", GOTO="camera_relay_mc_end"
SUBSYSTEM!="video4linux", GOTO="camera_relay_mc_end"

KERNEL=="video*", ENV{ID_V4L_IO_MC}=="", \
IMPORT{program}="/usr/lib/udev/camera-relay-v4l2-io-mc $devnode"

ENV{ID_V4L_IO_MC}=="1", GROUP="samsung-camera-relay", MODE="0660", TAG-="uaccess", \
ENV{ID_V4L_CAPABILITIES}="", ENV{ID_V4L_PRODUCT}="", \
RUN+="/usr/bin/setfacl -b $devnode"

LABEL="camera_relay_mc_end"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Hide IPU6 raw video nodes. Apps use the v4l2 relay instead.
monitor.v4l2.rules = [
{
matches = [
{ device.name = "~v4l2_device.pci-0000_00_05*" }
]
actions = {
update-props = {
device.disabled = true
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Hide the direct libcamera node. It shows black, apps use the relay instead.
monitor.libcamera.rules = [
{
matches = [
{ device.name = "~libcamera_device.*" }
]
actions = {
update-props = {
device.disabled = true
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[Desktop Entry]
Type=Application
Name=Samsung Camera Relay
Comment=On-demand libcamera to v4l2loopback relay for Samsung Galaxy Book
Exec=/usr/bin/camera-relay start --on-demand
X-GNOME-Autostart-enabled=true
122 changes: 122 additions & 0 deletions srcpkgs/samsung-camera-relay/patches/systemd-to-runit.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
--- a/camera-relay/camera-relay 2026-09-02 01:16:39.637718957 +0700
+++ b/camera-relay/camera-relay 2026-09-02 01:16:44.231689928 +0700
@@ -14,6 +14,8 @@

set -euo pipefail

+[[ -r /etc/default/samsung-camera-relay ]] && . /etc/default/samsung-camera-relay
+
CARD_LABEL="Camera Relay"
PID_FILE="${XDG_RUNTIME_DIR:-/tmp}/camera-relay.pid"
CACHE_DIR="${XDG_RUNTIME_DIR:-/tmp}"
@@ -22,9 +24,9 @@
STATE_CACHE="${CACHE_DIR}/camera-relay-state"
SERVICE_DIR="${HOME}/.config/systemd/user"
SERVICE_NAME="camera-relay.service"
-LOOPBACK_CONF="/etc/modprobe.d/99-camera-relay-loopback.conf"
-MONITOR_BIN="/usr/local/bin/camera-relay-monitor"
-LAUNCHER_BIN="/usr/local/bin/camera-relay-gst"
+LOOPBACK_CONF="/usr/lib/modprobe.d/99-camera-relay-loopback.conf"
+MONITOR_BIN="/usr/bin/camera-relay-monitor"
+LAUNCHER_BIN="/usr/bin/camera-relay-gst"

# Arguments shared by every launcher invocation. The launcher is setgid, so it
# replaces its environment wholesale rather than trusting what it inherited —
@@ -94,8 +96,8 @@
local -a cam_cmd=()
if [[ -x "$LAUNCHER_BIN" ]] && "$LAUNCHER_BIN" --list-cameras &>/dev/null; then
cam_cmd=("$LAUNCHER_BIN" --list-cameras)
- elif [[ -x /usr/local/bin/cam ]] && /usr/local/bin/cam -l &>/dev/null; then
- cam_cmd=(/usr/local/bin/cam -l)
+ elif [[ -x /usr/bin/cam ]] && /usr/bin/cam -l &>/dev/null; then
+ cam_cmd=(/usr/bin/cam -l)
elif command -v cam &>/dev/null; then
cam_cmd=(cam -l)
fi
@@ -223,7 +225,7 @@

if ! detect_loopback_device &>/dev/null; then
die "v4l2loopback loaded but no loopback device found.
-Check /etc/modprobe.d/ for v4l2loopback configuration."
+Check /usr/lib/modprobe.d/ for v4l2loopback configuration."
fi
}

@@ -241,7 +243,7 @@
}

is_persistent() {
- systemctl --user is-enabled "$SERVICE_NAME" &>/dev/null 2>&1
+ return 1
}

# Both relay modes keep the loopback open for as long as they run: the always-on
@@ -729,7 +731,6 @@

nudge_wireplumber() {
local dev="$1"
- command -v systemctl &>/dev/null || return 0
command -v pw-cli &>/dev/null || return 0

local real node advertised
@@ -767,10 +768,8 @@
fi

info "WirePlumber has stale formats for $dev (sees ${advertised:-none}, device offers $want)"
- info "Restarting WirePlumber so PipeWire-based apps (Chrome, Brave) see a usable camera"
- # --no-block: this unit is ordered After=wireplumber.service, so waiting on
- # a wireplumber job from inside our own ExecStartPost can deadlock.
- systemctl --user restart --no-block wireplumber 2>/dev/null || true
+ info "Killing WirePlumber — PipeWire will respawn it with correct formats"
+ pkill -x wireplumber 2>/dev/null || true
}

cmd_nudge_wireplumber() {
@@ -1225,7 +1224,7 @@
# first is not a curiosity — it is the bug.
local want_pin="" unit_pin="" env_pin="${__EGL_VENDOR_LIBRARY_FILENAMES:-}"
want_pin=$(detect_egl_vendor_pin) || want_pin=""
- if systemctl --user cat "$SERVICE_NAME" &>/dev/null; then
+ if false; then
unit_pin=$(systemctl --user cat "$SERVICE_NAME" 2>/dev/null \
| grep -oP '^Environment=__EGL_VENDOR_LIBRARY_FILENAMES=\K.*' | tail -1) || unit_pin=""
fi
@@ -1245,12 +1244,11 @@
# manager, and this service inherits it — so a pin can be present and inert.
# Report all three layers, because only the effective one is the answer.
local unit_mode="" inherited_mode="" mode_file="" mf effective_mode
- if systemctl --user cat "$SERVICE_NAME" &>/dev/null; then
+ if false; then
unit_mode=$(systemctl --user cat "$SERVICE_NAME" 2>/dev/null \
| grep -oP '^Environment=LIBCAMERA_SOFTISP_MODE=\K.*' | tail -1) || unit_mode=""
fi
- inherited_mode=$(systemctl --user show-environment 2>/dev/null \
- | grep -oP '^LIBCAMERA_SOFTISP_MODE=\K.*' | tail -1) || inherited_mode=""
+ inherited_mode="${LIBCAMERA_SOFTISP_MODE:-}"
[[ -z "$inherited_mode" ]] && inherited_mode="${LIBCAMERA_SOFTISP_MODE:-}"
for mf in /etc/environment.d/*.conf "$HOME/.config/environment.d"/*.conf; do
[[ -f "$mf" ]] || continue
@@ -1364,12 +1362,12 @@
else
echo " monitor binary: MISSING ($MONITOR_BIN) — on-demand mode cannot start"
fi
- if systemctl --user cat "$SERVICE_NAME" &>/dev/null; then
+ if false; then
# is-enabled/is-active print their answer AND exit non-zero when the
# answer is negative, so `|| echo ...` would print it a second time.
echo " service: $(systemctl --user is-enabled "$SERVICE_NAME" 2>/dev/null || true)/$(systemctl --user is-active "$SERVICE_NAME" 2>/dev/null || true)"
else
- echo " service: not installed"
+ echo " service: managed by xdg-autostart"
fi

# The decisive check. Everything above can look healthy while the loopback
@@ -1664,7 +1662,7 @@
echo " $lf: empty or missing"
fi
done
- if systemctl --user cat "$SERVICE_NAME" &>/dev/null; then
+ if false; then
echo " systemctl --user status $SERVICE_NAME:"
{ systemctl --user status "$SERVICE_NAME" --no-pager -n 15 2>&1 | sed 's/^/ /'; } || true
fi
60 changes: 60 additions & 0 deletions srcpkgs/samsung-camera-relay/template
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Template file for 'samsung-camera-relay'

pkgname=samsung-camera-relay
version=0.3.68
revision=1
short_desc="On-demand libcamera to v4l2loopback relay for Samsung Galaxy Book"
maintainer="Louis <git@louiszn.fyi>"
license="GPL-2.0-only"
homepage="https://github.com/Andycodeman/samsung-galaxy-book-linux-fixes"
changelog="https://github.com/Andycodeman/samsung-galaxy-book-linux-fixes/releases"
distfiles="https://github.com/Andycodeman/samsung-galaxy-book-linux-fixes/archive/refs/tags/v${version}.tar.gz"
checksum="817f0137f6ce32b72845d592168c63a7ef2f6638aa9d233eb3c9b76006c6adb9"
depends="gstreamer1 gst-plugins-base1 libcamera pipewire v4l2loopback v4l-utils python3"
system_groups="samsung-camera-relay"
archs="x86_64"

do_build() {
mkdir -p build

# camera-relay-gst drops privileges via setgid before touching /dev/video*
cc -O2 -Wall -o build/camera-relay-gst \
"${wrksrc}/camera-relay/camera-relay-gst.c"

# camera-relay-monitor idles with black frames until an app opens the device
cc -O2 -Wall -o build/camera-relay-monitor \
"${wrksrc}/camera-relay/camera-relay-monitor.c"

# v4l2-io-mc is imported by the udev rule to tag MC nodes
cc -O2 -Wall -o build/camera-relay-v4l2-io-mc \
"${wrksrc}/camera-relay/v4l2-io-mc.c"
}

do_install() {
vbin build/camera-relay-gst
vbin build/camera-relay-monitor
vinstall build/camera-relay-v4l2-io-mc 755 usr/lib/udev

vbin "${wrksrc}/camera-relay/camera-relay"
vbin "${wrksrc}/camera-relay/chromium-pipewire-camera.sh" chromium-pipewire-camera
vinstall "${wrksrc}/camera-relay/99-camera-relay-loopback.conf" 644 usr/lib/modprobe.d
vinstall "${FILESDIR}/udev/74-camera-relay-mc-nodes.rules" 644 usr/lib/udev/rules.d

# WirePlumber rules: disable the broken direct libcamera node and raw IPU6 V4L2
# nodes so apps use the v4l2 relay instead (WP 0.5+ conf-d format)
vmkdir etc/wireplumber/wireplumber.conf.d
vinstall "${FILESDIR}/wireplumber/50-disable-ipu6-v4l2.conf" 644 etc/wireplumber/wireplumber.conf.d
vinstall "${FILESDIR}/wireplumber/52-disable-libcamera-node.conf" 644 etc/wireplumber/wireplumber.conf.d

vmkdir etc/default
vinstall "${FILESDIR}/default/samsung-camera-relay" 644 etc/default samsung-camera-relay

vmkdir usr/lib/modules-load.d
vinstall "${FILESDIR}/modules-load/v4l2loopback.conf" 644 usr/lib/modules-load.d

vmkdir etc/xdg/autostart
vinstall "${FILESDIR}/xdg/samsung-camera-relay.desktop" 644 etc/xdg/autostart

vmkdir usr/share/libcamera/ipa/simple
vinstall "${FILESDIR}/libcamera/ipa/simple/ov02c10.yaml" 644 usr/share/libcamera/ipa/simple
}
28 changes: 28 additions & 0 deletions srcpkgs/samsung-ov02c10-clockfix/template
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Template file for 'samsung-ov02c10-clockfix'

pkgname=samsung-ov02c10-clockfix
version=0.3.68
revision=1
short_desc="OV02C10 26MHz clock fix for Samsung Galaxy Book"
maintainer="Louis <git@louiszn.fyi>"
license="GPL-2.0-only"
homepage="https://github.com/Andycodeman/samsung-galaxy-book-linux-fixes"
changelog="https://github.com/Andycodeman/samsung-galaxy-book-linux-fixes/releases"
distfiles="https://github.com/Andycodeman/samsung-galaxy-book-linux-fixes/archive/refs/tags/v${version}.tar.gz"
checksum="817f0137f6ce32b72845d592168c63a7ef2f6638aa9d233eb3c9b76006c6adb9"
depends="dkms xbps-triggers>=0.121_1"
dkms_modules="samsung-ov02c10-clockfix ${version}"
triggers="dkms"
archs="x86_64"

post_extract() {
sed -i \
-e 's/^PACKAGE_NAME=.*/PACKAGE_NAME="samsung-ov02c10-clockfix"/' \
-e 's/^PACKAGE_VERSION=.*/PACKAGE_VERSION="'"${version}"'"/' \
ov02c10-26mhz-fix/dkms.conf
}

do_install() {
vmkdir usr/src/samsung-ov02c10-clockfix-${version}
vcopy ov02c10-26mhz-fix/* usr/src/samsung-ov02c10-clockfix-${version}
}