summaryrefslogtreecommitdiff
path: root/custom/trivmix-service.nix
blob: 6a50224db165578f992666137ddf0d07a04895c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.trivmix;

  mixerModule = {
    connectIn = mkOption {
      type = with types; either str (listOf str);
      default = [];
      description = "Ports to connect mixer input to";
    };

    connectOut = mkOption {
      type = with types; either str (listOf str);
      default = [];
      description = "Ports to connect mixer output to";
    };

    onConnect = mkOption {
      type = types.lines;
      default = "";
      description = "Additional shell commands to run after connections are set up";
    };

    adjustable = mkOption {
      type = types.bool;
      default = true;
      description = "Should the volume on this mixer be adjustable?";
    };

    group = mkOption {
      type = types.nullOr types.str;
      default = null;
      description = "Volumes of mixers that share a group name are synchronised";
    };

    initial = mkOption {
      type = types.str;
      default = "1";
      description = "Initial volume";
    };
  };

  service = name: mixerCfg: let
    connectIn = if isList mixerCfg.connectIn then mixerCfg.connectIn else singleton mixerCfg.connectIn;
    connectOut = if isList mixerCfg.connectOut then mixerCfg.connectOut else singleton mixerCfg.connectOut;

    inherit (mixerCfg) onConnect adjustable group initial;
  
    connectScript = ''
      #!${pkgs.stdenv.shell}

      ${concatMapStringsSep "\n" (port: "jack_connect ${port} $1") connectIn}
      ${concatMapStringsSep "\n" (port: "jack_connect $2 ${port}") connectOut}
      ${onConnect}
    '';

    connect = (connectOut != []) || (connectIn != []) || (onConnect != []);

    mixerDeps = filter (x: any (hasPrefix (x + ":")) connectIn || any (hasPrefix (x + ":")) connectOut) (attrNames cfg);
  in {
    wantedBy = [ "sound.target" ];
    requires = [ "jack.service" ] ++ map (n: n + ".service") mixerDeps;
    path = with pkgs; [ jack2Full ];
    serviceConfig = {
      Type = "simple";
      ExecStart = ''${pkgs.trivmix}/bin/trivmix --client ${name} \
        ${optionalString connect "--run ${connectScript}"} \
        "--level ${initial}" \
        ${optionalString (adjustable && isNull group) "/dev/shm/mix/${name}/level"} \
        ${optionalString (! isNull group) "/dev/shm/mix/${group}/level"}
      '';
      User = "jack";
      Group = "audio";
      Nice = "-10";
      LimitRTPRIO = "95:95";
      LimitMEMLOCK = "infinity";
    };
  };
in {
  options.services.trivmix = mkOption {
    type = types.attrsOf (types.submodule mixerModule);
    default = {};
    description = "Definition of mixers";
  };

  config.systemd.services = mapAttrs service cfg;
}