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:
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:
hostandport: the address of the Icecast server. The defaults arelocalhostand8000.password: the source password, set in the<source-password>entry of youricecast.xml. The default ishackme: change it on any public server.user: the source user,sourceby 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,%fdkaacor%ffmpeg(...). The encoding formats page lists all of them. Theformatparameter sets the stream's content type, for instance"audio/mpeg". Whenformatis empty, Liquidsoap guesses the content type from the encoder. name,description,genreandurl: information about the stream shown by the Icecast server and by directory services.publictells 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_connectruns when the connection is established.on_disconnectruns when the connection stops.on_errorruns when an error happens. It receives the error and arestart_infunction. Callrestart_in(delay)to reconnect afterdelayseconds,restart_in(null)to stop reconnecting, or pass a negative delay to raise the error. Only oneon_errorhandler 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:
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:
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
truefor: mp3, aac, aac+, wav, flac - Set
falsefor 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:
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:
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:
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:
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.
Related pages
- 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.