Pipewire crashes with module-filter-chain
I've been trying to use Pipewire's module-filter-chain to build a systemwide parametric EQ based on the sink-eq6 example. I was never able to get the example to work properly, but came up with the following, pasted into the context.modules
array of the default pipewire.conf:
{ name = libpipewire-module-filter-chain
args = {
node.name = "effect_output.hpeq"
node.description = "Headphone EQ Sink"
media.name = "Headphone EQ Sink"
filter.graph = {
nodes = [
{
type = builtin
name = eq_preamp
label = bq_highshelf
control = { "Freq" = 0 "Q" = 1.0 "Gain" = -12.5 }
}
{
type = builtin
name = eq_band_1
label = bq_peaking
control = { "Freq" = 25.0 "Q" = 1.0 "Gain" = 7.0 }
}
{
type = builtin
name = eq_band_2
label = bq_lowshelf
control = { "Freq" = 105.0 "Q" = 0.71 "Gain" = 5.5 }
}
{
type = builtin
name = eq_band_3
label = bq_peaking
control = { "Freq" = 700.0 "Q" = 1.0 "Gain" = 1.0 }
}
{
type = builtin
name = eq_band_4
label = bq_peaking
control = { "Freq" = 1050.0 "Q" = 2.0 "Gain" = -1.8 }
}
{
type = builtin
name = eq_band_5
label = bq_peaking
control = { "Freq" = 1900.0 "Q" = 1.2 "Gain" = 5.7 }
}
{
type = builtin
name = eq_band_6
label = bq_peaking
control = { "Freq" = 2900.0 "Q" = 1.2 "Gain" = 2.0 }
}
{
type = builtin
name = eq_band_7
label = bq_peaking
control = { "Freq" = 6100.0 "Q" = 2.0 "Gain" = -2.8 }
}
{
type = builtin
name = eq_band_8
label = bq_peaking
control = { "Freq" = 6750.0 "Q" = 4.5 "Gain" = -4.7 }
}
{
type = builtin
name = eq_band_9
label = bq_peaking
control = { "Freq" = 8450.0 "Q" = 4.0 "Gain" = -2.9 }
}
]
links = [
{ output = "eq_preamp:Out" input = "eq_band_1:In" }
{ output = "eq_band_1:Out" input = "eq_band_2:In" }
{ output = "eq_band_2:Out" input = "eq_band_3:In" }
{ output = "eq_band_3:Out" input = "eq_band_4:In" }
{ output = "eq_band_4:Out" input = "eq_band_5:In" }
{ output = "eq_band_5:Out" input = "eq_band_6:In" }
{ output = "eq_band_6:Out" input = "eq_band_7:In" }
{ output = "eq_band_7:Out" input = "eq_band_8:In" }
{ output = "eq_band_8:Out" input = "eq_band_9:In" }
]
inputs = [ "eq_preamp:In" ]
outputs = [ "eq_band_9:Out" ]
}
capture.props = {
media.class = Audio/Sink
audio.channels = 2
audio.position = [ FL FR ]
}
playback.props = {
node.passive = true
audio.channels = 2
audio.position = [ FL FR ]
node.target = "alsa_output.pci-0000_2a_00.4.analog-stereo"
}
}
}
With Pipewire < 0.3.29 it largely failed with it producing 10 different nodes in the pw-link output. Trying it with 0.3.29 resulted in Pipewire running, and I had to manually add the channel mapping and node.target output device otherwise it wouldn't output anything. However only the preamp worked; the audio wasn't processed by further nodes i.e. it was just quieter.
With 0.3.31 vanilla Pipewire works OK, but adding the above filter just crashes Pipewire, with the following log from journalctl under Arch:
Jun 29 22:18:42 hostname systemd[1031]: Started Multimedia Service.
Jun 29 22:20:13 hostname pipewire[3086]: node 0x559d57703d20: output port 0 unknown
Jun 29 22:20:13 hostname pipewire[3086]: free(): double free detected in tcache 2
Jun 29 22:20:13 hostname systemd-coredump[3238]: [🡕] Process 3086 (pipewire) of user 1000 dumped core.
Stack trace of thread 3086:
#0 0x00007f0ffa21bd22 raise (libc.so.6 + 0x3cd22)
#1 0x00007f0ffa205862 abort (libc.so.6 + 0x26862)
#2 0x00007f0ffa25dd28 __libc_message (libc.so.6 + 0x7ed28)
#3 0x00007f0ffa26592a malloc_printerr (libc.so.6 + 0x8692a)
#4 0x00007f0ffa267408 _int_free (libc.so.6 + 0x88408)
#5 0x00007f0ffa26a9e8 __libc_free (libc.so.6 + 0x8b9e8)
#6 0x00007f0ffa42c3ea n/a (libpipewire-0.3.so.0 + 0x603ea)
#7 0x00007f0ff3e6894d n/a (libspa-audioconvert.so + 0x1994d)
#8 0x00007f0ff3e69527 n/a (libspa-audioconvert.so + 0x1a527)
#9 0x00007f0ff3ea217c n/a (libspa-audioconvert.so + 0x5317c)
#10 0x00007f0ff3ea2c04 n/a (libspa-audioconvert.so + 0x53c04)
#11 0x00007f0ff3e7710c n/a (libspa-audioconvert.so + 0x2810c)
#12 0x00007f0ff3e6a02e n/a (libspa-audioconvert.so + 0x1b02e)
#13 0x00007f0ffa433145 pw_impl_port_set_param (libpipewire-0.3.so.0 + 0x67145)
#14 0x00007f0ffa445933 n/a (libpipewire-0.3.so.0 + 0x79933)
#15 0x00007f0ffa445b84 n/a (libpipewire-0.3.so.0 + 0x79b84)
#16 0x00007f0ffa41cf37 pw_impl_link_destroy (libpipewire-0.3.so.0 + 0x50f37)
#17 0x00007f0ffa42c4c6 n/a (libpipewire-0.3.so.0 + 0x604c6)
#18 0x00007f0ff3e6894d n/a (libspa-audioconvert.so + 0x1994d)
#19 0x00007f0ff3e69527 n/a (libspa-audioconvert.so + 0x1a527)
#20 0x00007f0ff3ea217c n/a (libspa-audioconvert.so + 0x5317c)
#21 0x00007f0ff3ea2a11 n/a (libspa-audioconvert.so + 0x53a11)
#22 0x00007f0ff3e75e37 n/a (libspa-audioconvert.so + 0x26e37)
#23 0x00007f0ff3e76650 n/a (libspa-audioconvert.so + 0x27650)
#24 0x00007f0ff3e7232b n/a (libspa-audioconvert.so + 0x2332b)
#25 0x00007f0ff8238f80 n/a (libpipewire-module-client-node.so + 0xcf80)
#26 0x00007f0ff8249c75 n/a (libpipewire-module-client-node.so + 0x1dc75)
#27 0x00007f0ff929abc4 n/a (libpipewire-module-protocol-native.so + 0x11bc4)
#28 0x00007f0ff929b1b0 n/a (libpipewire-module-protocol-native.so + 0x121b0)
#29 0x00007f0ffa49c11b n/a (libspa-support.so + 0x811b)
#30 0x00007f0ffa415603 pw_main_loop_run (libpipewire-0.3.so.0 + 0x49603)
#31 0x0000559d567a0292 n/a (pipewire + 0x1292)
#32 0x00007f0ffa206b25 __libc_start_main (libc.so.6 + 0x27b25)
#33 0x0000559d567a03ee n/a (pipewire + 0x13ee)
Stack trace of thread 3087:
#0 0x00007f0ffa2dd92e epoll_wait (libc.so.6 + 0xfe92e)
#1 0x00007f0ffa4a5651 n/a (libspa-support.so + 0x11651)
#2 0x00007f0ffa49c084 n/a (libspa-support.so + 0x8084)
#3 0x00007f0ffa407250 n/a (libpipewire-0.3.so.0 + 0x3b250)
#4 0x00007f0ffa3b4259 start_thread (libpthread.so.0 + 0x9259)
#5 0x00007f0ffa2dd5e3 __clone (libc.so.6 + 0xfe5e3)
Jun 29 22:20:13 hostname systemd[1031]: pipewire.service: Main process exited, code=dumped, status=6/ABRT
Jun 29 22:20:13 hostname systemd[1031]: pipewire.service: Failed with result 'core-dump'.
Jun 29 22:20:13 hostname systemd[1031]: pipewire.service: Scheduled restart job, restart counter is at 2.
Jun 29 22:20:13 hostname systemd[1031]: Stopped Multimedia Service.
Thanks if you can consider debugging the filter chain so it works -- I hope I've got the rules right. The preamp I implemented from reading the biquad source code, it mentioned a freq of zero meant it was a gain filter only (this might be worth documenting or updating the sink-eq6 example, as without it any positive gain results in distortion).