Posting this if anyone else runs into the same issue and doesn’t want to spend 8 hours troubleshooting it. My first post and guide so suggestions welcome.
So I got a random subwoofer and wanted to set it up with my desktop, but trying to use a proper 2.1 setup was just not working as seemingly nothing would output over the CS-out port. Setting the output profile to analog stereo did clone the standard line out to the other ports, so a good workaround if you’re fine with no channel volume controls, and saves having to get a splitter. But I wanted to have that 3 channel volume control instead of needing to adjust the very sensitive physical gain knob way back under my desk constantly.
Eventually after tons of troubleshooting and trying to use upmixing rules from pipewire, I realized that Firefox was outputting to the subwoofer, but Finamp wasn’t. So it turns out Finamp uses MPV for its audio handler thing. And It’s too smart and recognizes the current audio config setup and outputs that many channels, including creating empty channels for the extra channels (like the sub). So while firefox will output correctly with plain upmixing rules, Finamp and likely other ‘smarter’ pipelines don’t work.
The solution is to create a virtual audio device instead that only accepts 2 channels, and then have pipewire process that on the backend by upmixing that into the 2.1 channels and outputting to your real audio device. Then setting your system to output everything over the virtual sink.
Directions:
- Create the config folder for the local override:
mkdir -p ~/.config/pipewire/pipewire.conf.d/ - Create a file in that new folder, I named mine
99-upmix-sink.conf - Throw this virtual device stuff into that file
context.modules = [
{ name = libpipewire-module-loopback
args = {
node.description = "Virtual Stereo Upmix Sink"
driver.mode = passenger
audio.position = [ FL FR ]
capture.props = {
node.name = "upmix_sink"
media.class = Audio/Sink
audio.position = [ FL FR ]
}
playback.props = {
node.name = "upmix_sink.output"
node.target = "alsa_output.pci-0000_2f_00.4.analog-surround-21"
audio.position = [ FL FR LFE ]
channelmix.upmix = true
channelmix.upmix-method = simple
channelmix.lfe-cutoff = 150
}
}
}
]
AND MAKE SURE TO UPDATE: this bit node.target = "alsa_output.pci-0000_2f_00.4.analog-surround-21" to match your actual intended output device. Which can be seen via pw-link -o, removing the channel specifier like ‘:monitor_L’ for just the main device. This might vary a lot so you might have to experiment, but it should be roughly similar in name and profile output to the intended device, like my “Starship/Matisse HD Audio Controller Analog Surround 2.1” is just the analog-surround alsa output above. Avoid the other “:output…” devices.
- Then just open KDE sound settings (or whatever) and switch your playback device to the new “Virtual Stereo Upmix Sink” device, and feel free to adjust the level of your sub channel using the real device channels which should still work. I just set the LR output to 90% volume, and adjusted the sub like 60% volume, and then just use the virtual device level for normal control such as via keyboard buttons.
AI Disclaimer
AI usage disclaimer: Original issue was troubleshooted with AI (mostly unsuccessfully) but it did generate the final virtual device script. Otherwise this entire guide was written by me with zero AI.