#!/usr/bin/env bash PIPEWIRE_HOME=/etc/pipewire WIREPLUMBER_HOME=/usr/share/wireplumber # https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/home # # with-alsa: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-ALSA sudo apt -y install \ libfdk-aac2 \ libldacbt-{abr,enc}2 \ libopenaptx0 sudo apt -y install \ gstreamer1.0-pipewire \ libpipewire-0.3-{0,dev,modules} \ libspa-0.2-{bluetooth,dev,jack,libcamera,modules} \ pipewire \ pipewire-{alsa,jack,v4l2,libcamera} sudo apt install \ pipewire-audio-client-libraries \ pipewire \ pipewire-alsa \ pipewire-audio \ pipewire-jack ## For WirePlumber - pipewire session manager sudo apt-get install wireplumber{,-doc} ## Other management tools sudo apt-get install qpwgraph vlc-plugin-pipewire # Copy conffiles to /etc sudo cp -vRa /usr/share/pipewire /etc/ sudo mkdir -p ${PIPEWIRE_HOME}/pipewire.conf.d # Wireplumber now expects configuration files in /usr/share and no more lua. # sudo cp -vRa /usr/share/wireplumber /etc/ # sudo mkdir -p ${WIREPLUMER_HOME}/wireplumber.conf.d # WirePlumber has profile auto-switching enabled by default. It can # automatically switch between HSP/HFP and A2DP profiles whenever an # input stream is detected. You can disable it with: conf_print_wireplumber_bt_autoswitch() { cat <<-EOF wireplumber.settings = { bluetooth.autoswitch-to-headset-profile = false } EOF } # conf_print_wireplumber_bt_autoswitch | sudo tee ${WIREPLUMBER_HOME}/wireplumber.conf.d/11-bluetooth-policy.conf # conf_print_wireplumber_bt_autoswitch | sudo tee ~/.config/wireplumber/wireplumber.conf.d/11-bluetooth-policy.conf sudo touch ${PIPEWIRE_HOME}/media-session.d/with-alsa sudo cp /usr/share/doc/pipewire/examples/ld.so.conf.d/pipewire-jack-x86_64-linux-gnu.conf /etc/ld.so.conf.d/ sudo ldconfig # sudo cp /usr/share/doc/pipewire/examples/alsa.conf.d/99-pipewire-default.conf /etc/alsa/conf.d/ sudo ln -s /usr/share/alsa/alsa.conf.d/99-pipewire-default.conf /etc/alsa/conf.d/99-pipewire-default.conf #conf_print_pipewire_default() { #cat <<-EOF #pcm.!default { # type pipewire # playback_node "-1" # capture_node "-1" # hint { # show on # description "Default ALSA Output (currently PipeWire Media Server)" # } #} # #ctl.!default { # type pipewire #} #EOF #} # conf_print_pipewire_default | sudo tee /etc/alsa/conf.d/99-pipewire-default.conf conf_print_pipewire_desktop() { cat <<-EOF [Desktop Entry] Version=1.0 Name=PipeWire Media System Comment=Start the PipeWire Media System Exec=/usr/bin/pipewire Terminal=false Type=Application X-GNOME-Autostart-Phase=Initialization X-KDE-autostart-phase=1 EOF } conf_print_pipewire_desktop | sudo tee /etc/xdg/autostart/pipewire.desktop  conf_print_wireplumber_desktop() { cat <<-EOF [Desktop Entry] Version=1.0 Name=WirePlumber PipeWire Media System Comment=Start the WirePlumber Exec=/usr/bin/wireplumber Terminal=false Type=Application X-GNOME-Autostart-Phase=Initialization X-KDE-autostart-phase=1 EOF } conf_print_wireplumber_desktop | sudo tee /etc/xdg/autostart/wireplumber.desktop # don't use this we make incremental changes to conf.d/.conf # # conf_print_pipewire_conf() { # cat <<-EOF # # PipeWire ALSA configuration # context.properties = { # # ALSA settings # alsa.jack.device = "hw:0" # alsa.jack.autoconnect = true # alsa.jack.autoconnect-ports = true # alsa.jack.latency = 100000 # } # EOF #} # conf_print_pipewire_conf | sudo tee /etc/pipewire/pipewire.conf # https://davejansen.com/disable-wireplumber-pipewire-suspend-on-idle-pops-delays-noise/ conf_print_alsa_conf_suspend-timeout() { cat <<-EOF alsa_monitor.enabled = true alsa_monitor.properties = { -- Your existing properties configuration } alsa_monitor.rules = { { matches = { { -- This matches all cards. { "device.name", "matches", "alsa_card.*" }, }, }, apply_properties = { -- Your existing apply_properties configuration ["session.suspend-timeout-seconds"] = 0, -- Add this line }, }, { matches = { { -- Matches all sources. { "node.name", "matches", "alsa_input.*" }, }, { -- Matches all sinks. { "node.name", "matches", "alsa_output.*" }, }, }, apply_properties = { -- Your existing apply_properties configuration ["session.suspend-timeout-seconds"] = 0, -- Add this line }, }, } EOF } # no more lua for wireplumber # conf_print_alsa_conf_suspend-timeout | sudo tee ${WIREPLUMBER_HOME}/main.lua.d/60-alsa_suspend-timeout.conf # improved crackling in fullscreen conf_print_pipewire_quantum() { cat <<-EOF conf_print_pipewire_quantum() { default.clock.quantum = "32" default.clock.min-quantum = "64" default.clock.max-quantum = "768" EOF } conf_print_pipewire_quantum | sudo tee ${PIPEWIRE_HOME}/pipewire.conf.d/clock_quantum.conf # default.clock.allowed-rates = [ 44100 48000 96000 192000 ] conf_print_pipewire_quantum() { cat <<-EOF default.clock.rate = 44100 default.clock.allowed-rates = 44100 default.clock.quantum = 512 default.clock.min-quantum = 16 default.clock.max-quantum = 2048 default.clock.quantum-limit = 512 settings.check-quantum = false settings.check-rate = false EOF } conf_print_pipewire_quantum | sudo tee ${PIPEWIRE_HOME}/pipewire.conf.d/clock_quantum.conf conf_print_pipewire_alsa-api() { cat <<-EOF # See: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-ALSA#alsa-buffer-properties api.alsa.headroom = 1024 api.alsa.period-size = 256 EOF } conf_print_pipewire_alsa-api | sudo tee ${PIPEWIRE_HOME}/pipewire.conf.d/alsa-api.conf conf_print_pipewire_clock-rate() { cat <<-EOF context.properties = { default.clock.rate = [ 44100 48000 ] } EOF } conf_print_pipewire_clock-rate | sudo tee ${PIPEWIRE_HOME}/pipewire.conf.d/alsa-dmix.conf conf_print_pipewire_alsa-dmix() { cat </dev/null 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 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