PipeWire: Difference between revisions
imported>Iopq more details on how to increase log level |
imported>Fufexan Update Advanced & Low-latency sections to newer config & WirePlumber |
||
Line 1: | Line 1: | ||
PipeWire is a new low-level multimedia framework. It aims to offer capture and playback for both audio and video with minimal latency and support for PulseAudio-, JACK-, ALSA- and GStreamer-based applications. PipeWire has a great bluetooth support: because Pulseaudio was [https://github.com/NixOS/nixpkgs/issues/123784 reported to have troubles with bluetooth], PipeWire can be a good alternative. | PipeWire is a new low-level multimedia framework. It aims to offer capture and playback for both audio and video with minimal latency and support for PulseAudio-, JACK-, ALSA- and GStreamer-based applications. PipeWire has a great bluetooth support: because Pulseaudio was [https://github.com/NixOS/nixpkgs/issues/123784 reported to have troubles with bluetooth], PipeWire can be a good alternative. | ||
Line 103: | Line 104: | ||
<syntaxHighlight lang="nix"> | <syntaxHighlight lang="nix"> | ||
environment.etc = let | |||
json = pkgs.formats.json {}; | |||
in { | |||
"pipewire/pipewire.d/91-null-sinks.conf".source = json.generate "91-null-sinks.conf" { | |||
context.objects = [ | |||
{ | { | ||
# A default dummy driver. This handles nodes marked with the "node.always-driver" | # A default dummy driver. This handles nodes marked with the "node.always-driver" | ||
Line 111: | Line 114: | ||
factory = "spa-node-factory"; | factory = "spa-node-factory"; | ||
args = { | args = { | ||
factory.name = "support.node.driver"; | |||
node.name = "Dummy-Driver"; | |||
priority.driver = 8000; | |||
}; | }; | ||
} | } | ||
Line 119: | Line 122: | ||
factory = "adapter"; | factory = "adapter"; | ||
args = { | args = { | ||
factory.name = "support.null-audio-sink"; | |||
node.name = "Microphone-Proxy"; | |||
node.description = "Microphone"; | |||
media.class = "Audio/Source/Virtual"; | |||
audio.position = "MONO"; | |||
}; | }; | ||
} | } | ||
Line 129: | Line 132: | ||
factory = "adapter"; | factory = "adapter"; | ||
args = { | args = { | ||
factory.name = "support.null-audio-sink"; | |||
node.name = "Main-Output-Proxy"; | |||
node.description = "Main Output"; | |||
media.class = "Audio/Sink"; | |||
audio.position = "FL,FR"; | |||
}; | }; | ||
} | } | ||
Line 160: | Line 163: | ||
The minimum period size controls how small a buffer can be. The lower it is, the less latency there is. PipeWire has a value of 32/48000 by default, which amounts to 0.667ms. It can be brought lower if needed: | The minimum period size controls how small a buffer can be. The lower it is, the less latency there is. PipeWire has a value of 32/48000 by default, which amounts to 0.667ms. It can be brought lower if needed: | ||
<syntaxHighlight lang="nix"> | <syntaxHighlight lang="nix"> | ||
environment.etc = let | |||
json = pkgs.generators.json {}; | |||
in { | |||
"pipewire/pipewire.d/92-low-latency.conf".source = json.generate "92-low-latency.conf" { | |||
context.properties = { | |||
default.clock.rate = 48000; | |||
default.clock.quantum = 32; | |||
default.clock.min-quantum = 32; | |||
default.clock.max-quantum = 32; | |||
}; | }; | ||
}; | }; | ||
}; | }; | ||
Line 211: | Line 182: | ||
Applications using the Pulse backend have a separate configuration. The default minimum value is 1024, so it needs to be tweaked if low-latency audio is desired. | Applications using the Pulse backend have a separate configuration. The default minimum value is 1024, so it needs to be tweaked if low-latency audio is desired. | ||
<syntaxHighlight lang="nix"> | <syntaxHighlight lang="nix"> | ||
environment.etc = let | |||
json = pkgs.generators.json {}; | |||
in { | |||
"pipewire/pipewire-pulse.d/92-low-latency.conf".source = json.generate "92-low-latency.conf" { | |||
context.modules = [ | |||
{ | { | ||
name = "libpipewire-module-protocol-pulse"; | name = "libpipewire-module-protocol-pulse"; | ||
args = { | args = { | ||
pulse.min.req = "32/48000"; | |||
pulse.default.req = "32/48000"; | |||
pulse.max.req = "32/48000"; | |||
pulse.min.quantum = "32/48000"; | |||
pulse.max.quantum = "32/48000"; | |||
}; | }; | ||
} | } | ||
]; | ]; | ||
stream.properties = { | |||
node.latency = "32/48000"; | |||
resample.quality = 1; | |||
}; | }; | ||
}; | }; | ||
Line 252: | Line 207: | ||
As a general rule, the values in <code>pipewire-pulse</code> should not be lower than the ones in <code>pipewire</code>. | As a general rule, the values in <code>pipewire-pulse</code> should not be lower than the ones in <code>pipewire</code>. | ||
===Controlling the ALSA devices=== | ===Controlling the ALSA devices=== | ||
It is possible to configure various aspects of soundcards through PipeWire, including format, period size and batch mode: | It is possible to configure various aspects of soundcards through PipeWire, including format, period size and batch mode: | ||
<syntaxHighlight lang="nix"> | <syntaxHighlight lang="nix"> | ||
environment.etc. | |||
"wireplumber/main.lua.d/99-alsa-lowlatency.lua".text = '' | |||
alsa_monitor.rules = { | |||
{ | |||
matches = {{{ "node.name", "matches", "alsa_output.*" }}}; | |||
apply_properties = { | |||
["audio.format"] = "S32LE", | |||
["audio.rate"] = "96000", -- for USB soundcards it should be twice your desired rate | |||
["api.alsa.period-size"] = 2, -- defaults to 1024, tweak by trial-and-error | |||
-- ["api.alsa.disable-batch"] = true, -- generally, USB soundcards use the batch mode | |||
}, | |||
}, | |||
} | |||
} | '';</syntaxHighlight> | ||
The <code>matches</code> attribute applies the <code>actions</code> to the devices/properties listed there. It is usually used with soundcard names, like shown in the config above. <code><matches></code> can match any of the outputs of | |||
} | |||
</syntaxHighlight> | |||
The <code>matches</code> attribute applies the <code>actions</code> to the devices/properties listed there. It is usually used with soundcard names, like shown in the config above. <code>< | |||
<syntaxHighlight lang="bash"> | <syntaxHighlight lang="bash"> | ||
$ pw-dump | grep node.name | grep alsa | $ pw-dump | grep node.name | grep alsa |