💾 Archived View for perso.pw › blog › articles › openbsd-sound-streaming.gmi captured on 2023-07-22 at 16:20:24. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-06-16)

-=-=-=-=-=-=-

Stream your OpenBSD desktop audio to other devices

Comment on Mastodon

Introduction

Hi, back on OpenBSD desktop, I miss being able to use my bluetooth headphones (especially the Shokz ones that allow me to listen to music without anything on my ears).

Unfortunately, OpenBSD doesn't have a bluetooth stack, but I have a smartphone (and a few other computers), so why not stream my desktop sound to another device with bluetooh? Let's see what we can do!

I'll often refer to the "monitor" input source, which is the name of an input that provides "what you hear" from your computer.

While it would be easy to just allow a remote device to play music files, I want to stream the computer's monitor input, so it could be litteraly anything, and not just music files.

This method can be used on any Linux distribution, and certainly on other BSDs, but I will only cover OpenBSD.

The different solutions

Icecast

One simple setup is to use icecast, the program used by most web radios, and ices, a companion program to icecast, in order to stream your monitor input to the network.

The pros:

The cons:

Sndiod

The default sound server in OpenBSD, namely sndiod, supports network streaming!

Too bad, if you want to use Bluetooth as an output, you would have to run sndiod on Linux (which is perfectly fine), but you can't use Bluetooth with sndiod, even on Linux.

So, no sndiod. Between two OpenBSD, or OpenBSD and Linux, it works perfectly well without latency, and it's a super simple setup, but as Bluetooth can't be used, I won't cover this setup.

The pros:

The cons:

Pulseaudio

This sound server is available as a port on OpenBSD, and has two streaming modes: native-protocol-tcp and RTP, the former is exchanging pulseaudio internal protocol from one server to another which isn't ideal and prone to problems over a bad network, the latter being more efficient and resilient.

However, the RTP sender doesn't work on OpenBSD, and I have no interest in finding out why (the bug doesn't seem to be straightforward), but the native protocol works just fine.

The pros:

Snapcast

Snapcast is an amazing piece of software that you can use to broadcast your audio toward multiple other client (using snapcast or a web page) with the twist that the audio will be synchronized on each client, allowing a multi room setup at no cost.

Unfortunately, I've not been able to build it on OpenBSD :(

The pros:

The cons:

Setup

Here are the instructions to setup different solutions.

Pulseaudio

Client setup (OpenBSD)

On the local OpenBSD, you need to install `pulseaudio` and `ffmpeg` packages.

You also need to set sndiod flags, using `rcctl set sndiod flags -s default -m play,mon -s mon`, this will allow you to use the monitor input through the device `snd/0.mon`.

Now, when you want to stream your monitor to a remote pulseaudio, run this command in your terminal:

ffmpeg -f sndio -i snd/0.mon -ar 44100 -f s16le - | pacat -s 10.42.42.199 --raw --process-time-msec=30 --latency-msec=30

The command is composed of two parts:

Server setup (the device with bluetooth)

The setup is easy, but note that this doesn't involve any authentication or encryption, so please use this on trusted network, or through a VPN.

On a system with pulseaudio, type:

pacmd load-module module-native-protocol-tcp auth-anonymous=1 auth-ip-acl=192.168.1.0/24

This will load the module accepting network connections, the `auth-anonymous` option is there to simplify connection to the server, otherwise you would have to share the pulseaudio cookie between computers, which I recommend doing but on a smartphone this can be really cumbersome to do, and out of scope here.

The other option is pretty obvious, just give a list of IPs you want to allow to connect to the server.

If you want the changes to be persistent, edit `/etc/pulse/default.pa` to add the line `load-module module-native-protocol-tcp auth-anonymous=1 auth-ip-acl=192.168.1.0/24`.

On Android, you can install pulseaudio using Termux (available on f-droid), using the commands:

pkg install pulseaudio
pulseaudio --start --exit-idle-time=3600
pacmd load-module module-native-protocol-tcp auth-anonymous=1 auth-ip-acl=192.168.1.0/24

There is a project named PulseDroid, the original project has been unmaintained for 13 years, but someone took it back quite recently, unfortunately no APK are provided, and I'm still trying to build it to try, it should provide an easier user experience to run pulseaudio on Android.

PulseDroid gitlab repository

Icecast

Using icecast, you will have to setup an icecast server, and locally use ices2 client to broadcast your monitor input. Then, any client can play the stream URL.

Install the component using:

pkg_add icecast ices--%ices2

Server part

As suggested by the file `/usr/local/share/doc/pkg-readmes/icecast`, run the following commands to populate icecast's chroot:

cp -p /etc/{hosts,localtime,resolv.conf} /var/icecast/etc
cp -p /usr/share/misc/mime.types /var/icecast/etc

Edit `/var/icecast/icecast.xml`:

Keep in mind this is the bare minimum for a working setup, if you want to open it to the wide Internet, I'd strongly recommend reading icecast documentation before. Using a VPN may be wiser if it's only for private use.

We can start icecast and set it to start at boot:

rcctl enable icecast
rcctl start icecast

Broadcast part

Then, to configure ices2, copy the file `/usr/local/share/examples/ices2/ices-sndio.xml` somewhere you feel comfortable for storing user configuration files. The example file is an almost working template to send sndio sources to icecast.

Edit the file, under the `<instance>` node:

Now, search for `<channels>` and set it to 2 because we want to broadcast stereo sound, and set `<downmix>` to 0 because we don't need to merge both channels into a mono output. (If those values aren't in sync, you will have funny results =D)

When you want to broadcast, run the command:

env AUDIORECDEVICE=snd/0.mon ices2 ices-sndio.xml

With any device, open the url `http://<hostname>:8000/file.ogg` with `file.ogg` being what you've put in `<mount>` earlier. And voilà, you have a working local audio streaming!

Limitations

Of course, the setup isn't ideal, you can't use your headset microphone or buttons (using MPRIS protocol).

Conclusion

With these two setup, you have a choice for occasionnaly streaming your audio to another device, which may have bluetooth support or something making it interesting enough to go through the setup.

I'm personally happy to be able to use bluetooth headphones through my smartphone to listen to my OpenBSD desktop sound.

Going further

If you want to directly attach bluetooth headphones to your OpenBSD, you can buy an USB dongle that will pair to the headphones and appear as a sound card to OpenBSD.

jcs@ article about Bluetooth audio on OpenBSD