feat: Custom gst webrtc signaller, runtime GPU driver package install and more (#140)

🔥 🔥

Yes lots of commits because rebasing and all.. thankfully I know Git
just enough to have backups 😅

---------

Co-authored-by: Wanjohi <elviswanjohi47@gmail.com>
Co-authored-by: Kristian Ollikainen <DatCaptainHorse@users.noreply.github.com>
Co-authored-by: Wanjohi <71614375+wanjohiryan@users.noreply.github.com>
Co-authored-by: AquaWolf <3daquawolf@gmail.com>
This commit is contained in:
Kristian Ollikainen
2024-12-08 15:37:36 +02:00
committed by GitHub
parent 20d5ff511e
commit b6196b1c69
27 changed files with 3402 additions and 1349 deletions

View File

@@ -0,0 +1,65 @@
#!/bin/bash
set -euo pipefail
# Wait for dbus socket to be ready
echo "Waiting for DBus system bus socket..."
DBUS_SOCKET="/run/dbus/system_bus_socket"
for _ in {1..10}; do # Wait up to 10 seconds
if [ -e "$DBUS_SOCKET" ]; then
echo "DBus system bus socket is ready."
break
fi
sleep 1
done
if [ ! -e "$DBUS_SOCKET" ]; then
echo "Error: DBus system bus socket did not appear. Exiting."
exit 1
fi
# Wait for PipeWire to be ready
echo "Waiting for PipeWire socket..."
PIPEWIRE_SOCKET="/run/user/${UID}/pipewire-0"
for _ in {1..10}; do # Wait up to 10 seconds
if [ -e "$PIPEWIRE_SOCKET" ]; then
echo "PipeWire socket is ready."
break
fi
sleep 1
done
if [ ! -e "$PIPEWIRE_SOCKET" ]; then
echo "Error: PipeWire socket did not appear. Exiting."
exit 1
fi
# Update system packages before proceeding
echo "Upgrading system packages..."
pacman -Syu --noconfirm
echo "Detecting GPU vendor and installing necessary GStreamer plugins..."
source /etc/nestri/gpu_helpers.sh
get_gpu_info
# Identify vendor
if [[ "${vendor_full_map[0],,}" =~ "intel" ]]; then
echo "Intel GPU detected, installing required packages..."
chwd -a
pacman -Syu --noconfirm gstreamer-vaapi gst-plugin-va gst-plugin-qsv
# chwd missed a thing
pacman -Syu --noconfirm vpl-gpu-rt
elif [[ "${vendor_full_map[0],,}" =~ "amd" ]]; then
echo "AMD GPU detected, installing required packages..."
chwd -a
pacman -Syu --noconfirm gstreamer-vaapi gst-plugin-va
elif [[ "${vendor_full_map[0],,}" =~ "nvidia" ]]; then
echo "NVIDIA GPU detected. Assuming drivers are linked"
else
echo "Unknown GPU vendor. No additional packages will be installed"
fi
# Clean up remainders
echo "Cleaning up old package cache..."
paccache -rk1
echo "Switching to nestri user for application startup..."
exec sudo -E -u nestri /etc/nestri/entrypoint_nestri.sh

View File

@@ -0,0 +1,156 @@
#!/bin/bash
set -euo pipefail
# Source environment variables from envs.sh
if [ -f /etc/nestri/envs.sh ]; then
echo "Sourcing environment variables from envs.sh..."
source /etc/nestri/envs.sh
else
echo "envs.sh not found! Ensure it exists at /etc/nestri/envs.sh."
exit 1
fi
# Configuration
MAX_RETRIES=3
# Helper function to restart the chain
restart_chain() {
echo "Restarting nestri-server, labwc, and wlr-randr..."
# Kill all child processes safely (if running)
if [[ -n "${NESTRI_PID:-}" ]] && kill -0 "${NESTRI_PID}" 2 >/dev/null; then
kill "${NESTRI_PID}"
fi
if [[ -n "${LABWC_PID:-}" ]] && kill -0 "${LABWC_PID}" 2 >/dev/null; then
kill "${LABWC_PID}"
fi
wait || true
# Start nestri-server
start_nestri_server
RETRY_COUNT=0
}
# Function to start nestri-server
start_nestri_server() {
echo "Starting nestri-server..."
nestri-server $(echo $NESTRI_PARAMS) &
NESTRI_PID=$!
# Wait for Wayland display (wayland-1) to be ready
echo "Waiting for Wayland display 'wayland-1' to be ready..."
WAYLAND_SOCKET="/run/user/${UID}/wayland-1"
for _ in {1..15}; do # Wait up to 15 seconds
if [ -e "$WAYLAND_SOCKET" ]; then
echo "Wayland display 'wayland-1' is ready."
start_labwc
return
fi
sleep 1
done
echo "Error: Wayland display 'wayland-1' did not appear. Incrementing retry count..."
((RETRY_COUNT++))
if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
echo "Max retries reached for nestri-server. Exiting."
exit 1
fi
restart_chain
}
# Function to start labwc
start_labwc() {
echo "Starting labwc..."
rm -rf /tmp/.X11-unix && mkdir -p /tmp/.X11-unix && chown nestri:nestri /tmp/.X11-unix
WAYLAND_DISPLAY=wayland-1 WLR_BACKENDS=wayland labwc &
LABWC_PID=$!
# Wait for labwc to initialize (using `wlr-randr` as an indicator)
echo "Waiting for labwc to initialize..."
for _ in {1..15}; do
if wlr-randr --json | jq -e '.[] | select(.enabled == true)' >/dev/null; then
echo "labwc is initialized and Wayland outputs are ready."
start_wlr_randr
return
fi
sleep 1
done
echo "Error: labwc did not initialize correctly. Incrementing retry count..."
((RETRY_COUNT++))
if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
echo "Max retries reached for labwc. Exiting."
exit 1
fi
restart_chain
}
# Function to run wlr-randr
start_wlr_randr() {
echo "Configuring resolution with wlr-randr..."
OUTPUT_NAME=$(wlr-randr --json | jq -r '.[] | select(.enabled == true) | .name' | head -n 1)
if [ -z "$OUTPUT_NAME" ]; then
echo "Error: No enabled outputs detected. Skipping wlr-randr."
return
fi
# Retry logic for wlr-randr
local WLR_RETRIES=0
while ! WAYLAND_DISPLAY=wayland-0 wlr-randr --output "$OUTPUT_NAME" --custom-mode "$RESOLUTION"; do
echo "Error: Failed to configure wlr-randr. Retrying..."
((WLR_RETRIES++))
if [ "$WLR_RETRIES" -ge "$MAX_RETRIES" ]; then
echo "Max retries reached for wlr-randr. Moving on without resolution setup."
return
fi
sleep 2
done
echo "wlr-randr configuration successful."
}
# Main loop to monitor processes
main_loop() {
trap 'echo "Terminating...";
if [[ -n "${NESTRI_PID:-}" ]] && kill -0 "${NESTRI_PID}" 2>/dev/null; then
kill "${NESTRI_PID}"
fi
if [[ -n "${LABWC_PID:-}" ]] && kill -0 "${LABWC_PID}" 2>/dev/null; then
kill "${LABWC_PID}"
fi
exit 0' SIGINT SIGTERM
while true; do
# Wait for any child process to exit
wait -n
# Check which process exited
if ! kill -0 ${NESTRI_PID:-} 2 >/dev/null; then
echo "nestri-server crashed. Restarting chain..."
((RETRY_COUNT++))
if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
echo "Max retries reached for nestri-server. Exiting."
exit 1
fi
restart_chain
elif ! kill -0 ${LABWC_PID:-} 2 >/dev/null; then
echo "labwc crashed. Restarting labwc and wlr-randr..."
((RETRY_COUNT++))
if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
echo "Max retries reached for labwc. Exiting."
exit 1
fi
start_labwc
fi
done
}
# Initialize retry counter
RETRY_COUNT=0
# Start the initial chain
restart_chain
# Enter monitoring loop
main_loop

View File

@@ -1,4 +1,5 @@
#!/bin/bash -e
#!/bin/bash
set -euo pipefail
export XDG_RUNTIME_DIR=/run/user/${UID}/
export WAYLAND_DISPLAY=wayland-0
@@ -9,4 +10,4 @@ export $(dbus-launch)
export PROTON_NO_FSYNC=1
# Our preferred prefix
export WINEPREFIX=${USER_HOME}/.nestripfx/
export WINEPREFIX=/home/${USER}/.nestripfx/

View File

@@ -1,277 +1,52 @@
#!/bin/bash -e
#!/bin/bash
set -euo pipefail
# Various helper functions for handling available GPUs
declare -a vendor_full_map=()
declare -a vendor_id_map=()
declare -A vendor_index_map=()
declare -ga gpu_map
declare -gA gpu_bus_map
declare -gA gpu_card_map
declare -gA gpu_product_map
declare -gA vendor_index_map
declare -gA vendor_full_map
function get_gpu_info {
# Initialize arrays/maps to avoid unbound variable errors
vendor_full_map=()
vendor_id_map=()
vendor_index_map=()
# Map to help get shorter vendor identifiers
declare -A vendor_keywords=(
["advanced micro devices"]='amd'
["ati"]='amd'
["amd"]='amd'
["radeon"]='amd'
["nvidia"]='nvidia'
["intel"]='intel'
)
# Use lspci to detect GPU info
gpu_info=$(lspci | grep -i 'vga\|3d\|display')
get_gpu_info() {
# Clear out previous data
gpu_map=()
gpu_bus_map=()
gpu_card_map=()
gpu_product_map=()
vendor_index_map=()
vendor_full_map=()
# Parse each line of GPU info
while IFS= read -r line; do
# Extract vendor name and ID from lspci output
vendor=$(echo "$line" | awk -F: '{print $3}' | sed -E 's/^[[:space:]]+//g' | tr '[:upper:]' '[:lower:]')
id=$(echo "$line" | awk '{print $1}')
local vendor=""
local product=""
local bus_info=""
local vendor_full=""
while read -r line; do
line="${line##*( )}"
if [[ "${line,,}" =~ "vendor:" ]]; then
vendor=""
vendor_full=$(echo "$line" | awk '{$1=""; print $0}' | xargs)
# Look for short vendor keyword in line
for keyword in "${!vendor_keywords[@]}"; do
if [[ "${line,,}" == *"$keyword"* ]]; then
vendor="${vendor_keywords[$keyword]}"
break
# Normalize vendor name
if [[ $vendor =~ .*nvidia.* ]]; then
vendor="nvidia"
elif [[ $vendor =~ .*intel.* ]]; then
vendor="intel"
elif [[ $vendor =~ .*advanced[[:space:]]micro[[:space:]]devices.* ]]; then
vendor="amd"
elif [[ $vendor =~ .*ati.* ]]; then
vendor="amd"
else
vendor="unknown"
fi
done
# If no vendor keywords match, use first word
if [[ -z "$vendor" ]]; then
vendor=$(echo "$vendor_full" | awk '{print tolower($1)}')
fi
elif [[ "${line,,}" =~ "product:" ]]; then
product=$(echo "$line" | awk '{$1=""; print $0}' | xargs)
elif [[ "${line,,}" =~ "bus info:" ]]; then
bus_info=$(echo "$line" | awk '{print $3}')
fi
if [[ -n "$vendor" && -n "$product" && -n "$bus_info" && ! "${line,,}" =~ \*"-display" ]]; then
# We have gathered all GPU info necessary, store it
# Check if vendor index is being tracked
if [[ -z "${vendor_index_map[$vendor]}" ]]; then
# Start new vendor index tracking
vendor_index_map[$vendor]=0
else
# Another GPU of same vendor, increment index
vendor_index_map[$vendor]="$((vendor_index_map[$vendor] + 1))"
fi
# Resolved GPU index
local gpu_index="${vendor_index_map[$vendor]}"
local gpu_key="$vendor:$gpu_index"
# Get /dev/dri/cardN of GPU
local gpu_card=$({ ls -1d /sys/bus/pci/devices/*${bus_info#pci@}/drm/*; } 2>&1 | grep card* | grep -oP '(?<=card)\d+')
# Store info in maps
gpu_map+=("$gpu_key")
gpu_bus_map["$gpu_key"]="$bus_info"
gpu_product_map["$gpu_key"]="$product"
vendor_full_map["$gpu_key"]="$vendor_full"
if [[ -n "$gpu_card" ]]; then
gpu_card_map["$gpu_key"]="$gpu_card"
fi
# Clear values for additional GPUs
vendor=""
product=""
bus_info=""
vendor_full=""
fi
if [[ "${line,,}" =~ \*"-display" ]]; then
# New GPU found before storing, clear incomplete values to prevent mixing
vendor=""
product=""
bus_info=""
vendor_full=""
fi
done < <(sudo lshw -c video)
# Add to arrays/maps if unique
if ! [[ "${vendor_index_map[$vendor]:-}" ]]; then
vendor_index_map[$vendor]="${#vendor_full_map[@]}"
vendor_full_map+=("$vendor")
fi
vendor_id_map+=("$id")
done <<< "$gpu_info"
}
check_and_populate_gpus() {
if [[ "${#gpu_map[@]}" -eq 0 ]]; then
get_gpu_info # Gather info incase info not gathered yet
if [[ "${#gpu_map[@]}" -eq 0 ]]; then
echo "No GPUs found on this system" >&2
return 1
fi
fi
}
check_selected_gpu() {
local selected_gpu="${1,,}"
if [[ ! " ${gpu_map[*]} " =~ " $selected_gpu " ]]; then
echo "No such GPU: '$selected_gpu'" >&2
return 1
fi
echo "$selected_gpu"
}
list_available_gpus() {
if ! check_and_populate_gpus; then
return 1
fi
echo "Available GPUs:" >&2
for gpu in "${gpu_map[@]}"; do
echo " [$gpu] \"${gpu_product_map[$gpu]}\" @[${gpu_bus_map[$gpu]}]"
done
}
convert_bus_id_to_xorg() {
local bus_info="$1"
IFS=":." read -ra bus_parts <<< "${bus_info#pci@????:}" # Remove "pci@" and the following 4 characters (domain)
# Check if bus_info has the correct format (at least 3 parts after removing domain)
if [[ "${#bus_parts[@]}" -lt 3 ]]; then
echo "Invalid bus info format: $bus_info" >&2
return 1
fi
# Convert each part from hexadecimal to decimal
bus_info_xorg="PCI:"
for part in "${bus_parts[@]}"; do
bus_info_xorg+="$((16#$part)):"
done
bus_info_xorg="${bus_info_xorg%:}" # Remove the trailing colon
echo "$bus_info_xorg"
}
print_gpu_info() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
echo "[$selected_gpu]"
echo " Vendor: ${vendor_full_map[$selected_gpu]}"
echo " Product: ${gpu_product_map[$selected_gpu]}"
echo " Bus: ${gpu_bus_map[$selected_gpu]}"
# Check if card path was found
if [[ "${gpu_card_map[$selected_gpu]}" ]]; then
echo " Card: /dev/dri/card${gpu_card_map[$selected_gpu]}"
fi
echo
}
get_gpu_vendor() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
echo "${selected_gpu%%:*}"
}
get_gpu_vendor_full() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
echo "${vendor_full_map[$selected_gpu]}"
}
get_gpu_index() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
echo "${selected_gpu#*:}"
}
get_gpu_product() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
echo "${gpu_product_map[$selected_gpu]}"
}
get_gpu_bus() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
echo "${gpu_bus_map[$selected_gpu]}"
}
get_gpu_bus_xorg() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
echo $(convert_bus_id_to_xorg "${gpu_bus_map[$selected_gpu]}")
}
get_gpu_card() {
if ! check_and_populate_gpus; then
return 1
fi
local selected_gpu
if ! selected_gpu=$(check_selected_gpu "$1"); then
return 1
fi
# Check if card path was found
if [[ -z "${gpu_card_map[$selected_gpu]}" ]]; then
echo "No card device found for GPU: $selected_gpu" >&2
return 1
fi
echo "/dev/dri/card${gpu_card_map[$selected_gpu]}"
function debug_gpu_info {
echo "Vendor Full Map: ${vendor_full_map[*]}"
echo "Vendor ID Map: ${vendor_id_map[*]}"
echo "Vendor Index Map:"
for key in "${!vendor_index_map[@]}"; do
echo " $key: ${vendor_index_map[$key]}"
done
}

View File

@@ -0,0 +1,53 @@
[supervisord]
user=root
nodaemon=true
loglevel=info
logfile=/tmp/supervisord.log
[program:dbus]
user=root
command=dbus-daemon --system --nofork --nopidfile
autorestart=true
autostart=true
startretries=3
priority=1
[program:seatd]
user=root
command=seatd
autorestart=true
autostart=true
startretries=3
priority=2
[program:pipewire]
user=nestri
command=dbus-launch pipewire
autorestart=true
autostart=true
startretries=3
priority=3
[program:pipewire-pulse]
user=nestri
command=dbus-launch pipewire-pulse
autorestart=true
autostart=true
startretries=3
priority=4
[program:wireplumber]
user=nestri
command=dbus-launch wireplumber
autorestart=true
autostart=true
startretries=3
priority=5
[program:entrypoint]
user=root
command=/etc/nestri/entrypoint.sh
autorestart=false
autostart=true
startretries=0
priority=10