diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index db753bbdf4ae4..1caa762d4ebf1 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -55,6 +55,8 @@ - [Bat](https://github.com/sharkdp/bat), a {manpage}`cat(1)` clone with wings. Available as [programs.bat](options.html#opt-programs.bat). +- [µStreamer](https://github.com/pikvm/ustreamer), a lightweight MJPEG-HTTP streamer. Available as [services.ustreamer](options.html#opt-services.ustreamer). + - [Whoogle Search](https://github.com/benbusby/whoogle-search), a self-hosted, ad-free, privacy-respecting metasearch engine. Available as [services.whoogle-search](options.html#opt-services.whoogle-search.enable). - [agorakit](https://github.com/agorakit/agorakit), an organization tool for citizens' collectives. Available with [services.agorakit](options.html#opt-services.agorakit.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index ae286756200c4..9fe8e3be6477d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1417,6 +1417,7 @@ ./services/video/mirakurun.nix ./services/video/photonvision.nix ./services/video/mediamtx.nix + ./services/video/ustreamer.nix ./services/video/v4l2-relayd.nix ./services/video/wivrn.nix ./services/wayland/cage.nix diff --git a/nixos/modules/services/video/ustreamer.nix b/nixos/modules/services/video/ustreamer.nix new file mode 100644 index 0000000000000..d32818fa3ab3d --- /dev/null +++ b/nixos/modules/services/video/ustreamer.nix @@ -0,0 +1,110 @@ +{ + config, + lib, + pkgs, + utils, + ... +}: +let + inherit (lib) + getExe + mkEnableOption + mkIf + mkOption + mkPackageOption + optionals + types + ; + + cfg = config.services.ustreamer; +in +{ + options.services.ustreamer = { + enable = mkEnableOption "µStreamer, a lightweight MJPEG-HTTP streamer"; + + package = mkPackageOption pkgs "ustreamer" { }; + + autoStart = mkOption { + description = '' + Wether to start µStreamer on boot. Disabling this will use socket + activation. The service will stop gracefully after some inactivity. + Disabling this will set `--exit-on-no-clients=300` + ''; + type = types.bool; + default = true; + example = false; + }; + + listenAddress = mkOption { + description = '' + Address to expose the HTTP server. This accepts values for + ListenStream= defined in {manpage}`systemd.socket(5)` + ''; + type = types.str; + default = "0.0.0.0:8080"; + example = "/run/ustreamer.sock"; + }; + + device = mkOption { + description = '' + The v4l2 device to stream. + ''; + type = types.path; + default = "/dev/video0"; + example = "/dev/v4l/by-id/usb-0000_Dummy_abcdef-video-index0"; + }; + + extraArgs = mkOption { + description = '' + Extra arguments to pass to `ustreamer`. See {manpage}`ustreamer(1)` + ''; + type = with types; listOf str; + default = [ ]; + example = [ "--resolution=1920x1080" ]; + }; + }; + + config = mkIf cfg.enable { + services.ustreamer.extraArgs = + [ + "--device=${cfg.device}" + ] + ++ optionals (!cfg.autoStart) [ + "--exit-on-no-clients=300" + ]; + + systemd.services."ustreamer" = { + description = "µStreamer, a lightweight MJPEG-HTTP streamer"; + after = [ "network.target" ]; + requires = [ "ustreamer.socket" ]; + wantedBy = mkIf cfg.autoStart [ "multi-user.target" ]; + serviceConfig = { + ExecStart = utils.escapeSystemdExecArgs ( + [ + (getExe cfg.package) + "--systemd" + ] + ++ cfg.extraArgs + ); + Restart = if cfg.autoStart then "always" else "on-failure"; + + DynamicUser = true; + SupplementaryGroups = [ "video" ]; + + NoNewPrivileges = true; + ProcSubset = "pid"; + ProtectProc = "noaccess"; + ProtectClock = "yes"; + DeviceAllow = [ cfg.device ]; + }; + }; + + systemd.sockets."ustreamer" = { + wantedBy = [ "sockets.target" ]; + partOf = [ "ustreamer.service" ]; + socketConfig = { + ListenStream = cfg.listenAddress; + }; + }; + }; +} diff --git a/nixos/tests/ustreamer.nix b/nixos/tests/ustreamer.nix index 12793ff8451df..a47dc42c0c66b 100644 --- a/nixos/tests/ustreamer.nix +++ b/nixos/tests/ustreamer.nix @@ -46,22 +46,13 @@ import ./make-test-python.nix ( ''; in { - environment.systemPackages = [ pkgs.ustreamer ]; - networking.firewall.enable = false; - systemd.services.ustreamer = { - description = "ustreamer service"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - DynamicUser = true; - ExecStart = "${pkgs.ustreamer}/bin/ustreamer --host=0.0.0.0 --port 8000 --device /dev/video9 --device-timeout=8"; - PrivateTmp = true; - BindReadOnlyPaths = "/dev/video9"; - SupplementaryGroups = [ - "video" - ]; - Restart = "always"; - }; + services.ustreamer = { + enable = true; + device = "/dev/video9"; + extraArgs = [ "--device-timeout=8" ]; }; + networking.firewall.allowedTCPPorts = [ 8080 ]; + boot.extraModulePackages = [ config.boot.kernelPackages.akvcam ]; boot.kernelModules = [ "akvcam" ]; boot.extraModprobeConfig = '' @@ -74,10 +65,10 @@ import ./make-test-python.nix ( start_all() camera.wait_for_unit("ustreamer.service") - camera.wait_for_open_port(8000) + camera.wait_for_open_port(8080) client.wait_for_unit("multi-user.target") - client.succeed("curl http://camera:8000") + client.succeed("curl http://camera:8080") ''; } ) diff --git a/pkgs/by-name/us/ustreamer/package.nix b/pkgs/by-name/us/ustreamer/package.nix index 58dce6de7c9a4..71c8c9a36a397 100644 --- a/pkgs/by-name/us/ustreamer/package.nix +++ b/pkgs/by-name/us/ustreamer/package.nix @@ -14,17 +14,20 @@ jansson, libopus, nixosTests, + systemdLibs, + which, + withSystemd ? true, withJanus ? true, }: stdenv.mkDerivation rec { pname = "ustreamer"; - version = "6.12"; + version = "6.18"; src = fetchFromGitHub { owner = "pikvm"; repo = "ustreamer"; rev = "v${version}"; - hash = "sha256-iaCgPHgklk7tbhJhQmyjKggb1bMWBD+Zurgfk9sCQ3E="; + hash = "sha256-VzhTfr0Swrv3jZUvBYYy5l0+iSokIztpeyA1CuG/roY="; }; buildInputs = @@ -34,6 +37,9 @@ stdenv.mkDerivation rec { libjpeg libdrm ] + ++ lib.optionals withSystemd [ + systemdLibs + ] ++ lib.optionals withJanus [ janus-gateway glib @@ -43,13 +49,19 @@ stdenv.mkDerivation rec { libopus ]; - nativeBuildInputs = [ pkg-config ]; + nativeBuildInputs = [ + pkg-config + which + ]; makeFlags = [ "PREFIX=${placeholder "out"}" "WITH_V4P=1" ] + ++ lib.optionals withSystemd [ + "WITH_SYSTEMD=1" + ] ++ lib.optionals withJanus [ "WITH_JANUS=1" # Workaround issues with Janus C Headers @@ -77,5 +89,6 @@ stdenv.mkDerivation rec { matthewcroughan ]; platforms = platforms.linux; + mainProgram = "ustreamer"; }; }