{ pkgs, ... }: let linkSinksScript = pkgs.writeShellApplication { name = "link-virtual-sinks"; runtimeInputs = with pkgs; [ coreutils gnugrep pipewire ]; runtimeEnv = { USB_C_SINK = "alsa_output.usb-HP__Inc_HyperX_Cloud_III_Wireless_0000000000000000-00.analog-stereo"; }; text = builtins.readFile ./linkSinks.sh; }; nullSink = name: { factory = "adapter"; args = { "factory.name" = "support.null-audio-sink"; "node.name" = name; "node.description" = name; "media.class" = "Audio/Sink"; "audio.position" = "FL,FR"; "monitor.channel-volumes" = true; }; }; in { services.pulseaudio.enable = false; security.rtkit.enable = true; services.pipewire = { enable = true; alsa.enable = true; alsa.support32Bit = true; pulse.enable = true; jack.enable = true; # disable automatic gain control for specific apps extraConfig.pipewire-pulse."10-block-source-volume.conf"."pulse.rules" = [ { matches = [ { "application.name" = "~Chromium.*"; } { "application.process.binary" = "Discord"; } { "application.process.binary" = "vesktop"; } # TODO: add element to this list ]; actions.quirks = [ "block-source-volume" ]; } ]; extraConfig.pipewire."91-virtual-sinks"."context.objects" = [ (nullSink "game") (nullSink "clementine") (nullSink "element") (nullSink "combine") ]; wireplumber.extraConfig."91-default-sink" = { "wireplumber.settings" = { "default.audio.sink" = "combine"; }; }; }; programs.nix-ld.libraries = [ pkgs.pipewire ]; systemd.user.services.link-virtual-sinks = { description = "Link virtual PipeWire sinks"; wantedBy = [ "graphical-session.target" ]; requires = [ "pipewire.service" "wireplumber.service" ]; after = [ "pipewire.service" "wireplumber.service" ]; serviceConfig = { Type = "simple"; ExecStart = "${linkSinksScript}/bin/link-virtual-sinks"; RemainAfterExit = true; }; }; users.users.djai.packages = with pkgs; [ pulseaudio pavucontrol pipewire qpwgraph alsa-utils ]; }