python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / audio / jack.nix
blob105e99cb2f5ed1137fc050be1413d00298c70199
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.jack;
8   pcmPlugin = cfg.jackd.enable && cfg.alsa.enable;
9   loopback = cfg.jackd.enable && cfg.loopback.enable;
11   enable32BitAlsaPlugins = cfg.alsa.support32Bit && pkgs.stdenv.isx86_64 && pkgs.pkgsi686Linux.alsa-lib != null;
13   umaskNeeded = versionOlder cfg.jackd.package.version "1.9.12";
14   bridgeNeeded = versionAtLeast cfg.jackd.package.version "1.9.12";
15 in {
16   options = {
17     services.jack = {
18       jackd = {
19         enable = mkEnableOption (lib.mdDoc ''
20           JACK Audio Connection Kit. You need to add yourself to the "jackaudio" group
21         '');
23         package = mkOption {
24           # until jack1 promiscuous mode is fixed
25           internal = true;
26           type = types.package;
27           default = pkgs.jack2;
28           defaultText = literalExpression "pkgs.jack2";
29           example = literalExpression "pkgs.jack1";
30           description = lib.mdDoc ''
31             The JACK package to use.
32           '';
33         };
35         extraOptions = mkOption {
36           type = types.listOf types.str;
37           default = [
38             "-dalsa"
39           ];
40           example = literalExpression ''
41             [ "-dalsa" "--device" "hw:1" ];
42           '';
43           description = lib.mdDoc ''
44             Specifies startup command line arguments to pass to JACK server.
45           '';
46         };
48         session = mkOption {
49           type = types.lines;
50           description = lib.mdDoc ''
51             Commands to run after JACK is started.
52           '';
53         };
55       };
57       alsa = {
58         enable = mkOption {
59           type = types.bool;
60           default = true;
61           description = lib.mdDoc ''
62             Route audio to/from generic ALSA-using applications using ALSA JACK PCM plugin.
63           '';
64         };
66         support32Bit = mkOption {
67           type = types.bool;
68           default = false;
69           description = lib.mdDoc ''
70             Whether to support sound for 32-bit ALSA applications on 64-bit system.
71           '';
72         };
73       };
75       loopback = {
76         enable = mkOption {
77           type = types.bool;
78           default = false;
79           description = lib.mdDoc ''
80             Create ALSA loopback device, instead of using PCM plugin. Has broader
81             application support (things like Steam will work), but may need fine-tuning
82             for concrete hardware.
83           '';
84         };
86         index = mkOption {
87           type = types.int;
88           default = 10;
89           description = lib.mdDoc ''
90             Index of an ALSA loopback device.
91           '';
92         };
94         config = mkOption {
95           type = types.lines;
96           description = lib.mdDoc ''
97             ALSA config for loopback device.
98           '';
99         };
101         dmixConfig = mkOption {
102           type = types.lines;
103           default = "";
104           example = ''
105             period_size 2048
106             periods 2
107           '';
108           description = lib.mdDoc ''
109             For music production software that still doesn't support JACK natively you
110             would like to put buffer/period adjustments here
111             to decrease dmix device latency.
112           '';
113         };
115         session = mkOption {
116           type = types.lines;
117           description = lib.mdDoc ''
118             Additional commands to run to setup loopback device.
119           '';
120         };
121       };
123     };
125   };
127   config = mkMerge [
129     (mkIf pcmPlugin {
130       sound.extraConfig = ''
131         pcm_type.jack {
132           libs.native = ${pkgs.alsa-plugins}/lib/alsa-lib/libasound_module_pcm_jack.so ;
133           ${lib.optionalString enable32BitAlsaPlugins
134           "libs.32Bit = ${pkgs.pkgsi686Linux.alsa-plugins}/lib/alsa-lib/libasound_module_pcm_jack.so ;"}
135         }
136         pcm.!default {
137           @func getenv
138           vars [ PCM ]
139           default "plug:jack"
140         }
141       '';
142     })
144     (mkIf loopback {
145       boot.kernelModules = [ "snd-aloop" ];
146       boot.kernelParams = [ "snd-aloop.index=${toString cfg.loopback.index}" ];
147       sound.extraConfig = cfg.loopback.config;
148     })
150     (mkIf cfg.jackd.enable {
151       services.jack.jackd.session = ''
152         ${lib.optionalString bridgeNeeded "${pkgs.a2jmidid}/bin/a2jmidid -e &"}
153       '';
154       # https://alsa.opensrc.org/Jack_and_Loopback_device_as_Alsa-to-Jack_bridge#id06
155       services.jack.loopback.config = ''
156         pcm.loophw00 {
157           type hw
158           card ${toString cfg.loopback.index}
159           device 0
160           subdevice 0
161         }
162         pcm.amix {
163           type dmix
164           ipc_key 219345
165           slave {
166             pcm loophw00
167             ${cfg.loopback.dmixConfig}
168           }
169         }
170         pcm.asoftvol {
171           type softvol
172           slave.pcm "amix"
173           control { name Master }
174         }
175         pcm.cloop {
176           type hw
177           card ${toString cfg.loopback.index}
178           device 1
179           subdevice 0
180           format S32_LE
181         }
182         pcm.loophw01 {
183           type hw
184           card ${toString cfg.loopback.index}
185           device 0
186           subdevice 1
187         }
188         pcm.ploop {
189           type hw
190           card ${toString cfg.loopback.index}
191           device 1
192           subdevice 1
193           format S32_LE
194         }
195         pcm.aduplex {
196           type asym
197           playback.pcm "asoftvol"
198           capture.pcm "loophw01"
199         }
200         pcm.!default {
201           type plug
202           slave.pcm aduplex
203         }
204       '';
205       services.jack.loopback.session = ''
206         alsa_in -j cloop -dcloop &
207         alsa_out -j ploop -dploop &
208         while [ "$(jack_lsp cloop)" == "" ] || [ "$(jack_lsp ploop)" == "" ]; do sleep 1; done
209         jack_connect cloop:capture_1 system:playback_1
210         jack_connect cloop:capture_2 system:playback_2
211         jack_connect system:capture_1 ploop:playback_1
212         jack_connect system:capture_2 ploop:playback_2
213       '';
215       assertions = [
216         {
217           assertion = !(cfg.alsa.enable && cfg.loopback.enable);
218           message = "For JACK both alsa and loopback options shouldn't be used at the same time.";
219         }
220       ];
222       users.users.jackaudio = {
223         group = "jackaudio";
224         extraGroups = [ "audio" ];
225         description = "JACK Audio system service user";
226         isSystemUser = true;
227       };
228       # http://jackaudio.org/faq/linux_rt_config.html
229       security.pam.loginLimits = [
230         { domain = "@jackaudio"; type = "-"; item = "rtprio"; value = "99"; }
231         { domain = "@jackaudio"; type = "-"; item = "memlock"; value = "unlimited"; }
232       ];
233       users.groups.jackaudio = {};
235       environment = {
236         systemPackages = [ cfg.jackd.package ];
237         etc."alsa/conf.d/50-jack.conf".source = "${pkgs.alsa-plugins}/etc/alsa/conf.d/50-jack.conf";
238         variables.JACK_PROMISCUOUS_SERVER = "jackaudio";
239       };
241       services.udev.extraRules = ''
242         ACTION=="add", SUBSYSTEM=="sound", ATTRS{id}!="Loopback", TAG+="systemd", ENV{SYSTEMD_WANTS}="jack.service"
243       '';
245       systemd.services.jack = {
246         description = "JACK Audio Connection Kit";
247         serviceConfig = {
248           User = "jackaudio";
249           SupplementaryGroups = lib.optional
250             (config.hardware.pulseaudio.enable
251             && !config.hardware.pulseaudio.systemWide) "users";
252           ExecStart = "${cfg.jackd.package}/bin/jackd ${lib.escapeShellArgs cfg.jackd.extraOptions}";
253           LimitRTPRIO = 99;
254           LimitMEMLOCK = "infinity";
255         } // optionalAttrs umaskNeeded {
256           UMask = "007";
257         };
258         path = [ cfg.jackd.package ];
259         environment = {
260           JACK_PROMISCUOUS_SERVER = "jackaudio";
261           JACK_NO_AUDIO_RESERVATION = "1";
262         };
263         restartIfChanged = false;
264       };
265       systemd.services.jack-session = {
266         description = "JACK session";
267         script = ''
268           jack_wait -w
269           ${cfg.jackd.session}
270           ${lib.optionalString cfg.loopback.enable cfg.loopback.session}
271         '';
272         serviceConfig = {
273           RemainAfterExit = true;
274           User = "jackaudio";
275           StateDirectory = "jack";
276           LimitRTPRIO = 99;
277           LimitMEMLOCK = "infinity";
278         };
279         path = [ cfg.jackd.package ];
280         environment = {
281           JACK_PROMISCUOUS_SERVER = "jackaudio";
282           HOME = "/var/lib/jack";
283         };
284         wantedBy = [ "jack.service" ];
285         partOf = [ "jack.service" ];
286         after = [ "jack.service" ];
287         restartIfChanged = false;
288       };
289     })
291   ];
293   meta.maintainers = [ ];