atagen

headroom

public
Star0
Watch0
65250d1c123cd41b77f4c598369085e0cca83f90
1
ssh://brewery@pls.lobotomise.me:33/atagen/headroom.git
flake.nixNix229 lines7.3 KB
1
{
2
  description = "automatic loudness and per-app volume control (pipewire)";
3
4
  inputs = {
5
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6
  };
7
8
  outputs =
9
    {
10
      self,
11
      nixpkgs,
12
    }:
13
    let
14
      systems = [
15
        "x86_64-linux"
16
        "aarch64-linux"
17
      ];
18
      forAllSystems = nixpkgs.lib.genAttrs systems;
19
20
      pkgsFor =
21
        system:
22
        import nixpkgs {
23
          inherit system;
24
        };
25
26
      perSystem =
27
        system:
28
        let
29
          pkgs = pkgsFor system;
30
31
          # native libs the audio crates link against
32
          nativeAudioBuildInputs = with pkgs; [
33
            pipewire
34
            pipewire.dev
35
          ];
36
37
          nativeBuildTools = with pkgs; [
38
            pkg-config
39
            clang
40
          ];
41
42
          # system libs iced (wgpu/winit/cosmic-text) compiles + dlopens at runtime.
43
          # wayland-only (x11 feature off); re-add libx11/libxcursor/libxi/libxrandr/libxcb if x11 re-enabled
44
          guiLibs = with pkgs; [
45
            vulkan-loader
46
            libxkbcommon
47
            wayland
48
            libGL
49
            fontconfig
50
          ];
51
52
          commonEnv = {
53
            LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
54
            PKG_CONFIG_PATH = "${pkgs.pipewire.dev}/lib/pkgconfig";
55
          };
56
        in
57
        {
58
          # nix develop — dev environment
59
          devShell = pkgs.mkShell (
60
            {
61
              name = "headroom-dev";
62
63
              nativeBuildInputs = nativeBuildTools ++ [
64
                pkgs.cargo
65
                pkgs.clippy
66
                pkgs.rust-analyzer
67
                pkgs.rustc
68
                pkgs.rustfmt
69
              ];
70
71
              buildInputs =
72
                nativeAudioBuildInputs
73
                ++ guiLibs
74
                ++ (with pkgs; [
75
                  socat # poke the ipc socket
76
                  jq # pretty-print json
77
                  pipewire # pw-cli, pw-cat, etc.
78
                  wireplumber
79
                ]);
80
81
              shellHook = ''
82
                echo "headroom dev shell — rustc $(rustc --version | cut -d' ' -f2)"
83
                echo "  cargo build / cargo test for iteration."
84
                echo "  nix build  .#headroom  for the packaged binary."
85
                echo "  cargo run -p headroom-gui  for the GUI (needs a display)."
86
                export RUST_BACKTRACE=1
87
                export RUST_LOG=headroom=debug,info
88
                # iced/wgpu dlopen vulkan/wayland/xkbcommon at runtime
89
                export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath guiLibs}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
90
              '';
91
            }
92
            // commonEnv
93
          );
94
95
          # nix build — packaged daemon + cli
96
          headroom = pkgs.rustPlatform.buildRustPackage (
97
            {
98
              pname = "headroom";
99
              # workspace version (per-crate manifests use version.workspace = true)
100
              version =
101
                (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.version
102
                + "-"
103
                + (toString self.lastModifiedDate);
104
105
              src = ./.;
106
107
              cargoLock = {
108
                lockFile = ./Cargo.lock;
109
                # allowBuiltinFetchGit = true;
110
              };
111
112
              nativeBuildInputs = nativeBuildTools;
113
              buildInputs = nativeAudioBuildInputs;
114
115
              # one binary: `headroom` (cli + daemon)
116
              cargoBuildFlags = [
117
                "-p"
118
                "headroom-cli"
119
              ];
120
              doCheck = true;
121
              # exclude headroom-gui from the test sweep — pulls iced's gpu stack, not part of the daemon
122
              cargoTestFlags = [
123
                "--workspace"
124
                "--exclude"
125
                "headroom-gui"
126
              ];
127
128
              # systemd user unit (@bindir@ templated to this derivation's bin, not PATH)
129
              # + canonical profiles under share/headroom/profiles (daemon finds via $XDG_DATA_DIRS)
130
              postInstall = ''
131
                install -Dm644 contrib/systemd/headroom.service \
132
                  "$out/lib/systemd/user/headroom.service"
133
                substituteInPlace "$out/lib/systemd/user/headroom.service" \
134
                  --replace-fail '@bindir@' "$out/bin"
135
136
                mkdir -p "$out/share/headroom/profiles"
137
                cp -r profiles/. "$out/share/headroom/profiles/"
138
              '';
139
140
              meta = with pkgs.lib; {
141
                description = "automatic loudness and per-app volume control (pipewire)";
142
                license = licenses.gpl3Plus;
143
                platforms = platforms.linux;
144
                mainProgram = "headroom";
145
              };
146
            }
147
            // commonEnv
148
          );
149
150
          # `nix build .#headroom-gui` — optional iced GUI monitor.
151
          # separate package so the default build stays graphics-free. iced/wgpu
152
          # dlopen vulkan/libGL/wayland/xkbcommon at runtime → wrap with LD_LIBRARY_PATH.
153
          # also ships the .desktop entry.
154
          headroom-gui = pkgs.rustPlatform.buildRustPackage (
155
            {
156
              pname = "headroom-gui";
157
              version =
158
                (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.version
159
                + "-"
160
                + (toString self.lastModifiedDate);
161
162
              src = ./.;
163
164
              cargoLock = {
165
                lockFile = ./Cargo.lock;
166
              };
167
168
              # makeWrapper for the LD_LIBRARY_PATH wrap. gui doesn't link pipewire
169
              # (talks to the daemon over the socket via headroom-client) → no pipewire/clang
170
              nativeBuildInputs = [
171
                pkgs.pkg-config
172
                pkgs.makeWrapper
173
              ];
174
              buildInputs = guiLibs;
175
176
              cargoBuildFlags = [
177
                "-p"
178
                "headroom-gui"
179
              ];
180
              # gui tests drive iced view/update; no display in the sandbox.
181
              # run them via `cargo test -p headroom-gui` in the dev shell instead
182
              doCheck = false;
183
184
              postInstall = ''
185
                install -Dm644 contrib/desktop/headroom-gui.desktop \
186
                  "$out/share/applications/headroom-gui.desktop"
187
                substituteInPlace "$out/share/applications/headroom-gui.desktop" \
188
                  --replace-fail '@bindir@' "$out/bin"
189
              '';
190
191
              postFixup = ''
192
                wrapProgram "$out/bin/headroom-gui" \
193
                  --prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath guiLibs}"
194
              '';
195
196
              meta = with pkgs.lib; {
197
                description = "automatic loudness and per-app volume control (pipewire)";
198
                license = licenses.eupl12;
199
                platforms = platforms.linux;
200
                mainProgram = "headroom-gui";
201
              };
202
            }
203
            // commonEnv
204
          );
205
        };
206
    in
207
    {
208
      devShells = forAllSystems (system: {
209
        default = (perSystem system).devShell;
210
      });
211
212
      packages = forAllSystems (
213
        system:
214
        let
215
          ps = perSystem system;
216
        in
217
        rec {
218
          default = headroom;
219
          headroom = ps.headroom;
220
          headroom-gui = ps.headroom-gui;
221
        }
222
      );
223
224
      formatter = forAllSystems (system: (pkgsFor system).nixpkgs-fmt);
225
226
      # System-independent outputs — modules.
227
      nixosModules.default = import ./nix/nixos-module.nix self;
228
    };
229
}