{ config, pkgs, lib, ... }: { environment.systemPackages = with pkgs; [ pipewire wireplumber alsa-utils pulseaudio pamixer pavucontrol ]; services.pipewire = { enable = true; alsa.enable = true; alsa.support32Bit = true; pulse.enable = true; jack.enable = true; wireplumber.enable = true; }; security.rtkit.enable = true; # Helps on many laptops (Intel SOF etc.) hardware.enableRedistributableFirmware = true; # Prefer analog over HDMI/DP in a machine-agnostic way services.pipewire.wireplumber.extraConfig."51-audio-priorities" = { "monitor.alsa.rules" = [ # De-prioritize HDMI / DisplayPort sinks { matches = [ { "node.name" = "~alsa_output\\..*HDMI.*"; } { "node.name" = "~alsa_output\\..*DisplayPort.*"; } ]; actions.update-props = { "priority.session" = 100; "priority.driver" = 100; }; } # Prefer analog sinks (speakers/headphones) { matches = [ { "node.name" = "~alsa_output\\..*analog.*"; } { "node.name" = "~alsa_output\\..*Headphones.*"; } { "node.name" = "~alsa_output\\..*Speaker.*"; } ]; actions.update-props = { "priority.session" = 2000; "priority.driver" = 2000; }; } ]; }; # Optional: clear "sticky" user-selected defaults so priority rules win systemd.user.services.wireplumber-clear-default-nodes = { description = "Clear WirePlumber saved default nodes (avoid HDMI becoming sticky)"; after = [ "wireplumber.service" ]; partOf = [ "wireplumber.service" ]; wantedBy = [ "default.target" ]; serviceConfig = { Type = "oneshot"; ExecStart = "${pkgs.coreutils}/bin/rm -f %h/.local/state/wireplumber/default-nodes"; }; }; }