···936937If you set `sound.enable` in your configuration:
938 - If you are using Pulseaudio or PipeWire, simply remove that option
939- - If you are using ALSA as your only sound system (no sound server), set `hardware.alsa.enable = true` instead
940941If you set `sound.enableOSSEmulation` in your configuration:
942 - Make sure it is still necessary, as very few applications actually use OSS
943- - If necessary, set `hardware.alsa.enableOSSEmulation = true`
944945If you set `sound.extraConfig` in your configuration:
946- - If you are using a sound server, like Pulseaudio, JACK or PipeWire, migrate your configuration to that
947- - 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.
948- - Otherwise, move your configuration directly into `hardware.alsa.config`
949950If you set `sound.mediaKeys` in your configuration:
951 - Preferably switch to handling media keys in your desktop environment/compositor
···936937If you set `sound.enable` in your configuration:
938 - If you are using Pulseaudio or PipeWire, simply remove that option
939+ - If you are not using an external sound server, and want volumes to be persisted across shutdowns, set `hardware.alsa.enablePersistence = true` instead
940941If you set `sound.enableOSSEmulation` in your configuration:
942 - Make sure it is still necessary, as very few applications actually use OSS
943+ - If necessary, set `boot.kernelModules = [ "snd_pcm_oss" ]`
944945If you set `sound.extraConfig` in your configuration:
946+ - If you are using another sound server, like Pulseaudio, JACK or PipeWire, migrate your configuration to that
947+ - If you are not using an external sound server, set `environment.etc."asound.conf".text = yourExtraConfig` instead
0948949If you set `sound.mediaKeys` in your configuration:
950 - Preferably switch to handling media keys in your desktop environment/compositor
+3
nixos/doc/manual/release-notes/rl-2505.section.md
···375- The paperless module now has an option for regular automatic export of
376 documents data using the integrated document exporter.
377000378- 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.
379380 Example:
···375- The paperless module now has an option for regular automatic export of
376 documents data using the integrated document exporter.
377378+- 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.
379+ Note: these are intended for users not running a sound server like PulseAudio or PipeWire, but having ALSA as their only sound system.
380+381- 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.
382383 Example:
+150-130
nixos/modules/services/audio/alsa.nix
···86 [ "sound" "enableOSSEmulation" ]
87 [ "hardware" "alsa" "enableOSSEmulation" ]
88 )
89- (lib.mkRenamedOptionModule
90- [ "sound" "extraConfig" ]
91- [ "hardware" "alsa" "config" ])
92 ];
9394 options.hardware.alsa = {
···191 };
192 })
193 );
194- default = {};
195 example = lib.literalExpression ''
196 {
197 firefox = { device = "front"; maxVolume = -25.0; };
···286287 };
288289- config = lib.mkIf cfg.enable {
00000000290291- # Disable sound servers enabled by default and,
292- # if the user enabled one manually, cause a conflict.
293- services.pipewire.enable = false;
294- hardware.pulseaudio.enable = false;
295296- hardware.alsa.config =
297- let
298- conf = [
299- ''
300- pcm.!default fromenv
301302- # Read the capture and playback device from
303- # the ALSA_AUDIO_IN, ALSA_AUDIO_OUT variables
304- pcm.fromenv {
305- type asym
306- playback.pcm {
307- type plug
308- slave.pcm {
309- @func getenv
310- vars [ ALSA_AUDIO_OUT ]
311- default pcm.sysdefault
0000000312 }
313- }
314- capture.pcm {
315- type plug
316- slave.pcm {
317- @func getenv
318- vars [ ALSA_AUDIO_IN ]
319- default pcm.sysdefault
320 }
321 }
322- }
323- ''
324- (lib.optional cfg.enableRecorder ''
325- pcm.!default "splitter:fromenv,recorder"
326327- # Send audio to two stereo devices
328- pcm.splitter {
329- @args [ A B ]
330- @args.A.type string
331- @args.B.type string
332- type asym
333- playback.pcm {
334- type plug
335- route_policy "duplicate"
336- slave.pcm {
337- type multi
338- slaves.a.pcm $A
339- slaves.b.pcm $B
340- slaves.a.channels 2
341- slaves.b.channels 2
342- bindings [
343- { slave a channel 0 }
344- { slave a channel 1 }
345- { slave b channel 0 }
346- { slave b channel 1 }
347- ]
0348 }
0349 }
350- capture.pcm $A
351- }
352353- # Device which records and plays back audio
354- pcm.recorder {
355- type asym
356- capture.pcm {
357- type dsnoop
358- ipc_key 9165218
359- ipc_perm 0666
360- slave.pcm "hw:loopback,1,0"
361- slave.period_size 1024
362- slave.buffer_size 8192
363- }
364- playback.pcm {
365- type dmix
366- ipc_key 6181923
367- ipc_perm 0666
368- slave.pcm "hw:loopback,0,0"
369- slave.period_size 1024
370- slave.buffer_size 8192
0371 }
372- }
373- '')
374- (lib.mapAttrsToList mkControl cfg.controls)
375- (lib.mapAttrsToList (n: v: "pcm.${n} ${quote v}") cfg.deviceAliases)
376- ];
377- in
378- lib.mkBefore (lib.concatStringsSep "\n" (lib.flatten conf));
379380- hardware.alsa.cardAliases = lib.mkIf cfg.enableRecorder {
381- loopback.driver = "snd_aloop";
382- loopback.id = 2;
383- };
384385- # Set default PCM devices
386- environment.sessionVariables = defaultDeviceVars;
387- systemd.globalEnvironment = defaultDeviceVars;
388389- environment.etc."asound.conf".text = cfg.config;
390391- boot.kernelModules =
392- [ ]
393- ++ lib.optionals cfg.enableOSSEmulation [ "snd_pcm_oss" "snd_mixer_oss" ]
394- ++ lib.optionals cfg.enableRecorder [ "snd_aloop" ];
000395396- # Assign names to the sound cards
397- boot.extraModprobeConfig = lib.concatStringsSep "\n" cardsConfig;
398399- # Provide alsamixer, aplay, arecord, etc.
400- environment.systemPackages = [ pkgs.alsa-utils ];
0401402- # Install udev rules for restoring card settings on boot
403- services.udev.extraRules = ''
404- ACTION=="add", SUBSYSTEM=="sound", KERNEL=="controlC*", KERNELS!="card*", GOTO="alsa_restore_go"
405- GOTO="alsa_restore_end"
406407- LABEL="alsa_restore_go"
408- TEST!="/etc/alsa/state-daemon.conf", RUN+="${alsactl} restore -gU $attr{device/number}"
409- TEST=="/etc/alsa/state-daemon.conf", RUN+="${alsactl} nrestore -gU $attr{device/number}"
410- LABEL="alsa_restore_end"
411- '';
412413- # Service to store/restore the sound card settings
414- systemd.services.alsa-store = {
415- description = "Store Sound Card State";
416- wantedBy = [ "multi-user.target" ];
417- restartIfChanged = false;
418- unitConfig = {
419- RequiresMountsFor = "/var/lib/alsa";
420- ConditionVirtualization = "!systemd-nspawn";
421- };
422- serviceConfig = {
423- Type = "oneshot";
424- RemainAfterExit = true;
425- StateDirectory = "alsa";
426- # Note: the service should never be restated, otherwise any
427- # setting changed between the last `store` and now will be lost.
428- # To prevent NixOS from starting it in case it has failed we
429- # expand the exit codes considered successful
430- SuccessExitStatus = [ 0 99 ];
431- ExecStart = "${alsactl} restore -gU";
432- ExecStop = "${alsactl} store -gU";
0000000000433 };
434- };
435- };
0436437 meta.maintainers = with lib.maintainers; [ rnhmjoj ];
438
···86 [ "sound" "enableOSSEmulation" ]
87 [ "hardware" "alsa" "enableOSSEmulation" ]
88 )
89+ (lib.mkRenamedOptionModule [ "sound" "extraConfig" ] [ "hardware" "alsa" "config" ])
0090 ];
9192 options.hardware.alsa = {
···189 };
190 })
191 );
192+ default = { };
193 example = lib.literalExpression ''
194 {
195 firefox = { device = "front"; maxVolume = -25.0; };
···284285 };
286287+ options.hardware.alsa.enablePersistence = lib.mkOption {
288+ type = lib.types.bool;
289+ defaultText = lib.literalExpression "config.hardware.alsa.enable";
290+ default = config.hardware.alsa.enable;
291+ description = ''
292+ Whether to enable ALSA sound card state saving on shutdown.
293+ This is generally not necessary if you're using an external sound server.
294+ '';
295+ };
296297+ config = lib.mkMerge [
000298299+ (lib.mkIf cfg.enable {
300+ # Disable sound servers enabled by default and,
301+ # if the user enabled one manually, cause a conflict.
302+ services.pipewire.enable = false;
303+ services.pulseaudio.enable = false;
304305+ hardware.alsa.config =
306+ let
307+ conf = [
308+ ''
309+ pcm.!default fromenv
310+311+ # Read the capture and playback device from
312+ # the ALSA_AUDIO_IN, ALSA_AUDIO_OUT variables
313+ pcm.fromenv {
314+ type asym
315+ playback.pcm {
316+ type plug
317+ slave.pcm {
318+ @func getenv
319+ vars [ ALSA_AUDIO_OUT ]
320+ default pcm.sysdefault
321+ }
322 }
323+ capture.pcm {
324+ type plug
325+ slave.pcm {
326+ @func getenv
327+ vars [ ALSA_AUDIO_IN ]
328+ default pcm.sysdefault
329+ }
330 }
331 }
332+ ''
333+ (lib.optional cfg.enableRecorder ''
334+ pcm.!default "splitter:fromenv,recorder"
0335336+ # Send audio to two stereo devices
337+ pcm.splitter {
338+ @args [ A B ]
339+ @args.A.type string
340+ @args.B.type string
341+ type asym
342+ playback.pcm {
343+ type plug
344+ route_policy "duplicate"
345+ slave.pcm {
346+ type multi
347+ slaves.a.pcm $A
348+ slaves.b.pcm $B
349+ slaves.a.channels 2
350+ slaves.b.channels 2
351+ bindings [
352+ { slave a channel 0 }
353+ { slave a channel 1 }
354+ { slave b channel 0 }
355+ { slave b channel 1 }
356+ ]
357+ }
358 }
359+ capture.pcm $A
360 }
00361362+ # Device which records and plays back audio
363+ pcm.recorder {
364+ type asym
365+ capture.pcm {
366+ type dsnoop
367+ ipc_key 9165218
368+ ipc_perm 0666
369+ slave.pcm "hw:loopback,1,0"
370+ slave.period_size 1024
371+ slave.buffer_size 8192
372+ }
373+ playback.pcm {
374+ type dmix
375+ ipc_key 6181923
376+ ipc_perm 0666
377+ slave.pcm "hw:loopback,0,0"
378+ slave.period_size 1024
379+ slave.buffer_size 8192
380+ }
381 }
382+ '')
383+ (lib.mapAttrsToList mkControl cfg.controls)
384+ (lib.mapAttrsToList (n: v: "pcm.${n} ${quote v}") cfg.deviceAliases)
385+ ];
386+ in
387+ lib.mkBefore (lib.concatStringsSep "\n" (lib.flatten conf));
0388389+ hardware.alsa.cardAliases = lib.mkIf cfg.enableRecorder {
390+ loopback.driver = "snd_aloop";
391+ loopback.id = 2;
392+ };
393394+ # Set default PCM devices
395+ environment.sessionVariables = defaultDeviceVars;
396+ systemd.globalEnvironment = defaultDeviceVars;
397398+ environment.etc."asound.conf".text = cfg.config;
399400+ boot.kernelModules =
401+ [ ]
402+ ++ lib.optionals cfg.enableOSSEmulation [
403+ "snd_pcm_oss"
404+ "snd_mixer_oss"
405+ ]
406+ ++ lib.optionals cfg.enableRecorder [ "snd_aloop" ];
407408+ # Assign names to the sound cards
409+ boot.extraModprobeConfig = lib.concatStringsSep "\n" cardsConfig;
410411+ # Provide alsamixer, aplay, arecord, etc.
412+ environment.systemPackages = [ pkgs.alsa-utils ];
413+ })
414415+ (lib.mkIf config.hardware.alsa.enablePersistence {
000416417+ # Install udev rules for restoring card settings on boot
418+ services.udev.extraRules = ''
419+ ACTION=="add", SUBSYSTEM=="sound", KERNEL=="controlC*", KERNELS!="card*", GOTO="alsa_restore_go"
420+ GOTO="alsa_restore_end"
0421422+ LABEL="alsa_restore_go"
423+ TEST!="/etc/alsa/state-daemon.conf", RUN+="${alsactl} restore -gU $attr{device/number}"
424+ TEST=="/etc/alsa/state-daemon.conf", RUN+="${alsactl} nrestore -gU $attr{device/number}"
425+ LABEL="alsa_restore_end"
426+ '';
427+428+ # Service to store/restore the sound card settings
429+ systemd.services.alsa-store = {
430+ description = "Store Sound Card State";
431+ wantedBy = [ "multi-user.target" ];
432+ restartIfChanged = false;
433+ unitConfig = {
434+ RequiresMountsFor = "/var/lib/alsa";
435+ ConditionVirtualization = "!systemd-nspawn";
436+ };
437+ serviceConfig = {
438+ Type = "oneshot";
439+ RemainAfterExit = true;
440+ StateDirectory = "alsa";
441+ # Note: the service should never be restated, otherwise any
442+ # setting changed between the last `store` and now will be lost.
443+ # To prevent NixOS from starting it in case it has failed we
444+ # expand the exit codes considered successful
445+ SuccessExitStatus = [
446+ 0
447+ 99
448+ ];
449+ ExecStart = "${alsactl} restore -gU";
450+ ExecStop = "${alsactl} store -gU";
451+ };
452 };
453+ })
454+455+ ];
456457 meta.maintainers = with lib.maintainers; [ rnhmjoj ];
458