diff --git a/configuration.nix b/configuration.nix index 9b82365..cb3628e 100644 --- a/configuration.nix +++ b/configuration.nix @@ -115,25 +115,46 @@ in services.pipewire = { enable = true; alsa.enable = true; pulse.enable = true; }; - # --- Pin system audio to 100% before RadiantWave launches --- + # New sinks with no stored volume default to ~40% in WirePlumber 0.5+. + # Force every newly-created sink to 100% so switching the default sink + # never changes the volume. + services.pipewire.wireplumber.extraConfig."99-kiosk-audio" = { + "wireplumber.settings"."device.routes.default-sink-volume" = 1.0; + }; + + # --- Pin all system audio sinks to 100% before RadiantWave launches --- # User unit (PipeWire runs per-user in the kiosk session), owned by this # system config. Ordered after PipeWire/WirePlumber; the retry loop covers - # default-sink readiness at boot. RadiantWave's loginShellInit waits on this - # before exec'ing cage. + # sink readiness at boot. Pins every connected sink (not just the default) + # and unmutes them, so switching the default sink never changes the volume. + # RadiantWave's loginShellInit waits on this before exec'ing cage. systemd.user.services.radiantwave-audio-init = { - description = "Pin system audio volume to 100% and unmute"; + description = "Pin all system audio sinks to 100% and unmute"; after = [ "pipewire.service" "wireplumber.service" ]; wants = [ "pipewire.service" "wireplumber.service" ]; serviceConfig = { Type = "oneshot"; }; script = '' + # Wait until WirePlumber exposes at least one sink + sinks="" for i in {1..30}; do - if ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0 2>/dev/null; then + sinks=$(${pkgs.wireplumber}/bin/wpctl list audio sinks 2>/dev/null \ + | ${pkgs.gnused}/bin/sed -nE 's/^.*[^0-9]([0-9]+)\. .*$/\1/p') + if [ -n "$sinks" ]; then break fi sleep 1 done + + # Pin and unmute every connected sink + for sink_id in $sinks; do + ${pkgs.wireplumber}/bin/wpctl set-volume "$sink_id" 1.0 2>/dev/null || true + ${pkgs.wireplumber}/bin/wpctl set-mute "$sink_id" 0 2>/dev/null || true + done + + # Fallback in case the sink list came up empty + ${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0 2>/dev/null || true ${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ 0 2>/dev/null || true ''; }; diff --git a/dev-iso.nix b/dev-iso.nix index 414f409..41eb0a6 100644 --- a/dev-iso.nix +++ b/dev-iso.nix @@ -8,23 +8,27 @@ let targetSystem = self.nixosConfigurations.radiantwavekiosk-dev.config.system.build.toplevel; - # 🔧 FIX: prebuilt disko script (restores v1.0.1 behavior) diskoScript = self.nixosConfigurations.radiantwavekiosk-dev.config.system.build.diskoScript; in { + ############################################################ + # System configuration + ############################################################ + nix.settings = { experimental-features = [ "nix-command" "flakes" ]; - # 🔧 FIX: restore cache (prevents massive rebuild/download cascade) substituters = [ "https://cache.nixos.org" ]; flake-registry = ""; + + connect-timeout = 0; }; nix.registry.nixpkgs = pkgs.lib.mkForce { @@ -34,19 +38,11 @@ in }; }; - environment.variables.KIOSK_FLAKE = "${self}"; + nix.extraOptions = '' + netrc-file = /etc/nix/netrc + ''; - virtualisation.vmVariant = { - virtualisation.memorySize = 8096; - virtualisation.diskSize = 100000; - virtualisation.cores = 4; - virtualisation.qemu.options = [ - # "-nic none" - ]; - virtualisation.forwardPorts = [ - { from = "host"; host.port = 2222; guest.port = 22; } - ]; - }; + environment.variables.KIOSK_FLAKE = "${self}"; environment.etc."nix/netrc" = { text = '' @@ -55,30 +51,33 @@ in mode = "0400"; }; - nix.extraOptions = '' - netrc-file = /etc/nix/netrc - ''; - networking.networkmanager.enable = true; - systemd.services.NetworkManager-wait-online.enable = false; + ############################################################ + # User configuration + ############################################################ - nix.settings.connect-timeout = 0; + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook" + ]; + + ############################################################ + # Service configuration + ############################################################ services.openssh.enable = true; - users.users.root.openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB4vXx7sOOVAyxdS/N1LEI+L8wYICf+gbzs6Kz7K8Je5 cnclack@pm.me:Thinkpad" - ]; + systemd.services.NetworkManager-wait-online.enable = false; systemd.services.zero-touch-install = { description = "Zero-Touch Kiosk Installation"; wantedBy = [ "multi-user.target" ]; - # 🔧 FIX: remove runtime network dependency - wants = [ ]; - after = [ "systemd-udev-settle.service" ]; + # Make sure we own tty1 exclusively - getty@tty1 will otherwise + # try to spawn a login prompt on the same console. + conflicts = [ "getty@tty1.service" ]; + after = [ "systemd-udev-settle.service" "getty@tty1.service" ]; path = with pkgs; [ nix @@ -98,15 +97,22 @@ in DISKO_SCRIPT = "${diskoScript}"; }; + serviceConfig = { + StandardInput = "tty"; + StandardOutput = "tty"; + StandardError = "tty"; + TTYPath = "/dev/tty1"; + TTYReset = true; + TTYVHangup = true; + TTYVTDisallocate = true; + }; + script = '' set -euo pipefail - DISK=/dev/vda - echo "Running disko script..." echo "Script: $DISKO_SCRIPT" - # 🔧 FIX: use prebuilt script instead of runtime disko eval ${diskoScript} echo "Installing RadiantWave" @@ -119,10 +125,9 @@ in echo "============================================" echo " Installation complete!" - echo " Rebooting in 5 seconds..." + echo " Please shut down and remove the flash drive before restarting" echo "============================================" - sleep 5 - systemctl reboot --force + sleep 10000000 ''; }; } \ No newline at end of file