#!/usr/bin/env bash DEST=${1:-/etc/skel} PIPEWIRE_HOME=${DEST}/.config/pipewire WIREPLUMBER_HOME=${DEST}/.config/wireplumber mkdir -p ${DEST}/.config/pipewire,wireplumber # https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/home # # with-alsa: # https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-ALSA : <<'!' pipewire-audio-client-libraries pipewire-alsa pipewire-jack pipewire-pulse pipewire-v4l2 pipewire ! sudo apt install -y \ libfdk-aac2 \ libldacbt-{abr,enc}2 \ libopenaptx0 sudo apt install -y gstreamer1.0-pipewire \ libpipewire-0.3-{0,dev,modules} \ libspa-0.2-{bluetooth,dev,jack,libcamera,modules} sudo apt install -y \ pipewire-audio-client-libraries \ pipewire \ pipewire-{audio,alsa,jack,v4l2,libcamera} \ wireplumber \ wireplumber-system-services \ coppwr \ xdg-desktop-portal-wlr ## For WirePlumber - pipewire session manager sudo apt-get install -y wireplumber{,-doc} ## Other management tools - jackd2 will set /etc/security/limits.conf for rt # if you not using jackd2 you can use the heredoc to set them manually. sudo apt-get install -y jackd2 qpwgraph vlc-plugin-pipewire libcamera-ipa conf_print_audio_limits() { cat </dev/null # The context.spa-libs section maps SPA factory name regex patterns to their # corresponding library names conf_print_client-rt_context_spa-libs() { cat <<-EOF context.spa-libs = { # = # # Used to find spa factory names. It maps an spa factory name # regular expression to a library name that should contain # that factory. # audio.convert.* = audioconvert/libspa-audioconvert support.* = support/libspa-support } EOF } conf_print_client-rt_context_spa-libs | sudo tee ${PIPEWIRE_HOME}/client-rt.conf.d/client-rt_context_spa-libs.conf >/dev/null # use of context.modules to load modules like libpipewire-module-rt conf_print_client-rt_context_modules() { cat <<-EOF context.modules = [ #{ name = # ( args = { = ... } ) # ( flags = [ ( ifexists ) ( nofail ) ] ) # ( condition = [ { = ... } ... ] ) #} # # Loads a module with the given parameters. # If ifexists is given, the module is ignored when it is not found. # If nofail is given, module initialization failures are ignored. # # Uses realtime scheduling to boost the audio thread priorities { name = libpipewire-module-rt args = { #rt.prio = 88 #rt.time.soft = -1 #rt.time.hard = -1 } flags = [ ifexists nofail ] } # The native communication protocol. { name = libpipewire-module-protocol-native } # Allows creating nodes that run in the context of the # client. Is used by all clients that want to provide # data to PipeWire. { name = libpipewire-module-client-node } # Allows creating devices that run in the context of the # client. Is used by the session manager. { name = libpipewire-module-client-device } # Makes a factory for wrapping nodes in an adapter with a # converter and resampler. { name = libpipewire-module-adapter } # Allows applications to create metadata objects. It creates # a factory for Metadata objects. { name = libpipewire-module-metadata } # Provides factories to make session manager objects. { name = libpipewire-module-session-manager } ] EOF } conf_print_client-rt_context_modules | sudo tee ${PIPEWIRE_HOME}/client-rt.conf.d/client-rt_context_modules.conf >/dev/null conf_print_client-rt_filter_properties() { cat <<-EOF filter.properties = { #node.latency = 1024/48000 } EOF } conf_print_client-rt_filter_properties | sudo tee ${PIPEWIRE_HOME}/client-rt.conf.d/client-rt_filter_properties.conf >/dev/null conf_print_client-rt_stream_properties() { cat <<-EOF stream.properties = { #node.latency = 1024/48000 #node.autoconnect = true #resample.quality = 4 #channelmix.normalize = false #channelmix.mix-lfe = true #channelmix.upmix = true #channelmix.upmix-method = psd # none, simple #channelmix.lfe-cutoff = 150 #channelmix.fc-cutoff = 12000 #channelmix.rear-delay = 12.0 #channelmix.stereo-widen = 0.0 #channelmix.hilbert-taps = 0 #dither.noise = 0 } EOF } conf_print_client-rt_stream_properties | sudo tee ${PIPEWIRE_HOME}/client-rt.conf.d/client-rt_stream_properties.conf >/dev/null conf_print_client-rt_stream_rules() { cat <<-EOF stream.rules = [ { matches = [ { # all keys must match the value. ! negates. ~ starts regex. #application.name = "pw-cat" #node.name = "~Google Chrome$" } ] actions = { update-props = { #node.latency = 512/48000 } } } ] EOF } conf_print_client-rt_stream_rules | sudo tee ${PIPEWIRE_HOME}/client-rt.conf.d/client-rt_stream_rules.conf >/dev/null conf_print_client-rt_alsa_properties() { cat <<-EOF alsa.properties = { #alsa.deny = false # ALSA params take a single value, an array [] of values # or a range { min=.. max=... } #alsa.access = [ MMAP_INTERLEAVED MMAP_NONINTERLEAVED RW_INTERLEAVED RW_NONINTERLEAVED ] #alsa.format = [ FLOAT S32 S24 S24_3 S16 U8 ] #alsa.rate = { min=1 max=384000 } # or [ 44100 48000 .. ] #alsa.channels = { min=1 max=64 } # or [ 2 4 6 .. ] #alsa.period-bytes = { min=128 max=2097152 } # or [ 128 256 1024 .. ] #alsa.buffer-bytes = { min=256 max=4194304 } # or [ 256 512 4096 .. ] #alsa.volume-method = cubic # linear, cubic } EOF } conf_print_client-rt_alsa_properties | sudo tee ${PIPEWIRE_HOME}/client-rt.conf.d/client-rt_alsa_properties.conf >/dev/null conf_print_client-rt_alsa_rules() { cat <<-EOF # client specific properties alsa.rules = [ { matches = [ { application.process.binary = "resolve" } ] actions = { update-props = { alsa.buffer-bytes = 131072 } } } ] EOF } conf_print_client-rt_alsa_rules | sudo tee ${PIPEWIRE_HOME}/client-rt.conf.d/client-rt_alsa_rules.conf >/dev/null