nixos/jack: init
This commit is contained in:
parent
bc94dcf500
commit
ea82b7f98d
@ -180,6 +180,7 @@
|
||||
./services/amqp/activemq/default.nix
|
||||
./services/amqp/rabbitmq.nix
|
||||
./services/audio/alsa.nix
|
||||
./services/audio/jack.nix
|
||||
./services/audio/icecast.nix
|
||||
./services/audio/liquidsoap.nix
|
||||
./services/audio/mpd.nix
|
||||
|
275
nixos/modules/services/audio/jack.nix
Normal file
275
nixos/modules/services/audio/jack.nix
Normal file
@ -0,0 +1,275 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.jack;
|
||||
|
||||
pcmPlugin = cfg.jackd.enable && cfg.alsa.enable;
|
||||
loopback = cfg.jackd.enable && cfg.loopback.enable;
|
||||
|
||||
enable32BitAlsaPlugins = cfg.alsa.support32Bit && pkgs.stdenv.isx86_64 && pkgs.pkgsi686Linux.alsaLib != null;
|
||||
|
||||
umaskNeeded = versionOlder cfg.jackd.package.version "1.9.12";
|
||||
bridgeNeeded = versionAtLeast cfg.jackd.package.version "1.9.12";
|
||||
in {
|
||||
options = {
|
||||
services.jack = {
|
||||
jackd = {
|
||||
enable = mkEnableOption ''
|
||||
JACK Audio Connection Kit. You need to add yourself to the "jackaudio" group
|
||||
'';
|
||||
|
||||
package = mkOption {
|
||||
# until jack1 promiscuous mode is fixed
|
||||
internal = true;
|
||||
type = types.package;
|
||||
default = pkgs.jack2;
|
||||
defaultText = "pkgs.jack2";
|
||||
example = literalExample "pkgs.jack1";
|
||||
description = ''
|
||||
The JACK package to use.
|
||||
'';
|
||||
};
|
||||
|
||||
extraOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"-dalsa"
|
||||
];
|
||||
example = literalExample ''
|
||||
[ "-dalsa" "--device" "hw:1" ];
|
||||
'';
|
||||
description = ''
|
||||
Specifies startup command line arguments to pass to JACK server.
|
||||
'';
|
||||
};
|
||||
|
||||
session = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Commands to run after JACK is started.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
alsa = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Route audio to/from generic ALSA-using applications using ALSA JACK PCM plugin.
|
||||
'';
|
||||
};
|
||||
|
||||
support32Bit = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to support sound for 32-bit ALSA applications on 64-bit system.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
loopback = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Create ALSA loopback device, instead of using PCM plugin. Has broader
|
||||
application support (things like Steam will work), but may need fine-tuning
|
||||
for concrete hardware.
|
||||
'';
|
||||
};
|
||||
|
||||
index = mkOption {
|
||||
type = types.int;
|
||||
default = 10;
|
||||
description = ''
|
||||
Index of an ALSA loopback device.
|
||||
'';
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
ALSA config for loopback device.
|
||||
'';
|
||||
};
|
||||
|
||||
session = mkOption {
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Additional commands to run to setup loopback device.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
|
||||
(mkIf pcmPlugin {
|
||||
sound.extraConfig = ''
|
||||
pcm_type.jack {
|
||||
libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_jack.so ;
|
||||
${lib.optionalString enable32BitAlsaPlugins
|
||||
"libs.32Bit = ${pkgs.pkgsi686Linux.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_jack.so ;"}
|
||||
}
|
||||
pcm.!default {
|
||||
@func getenv
|
||||
vars [ PCM ]
|
||||
default "plug:jack"
|
||||
}
|
||||
'';
|
||||
})
|
||||
|
||||
(mkIf loopback {
|
||||
boot.kernelModules = [ "snd-aloop" ];
|
||||
boot.kernelParams = [ "snd-aloop.index=${toString cfg.loopback.index}" ];
|
||||
sound.extraConfig = cfg.loopback.config;
|
||||
})
|
||||
|
||||
(mkIf cfg.jackd.enable {
|
||||
services.jack.jackd.session = ''
|
||||
${lib.optionalString bridgeNeeded "${pkgs.a2jmidid}/bin/a2jmidid -e &"}
|
||||
'';
|
||||
# https://alsa.opensrc.org/Jack_and_Loopback_device_as_Alsa-to-Jack_bridge#id06
|
||||
services.jack.loopback.config = ''
|
||||
pcm.loophw00 {
|
||||
type hw
|
||||
card ${toString cfg.loopback.index}
|
||||
device 0
|
||||
subdevice 0
|
||||
}
|
||||
pcm.amix {
|
||||
type dmix
|
||||
ipc_key 219345
|
||||
slave {
|
||||
pcm loophw00
|
||||
}
|
||||
}
|
||||
pcm.asoftvol {
|
||||
type softvol
|
||||
slave.pcm "amix"
|
||||
control { name Master }
|
||||
}
|
||||
pcm.cloop {
|
||||
type hw
|
||||
card ${toString cfg.loopback.index}
|
||||
device 1
|
||||
subdevice 0
|
||||
format S32_LE
|
||||
}
|
||||
pcm.loophw01 {
|
||||
type hw
|
||||
card ${toString cfg.loopback.index}
|
||||
device 0
|
||||
subdevice 1
|
||||
}
|
||||
pcm.ploop {
|
||||
type hw
|
||||
card ${toString cfg.loopback.index}
|
||||
device 1
|
||||
subdevice 1
|
||||
format S32_LE
|
||||
}
|
||||
pcm.aduplex {
|
||||
type asym
|
||||
playback.pcm "asoftvol"
|
||||
capture.pcm "loophw01"
|
||||
}
|
||||
pcm.!default {
|
||||
type plug
|
||||
slave.pcm aduplex
|
||||
}
|
||||
'';
|
||||
services.jack.loopback.session = ''
|
||||
alsa_in -j cloop -dcloop &
|
||||
alsa_out -j ploop -dploop &
|
||||
while [ "$(jack_lsp cloop)" == "" ] || [ "$(jack_lsp ploop)" == "" ]; do sleep 1; done
|
||||
jack_connect cloop:capture_1 system:playback_1
|
||||
jack_connect cloop:capture_2 system:playback_2
|
||||
jack_connect system:capture_1 ploop:playback_1
|
||||
jack_connect system:capture_2 ploop:playback_2
|
||||
'';
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion = !(cfg.alsa.enable && cfg.loopback.enable);
|
||||
message = "For JACK both alsa and loopback options shouldn't be used at the same time.";
|
||||
}
|
||||
];
|
||||
|
||||
users.users.jackaudio = {
|
||||
group = "jackaudio";
|
||||
extraGroups = [ "audio" ];
|
||||
description = "JACK Audio system service user";
|
||||
};
|
||||
# http://jackaudio.org/faq/linux_rt_config.html
|
||||
security.pam.loginLimits = [
|
||||
{ domain = "@jackaudio"; type = "-"; item = "rtprio"; value = "99"; }
|
||||
{ domain = "@jackaudio"; type = "-"; item = "memlock"; value = "unlimited"; }
|
||||
];
|
||||
users.groups.jackaudio = {};
|
||||
|
||||
environment = {
|
||||
systemPackages = [ cfg.jackd.package ];
|
||||
etc."alsa/conf.d/50-jack.conf".source = "${pkgs.alsaPlugins}/etc/alsa/conf.d/50-jack.conf";
|
||||
variables.JACK_PROMISCUOUS_SERVER = "jackaudio";
|
||||
};
|
||||
|
||||
services.udev.extraRules = ''
|
||||
ACTION=="add", SUBSYSTEM=="sound", ATTRS{id}!="Loopback", TAG+="systemd", ENV{SYSTEMD_WANTS}="jack.service"
|
||||
'';
|
||||
|
||||
systemd.services.jack = {
|
||||
description = "JACK Audio Connection Kit";
|
||||
serviceConfig = {
|
||||
User = "jackaudio";
|
||||
ExecStart = "${cfg.jackd.package}/bin/jackd ${lib.escapeShellArgs cfg.jackd.extraOptions}";
|
||||
LimitRTPRIO = 99;
|
||||
LimitMEMLOCK = "infinity";
|
||||
} // optionalAttrs umaskNeeded {
|
||||
UMask = "007";
|
||||
};
|
||||
path = [ cfg.jackd.package ];
|
||||
environment = {
|
||||
JACK_PROMISCUOUS_SERVER = "jackaudio";
|
||||
JACK_NO_AUDIO_RESERVATION = "1";
|
||||
};
|
||||
restartIfChanged = false;
|
||||
};
|
||||
systemd.services.jack-session = {
|
||||
description = "JACK session";
|
||||
script = ''
|
||||
jack_wait -w
|
||||
${cfg.jackd.session}
|
||||
${lib.optionalString cfg.loopback.enable cfg.loopback.session}
|
||||
'';
|
||||
serviceConfig = {
|
||||
RemainAfterExit = true;
|
||||
User = "jackaudio";
|
||||
StateDirectory = "jack";
|
||||
LimitRTPRIO = 99;
|
||||
LimitMEMLOCK = "infinity";
|
||||
};
|
||||
path = [ cfg.jackd.package ];
|
||||
environment = {
|
||||
JACK_PROMISCUOUS_SERVER = "jackaudio";
|
||||
HOME = "/var/lib/jack";
|
||||
};
|
||||
wantedBy = [ "jack.service" ];
|
||||
partOf = [ "jack.service" ];
|
||||
after = [ "jack.service" ];
|
||||
restartIfChanged = false;
|
||||
};
|
||||
})
|
||||
|
||||
];
|
||||
|
||||
meta.maintainers = [ maintainers.gnidorah ];
|
||||
}
|
Loading…
Reference in New Issue
Block a user