Skip to main content
Version: 2.5.x (dev)

Streaming to Icecast and Shoutcast

Icecast is the most common way to put a radio on the internet. Liquidsoap generates and encodes the stream, sends it to an Icecast server, and the Icecast server relays it to all your listeners. Each stream on the server lives at its own mount point, for instance /radio.mp3, so a single Icecast server can carry several streams. The quick start explains how Liquidsoap, the streaming server and the listeners fit together.

Liquidsoap can also stream to Shoutcast servers, see Shoutcast below.

Icecast output​

Icecast outputs are done using the output.icecast operator. It takes an encoding format, the source to stream, and the connection details of the server:

icecast-output-basic.liq
radio = mksafe(playlist("~/music"))

output.icecast(
%mp3(bitrate = 128),
host="icecast.example.org",
port=8000,
password="hackme",
mount="/radio.mp3",
name="My radio",
description="Music all day long",
genre="Various",
url="https://radio.example.org",
radio
)

The main parameters are:

  • host and port: the address of the Icecast server. The defaults are localhost and 8000.
  • password: the source password, set in the <source-password> entry of your icecast.xml. The default is hackme: change it on any public server.
  • user: the source user, source by default. Set it when your server uses per-mount-point users.
  • mount: the mount point of the stream. This parameter is mandatory.
  • the encoding format, for instance %mp3, %vorbis, %opus, %fdkaac or %ffmpeg(...). The encoding formats page lists all of them. The format parameter sets the stream's content type, for instance "audio/mpeg". When format is empty, Liquidsoap guesses the content type from the encoder.
  • name, description, genre and url: information about the stream shown by the Icecast server and by directory services. public tells the Icecast server whether the stream may be listed in public directories.

As usual, liquidsoap -h output.icecast gives you the full list of options for this operator.

Fallible sources​

By default, output.icecast expects a source that is always available. This is why the example above wraps the playlist in mksafe. If you want the output to stop streaming when the source has nothing to play, set fallible=true: the output stops when its source fails and starts again when the source becomes available.

Connection and reconnection​

When the connection to the Icecast server fails, or when the server closes it, Liquidsoap logs the error and tries to reconnect after 3 seconds. It keeps trying for as long as the script runs. The connection_timeout parameter sets how long Liquidsoap waits when establishing the connection (5 seconds by default) and timeout sets how long it waits on reads and writes (30 seconds by default).

The output has callback methods to react to the connection state:

  • on_connect runs when the connection is established.
  • on_disconnect runs when the connection stops.
  • on_error runs when an error happens. It receives the error and a restart_in function. Call restart_in(delay) to reconnect after delay seconds, restart_in(null) to stop reconnecting, or pass a negative delay to raise the error. Only one on_error handler is active at a time: a new registration replaces the previous one.

For instance, the following script logs connection changes and waits 10 seconds before each reconnection:

icecast-output-callbacks.liq
radio = mksafe(playlist("~/music"))

o =
output.icecast(
%mp3,
host="icecast.example.org",
password="hackme",
mount="/radio.mp3",
radio
)

o.on_connect(
synchronous=false,
fun () ->
log.important(
"Connected to icecast"
)
)

o.on_disconnect(
synchronous=false,
fun () ->
log.important(
"Disconnected from icecast"
)
)

o.on_error(
synchronous=true,
fun (~restart_in, err) ->
begin
log.important(
"Icecast error: #{error.message(err)}, reconnecting in 10 seconds"
)
restart_in(10.)
end
)

When Liquidsoap connects, it sends the last metadata of the source, so that listeners see the current song right away. Set send_last_metadata_on_connect=false to disable this.

Protocols​

output.icecast talks to the server using the HTTP protocol of Icecast 2. The method parameter selects the HTTP request used to send the stream: "source" (the default), "put" or "post". Recent Icecast versions accept "put". Set chunked=true to use chunked transfer encoding.

Shoutcast servers use the older ICY protocol. output.shoutcast uses it, see Shoutcast below.

HTTPS​

To send the stream over an encrypted connection, pass an SSL or TLS transport to the transport parameter. http.transport.ssl is available when Liquidsoap is compiled with libssl, and http.transport.tls when it is compiled with ocaml-tls:

icecast-output-https.liq
radio = mksafe(playlist("~/music"))

output.icecast(
%mp3,
transport=http.transport.ssl(),
host="icecast.example.org",
port=8443,
password="hackme",
mount="/radio.mp3",
radio
)

The Icecast server must listen for TLS connections on that port.

ICY metadata​

ICY metadata is the name for the mechanism used to update metadata in icecast's source streams. The technique is primarily intended for data formats that do not support in-stream metadata, such as mp3 or AAC. However, it appears that icecast also supports ICY metadata update for ogg/vorbis streams.

When using the ICY metadata update mechanism, new metadata are submitted separately from the stream's data, via an HTTP GET request. The format of the request depends on the protocol you are using (ICY for shoutcast or HTTP for icecast 2).

Formats using the ogg container, such as %vorbis or %opus, carry their metadata inside the stream. Liquidsoap inserts the metadata in the encoded data and listeners receive it along with the audio.

You can do several interesting things with ICY metadata updates in liquidsoap. We list some of those here.

Enable/disable ICY metadata updates​

You can enable or disable icy metadata update in output.icecast by setting the send_icy_metadata parameter to null, true or false. The default value is null and does the following:

  • Set true for: mp3, aac, aac+, wav, flac
  • Set false for any format using the ogg container

In some cases, liquidsoap might not be able to detect if ICY metadata need to be enabled, in which case it will ask you to set a true or false value for this parameter.

Choosing the metadata sent​

The icy_metadata parameter lists the metadata fields sent with each ICY update. The default list is song, title, artist, genre, date, album, tracknum, comment, dj and next. Only the fields in this list are sent.

The encoding parameter sets the character encoding used to send metadata and the stream information (name, genre and description). The default is UTF-8. Some older servers and players expect ISO-8859-1.

song metadata​

Most Icecast listeners expect a song metadata to be generated. This metadata should combine both artist and title metadata and will be displayed preferably.

We provide a default implementation that returns artist or title metadata when only one of these two is available and $(artist) - $(title) otherwise.

You can use the icy_song parameter to use your own implementation. Returning null from that function disables the metadata altogether.

The following example sends a shorter list of fields, builds song as artist: title, and uses ISO-8859-1:

icecast-output-icy.liq
radio = mksafe(playlist("~/music"))

output.icecast(
%mp3,
host="icecast.example.org",
password="hackme",
mount="/radio.mp3",
send_icy_metadata=true,
icy_metadata=["song", "title", "artist", "album"],
icy_song=fun (m) ->
m["title"] == ""
? null
: "#{m['artist']}: #{m['title']}",
encoding="ISO-8859-1",
radio
)

Update metadata manually​

The function icy.update_metadata implements a manual metadata update using the ICY mechanism. It can be used independently from the send_icy_metadata parameter described above, provided icecast supports ICY metadata for the intended stream.

For instance the following script registers a telnet command named metadata.update that can be used to manually update metadata:

icy-update.liq
def icy_update(v) =
# Parse the argument
l = string.split(separator=",", v)
def split(l, v) =
v = string.split(separator="=", v)
if
list.length(v) >= 2
then
list.append(l, [(list.nth(v, 0, default=""), list.nth(v, 1, default=""))])
else
l
end
end
meta = list.fold(split, [], l)

# Update metadata
icy.update_metadata(
mount="/mystream",
password="hackme",
host="myserver.net",
meta
)
"Done !"
end

server.register(
"update",
namespace="metadata",
description="Update metadata",
usage="update title=foo,album=bar,..",
icy_update
)

As usual, liquidsoap -h icy.update_metadata lists all the arguments of the function.

Shoutcast​

Although Liquidsoap is primarily aimed at streaming to Icecast servers (which provide many more features than Shoutcast), it is also able to stream to Shoutcast.

Shoutcast servers accept streams encoded with the MP3 or AAC/AAC+ codec. You need to compile Liquidsoap with lame or FFmpeg support, so it can encode in MP3. Liquidsoap also has support for AAC+ encoding using FDK-AAC or using an external encoder. The recommended format is MP3.

Shoutcast outputs are done using the output.shoutcast operator with the appropriate parameters. An example is:

shoutcast.liq
radio = single("audiofile.ogg")

output.shoutcast(
%mp3,
host="shoutcast.example.org",
port=8000,
password="changeme",
radio
)

output.shoutcast takes the same parameters as output.icecast, except mount, description and method. Shoutcast v2 servers can carry several streams: select the stream with the icy_id parameter (1 by default). The dj parameter adds a dj metadata field to the stream, and aim, icq and irc fill in the matching contact fields of the stream.

As usual, liquidsoap -h output.shoutcast gives you the full list of options for this operator.

Shoutcast as relay​

A side note for those of you who feel they "need" to use Shoutcast for non-technical reasons (such as their stream directory service...): you can still stream to an Icecast server with all its features, and then relay the Icecast stream through a Shoutcast server. In the Shoutcast v2 server configuration, set the relay URL of the stream to the full address of the Icecast mount point, for instance http://icecast.example.org:8000/radio.mp3.

Multiple outputs​

A single source can feed as many outputs as you want. A common setup streams the same radio in several formats, each on its own mount point, so that every listener can pick one that suits their player and bandwidth:

icecast-output-multiple.liq
radio = mksafe(playlist("~/music"))

output.icecast(
%mp3(bitrate = 128),
host="icecast.example.org",
password="hackme",
mount="/radio.mp3",
radio
)

output.icecast(
%vorbis(quality = 0.5),
host="icecast.example.org",
password="hackme",
mount="/radio.ogg",
radio
)

output.icecast(
%fdkaac(bitrate = 64),
host="icecast.example.org",
password="hackme",
mount="/radio.aac",
radio
)

Each output encodes the source separately. Liquidsoap computes the source once and shares it between the outputs.

  • To run an Icecast-compatible server inside Liquidsoap, and serve your streams to listeners without a separate Icecast server, see Icecast server.
  • To stream with HLS, see HLS output.