···936936937937If you set `sound.enable` in your configuration:
938938 - If you are using Pulseaudio or PipeWire, simply remove that option
939939- - If you are using ALSA as your only sound system (no sound server), set `hardware.alsa.enable = true` instead
939939+ - If you are not using an external sound server, and want volumes to be persisted across shutdowns, set `hardware.alsa.enablePersistence = true` instead
940940941941If you set `sound.enableOSSEmulation` in your configuration:
942942 - Make sure it is still necessary, as very few applications actually use OSS
943943- - If necessary, set `hardware.alsa.enableOSSEmulation = true`
943943+ - If necessary, set `boot.kernelModules = [ "snd_pcm_oss" ]`
944944945945If you set `sound.extraConfig` in your configuration:
946946- - If you are using a sound server, like Pulseaudio, JACK or PipeWire, migrate your configuration to that
947947- - If you are using ALSA as your only sound system, check if you can use the new structured ALSA options `hardware.alsa.defaultDevice`, `hardware.alsa.cardAliases`, `hardware.alsa.controls`, etc.
948948- - Otherwise, move your configuration directly into `hardware.alsa.config`
946946+ - If you are using another sound server, like Pulseaudio, JACK or PipeWire, migrate your configuration to that
947947+ - If you are not using an external sound server, set `environment.etc."asound.conf".text = yourExtraConfig` instead
949948950949If you set `sound.mediaKeys` in your configuration:
951950 - Preferably switch to handling media keys in your desktop environment/compositor
+3
nixos/doc/manual/release-notes/rl-2505.section.md
···375375- The paperless module now has an option for regular automatic export of
376376 documents data using the integrated document exporter.
377377378378+- New options for the declarative configuration of the user space part of ALSA have been introduced under [hardware.alsa](options.html#opt-hardware.alsa.enable), including setting the default capture and playback device, defining sound card aliases and volume controls.
379379+ Note: these are intended for users not running a sound server like PulseAudio or PipeWire, but having ALSA as their only sound system.
380380+378381- Caddy can now be built with plugins by using `caddy.withPlugins`, a `passthru` function that accepts an attribute set as a parameter. The `plugins` argument represents a list of Caddy plugins, with each Caddy plugin being a versioned module. The `hash` argument represents the `vendorHash` of the resulting Caddy source code with the plugins added.
379382380383 Example:
+150-130
nixos/modules/services/audio/alsa.nix
···8686 [ "sound" "enableOSSEmulation" ]
8787 [ "hardware" "alsa" "enableOSSEmulation" ]
8888 )
8989- (lib.mkRenamedOptionModule
9090- [ "sound" "extraConfig" ]
9191- [ "hardware" "alsa" "config" ])
8989+ (lib.mkRenamedOptionModule [ "sound" "extraConfig" ] [ "hardware" "alsa" "config" ])
9290 ];
93919492 options.hardware.alsa = {
···191189 };
192190 })
193191 );
194194- default = {};
192192+ default = { };
195193 example = lib.literalExpression ''
196194 {
197195 firefox = { device = "front"; maxVolume = -25.0; };
···286284287285 };
288286289289- config = lib.mkIf cfg.enable {
287287+ options.hardware.alsa.enablePersistence = lib.mkOption {
288288+ type = lib.types.bool;
289289+ defaultText = lib.literalExpression "config.hardware.alsa.enable";
290290+ default = config.hardware.alsa.enable;
291291+ description = ''
292292+ Whether to enable ALSA sound card state saving on shutdown.
293293+ This is generally not necessary if you're using an external sound server.
294294+ '';
295295+ };
290296291291- # Disable sound servers enabled by default and,
292292- # if the user enabled one manually, cause a conflict.
293293- services.pipewire.enable = false;
294294- hardware.pulseaudio.enable = false;
297297+ config = lib.mkMerge [
295298296296- hardware.alsa.config =
297297- let
298298- conf = [
299299- ''
300300- pcm.!default fromenv
299299+ (lib.mkIf cfg.enable {
300300+ # Disable sound servers enabled by default and,
301301+ # if the user enabled one manually, cause a conflict.
302302+ services.pipewire.enable = false;
303303+ services.pulseaudio.enable = false;
301304302302- # Read the capture and playback device from
303303- # the ALSA_AUDIO_IN, ALSA_AUDIO_OUT variables
304304- pcm.fromenv {
305305- type asym
306306- playback.pcm {
307307- type plug
308308- slave.pcm {
309309- @func getenv
310310- vars [ ALSA_AUDIO_OUT ]
311311- default pcm.sysdefault
305305+ hardware.alsa.config =
306306+ let
307307+ conf = [
308308+ ''
309309+ pcm.!default fromenv
310310+311311+ # Read the capture and playback device from
312312+ # the ALSA_AUDIO_IN, ALSA_AUDIO_OUT variables
313313+ pcm.fromenv {
314314+ type asym
315315+ playback.pcm {
316316+ type plug
317317+ slave.pcm {
318318+ @func getenv
319319+ vars [ ALSA_AUDIO_OUT ]
320320+ default pcm.sysdefault
321321+ }
312322 }
313313- }
314314- capture.pcm {
315315- type plug
316316- slave.pcm {
317317- @func getenv
318318- vars [ ALSA_AUDIO_IN ]
319319- default pcm.sysdefault
323323+ capture.pcm {
324324+ type plug
325325+ slave.pcm {
326326+ @func getenv
327327+ vars [ ALSA_AUDIO_IN ]
328328+ default pcm.sysdefault
329329+ }
320330 }
321331 }
322322- }
323323- ''
324324- (lib.optional cfg.enableRecorder ''
325325- pcm.!default "splitter:fromenv,recorder"
332332+ ''
333333+ (lib.optional cfg.enableRecorder ''
334334+ pcm.!default "splitter:fromenv,recorder"
326335327327- # Send audio to two stereo devices
328328- pcm.splitter {
329329- @args [ A B ]
330330- @args.A.type string
331331- @args.B.type string
332332- type asym
333333- playback.pcm {
334334- type plug
335335- route_policy "duplicate"
336336- slave.pcm {
337337- type multi
338338- slaves.a.pcm $A
339339- slaves.b.pcm $B
340340- slaves.a.channels 2
341341- slaves.b.channels 2
342342- bindings [
343343- { slave a channel 0 }
344344- { slave a channel 1 }
345345- { slave b channel 0 }
346346- { slave b channel 1 }
347347- ]
336336+ # Send audio to two stereo devices
337337+ pcm.splitter {
338338+ @args [ A B ]
339339+ @args.A.type string
340340+ @args.B.type string
341341+ type asym
342342+ playback.pcm {
343343+ type plug
344344+ route_policy "duplicate"
345345+ slave.pcm {
346346+ type multi
347347+ slaves.a.pcm $A
348348+ slaves.b.pcm $B
349349+ slaves.a.channels 2
350350+ slaves.b.channels 2
351351+ bindings [
352352+ { slave a channel 0 }
353353+ { slave a channel 1 }
354354+ { slave b channel 0 }
355355+ { slave b channel 1 }
356356+ ]
357357+ }
348358 }
359359+ capture.pcm $A
349360 }
350350- capture.pcm $A
351351- }
352361353353- # Device which records and plays back audio
354354- pcm.recorder {
355355- type asym
356356- capture.pcm {
357357- type dsnoop
358358- ipc_key 9165218
359359- ipc_perm 0666
360360- slave.pcm "hw:loopback,1,0"
361361- slave.period_size 1024
362362- slave.buffer_size 8192
363363- }
364364- playback.pcm {
365365- type dmix
366366- ipc_key 6181923
367367- ipc_perm 0666
368368- slave.pcm "hw:loopback,0,0"
369369- slave.period_size 1024
370370- slave.buffer_size 8192
362362+ # Device which records and plays back audio
363363+ pcm.recorder {
364364+ type asym
365365+ capture.pcm {
366366+ type dsnoop
367367+ ipc_key 9165218
368368+ ipc_perm 0666
369369+ slave.pcm "hw:loopback,1,0"
370370+ slave.period_size 1024
371371+ slave.buffer_size 8192
372372+ }
373373+ playback.pcm {
374374+ type dmix
375375+ ipc_key 6181923
376376+ ipc_perm 0666
377377+ slave.pcm "hw:loopback,0,0"
378378+ slave.period_size 1024
379379+ slave.buffer_size 8192
380380+ }
371381 }
372372- }
373373- '')
374374- (lib.mapAttrsToList mkControl cfg.controls)
375375- (lib.mapAttrsToList (n: v: "pcm.${n} ${quote v}") cfg.deviceAliases)
376376- ];
377377- in
378378- lib.mkBefore (lib.concatStringsSep "\n" (lib.flatten conf));
382382+ '')
383383+ (lib.mapAttrsToList mkControl cfg.controls)
384384+ (lib.mapAttrsToList (n: v: "pcm.${n} ${quote v}") cfg.deviceAliases)
385385+ ];
386386+ in
387387+ lib.mkBefore (lib.concatStringsSep "\n" (lib.flatten conf));
379388380380- hardware.alsa.cardAliases = lib.mkIf cfg.enableRecorder {
381381- loopback.driver = "snd_aloop";
382382- loopback.id = 2;
383383- };
389389+ hardware.alsa.cardAliases = lib.mkIf cfg.enableRecorder {
390390+ loopback.driver = "snd_aloop";
391391+ loopback.id = 2;
392392+ };
384393385385- # Set default PCM devices
386386- environment.sessionVariables = defaultDeviceVars;
387387- systemd.globalEnvironment = defaultDeviceVars;
394394+ # Set default PCM devices
395395+ environment.sessionVariables = defaultDeviceVars;
396396+ systemd.globalEnvironment = defaultDeviceVars;
388397389389- environment.etc."asound.conf".text = cfg.config;
398398+ environment.etc."asound.conf".text = cfg.config;
390399391391- boot.kernelModules =
392392- [ ]
393393- ++ lib.optionals cfg.enableOSSEmulation [ "snd_pcm_oss" "snd_mixer_oss" ]
394394- ++ lib.optionals cfg.enableRecorder [ "snd_aloop" ];
400400+ boot.kernelModules =
401401+ [ ]
402402+ ++ lib.optionals cfg.enableOSSEmulation [
403403+ "snd_pcm_oss"
404404+ "snd_mixer_oss"
405405+ ]
406406+ ++ lib.optionals cfg.enableRecorder [ "snd_aloop" ];
395407396396- # Assign names to the sound cards
397397- boot.extraModprobeConfig = lib.concatStringsSep "\n" cardsConfig;
408408+ # Assign names to the sound cards
409409+ boot.extraModprobeConfig = lib.concatStringsSep "\n" cardsConfig;
398410399399- # Provide alsamixer, aplay, arecord, etc.
400400- environment.systemPackages = [ pkgs.alsa-utils ];
411411+ # Provide alsamixer, aplay, arecord, etc.
412412+ environment.systemPackages = [ pkgs.alsa-utils ];
413413+ })
401414402402- # Install udev rules for restoring card settings on boot
403403- services.udev.extraRules = ''
404404- ACTION=="add", SUBSYSTEM=="sound", KERNEL=="controlC*", KERNELS!="card*", GOTO="alsa_restore_go"
405405- GOTO="alsa_restore_end"
415415+ (lib.mkIf config.hardware.alsa.enablePersistence {
406416407407- LABEL="alsa_restore_go"
408408- TEST!="/etc/alsa/state-daemon.conf", RUN+="${alsactl} restore -gU $attr{device/number}"
409409- TEST=="/etc/alsa/state-daemon.conf", RUN+="${alsactl} nrestore -gU $attr{device/number}"
410410- LABEL="alsa_restore_end"
411411- '';
417417+ # Install udev rules for restoring card settings on boot
418418+ services.udev.extraRules = ''
419419+ ACTION=="add", SUBSYSTEM=="sound", KERNEL=="controlC*", KERNELS!="card*", GOTO="alsa_restore_go"
420420+ GOTO="alsa_restore_end"
412421413413- # Service to store/restore the sound card settings
414414- systemd.services.alsa-store = {
415415- description = "Store Sound Card State";
416416- wantedBy = [ "multi-user.target" ];
417417- restartIfChanged = false;
418418- unitConfig = {
419419- RequiresMountsFor = "/var/lib/alsa";
420420- ConditionVirtualization = "!systemd-nspawn";
421421- };
422422- serviceConfig = {
423423- Type = "oneshot";
424424- RemainAfterExit = true;
425425- StateDirectory = "alsa";
426426- # Note: the service should never be restated, otherwise any
427427- # setting changed between the last `store` and now will be lost.
428428- # To prevent NixOS from starting it in case it has failed we
429429- # expand the exit codes considered successful
430430- SuccessExitStatus = [ 0 99 ];
431431- ExecStart = "${alsactl} restore -gU";
432432- ExecStop = "${alsactl} store -gU";
422422+ LABEL="alsa_restore_go"
423423+ TEST!="/etc/alsa/state-daemon.conf", RUN+="${alsactl} restore -gU $attr{device/number}"
424424+ TEST=="/etc/alsa/state-daemon.conf", RUN+="${alsactl} nrestore -gU $attr{device/number}"
425425+ LABEL="alsa_restore_end"
426426+ '';
427427+428428+ # Service to store/restore the sound card settings
429429+ systemd.services.alsa-store = {
430430+ description = "Store Sound Card State";
431431+ wantedBy = [ "multi-user.target" ];
432432+ restartIfChanged = false;
433433+ unitConfig = {
434434+ RequiresMountsFor = "/var/lib/alsa";
435435+ ConditionVirtualization = "!systemd-nspawn";
436436+ };
437437+ serviceConfig = {
438438+ Type = "oneshot";
439439+ RemainAfterExit = true;
440440+ StateDirectory = "alsa";
441441+ # Note: the service should never be restated, otherwise any
442442+ # setting changed between the last `store` and now will be lost.
443443+ # To prevent NixOS from starting it in case it has failed we
444444+ # expand the exit codes considered successful
445445+ SuccessExitStatus = [
446446+ 0
447447+ 99
448448+ ];
449449+ ExecStart = "${alsactl} restore -gU";
450450+ ExecStop = "${alsactl} store -gU";
451451+ };
433452 };
434434- };
435435- };
453453+ })
454454+455455+ ];
436456437457 meta.maintainers = with lib.maintainers; [ rnhmjoj ];
438458