{ config, lib, pkgs, ... }: { options.c3d2.audioServer = { enable = lib.mkEnableOption "Enable PulseAudio and Bluetooth sinks"; }; config = lib.mkIf config.c3d2.audioServer.enable { environment.systemPackages = with pkgs; [ mpd mpv ncmpcpp ncpamixer pulseaudio # required for pactl ]; hardware = { bluetooth.settings = { Policy.AutoEnable = true; General.DiscoverableTimeout = 0; }; pulseaudio = { enable = !config.services.pipewire.pulse.enable; systemWide = true; tcp = { enable = true; anonymousClients.allowedIpRanges = [ "127.0.0.0/8" "::1/128" "fd23:42:c3d2:500::/56" "172.22.99.0/24" "172.20.72.0/21" "2a00:8180:2c00:200::/56" "2a0f:5382:acab:1400::/56" ]; }; zeroconf.publish.enable = true; package = (pkgs.pulseaudio.override { bluetoothSupport = true; advancedBluetoothCodecs = true; zeroconfSupport = true; }).overrideAttrs (_: { # one test times out doCheck = false; }); }; }; networking.firewall = { allowedTCPPorts = [ 80 # ledfx 4713 # pulseaudio/pipewire network sync ]; allowedUDPPorts = [ 5353 # mdns ]; }; nixpkgs.overlays = [ (final: prev: { python3 = prev.python3.override { packageOverrides = python-final: python-prev: { aiohttp = python-prev.aiohttp.overrideAttrs ({ nativeBuildInputs ? [],... }: { nativeBuildInputs = nativeBuildInputs ++ [python-final.setuptools]; doCheck = false; doInstallCheck = false; }); pystray = python-prev.pystray.overrideAttrs (_: { doCheck = false; doInstallCheck = false; }); samplerate = python-prev.samplerate.overrideAttrs (_: { dontUseSetuptoolsCheck = true; }); }; }; python3Packages = final.python3.pkgs; }) ]; security.rtkit.enable = true; services.pipewire = { enable = true; alsa.enable = true; # required for ledfx config.pipewire-pulse = let default-pipewire-pulse = lib.importJSON (pkgs.path + "/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json"); in default-pipewire-pulse // { "context.exec" = default-pipewire-pulse."context.exec" ++ [ { "path" = "pactl"; "args" = "load-module module-zeroconf-publish"; } ]; "pulse.properties" = { "auth-ip-acl" = [ "127.0.0.0/8" "::1/128" "fd23:42:c3d2:500::/56" "172.22.99.0/24" "172.20.72.0/21" "2a00:8180:2c00:200::/56" "2a0f:5382:acab:1400::/56" ]; "server.address" = [ "unix:native" "tcp:4713" ]; }; }; pulse.enable = true; }; # tell Avahi to publish services like Pipewire/PulseAudio services.avahi = { enable = true; nssmdns = true; publish = { enable = true; addresses = true; userServices = true; }; }; sound.enable = true; system.activationScripts.enableLingering = lib.optionalString config.services.pipewire.pulse.enable ('' rm -r /var/lib/systemd/linger mkdir /var/lib/systemd/linger '' + lib.optionalString config.c3d2.k-ot.enable '' touch /var/lib/systemd/linger/k-ot ''); systemd = { services.bluetooth-agent = lib.mkIf config.hardware.bluetooth.enable { description = "Allow anyone to pair via Bluetooth"; wantedBy = [ "multi-user.target" ]; requires = [ "bluetooth.target" ]; after = [ "bluetooth.service" ]; serviceConfig = { Type = "simple"; ExecStart = "${pkgs.bluez-tools}/bin/bt-agent -c NoInputNoOutput"; Restart = "on-failure"; RestartSec = 60; }; }; user.services.ledfx = { after = [ "pipewire.target" ]; wantedBy = [ "default.target" ]; serviceConfig = { ExecStart = "${pkgs.ledfx}/bin/ledfx"; }; }; }; users = { groups.pulse-access = { }; users.k-ot = lib.mkIf config.c3d2.k-ot.enable { extraGroups = [ "pipewire" "pulse-access" # required for system wide pulseaudio "rtkit" ]; packages = with pkgs; [ (yt-dlp.override { withAlias = true; }) ]; }; }; }; }