Anonymous Guest
|
Posted: Wed Jul 25, 2007 2:41 pm Post subject: A versatile source client: liquidsoap |
|
|
Hi all !
I'd like to present the source client we've been working on.
The specificity of liquidsoap is that, instead of building an ad-hoc solution for that single netradio, it was developped as a flexible tool in which you can combine as you like the features that you want. Hence, it has then been used successfully for several other netradios, for which the usual streaming tools did not suffice.
Describing an audio stream can be very complex: several inputs (file, stream relay, soundcard) can come into play, they can be combined in various ways (audio processing, mixing, track scheduling, fallbacks) and finally output in various ways (several servers/contents/formats). To make it easy without loosing in expressivity, liquidsoap configurations are written in its own little script language.
Let's say that you run an icecast server at host 'myhost' with source's passowrd being 'hackmeimcool', and you want to stream in Ogg/Vorbis a single looped file (Ogg/Vorbis, MP3, WAV, even AAC on the SVN version). Then this may do the job for you:
Code: |
liquidsoap 'output.icecast.vorbis(host="myhost",password="hackmeimcool",mount="mystream.ogg",single("/path/to/my/file"))' |
Now a more complex example.. Let's say that you want to stream all the files contained in a given directory, but relay a live stream as soon as it is available. At this point we need to introduce the notion of 'faillible source'. As we said before, the most important constraint when streaming is to be able to provide data at anytime. Liquidsoap checks this property when starting. For instance, playing a list of files is not safe unless you check that the files are local and valid first, etc..
So, the basic way to start a complex stream is to define a fallback source, which can be a single file (single files are checked at start-up):
Code: |
emergency = single("/path/to/my/file") |
Now define your playlist:
Code: |
main = playlist("/path/to/playlist/directory") |
At this point, you will also create the other source that you want to stream as soon as it is available:
Code: |
live = input.http("http://host:8000/live.ogg") |
For instance this source may be a live show streamed to this mountpoint.
Then you can write the full script, where /usr/bin/liquidsoap is the actual place for the binary:
Code: |
#!/usr/bin/liquidsoap
# Set logging to stdout
set log.dir = "/tmp"
set log.stdout = true
# fallback source:
emergency = single("/path/to/my/file")
# Playlist:
main = playlist("/path/to/playlist/directory")
# Live stream
live = input.http("http://host:8000/live.ogg")
# Fallback from fallback source to playlist:
# The "track_sensitive" parameter is set if we want to wait for the end of
# current song before switching.
source = fallback(track_sensitive=true,[main,emergency])
# Fallback from playlist to live:
# No track_sensitivity here since we do not want to cut the
# begining of the live show... !
source = fallback(track_sensitive=false,[live,source])
# Output source to icecast:
output.icecast.vorbis(host="myhost",password="hackmeimcool",
mount="mystream.ogg",source) |
The complete API is available here: http://savonet.sourceforge.net/wiki/LiqReference
Let's finish instead with a poweruser example, which I hope will make you eager to learn more. Just copy-paste and run, there's nothing to edit!
Code: |
#!/usr/bin/liquidsoap
set log.stdout = true
set log.dir = "/tmp"
set telnet = true
# Define a numbers source that plays a number station,
# or files from a queue that can be fed by the user using telnet.
numbers = input.http("http://zenodore.streaming.radiopytagor.net:8000/numbers-station.ogg")
numbers = strip_blank(length=2.,threshold=-30.,numbers)
numbers = fallback([normalize(request.queue(id="q")),numbers])
# We relay the Dolebraī libre music netradio.
# We wrap it in mksafe(), a predefined operator that plays
# blank when dolebrai fails to relay anything.
normal = mksafe(input.http("http://dolebrai.net:8000/dolebrai.ogg"))
# And now the magic :)
def smooth_add(~normal,~special)
d = 1. # delay before mixing after beginning of mix
p = 0.2 # portion of normal when mixed
fade.final = fade.final(duration=d*.2.)
fade.initial = fade.initial(duration=d*.2.)
q = 1. -. p
# We alias change_volume to c
c = change_volume
fallback(track_sensitive=false,
[special,normal],
transitions=[
fun(normal,special)->
add(normalize=false,[sequence([blank(duration=d),c(q,special)]),
c(q,fade.final(normal)),
c(p,normal)]),
fun(special,normal)->
add(normalize=false,[c(p,normal),c(q,fade.initial(normal))])
])
end
# out is a predefined operator that
# outputs to your local sound card using libao
out(smooth_add(normal=normal,special=numbers)) |
Usage:
copy-paste this to test.liq
make it executable
Run it !
Optionally you can test the following:
telnet localhost 1234
q.push /path/to/file
And listen !
If you are interested in a very flexible way to design your audio stream, feel free to visit our website, drop us a mail at savonet-users@lists.sourceforge.net or join our IRC channel, #savonet on freenode. Liquidsoap is available in debian testing and unstable. |
|