Creating an Internet Radio Station with Icecast and Liquidsoap

Creating an Internet Radio Station with Icecast and Liquidsoap

Image
radio

Bill Dengler
Mon, 01/15/2018 – 08:34

Ever wanted to stream prerecorded music or a live event, such as a lecture or
concert for an internet audience? With Icecast and Liquidsoap, you can set up a
full-featured, flexible internet radio station using free software and open
standards.

Icecast is «a streaming media (audio/video) server that currently
supports Ogg (Vorbis and Theora), Opus, WebM and MP3 streams. It can
be used to create an internet radio station or a privately running
jukebox and many things in between. It is very versatile in that new
formats can be added relatively easily and supports open standards for
communication and interaction.»

Liquidsoap is «a powerful and flexible
language for describing your streams. It offers a rich collection of
operators that you can combine at will, giving you more power than you
need for creating or transforming streams. But Liquidsoap is still very
light and easy to use, in the UNIX tradition of simple strong components
working together.»

When combined, Icecast and Liquidsoap can
create a flexible, feature-rich internet radio station. In this article,
I describe how to configure Icecast to host an internet radio station. Then, I
explain how to
install and configure Liquidsoap to connect to Icecast, adding random
(or sequential) music playback with smart cross-fading, prerecorded
randomly inserted announcements and jingles, a song request system
and support for live streams, with automated recording and seamless
switching between live and automated programming. I also show how to configure the
server to serve your stream in MP3, Ogg and Opus formats for maximum
player compatibility.

Icecast, Vorbis and related projects are maintained by Xiph.Org,
a nonprofit organization that develops open multimedia standards and
software. To ensure that you are running the latest version of Icecast,
with all (or most) features, you should install from an official Xiph.Org
repository. Visit the list of official repositories here, and follow the instructions on that page to add the Icecast
repository for your distribution. Then, install using your system’s
package manager. On Debian-based systems (such as Ubuntu), you may be
asked to «configure Icecast» during package installation; select
«no»
as you will configure the server manually if you are following along with this
article.

Open the Icecast configuration file using your preferred
text editor. On Debian-based systems, the file is located at
/etc/icecast2/icecast.xml. The location on other systems may differ; check
your package’s documentation for the correct path. The configuration
file is in XML format and is divided into several sections. First,
enter your server’s location and email into the location and admin fields,
respectively—for example:


The Heart of Gold
zaphodb42@mail.example.com

Since each format you’ll set up in Liquidsoap is a separate Icecast
«source», you’ll quickly exhaust the default source limit of two.
So, change
that to ten:


10

Unless you anticipate listeners connecting from slow or low-bandwidth
environments, disabling Icecast’s burst-on-connect feature will
significantly decrease latency:


0
        0

The default passwords, «hackme», invite security compromise. Change them
to something else. Also, it’s probably a good idea to change the default
admin user name. The following passwords are just examples; change them
for your configuration both here and when they are mentioned later in
the article:


dontpanic
    dontpanic42
            zaphod
            2Headsarebetterthanone!

Enter your system’s fully qualified domain name in the hostname field:


example.com

Save and close the file. If you edited the file as root, you’ll need
to reset its permissions. On Debian-based systems, Icecast runs under
user icecast2 and group icecast. To fix permissions on a Debian-based
system, run:


chown icecast2:icecast /etc/icecast2/icecast.xml

On Debian-based systems, Icecast’s system service is disabled by
default. Open the file /etc/default/icecast2, and set enabled to
true. Then save and close the file.

Most modern Linux systems use systemd for service management. To enable
Icecast on boot and start it for this session, run the following commands
as root (using sudo or similar):


systemctl enable icecast2
systemctl start icecast2

Service names on various systems differ; if those commands don’t work,
check your system’s documentation for the correct service name.

Many distributions provide broken and out-of-date versions of Liquidsoap
in their repositories. For this reason (along with improved ability
to customize your installation), the Liquidsoap developers recommend
installing it using the OCaml Package Manager (opam). Use your distro’s
package manager to install opam. If you’ve been doing everything up to
this point logged in as root, you’ll now need to create a non-root user
under which to install Liquidsoap. You also need to install sudo and give
this new user permission to use it. On Debian-based systems, the
adduser
and gpasswd utilities allow you to create users and add them to groups,
respectively. On Debian-based systems, run the following commands as root
to add a new user and grant it sudo access (for other systems, refer to
the documentation). Let username represent the user name of the new user:


adduser username
gpasswd -a username sudo

Performing as your non-root user, initialize the OCaml Package Manager
by running:


opam init

Answer «yes» when asked to modify your profile; this will place Liquidsoap
on your path and allow it to be executed when you type its name. To
apply opam changes, run:


eval `opam config env`

Next, install Liquidsoap’s system dependencies:


opam install depext
opam depext taglib mad lame vorbis cry ssl samplerate
 ↪magic opus liquidsoap

Now, install liquidsoap by replacing depext with
install:


opam install taglib mad lame vorbis cry ssl samplerate
 ↪magic opus liquidsoap

To set up a starting point for the station configuration and enable
Liquidsoap as a service, the developers have created liquidsoap-daemon, a
set of scripts for using Liquidsoap as a system service. Liquidsoap-daemon
uses systemd for service management by default; therefore, it is compatible
with most modern Linux distributions. To set it up, install Git using your
system’s package manager, then run the following as your non-root user:


git clone https://github.com/savonet/liquidsoap-daemon
cd liquidsoap-daemon
./daemonize-liquidsoap.sh

You may be prompted to enter your user’s password to authenticate
sudo. Once the dæmon is installed, you’ll now create a directory
structure for storing music, jingles and archives of live streams in
your non-root user’s home directory. Run the following command:


mkdir -p ~/music/music1 ~/music/jingles ~/archives

Now, open the file main.liq in the liquidsoap-daemon directory. At this point,
that file just contains:


output.dummy(blank())

This line sends no audio nowhere, which is not very interesting, so delete that
line and add the following base configuration (lines starting with # are
comments, so they are ignored by Liquidsoap). This base configuration sets up
one music playlist with songs played in random order, jingles inserted
approximately every seven songs, smart cross-fading, song requests and
automatically recorded live streams. music.mp3, music.ogg and music.opus
stream stored music and jingles in MP3, Ogg Vorbis and Ogg Opus formats
respectively; stream.mp3, stream.ogg and stream.opus play a live stream
when available, falling back to music when the live stream is down:


#Settings
set("server.telnet", true)
set("server.telnet.port", 1234)
set("harbor.bind_addr","0.0.0.0")
# Music playlists
music1 = playlist("~/music/music1")
# Some jingles
jingles = playlist("~/music/jingles")
# If something goes wrong, we'll play this
security = single("~/music/default.ogg")
# Start building the feed with music
radio = random([music1])
# Add the security, requests and smart crossfade
radio = fallback(track_sensitive = false,
 ↪[smart_crossfade(fallback([request.queue(id="request"),
↪radio])),security])
# Now add some jingles
radio = random(weights = [1, 7],[jingles, radio]) # This plays
# a jingle once every approximately seven songs, change 7 to
# another number to change this
# Add a skip command for the music stream
server.register(
usage="skip",
description="Skip the current song.",
"skip",
fun(_) -> begin source.skip(radio) "Done!" end
#Add support for live streams.
live =
audio_to_stereo(input.harbor("live",port=8080,password=
↪"dontpanic1764",buffer=1.0)) #dontpanic1764 is the
# password used to connect a live stream; it can (and should) be
# different from the source-password in icecast.xml.
full = fallback(track_sensitive=false,
[live,radio])
# Dump archives
file_name = '~/archives/%Y-%m-%d-%H:%M:%S$(if $(title),
↪"-$(title)","").ogg'
output.file(%vorbis,file_name,live,fallible=true)
# Stream it out
output.icecast(%mp3.vbr,
host = "localhost", port = 8000,
password = "dontpanic", mount = "music.mp3",
name="myStation Music Service", description="This is the myStation
 ↪music stream. Add some information about your station's automated
 ↪programming.",
radio)
output.icecast(%vorbis,
host = "localhost", port = 8000,
password = "dontpanic", mount = "music.ogg",
name="myStation Music Service", description="This is the myStation
 ↪music stream. Add some information about your station's
 ↪automated programming.",
radio)
output.icecast(%opus(vbr="unconstrained",bitrate=60),
host = "localhost", port = 8000,
password = "dontpanic", mount = "music.opus",
name="myStation Music Service", description="This is the myStation
 ↪music stream. Add some information about your station's
 ↪automated programming.",
radio)
output.icecast(%mp3.vbr,
host = "localhost", port = 8000,
password = "dontpanic", mount = "stream.mp3",
name="myStation Main Stream", description="The myStation main stream.",
full)
output.icecast(%vorbis,
host="localhost",port=8000,password="dontpanic",
mount="stream.ogg",
name="myStation Main Stream", description="The myStation main stream.",
full)
output.icecast(%opus(vbr="unconstrained",bitrate=60),
 ↪description="The myStation main stream.",
host="localhost",port=8000,password="dontpanic",
mount="stream.opus",
full)

Multiple Music Playlists

You may wish to set up multiple
music playlists, perhaps with different types of music, and change the
frequency at which songs from each playlist are played. To do this,
create directories under music for each playlist, named music2, music3 and so on.
Then just copy the music1 line in the music playlists section of
main.liq, changing the reference to music1 accordingly.

To insert songs randomly from the new playlist every n songs in the stream, add
a line below radio = random([music1]), where
n represents the approximate number of songs to play
before inserting a song from the new playlist:


radio = random(weights = [1, n],[music2, radio])

Here’s an example with three music playlists:


# Music playlists
music1 = playlist("~/music/music1")
music2 = playlist("~/music/music2")
music3 = playlist("~/music/music3")
...
radio = random([music1])
radio = random(weights = [1, 6],[music2, radio])
radio = random(weights = [1,12],[music3, radio])

File-Based Playlists

In the base configuration, Liquidsoap
will search the directory ~/music/music1 recursively for songs to
play. However, you also can give Liquidsoap a newline-delimited text
file of paths to songs, either locally on your system or on the web. To
do this, simply change the path to a directory to a path to your text
file, like this:


music1 = playlist("~/music/music1.pls")

Sequential Playback

By default, Liquidsoap plays tracks in random
order. If you want to play tracks sequentially, add
mode="sequential"
to your playlist definition, like this:


music1 = playlist("~/music/music1",mode="sequential")

Instead of using random (for example, when adding other playlists or jingles),
use rotate:


radio = rotate(weights = [1, 7],[jingles, radio])

Sequential playback is best combined with file-based playlists as they
both give you total control over the order in which tracks are played
by Liquidsoap.

Compression and Normalization

If you’d like to add a more
«radio-like» sound to your automated programming, Liquidsoap supports
automatic compression and normalization. To compress and normalize the
tracks of a playlist or input.harbor live stream, wrap it in an
nrj()
operator, like so:


music1 = nrj(playlist("~/music/music1"))

Talking Over Automated Programming

You can add a mountpoint allowing you to
talk over the automated programming, which will have its volume reduced
while you’re connected. Add the following to your configuration above
#Add support for live streams. The automated programming volume will
be changed to 15% of normal while the mic is connected; change
p=0.15 to adjust:


# Talk over stream using microphone mount.
mic=input.harbor("mic",port=8080,password="dontpanic1764",buffer=1.0)
radio = smooth_add(delay=0.8, p=0.15, normal=radio, special=mic)

Finishing Up

Edit the configuration as necessary, then save and close the file. Record
a file to ~/music/default.ogg; this file will be played when Liquidsoap
cannot find other tracks to play. The file should tell listeners that
the stream is down and give them information for contacting you to
notify you of the problem. Populate the playlist(s) with music, then
start Liquidsoap with the following command:


sudo systemctl start liquidsoap

Enable it on boot:


sudo systemctl enable liquidsoap

Once Liquidsoap is started, visit http://example.com:8000 in a web browser
(where example.com is the fully qualified domain name of your server). If
your system is configured properly, music.mp3, music.ogg and music.opus
will appear, playing automated programming. Also, stream.mp3, stream.ogg
and stream.opus will play automated programming unless a live stream
is connected.

If Icecast appears but no mountpoints are listed, check the Liquidsoap
logs at liquidsoap-daemon/log/run.log for errors. If Icecast doesn’t
load, restart it with systemctl restart icecast2.

To broadcast a live stream through your server, you will need a
compatible source client. For Windows, I recommend Altacast.
For Mac users, I suggest Ladiocast, available in the Mac
App Store. For Linux, install DarkIce through your system’s package
manager. On iOS, I recommend iCast. On Android, I suggest Cool Mic. In
all cases, use the following configuration:

  • Host: your server’s fully
    qualified domain name.

  • Port: 8080

  • Mount (mountpoint): live (or /live)
    for a live stream.
    If you enabled the ability to talk over automated
    programming, replace live with mic to talk over the music.

  • username:
    source (some clients don’t prompt for a user name, in which case, source
    is the implied default).

  • password: dontpanic1764 (or the password you
    specified in the input.harbor configuration).

You can stream in Ogg Vorbis
or MP3. Ogg Opus may or may not work, depending on your source client.

Liquidsoap offers control via TCP (over telnet or similar). The base
configuration presented in this article enables a song request system
and the ability to skip tracks on demand. By default, this interface is
available only to users on the local system. The telnet protocol does not
support authentication. If you want to make song request functionality
available to your users, you’ll need to write a program or script
customized for your station that interfaces with Liquidsoap.

Connect to Liquidsoap via telnet, like so:


telnet localhost 1234

Once connected, you can request a song with the following, where
uri is an absolute path to an audio file on your system or
a URL of an audio file on the internet:


request.push uri

To skip the currently playing song
and immediately play the next one, simply type skip.

For a list of all available commands, type help,
or type help followed by the name of a command for usage information on
a particular command.

To end your session, type quit.

In addition to Liquidsoap’s telnet interface, Icecast also has a web-based
administrative interface that you can use to view listener statistics, kill
Liquidsoap’s streams or move listeners among mountpoints. Access it at
http://example.com:8000/admin (where example.com is your server’s fully
qualified domain name). Use the admin-user and admin-password you set
in icecast.xml.

At this point, you now have a fully functional streaming server that
should fit the needs of most users. However, Liquidsoap is extremely
flexible, allowing for more exotic setups for special use cases. Refer to
the Liquidsoap
documentation
for information
on additional language features that may be useful to you.