Introduction
Introduction Statistics Contact Development Disclaimer Help
Title: Stream your OpenBSD desktop audio to other devices
Author: Solène
Date: 05 May 2023
Tags: openbsd streaming icecast hacking
Description: In this article, you will learn how to set up icecast or
pulseaudio to broadcast your OpenBSD system audio to a remote system
(and make use of bluetooth)
# 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:
* it works with anything that can read OGG from the network (any
serious audio client or web browser can do this)
* it's easy to set up
* you can have multiple clients at once
* secure (icecast is in a chroot, and other components are sending data
or playing music)
The cons:
* there is a ~10s delay, which prevents you from watching a video on
your computer and listening the audio from another device (you could
still set 10s offset, but it's not constant)
* reencoding happens, which can slightly reduce the sound quality (if
you are able to tell the difference)
## 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:
* easy to setup
* works fine
The cons:
* no android support
## 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:
* almost no latency (may depend of the network and remote hardware)
* easy to setup
## 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:
* multi room setup with synchronized clients
* compatible with almost any client able to display an HTML5 page
The cons:
* playback latency
* not so easy to setup
# 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…
```
The command is composed of two parts:
* ffmpeg reading the monitor input and sending it to the pipe
* pacat (pulseaudio cat) relaying the pipe input to the pulseaudio
server 10.42.42.199, with some tweaks to reduce the latency
## 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.1…
```
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.1…
```
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`:
* in the `<authentication>` node, change all the passwords. The only
one you will need is the `source` password used to send the audio to
icecast, but set all other passwords to something random.
* in the `<hostname>` node, set the IP or hostname of the computer with
icecast.
* add a `<bind-address>` node to `<listen-socket>` using the example
for 127.0.0.1, but use the IP of the icecast server, this will allow
other to connect.
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:
```shell
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:
* modify `<hostname>` with the hostname used in icecast.
* modify `<password>` with the source password defined earlier.
* modify `<mount>` to something ending in `.ogg` of your liking, this
will be the filename in the URL (can be `/stream.ogg` if you are out of
ideas).
* set `<yp>` to 0, otherwise the stream will appear on the icecast
status page (you may want to have it displayed though).
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:
```shell
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
You are viewing proxied material from dataswamp.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.