This will probably work on any computer that has a network connection and runs mpd but I used a Raspberry Pi. Goal: play internet radio via the command line and learn about Bash programming.
My setup is as follows: RPi Model B powered by micro-USB cable, ethernet cable from RPi to router, HDMI cable from HDMI port to home stereo. I use ssh -x pi@raspberrypi
to log in to the RPi from another computer on the same router via ssh, without X11. Audio output might be impacted by more connections or other forms of remote access.
Bring your system up-to-date, install base audio tools and mpd/mpc, add yourself to the audio group (standard user pi
is already a member), create a file called piradio
in the /usr/local/bin
directory (file content to be copied now or later from The Script), configure the mpd server dæmon. Commands:
sudo apt-get update sudo apt-get -y dist-upgrade sudo apt-get -y install avahi-daemon avahi-utils alsa-base alsa-tools alsa-utils mpd mpc sudo adduser `whoami` audio sudo touch /usr/local/bin/piradio sudo chmod 755 /usr/local/bin/piradio sudo nano /etc/mpd.conf sudo service mpd restart
When editing the mpd.conf
file, check or add the following lines, where raspberrypi
is the hostname of your RPi (change it with sudo raspi-config
but then also change these lines!) and .fritz.box
is the DNS suffix of your local router (modem). It could be this or .lan
or something else entirely. If you don't bind to "any" or to IP addresses explicitly, the following will work on a mixed IPv4/IPv6 network. At least it does on mine :)
bind_to_address "localhost" bind_to_address "raspberrypi" bind_to_address "raspberrypi.local" bind_to_address "raspberrypi.fritz.box"
You might need to expressly select either the headphone jack or the HDMI port for audio output. In the cset
variant of the following command, the last number determines which way the audio output goes: 0
= automatic (system default), 1
= headphone, 2
= hdmi.
amixer cget numid=3 amixer cset numid=3 0
You may also use amixer
to set the system volume independent from mpd/mpc or other audio programs. Use a percentage from zero to a hundred:
amixer cset numid=1 85%
The piradio
script uses a file called .radiodb
in your home directory to look up radio stations. Any station you wish to use, should be listed in that plain text file. Every station goes on a new line. Start with a Station ID (just make one up) and finish with the Stream URL. Separate the IDs and URLs with spaces or tabs. No spaces or tabs at the start or end of the line! Also, no spaces in the Station ID. Station IDs don't have to be unique but only the first match will be accessible. Below is my ~/.radiodb
file with mostly Dutch and BBC radio stations. To create this file, upload it to your home directory (get it from my GitHub) or start with nano ~/.radiodb
. If you change the name or location of the station database file, make sure to change The Script correspondingly where it says DBNAME=name
and DBFILE=location
.
fip http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-midfi.mp3 fip5 http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio5.mp3 arrow http://91.221.151.155:80/ 10 http://stream.radio10.nl/radio10aac class http://19333.live.streamtheworld.com:80/CLASSICFMAAC.aac 1 http://icecast.omroep.nl/radio1-bb-aac 2 http://icecast.omroep.nl/radio2-bb-aac 3 http://icecast.omroep.nl/3fm-bb-aac 4 http://icecast.omroep.nl/radio4-bb-aac 5 http://icecast.omroep.nl/radio5-bb-aac 6 http://icecast.omroep.nl/radio6-bb-aac bbc1 http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio1_p bbc1x http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_1xtra_p bbc2 http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio2_p bbc3 http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio3_p bbc4 http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio4_p bbc4x http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_radio4extra_p bbc5 http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_5live_p bbc5x http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_5sportxtra_p bbc6 http://bbcmedia.ic.llnwd.net/stream/bbcmedia_intl_he_6music_p bbcws http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-eieuk bbcwn http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-einws stubru http://mp3.streampower.be/stubru-high.mp3 mnm http://mp3.streampower.be/mnm-high.mp3 klara http://mp3.streampower.be/klara-high.mp3 frclass http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/francemusique-midfi.mp3 ancient http://5.152.208.98:8058/ trip http://ice.somafm.com/thetrip ds1 http://ice.somafm.com/deepspaceone space http://ice.somafm.com/spacestation 192 http://server-14.stream-server.nl:8030/ bnr http://81.173.3.251/ veron http://8633.live.streamtheworld.com:80/VERONICAAAC_SC sky http://8543.live.streamtheworld.com:80/SKYRADIOAAC_SC 538 http://82.201.100.23/RADIO538_WEB_AAC fresh http://stream12.freshfmonline.com/ dB http://91.221.151.253:80/ slam http://vip-icecast.538.lw.triple-it.nl:80/SLAMFM_MP3 funx http://icecast.omroep.nl/funx-bb-mp3 fip1 http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio1.mp3 fip2 http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio2.mp3 fip3 http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio3.mp3 fip4 http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio4.mp3 fip6 http://aifae8cah8.lb.vip.cdn.dvmr.fr:80/fip-webradio6.mp3 nprmp3 http://current.stream.publicradio.org/kcmp.mp3 npraac http://current.stream.publicradio.org/kcmp.aac
If you hadn't already, create an executable bash script file called piradio
in the /usr/local/bin
directory and start editing it: sudo nano /usr/local/bin/piradio
. Copy all text from the block below and paste it into the piradio
script, or download it from my GitHub. The GitHub might be slightly more up-to-date.
#!/bin/bash ####################################################################### # Made by : Ewoud Dronkert # Licence : GNU GPL v3 # Platform : Raspberry Pi # Requires : Bash, mpd, mpc # Location : /usr/local/bin/ # Name : piradio # Version : 1.0.0 # Date : 2014-12-02 # Purpose : Play radio streams via local mpd audio server # Use station abbreviations from user file .radiodb # Parameters : <none> | <station> | list | # vol [ + | - | min | max | def | 0..100 ] | # on | off | help # Exit 0 : success # 1 : help displayed # 2 : .radiodb local user file not found # 3 : station abbreviation not recognised # 4 : mpc executable not found ####################################################################### # Variables PLAYER=/usr/bin/mpc DBNAME=.radiodb DBFILE=/home/pi/$DBNAME DEFVOL=85 ADJVOL=5 # Error codes declare -i ERR_OK=0 declare -i ERR_HELP=1 declare -i ERR_DBNOTFOUND=2 declare -i ERR_IDNOTFOUND=3 declare -i ERR_APPNOTFOUND=4 # Copy/redirect output to stderr function StdErr () { cat - 1>&2 } if [ ! -x "$PLAYER" ]; then echo | StdErr echo " Radio player not found: $PLAYER" | StdErr echo | StdErr exit $ERR_APPNOTFOUND fi # Help if [[ "$1" == "help" || "$1" == "--help" || "$1" == "/help" || \ "$1" == "-h" || "$1" == "/h" || \ "$1" == "?" || "$1" == "-?" || "$1" == "/?" ]]; then echo | StdErr echo " Usage:" | StdErr echo " - Which station is on? : radio" | StdErr echo " - Tune to a station : radio <station-id>" | StdErr echo " - List all stations : radio list" | StdErr echo " - Show or adjust volume : radio vol [ + | - | min | max | def | 0..100 ]" | StdErr echo " - Mute or unmute : radio mute" | StdErr echo " - Turn radio on or off : radio on | off" | StdErr echo | StdErr exit $ERR_HELP fi # Display current station/stream/volume if no argument if [ -z "$1" ]; then curvolume=$($PLAYER volume | grep --colour=never -m 1 -oP '\d+') curstream=$($PLAYER -f "%file%" current) if [ -z "$curstream" ]; then curstation="(no stream found)" else if [ -f $DBFILE ]; then curstation=$(cat $DBFILE | grep --colour=never -m 1 -F "$curstream" | grep --colour=never -oP '^\S+') if [ -z "$curstation" ]; then curstation="(station not found)" fi else curstation="(station database not found at \"$DBFILE\")" fi fi echo [ -z "$curstation" ] || echo " Station : $curstation" [ -z "$curstream" ] || echo " Stream : $curstream" [ -z "$curvolume" ] || echo " Volume : $curvolume" echo exit $ERR_OK fi # List station IDs from station database if [[ "$1" == "list" ]]; then if [ -f $DBFILE ]; then echo echo " List of all stations:" cat $DBFILE | grep --color=never -oP "^\S+" | sort | sed s/^/\\t/ echo exit $ERR_OK else echo | StdErr echo " Station database not found at \"$DBFILE\"" | StdErr echo | StdErr exit $ERR_DBNOTFOUND fi fi # Turn radio on if [[ "$1" == "on" || "$1" == "play" ]]; then # TODO: check if a radio stream is lined up $PLAYER play > /dev/null exit $ERR_OK fi # Turn radio off if [[ "$1" == "off" || "$1" == "stop" ]]; then $PLAYER stop > /dev/null exit $ERR_OK fi # Display volume, optionally set or adjust or mute/unmute if [[ "$1" == "vol" || "$1" == "mute" ]]; then declare -i curvol=$($PLAYER volume | grep --colour=never -m 1 -oP '\d+') declare -i newvol=$curvol declare -i minvol=10 declare -i maxvol=100 if [[ "$1" == "mute" || "$2" == "mute" ]]; then if (( curvol > minvol )); then # mute newvol=$minvol else # unmute newvol=$DEFVOL fi else if [ -n "$2" ]; then case "$2" in min) newvol=$minvol;; max) newvol=$maxvol;; def) newvol=$DEFVOL;; +) (( newvol = curvol + ADJVOL ));; -) (( newvol = curvol - ADJVOL ));; *) newvol="$2";; esac if (( newvol >= maxvol )); then newvol=$maxvol elif (( newvol <= minvol )); then newvol=$minvol fi fi fi if (( newvol != curvol )); then # volume adjustment $PLAYER volume $newvol > /dev/null curvol=$newvol fi echo echo " Volume: $curvol" echo exit $ERR_OK fi # Argument is a Station ID # Escape argument for use with grep -P # Is it really safe? Not sure. Couldn't make escaping ] work, for instance. safe=$(echo "$1" | sed -e 's/\s*//g' | sed -e 's/[\[\\^$.*?"-]/\\\0/g') [ -f $DBFILE ] && stream=$(cat $DBFILE | grep --color=never -m 1 -P "^$safe\s" | grep --color=never -oP '\S+$') if [ -z "$stream" ]; then echo | StdErr echo " Station \"$1\" not found." | StdErr echo " List stations : radio list" | StdErr echo " Usage info : radio help" | StdErr echo | StdErr exit $ERR_IDNOTFOUND fi $PLAYER stop > /dev/null $PLAYER clear > /dev/null #$PLAYER volume $DEFVOL > /dev/null $PLAYER add $stream > /dev/null $PLAYER play > /dev/null exit $ERR_OK
Type piradio help
to see all options.
pi@raspberrypi ~ $ piradio pi@raspberrypi ~ $ piradio list pi@raspberrypi ~ $ piradio fip pi@raspberrypi ~ $ piradio 1 pi@raspberrypi ~ $ piradio vol + pi@raspberrypi ~ $ piradio off