This is a tutorial on how to use pulseaudio to stream the audio output of any program as an internet radio station.
I arrived at this solution because I have kind of a weird music set up: My collection of mostly Ogg Vorbis files are on a network-attached storage device in my apartment, exposed to the local network as a DAAP service. I can use rhythmbox to browse and play my music via this service.
When I became interested in internet radio, I learned that my setup wasn't conducive to streaming. Most tools that make broadcasting easy are designed to work with local files, but I specifically wanted to keep using rhythmbox and DAAP to play my music, even when broadcasting. It turns out that if you're already using pulseaudio, this is not that difficult to do! In fact, it comes with a significant upside: You can stream the sound from any program you want, and even include a microphone monitor!
Obviously there are a lot of ways to do this, but if you want to do things exactly as I did, this is what you'll need:
- the radio station: an internet-accessible host for running 
icecast2, I use a Linode VPS - the recording studio: a computer that uses 
pulseaudiofor sound, I use Ubuntu on a Thinkpad X1 Carbon - an audio player of your choice, I use 
rhythmboxbut anything will do - the command-line tool 
darkicefor streaming pulseaudio to icecast - the GUI tool 
pavucontrol(Pulse Audio Volume Control) for managing the inputs and outputs 
The radio station
The first thing you'll need is an internet-accessible host for running your
radio station. For this, I'm using a cheap Linode VPS with the name
radio.butts.team pointed at it, on which I install icecast2 as root:
# as root on the icecast host
apt install icecast2
By default, icecast2 will start automatically and only needs to have the config
updated to add the password we will use to authenticate when broadcasting:
# as root on the icecast host
vim /etc/icecast2/icecast.xml # edit authentication block to set passwords
service icecast2 restart
That's it! Your internet radio station is now waiting for you to start streaming. It's worth mentioning that at this point you can easily use a conventional player like Internet DJ Console to broadcast, and skip the rest of this tutorial.
If you want the flexibilty of using pulseaudio instead, what follows is a method for configuring your workstation to do just that.
The recording studio
NOTE The remainder of these examples are meant to be run on the machine you use to play music.
Step 1: broadcasting music
The trick to streaming via pulseaudio while still having normal use of your
computer audio is to create a new sink specifically for your radio stream:
pactl load-module module-null-sink sink_name=Radio sink_properties="device.description='Radio'"
In pulse, sound comes from a source and outputs to a sink. This command creates a null sink named "Radio" that will be used to isolate the radio stream from other audio on the computer.
In order to stream that audio to your radio station for broadcasting, we'll use darkice:
sudo apt install darkice
cp /etc/share/darkice.cfg.gz .
gunzip darkice.cfg.gz
vim darkice.cfg
In darkice.cfg update the input section to use pulse:
[input]
device = pulse
# ...
Also, update the icecast2 config:
[icecast2-0]
server = <radio station hostname>
password = <radio station password>
# ...
The remaining config blocks in the file (for streaming to other types of service) can be deleted.
With this done, you can start darkice to enable streaming to your radio station:
darkice -c darkice.cfg
Now that we have an audio sink and a streaming source we can use pavucontrol
to configure them:
sudo apt install pavucontrol
pavucontrol
In the "Recording" tab of pavucontrol (make sure "All Streams" are showing)
you'll see a new device that streams all audio to your radio station. Set it to
monitor the "Radio" sink that you created earlier.
Then, in the "Playback" tab of pavucontrol find the app that you want to
stream from and set it to output to "Radio".
That's it! If everything worked, the audio from your seleted app is now streaming over the internet!
Step 2: the microphone monitor
At this point, we can use any app as an audio source for our internet radio station, but we don't yet have a way to use our microphone! To enable it, we need a way to use the microphone as an audio source that can be pointed at the Radio sink. This is accomplished by adding a loopback interface:
pactl load-module module-loopback latency_msec=1 sink=Radio sink_dont_move=true
Now in the "Recording" tab of pavucontrol there is another entry for the
loopback interface, which you can then point at your microphone. You'll want to
leave it muted except when you're broadcasting your mic, or your microphone
audio will always be broadcast on the stream, probably not what you intended!
Step 3: make it permanent
Once all this is done, you might not want to re-do all of this the next time
you restart your computer, so be sure to add your pulseaudio config to the end
of /etc/pulse/default.pa:
# at the end of /ect/pulse/default.pa
load-module module-null-sink sink_name=Radio sink_properties="device.description='Radio'"
load-module module-loopback latency_msec=1 sink=Radio sink_dont_move=true
This will ensure that pulseaudio is configured on system start, but you will
still need to start darkice and use pavucontrol to resume streaming.
Listening to the radio
Visiting your radio station host and port with a web browser will show you a useful interface for accessing your stream. Here's the icecast UI for my own radio station: radio.butts.team. I recommend using VLC, but any media player should be able to stream it.
Caveats
The default Ubuntu volume controls will mess up your stream if you touch them!
If you don't stick with pavucontrol exclusively when you're streaming, a
volume change will likely reset your music program to output to your speakers.
This can probably be alleviated with the right pulseaudio settings but I
haven't figure this out yet.
It's probably too easy to broadcast your mic accidentally, I might be able to alleviate this as well by setting it mute by defaut or something similar. I haven't figured this out yet either.