Playing sound over the network with Pipewire and ROC on Arch Linux
Table of Contents
Originally posted on 18 July 2023.
My homeserver is connected to a DAC and good (enough) speakers. I use it to play music using Logitech Media Server (which I highly recommend!).
I have been willing to be able to play sound from my laptop
(henceforth "the client") on my homeserver (henceforth "the server")
over the LAN smoothly for years now, especially when I (very seldom)
watch films on it, because I don't want to use a second set of
speakers. While both my laptop and my homeserver are connected to the
network via Ethernet, Pulseaudio's native TCP module was always very
slow and the sound was often out of sync. Moreover, I was never able
to understand what the differences between its various network modules
(simple-protocol
? tunnel
? native-tcp
?) were.
Some time ago, I switched from Pulseaudio to Pipewire. This got me very confused, because I couldn't understand what needed to be configured on which side. For once, the Arch wiki was not very helpful, as its instructions did not work for me.
I gave it another go today, using ROC. And, much to my satisfaction, it worked perfectly out of the box. And it uses native Pipewire modules.
Tutorial
Here's a quick summary of what you need to do in order to achieve this if you use Pipewire on Arch Linux:
Install
pipewire-roc
both on the client and the server:sudo pacman -S pipewire-roc
On the server, add this to
/etc/pipewire/pipewire.conf.d/roc-source.conf
:context.modules = [ { name = libpipewire-module-roc-source args = { local.ip = 192.168.1.x resampler.profile = medium fec.code = rs8m sess.latency.msec = 100 local.source.port = 4713 local.repair.port = 4714 source.name = "My server's speakers" source.props = { node.name = "roc-source" } } } ]
Replace 192.168.1.x with the server's local IP and both 4713
and 4714
with the port numbers of your liking, making sure you have opened them
in your server's firewall first.
On the client, add this to
/etc/pipewire/pipewire.conf.d/roc-sink.conf
:context.modules = [ { name = libpipewire-module-roc-sink args = { fec.code = rs8m remote.ip = 192.168.1.x remote.source.port = 4713 remote.repair.port = 4714 sink.name = "My laptop's soundcard" sink.props = { node.name = "roc-sink" } } } ]
Again, specify the IP and ports accordingly.
Restart Pipewire both on the server and client:
systemctl --user restart pipewire
Now look at the list of sinks on your laptop, using pavucontrol
for
instance (I use Gnome Shell's sound menu for that). You'll see a new
ROC sink
. Select it and enjoy your new sound output!
Related links and acknowledgements
- roc-droid is an Android app which allows a phone to become a
roc
sender or receiver (and it works!). - This article by the developer of
roc
inspired this one.