Zack Scholl

zack.scholl@gmail.com

Internet radio

 / #music #software #raspberrypi 

Easily broadcast music from your computer.

For several years I’ve been interested in easily making an internet broadcast of live audio or recorded audio without using social media apps (i.e. Instagram/Youtube/Twitch/etc). The most problematic for me thing about broadcasting audio is port forwarding (I’m often on devices that don’t have access to routers). To solve this problem I wrote a simple server that runs in the cloud which can handle any number of realtime broadcasts uploaded using a simple curl command. This allows you to essentially broadcast radio feeds with a single line.

Publicizing internet streams without port forwarding

For me, the hardest part about making an internet radio is opening it up to the public internet. I don’t have access to port-forwarding in many scenarios where I want to broadcast (i.e. broadcasting from friends places, or from a music device). My solution to the problem of broadcasting audio without port-forwarding was to create a free and public “dummy” server that handles any incoming traffic and forwards to any number of connected clients. This server keeps track of connected clients and routes incoming packets to them, otherwise discarding the packets.

You could then simply use a common utility like curl to stream data to this server to those peers. This is essentially what Twitch/Youtube/Instagram do, but I designed a server without any social aspects, its just a dumb URL endpoint that can consume and produce audio streams (or any stream).

The server itself lives at broadcast.schollz.com. The code is open-source and available on Github at schollz/broadcast-server. The code is less than 400 lines, and exceedingly simple. You POST data streams to any endpoint you want, and processing GET requests to that endpoint just return the data in that stream. There are special flags if you want to advertise or archive your stream.

Now using this really dumb server which just lives on a DigitalOcean droplet you can easily create internet streams from anywhere, with anything, using a variety of methods.

Live station using ffmpeg

To make a live internet radio from the input of your computer, you can do it in one line (albeit long line):

1ffmpeg -f alsa -i hw:0 -f mp3 - | \
2    curl -s -k -H "Transfer-Encoding: chunked" -X POST -T - \
3    "https://broadcast.schollz.com/YOURSTATIONNAME.mp3?stream=true&advertise=true"

That one-liner takes input from your default input hw:0 and streams it into a POST request to the dummy server making the stream available at broadcast.schollz.com/YOURSTATIONNAME.mp3. Make sure you wear headphones if you create a stream on the same computer you are listening to the stream (because feedback)!

Live station using vlc

Linux:

1vlc -I dummy alsa://plughw:0,0 --sout='#transcode{vcodec=none,acodec=mp3,ab=256,channels=2,samplerate=44100,scodec=none}:standard{access=file,mux=mp3,dst=-}' --no-sout-all --sout-keep | curl -k -H "Transfer-Encoding: chunked" -X POST -T -  'https://broadcast.schollz.com/YOURSTATIONNAME.mp3?stream=true&advertise=true'

Mac (requires VLC 2.0.0 or later):

1vlc -I dummy -vvv qtsound:// --sout='#transcode{vcodec=none,acodec=mp3,ab=256,channels=2,samplerate=44100,scodec=none}:standard{access=file,mux=mp3,dst=-}' --no-sout-all --sout-keep | curl -k -H "Transfer-Encoding: chunked" -X POST -T -  'https://broadcast.schollz.com/YOURSTATIONNAME.mp3?stream=true&advertise=true'

Playlist station using ffmpeg

Creating an internet radio station from a music playlist is also easily done. You need one extra common utility: cstream which will make sure the stream is sent in realtime, so its not loaded into memory. Here’s a one liner that will take any folder and create a randomly shuffled playlist and stream it to the station:

1find ~/Music/ | grep 'wav\|mp3\|flac' | shuf | sed -e "s/^/file '/" | \
2    sed -e "s/$/'/" > /tmp/playlist.txt && \
3    ffmpeg -f concat -safe 0 -i /tmp/playlist.txt -f mp3 -ar 44100 -b:a 256k - | \
4    cstream -t 32k | \
5    curl -s -k -H "Transfer-Encoding: chunked" -X POST -T -  \
6    "https://broadcast.schollz.com/YOURSTATIONNAME.mp3?stream=true&advertise=true"

In this case we are streaming at 256 kbps, which is 32 KB/s, so cstream is set to throttle the data to that rate so it transfers in “realtime”.

Play file using vlc

1vlc -I dummy ANYFILE ':sout=#transcode{acodec=mp3,ab=52,channels=2}:standard{access=file,mux=mp3,dst=-}'  | cstream -t 16k | curl -k -H "Transfer-Encoding: chunked" -X POST -T -  'https://broadcast.schollz.com/YOURSTATIONNAME.mp3?stream=true&advertise=true'

Method 2 of 2: Broadcasting using icecast2 and darkice

The icecast2 and darkice utilities are installed via apt-get and really powerful when it comes to streaming. I won’t go into much detail with these two, because there are a lot of guides for it at other places. Here is a great guide for doing live radio on a Raspberry Pi.

If you are on Linux, you can also make your entire computer audio part of the stream (i.e. your browser, VLC, etc.). You can do this with JACK. Simply install JACK:

1sudo apt install jackd pulseaudio-module-jack 

Then start JACK and load the sink/source for pulse audio:

1jackd -R -dalsa -dhw:0,0 &
2pactl load-module module-jack-sink channels=2
3pactl load-module module-jack-source channels=2
4pacmd set-default-sink jack_out
5pacmd set-default-source jack_in

Now start icecast2 and darkice with a JACK configuration.

1wget https://raw.githubusercontent.com/schollz/broadcast/main/icecast.xml
2wget https://raw.githubusercontent.com/schollz/broadcast/main/darkice.cfg
3icecast2 -c icecast.xml & 
4darkice -c darkice.cfg

Now simply connect darkice into JACK!

1jack_connect 'PulseAudio JACK Sink:front-right' darkice:right
2jack_connect 'PulseAudio JACK Sink:front-left' darkice:left

Making a darkice stream public

Once you have your darkice/icecast2 stream, you can make it public by port forwarding. There are lots of guides for that. But another way you could do it is using the dummy broadcast server I mention above. Simply pipe the output from darkice and POST it to the server!

1curl http://localhost:8000/radio.mp3 | \
2    curl -H "Transfer-Encoding: chunked" -X POST -T -  \
3    'https://broadcast.schollz.com/YOURSTATIONNAME.mp3?stream=true'

That’s it! Now your stream will be available at broadcast.schollz.com/YOURSTATIONNAME.mp3.

Integration with live music tools

I do a lot of projects with the pi-based sound computer called “norns” which lets you define its behavior with scripts and DSP and basically functions as a sample-cutter, polysynth, drum machine, drone box, granulator, etc.

The norns music tool is based in Linux, so the above methods are just as applicable. This means that the norns can be turned into a broadcast station, while retaining all the functionality as a DSP device! Here’s my little script that converts live audio into a broadcast, directly from your house or live music venue (as long as you have WiFi).

norns broadcasting internet radio

The above norns script uses the darkice/icecast2 because it is based around JACK, but it works beautifully despite running on a Raspberry Pi 3+ and simultaneously running a sample-cutter and SuperCollider synthesizers.