From 22d58bfb4d5854d16bd55dac732de95e7b8d253e Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Mon, 30 Jun 2025 13:15:08 +0200 Subject: [PATCH 1/3] galene-stream: init at 0.2.0 --- pkgs/by-name/ga/galene-stream/package.nix | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 pkgs/by-name/ga/galene-stream/package.nix diff --git a/pkgs/by-name/ga/galene-stream/package.nix b/pkgs/by-name/ga/galene-stream/package.nix new file mode 100644 index 000000000000..b48b0664c161 --- /dev/null +++ b/pkgs/by-name/ga/galene-stream/package.nix @@ -0,0 +1,79 @@ +{ + lib, + python3Packages, + fetchFromGitHub, + gitUpdater, + galene, + gobject-introspection, + gst_all_1, + libnice, + wrapGAppsHook3, +}: + +python3Packages.buildPythonApplication rec { + pname = "galene-stream"; + version = "0.2.0"; + pyproject = true; + + src = fetchFromGitHub { + owner = "erdnaxe"; + repo = "galene-stream"; + tag = "${version}"; + hash = "sha256-3TdU3vBVuFle+jon2oJLa/rTLIiwYkvzscTDbMEXD1Q="; + }; + + # When insecure is enabled on both galene and galene-stream, passing the ssl_context with certificate checking disabled when trying to open a websocket connection to ws:// errors out, because no ssl_context is expected to be passed for an SSL-less websocket like that + # When --insecure in galene-stream, don't pass ssl_context here + # TODO: How does this interact with a galene with insecure disabled? Expecting endpoint there to be wss://. Might need more sophisticated patch. + postPatch = '' + substituteInPlace galene_stream/galene.py \ + --replace-fail 'await websockets.connect(status["endpoint"], ssl=ssl_context)' 'await websockets.connect(status["endpoint"], ssl=None if self.insecure else ssl_context)' + ''; + + strictDeps = true; + + nativeBuildInputs = [ + gobject-introspection + wrapGAppsHook3 + ]; + + build-system = with python3Packages; [ + setuptools + setuptools-scm + ]; + + buildInputs = + [ + libnice # libgstnice.so + ] + ++ (with gst_all_1; [ + gst-plugins-base + gst-plugins-good + gst-plugins-bad + gst-plugins-ugly # libgstx264.so + ]); + + dependencies = with python3Packages; [ + pygobject3 + websockets + ]; + + dontWrapGApps = true; + + preFixup = '' + makeWrapperArgs+=("''${gappsWrapperArgs[@]}") + ''; + + passthru = { + updateScript = gitUpdater { }; + }; + + meta = { + description = "Gateway to send UDP, RTMP, SRT or RIST streams to Galène videoconference server"; + homepage = "https://github.com/erdnaxe/galene-stream"; + changelog = "https://github.com/erdnaxe/galene-stream/releases/tag/${src.tag}"; + license = lib.licenses.mit; + platforms = lib.platforms.linux; + inherit (galene.meta) maintainers; + }; +} From 446617549c0a29e8e85896439378f34f362945cf Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Fri, 9 May 2025 14:27:05 +0200 Subject: [PATCH 2/3] nixosTests.galene.stream: init --- nixos/tests/galene.nix | 132 ++++++++++++++++++++++ pkgs/by-name/ga/galene-stream/package.nix | 2 + 2 files changed, 134 insertions(+) diff --git a/nixos/tests/galene.nix b/nixos/tests/galene.nix index 8805a088a56c..a05dea24eb01 100644 --- a/nixos/tests/galene.nix +++ b/nixos/tests/galene.nix @@ -208,4 +208,136 @@ in ''; } ); + + stream = makeTest ( + { pkgs, lib, ... }: + let + galeneTestGroupBotName = "bot"; + galeneTestGroupBotPassword = "1234"; + galeneStreamSrtPort = 9710; + galeneStreamFeedImage = "galene-stream-feed.png"; + galeneStreamFeedLabel = "Example"; + in + { + name = "galene-stream-works"; + meta = { + # inherit (pkgs.galene-stream.meta) teams; + inherit (pkgs.galene.meta) maintainers; + platforms = lib.platforms.linux; + }; + + nodes.machine = + { config, pkgs, ... }: + { + imports = [ ./common/x11.nix ]; + + services.xserver.enable = true; + + environment = { + # https://galene.org/INSTALL.html + etc = { + ${galeneTestGroupFile}.source = (pkgs.formats.json { }).generate galeneTestGroupFile { + presenter = [ + { + username = galeneTestGroupBotName; + password = galeneTestGroupBotPassword; + } + ]; + other = [ { } ]; + }; + + ${galeneStreamFeedImage}.source = + pkgs.runCommand galeneStreamFeedImage + { + nativeBuildInputs = with pkgs; [ + (imagemagick.override { ghostscriptSupport = true; }) # Add text to image + ]; + } + '' + magick -size 400x400 -background white -fill black canvas:white -pointsize 70 -annotate +100+200 '${galeneStreamFeedLabel}' $out + ''; + }; + + systemPackages = with pkgs; [ + ffmpeg + firefox + galene-stream + ]; + }; + + services.galene = { + enable = true; + insecure = true; + httpPort = galenePort; + groupsDir = galeneTestGroupsDir; + }; + }; + + enableOCR = true; + + testScript = '' + machine.wait_for_x() + + with subtest("galene starts"): + # Starts? + machine.wait_for_unit("galene") + + # Keeps running after startup? + machine.sleep(10) + machine.wait_for_unit("galene") + + # Reponds fine? + machine.succeed("curl -s -D - -o /dev/null 'http://localhost:${builtins.toString galenePort}' >&2") + + machine.succeed("cp -v /etc/${galeneTestGroupFile} ${galeneTestGroupsDir}/test.json >&2") + machine.wait_until_succeeds("curl -s -D - -o /dev/null 'http://localhost:${builtins.toString galenePort}/group/test/' >&2") + + with subtest("galene-stream works"): + # Start interface for stream data + machine.succeed( + "galene-stream " + + "--input 'srt://localhost:${builtins.toString galeneStreamSrtPort}?mode=listener' " + + "--insecure --output 'http://localhost:${builtins.toString galenePort}/group/test/' " + + "--username ${galeneTestGroupBotName} --password ${galeneTestGroupBotPassword} " + + ">&2 &" + ) + machine.wait_for_console_text("Waiting for incoming stream...") + + # Start streaming + machine.succeed( + "ffmpeg " + + "-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000 " # need an audio track + + "-re -loop 1 -i /etc/${galeneStreamFeedImage} " # loop of feed image + + "-map 0:a -map 1:v " # arrange the output stream to have silent audio & looped video + + "-c:a mp2 " # stream audio codec + + "-c:v libx264 -pix_fmt yuv420p " # stream video codec + + "-f mpegts " # stream format + + "'srt://localhost:${builtins.toString galeneStreamSrtPort}' " + + ">/dev/null 2>&1 &" + ) + machine.wait_for_console_text("Setting remote session description") + + # Open site + machine.succeed("firefox --new-window 'http://localhost:${builtins.toString galenePort}/group/test/' >&2 &") + # Note: Firefox doesn't use a regular "-" in the window title, but "—" (Hex: 0xe2 0x80 0x94) + machine.wait_for_window("Test — Mozilla Firefox") + machine.send_key("ctrl-minus") + machine.send_key("ctrl-minus") + machine.send_key("alt-f10") + machine.wait_for_text(r"(Galène|Username|Password|Connect)") + machine.screenshot("galene-group-test-join") + + # Log in as anon + machine.send_key("ret") + machine.sleep(5) + # Close "Remember credentials?" FF prompt + machine.send_key("esc") + machine.sleep(5) + + # Look for stream + machine.wait_for_text("${galeneStreamFeedLabel}") + machine.screenshot("galene-stream-group-test-streams") + ''; + } + ); } diff --git a/pkgs/by-name/ga/galene-stream/package.nix b/pkgs/by-name/ga/galene-stream/package.nix index b48b0664c161..e2f2e07bc52f 100644 --- a/pkgs/by-name/ga/galene-stream/package.nix +++ b/pkgs/by-name/ga/galene-stream/package.nix @@ -3,6 +3,7 @@ python3Packages, fetchFromGitHub, gitUpdater, + nixosTests, galene, gobject-introspection, gst_all_1, @@ -65,6 +66,7 @@ python3Packages.buildPythonApplication rec { ''; passthru = { + tests.vm = nixosTests.galene.stream; updateScript = gitUpdater { }; }; From 6bfa191ec321e7cc0c87f7f5437e818bd173100a Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Mon, 30 Jun 2025 13:45:33 +0200 Subject: [PATCH 3/3] nixosTests.galene: Modernise / simplify test code - makeTest -> passed-through runTest - Drop hardcoded sleep & check if galene still runs, it's not really necessary --- nixos/tests/all-tests.nix | 2 +- nixos/tests/galene.nix | 24 ++++++++---------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index b92e76ed60af..802e2030bc4c 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -546,7 +546,7 @@ in ft2-clone = runTest ./ft2-clone.nix; legit = runTest ./legit.nix; mimir = runTest ./mimir.nix; - galene = discoverTests (import ./galene.nix); + galene = discoverTests (import ./galene.nix { inherit runTest; }); gancio = runTest ./gancio.nix; garage_1 = import ./garage { inherit runTest; diff --git a/nixos/tests/galene.nix b/nixos/tests/galene.nix index a05dea24eb01..3918e1048147 100644 --- a/nixos/tests/galene.nix +++ b/nixos/tests/galene.nix @@ -1,5 +1,6 @@ +{ runTest }: + let - makeTest = import ./make-test-python.nix; galeneTestGroupsDir = "/var/lib/galene/groups"; galeneTestGroupFile = "galene-test-config.json"; galenePort = 8443; @@ -7,7 +8,7 @@ let galeneTestGroupAdminPassword = "1234"; in { - basic = makeTest ( + basic = runTest ( { pkgs, lib, ... }: { name = "galene-works"; @@ -56,10 +57,7 @@ in with subtest("galene starts"): # Starts? machine.wait_for_unit("galene") - - # Keeps running after startup? - machine.sleep(10) - machine.wait_for_unit("galene") + machine.wait_for_open_port(${builtins.toString galenePort}) # Reponds fine? machine.succeed("curl -s -D - -o /dev/null 'http://localhost:${builtins.toString galenePort}' >&2") @@ -93,7 +91,7 @@ in } ); - file-transfer = makeTest ( + file-transfer = runTest ( { pkgs, lib, ... }: { name = "galene-file-transfer-works"; @@ -143,10 +141,7 @@ in with subtest("galene starts"): # Starts? machine.wait_for_unit("galene") - - # Keeps running after startup? - machine.sleep(10) - machine.wait_for_unit("galene") + machine.wait_for_open_port(${builtins.toString galenePort}) # Reponds fine? machine.succeed("curl -s -D - -o /dev/null 'http://localhost:${builtins.toString galenePort}' >&2") @@ -209,7 +204,7 @@ in } ); - stream = makeTest ( + stream = runTest ( { pkgs, lib, ... }: let galeneTestGroupBotName = "bot"; @@ -281,10 +276,7 @@ in with subtest("galene starts"): # Starts? machine.wait_for_unit("galene") - - # Keeps running after startup? - machine.sleep(10) - machine.wait_for_unit("galene") + machine.wait_for_open_port(${builtins.toString galenePort}) # Reponds fine? machine.succeed("curl -s -D - -o /dev/null 'http://localhost:${builtins.toString galenePort}' >&2")