wivrn: init at 0.19 (#316975)

This commit is contained in:
Tomo 2024-10-19 20:02:50 -07:00 committed by GitHub
commit d249539594
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 378 additions and 0 deletions

View File

@ -201,6 +201,8 @@ The pre-existing `services.ankisyncd` has been marked deprecated and will be dro
- [watchdogd](https://troglobit.com/projects/watchdogd/), a system and process supervisor using watchdog timers. Available as [services.watchdogd](#opt-services.watchdogd.enable).
- [WiVRn](https://github.com/Meumeu/WiVRn), an OpenXR streaming application. Available as [services.wivrn](#opt-services.wivrn.enable).
- [Workout-tracker](https://github.com/jovandeginste/workout-tracker), a workout tracking web application for personal use.
- [wyoming-satellite](https://github.com/rhasspy/wyoming-satellite), a voice assistant satellite for Home Assistant using the Wyoming protocol. Available as [services.wyoming.satellite](#opt-services.wyoming.satellite.enable).

View File

@ -1380,6 +1380,7 @@
./services/video/photonvision.nix
./services/video/mediamtx.nix
./services/video/v4l2-relayd.nix
./services/video/wivrn.nix
./services/wayland/cage.nix
./services/wayland/hypridle.nix
./services/web-apps/akkoma.nix

View File

@ -0,0 +1,226 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (lib)
mkIf
mkEnableOption
mkPackageOption
mkOption
optionalString
optionalAttrs
isDerivation
recursiveUpdate
getExe
literalExpression
types
maintainers
;
cfg = config.services.wivrn;
configFormat = pkgs.formats.json { };
# For the application option to work with systemd PATH, we find the store binary path of
# the package, concat all of the following strings, and then update the application attribute.
# Application can either be a package or a list that has a package as the first element.
applicationExists = builtins.hasAttr "application" cfg.config.json;
applicationListNotEmpty = (
if builtins.isList cfg.config.json.application then
(builtins.length cfg.config.json.application) != 0
else
true
);
applicationCheck = applicationExists && applicationListNotEmpty;
applicationBinary = (
if builtins.isList cfg.config.json.application then
builtins.head cfg.config.json.application
else
cfg.config.json.application
);
applicationStrings = builtins.tail cfg.config.json.application;
applicationPath = mkIf applicationCheck applicationBinary;
applicationConcat = (
if builtins.isList cfg.config.json.application then
builtins.concatStringsSep " " ([ (getExe applicationBinary) ] ++ applicationStrings)
else
(getExe applicationBinary)
);
applicationUpdate = recursiveUpdate cfg.config.json (
optionalAttrs applicationCheck { application = applicationConcat; }
);
configFile = configFormat.generate "config.json" applicationUpdate;
in
{
options = {
services.wivrn = {
enable = mkEnableOption "WiVRn, an OpenXR streaming application";
package = mkPackageOption pkgs "wivrn" { };
openFirewall = mkEnableOption "the default ports in the firewall for the WiVRn server";
defaultRuntime = mkEnableOption ''
WiVRn Monado as the default OpenXR runtime on the system.
The config can be found at `/etc/xdg/openxr/1/active_runtime.json`.
Note that applications can bypass this option by setting an active
runtime in a writable XDG_CONFIG_DIRS location like `~/.config`
'';
autoStart = mkEnableOption "starting the service by default";
monadoEnvironment = mkOption {
type = types.attrs;
description = "Environment variables to be passed to the Monado environment.";
default = {
XRT_COMPOSITOR_LOG = "debug";
XRT_PRINT_OPTIONS = "on";
IPC_EXIT_ON_DISCONNECT = "off";
};
};
extraPackages = mkOption {
type = types.listOf types.package;
description = "Packages to add to the wivrn-application service $PATH.";
default = [ ];
example = literalExpression "[ pkgs.bash pkgs.procps ]";
};
config = {
enable = mkEnableOption "configuration for WiVRn";
json = mkOption {
type = configFormat.type;
description = ''
Configuration for WiVRn. The attributes are serialized to JSON in config.json.
Note that the application option must be either a package or a
list with package as the first element.
See https://github.com/Meumeu/WiVRn/blob/master/docs/configuration.md
'';
default = { };
example = literalExpression ''
{
scale = 0.8;
bitrate = 100000000;
encoders = [
{
encoder = "nvenc";
codec = "h264";
width = 1.0;
height = 1.0;
offset_x = 0.0;
offset_y = 0.0;
}
];
application = [ pkgs.wlx-overlay-s ];
tcp_only = true;
}
'';
};
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = !applicationCheck || isDerivation applicationBinary;
message = "The application in WiVRn configuration is not a package. Please ensure that the application is a package or that a package is the first element in the list.";
}
];
systemd.user = {
services = {
# The WiVRn server runs in a hardened service and starts the applications in a different service
wivrn = {
description = "WiVRn XR runtime service";
environment = {
# Default options
# https://gitlab.freedesktop.org/monado/monado/-/blob/598080453545c6bf313829e5780ffb7dde9b79dc/src/xrt/targets/service/monado.in.service#L12
XRT_COMPOSITOR_LOG = "debug";
XRT_PRINT_OPTIONS = "on";
IPC_EXIT_ON_DISCONNECT = "off";
} // cfg.monadoEnvironment;
serviceConfig = {
ExecStart = (
(getExe cfg.package) + " --systemd" + optionalString cfg.config.enable " -f ${configFile}"
);
# Hardening options
CapabilityBoundingSet = [ "CAP_SYS_NICE" ];
AmbientCapabilities = [ "CAP_SYS_NICE" ];
LockPersonality = true;
NoNewPrivileges = true;
PrivateTmp = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictSUIDSGID = true;
};
wantedBy = mkIf cfg.autoStart [ "default.target" ];
restartTriggers = [
cfg.package
configFile
];
};
wivrn-application = mkIf applicationCheck {
description = "WiVRn application service";
requires = [ "wivrn.service" ];
serviceConfig = {
ExecStart = (
(getExe cfg.package) + " --application" + optionalString cfg.config.enable " -f ${configFile}"
);
Restart = "on-failure";
RestartSec = 0;
PrivateTmp = true;
};
# We need to add the application to PATH so WiVRn can find it
path = [ applicationPath ] ++ cfg.extraPackages;
};
};
};
services = {
# WiVRn can be used with some wired headsets so we include xr-hardware
udev.packages = with pkgs; [
android-udev-rules
xr-hardware
];
avahi = {
enable = true;
publish = {
enable = true;
userServices = true;
};
};
};
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ 9757 ];
allowedUDPPorts = [ 9757 ];
};
environment = {
systemPackages = [
cfg.package
applicationPath
];
pathsToLink = [ "/share/openxr" ];
etc."xdg/openxr/1/active_runtime.json" = mkIf cfg.defaultRuntime {
source = "${cfg.package}/share/openxr/1/openxr_wivrn.json";
};
};
};
meta.maintainers = with maintainers; [ passivelemon ];
}

View File

@ -0,0 +1,149 @@
{
config,
lib,
stdenv,
fetchFromGitHub,
fetchFromGitLab,
applyPatches,
autoAddDriverRunpath,
avahi,
boost,
cli11,
cmake,
cudaPackages ? { },
cudaSupport ? config.cudaSupport,
eigen,
ffmpeg,
freetype,
git,
glm,
glslang,
harfbuzz,
libdrm,
libGL,
libva,
libpulseaudio,
libX11,
libXrandr,
nix-update-script,
nlohmann_json,
onnxruntime,
openxr-loader,
pipewire,
pkg-config,
python3,
shaderc,
spdlog,
systemd,
udev,
vulkan-headers,
vulkan-loader,
vulkan-tools,
x264,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "wivrn";
version = "0.19";
src = fetchFromGitHub {
owner = "wivrn";
repo = "wivrn";
rev = "v${finalAttrs.version}";
hash = "sha256-DYV+JUWjjhLZLq+4Hv7jxOyxDqQut/mU1X0ZFMoNkDI=";
};
monado = applyPatches {
src = fetchFromGitLab {
domain = "gitlab.freedesktop.org";
owner = "monado";
repo = "monado";
rev = "bcbe19ddd795f182df42051e5495e9727db36c1c";
hash = "sha256-sh5slHROcuC3Dgenu1+hm8U5lUOW48JUbiluYvc3NiQ=";
};
patches = [
"${finalAttrs.src}/patches/monado/0001-c-multi-disable-dropping-of-old-frames.patch"
"${finalAttrs.src}/patches/monado/0002-ipc-server-Always-listen-to-stdin.patch"
"${finalAttrs.src}/patches/monado/0003-c-multi-Don-t-log-frame-time-diff.patch"
"${finalAttrs.src}/patches/monado/0005-distortion-images.patch"
"${finalAttrs.src}/patches/monado/0008-Use-mipmaps-for-distortion-shader.patch"
"${finalAttrs.src}/patches/monado/0009-convert-to-YCbCr-in-monado.patch"
];
};
strictDeps = true;
postUnpack = ''
# Let's make sure our monado source revision matches what is used by WiVRn upstream
ourMonadoRev="${finalAttrs.monado.src.rev}"
theirMonadoRev=$(grep "GIT_TAG" ${finalAttrs.src.name}/CMakeLists.txt | awk '{print $2}')
if [ ! "$theirMonadoRev" == "$ourMonadoRev" ]; then
echo "Our Monado source revision doesn't match CMakeLists.txt." >&2
echo " theirs: $theirMonadoRev" >&2
echo " ours: $ourMonadoRev" >&2
return 1
fi
'';
nativeBuildInputs = [
cmake
git
glslang
pkg-config
python3
] ++ lib.optionals cudaSupport [ autoAddDriverRunpath ];
buildInputs = [
avahi
boost
cli11
eigen
ffmpeg
freetype
glm
harfbuzz
libdrm
libGL
libva
libX11
libXrandr
libpulseaudio
nlohmann_json
onnxruntime
openxr-loader
pipewire
shaderc
spdlog
systemd
udev
vulkan-headers
vulkan-loader
vulkan-tools
x264
] ++ lib.optionals cudaSupport [ cudaPackages.cudatoolkit ];
cmakeFlags = [
(lib.cmakeBool "WIVRN_USE_VAAPI" true)
(lib.cmakeBool "WIVRN_USE_X264" true)
(lib.cmakeBool "WIVRN_USE_NVENC" cudaSupport)
(lib.cmakeBool "WIVRN_USE_SYSTEMD" true)
(lib.cmakeBool "WIVRN_USE_PIPEWIRE" true)
(lib.cmakeBool "WIVRN_USE_PULSEAUDIO" true)
(lib.cmakeBool "WIVRN_BUILD_CLIENT" false)
(lib.cmakeBool "WIVRN_OPENXR_INSTALL_ABSOLUTE_RUNTIME_PATH" true)
(lib.cmakeBool "FETCHCONTENT_FULLY_DISCONNECTED" true)
(lib.cmakeFeature "FETCHCONTENT_SOURCE_DIR_MONADO" "${finalAttrs.monado}")
];
passthru.updateScript = nix-update-script { };
meta = with lib; {
description = "An OpenXR streaming application to a standalone headset";
homepage = "https://github.com/Meumeu/WiVRn/";
changelog = "https://github.com/Meumeu/WiVRn/releases/";
license = licenses.gpl3Only;
maintainers = with maintainers; [ passivelemon ];
platforms = platforms.linux;
mainProgram = "wivrn-server";
};
})