Building an advanced stream: file-based sources
The purpose of this part is to document and illustrate the creation of an advanced stream using static files.
In order to be self-contained, we will use here only pure liquidsoap scripting functionalities. However, all the parts that use pre-defined functions can be implemented using external scripts, which is the most common practice, and has proved to be very convenient in order to integrate your liquidsoap stream into the framework that you use to manage your radio.
Preliminaries
In order to make things more clear and modular, we will separate the code in two parts:
-
radio.liqis the script that contains the definition of the main stream -
library.liqis the script that contains the functions used to build the stream
The scripts here should be tested using the following command line:
liquidsoap /path/to/radio.liq
Thus, we do not define here daemonized script. In order to make
things work smoothly, you should put the following lines at the beginning
of radio.liq:
set("log.file",false)
set("log.stdout",true)
set("log.level",3)
Finally, we add the following line at the beginning of radio.liq,
in order to load our pre-defined functions:
%include "/path/to/library.liq"
We will use the telnet server to interact with the radio.
Thus, we enable the telnet server by adding the following line in radio.liq:
set("server.telnet",true)
An initial model
In this part, we describe the initial stream that we want. We start with a simple stream that contains songs from a static playlist, with some jingles, with 3 songs for one jingle, and output the result to an icecast server. This is described by the following graph:
This very simple stream is defined by the following content
in radio.liq:
# The file source
songs = playlist("/path/to/some/files/")
# The jingle source
jingles = playlist("/path/to/some/jingles")
# We combine the sources and play
# one single every 3 songs:
s = rotate(weights=[1,3], [jingles, songs])
# We output the stream to an icecast
# server, in ogg/vorbis format.
output.icecast(%vorbis,id="icecast",
fallible=true,mount="my_radio.ogg",
host="my_server", password="hack_me_not",
s)
For now, library.liq does not contain any code so we only do:
touch /path/to/library.liq
- Write this script to a file, change the default directories and parameters.
- Run it.
- Listen to your initial stream.
-
Connect to the telnet server (
telnet localhost 1234) -
Try the telnet comment:
icecast.skip - Check that a jingle is played every 3 songs.
-
Sometimes, when skipping, the source does not prepare a new file quickly enough, which breaks the rotation. If this is the case, add the parameter
conservative=trueto each playlist and try again.
Now, we extend this initial stream with some advanced features:
Notify when a song is played
Once the stream is started, we may want to be able to keep track of the songs that are played,
for instance to display this information on a website.
One nice way to do this is to call a function every time that a new track is passed to the
output, which will inform the user of which tracks are played and when. This can be done
using the on_metadata operator.
First, we define a function that is called every time a new metadata is seen in the stream.
This is a function of type (metadata)->unit, i.e. a function that receives the metadata
as argument and returns nothing.
The metadata type is actually [(string*string)],
i.e. a list of elements of the form ("label","value").
Thus, we add the following in library.liq:
# This function is called when
# a new metadata block is passed in
# the stream.
def apply_metadata(m) =
title = m["title"]
artist = m["artist"]
print("Now playing: #{title} by #{artist}")
end
Note:
the string "foo #{bla}" can also be written "foo " ^ bla and is the
string “foo bar”, if bla is the string "bar".
Now, we apply the on_metadata operator with this function just
before passing the final source to the output, so we write in radio.liq,
before the output line:
s = on_metadata(apply_metadata,s)
- Update your scripts.
- Run the new radio.
- Observe the lines printed on new metadata.
-
You may prefer to use the
logfunction rather thanprint.
Solutions:
Custom scheduling
Another issue with the above stream is the fact that jingles have a strict frequency of one jingle every 3 songs. In a lot of cases, you may want more flexibility and have full-features scheduling of your songs. The best approach in this case is t