/usr/share/doc/liquidsoap/html/dynamic_sources.html is in liquidsoap 1.0.0-4build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | <?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML \
1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>Liquidsoap :: Dynamic source creation</title>
<link href="style.css" type="text/css" rel="stylesheet" />
<link href="homepage.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div id="wrapper">
<div id="header">
<div id="logo">
<h1>Liquidsoap</h1>
<h2>audio stream generation</h2>
</div>
<div>
<ul id="menu">
<li id="menu-about">
<a href="index.html">about</a></li>
<li id="menu-doc-index">
<a href="documentation.html">documentation</a></li>
<li id="menu-doc-api">
<a href="reference.html">API</a></li>
<li id="menu-doc-snippets">
<a href="scripts/index.html">snippets</a></li>
<li id="menu-developers">
<a href="http://savonet.rastageeks.org/">developers</a></li>
</ul>
</div>
</div>
<div id="content"><div>
<p>
Liquidsoap supports dynamic creation and destruction of sources
during the execution of a script. The following gives an example
of this.
</p>
<p>
First some outlines:
</p>
<ul>
<li>
This example is meant to create a new source and outputs. It is not easy currently to change a source being streamed</li>
<li>
The idea is to create a new output using a telnet/server command.</li>
</ul>
<p>
In this example, we will register a command that creates a playlist source using an uri passed
as argument and outputs it to a fixed icecast output.
</p>
<p>
With more work on parsing the argument passed to the telnet command,
you may write more evolved options, such as the possibility to change
the output parameters etc..
</p>
<p>
Due to some limitations of the language, we have used some
intricate (but classic) functional programming tricks. They are
commented in order to help reading the code..
</p>
<p>
New here's the code:
</p>
<pre># First, we create a list referencing the dynamic sources:
dyn_sources = ref []
# This is our icecast output.
# It is a partial application: the source needs to be given!
out = output.icecast(%mp3,
host="test",
password="hackme",
fallible=true)
# Now we write a function to create
# a playlist source and output it.
def create_playlist(uri) =
# The playlist source
s = playlist(uri)
# The output
output = out(s)
# We register both source and output
# in the list of sources
dyn_sources :=
list.append( [(uri,s),(uri,output)],
!dyn_sources )
"Done!"
end
# And a function to destroy a dynamic source
def destroy_playlist(uri) =
# We need to find the source in the list,
# remove it and destroy it. Currently, the language
# lacks some nice operators for that so we do it
# the functional way
# This function is executed on every item in the list
# of dynamic sources
def parse_list(ret, current_element) =
# ret is of the form: (matching_sources, remaining_sources)
# We extract those two:
matching_sources = fst(ret)
remaining_sources = snd(ret)
# current_element is of the form: ("uri", source) so
# we check the first element
current_uri = fst(current_element)
if current_uri == uri then
# In this case, we add the source to the list of
# matched sources
(list.append( [snd(current_element)],
matching_sources),
remaining_sources)
else
# In this case, we put the element in the list of remaining
# sources
(matching_sources,
list.append([current_element],
remaining_sources))
end
end
# Now we execute the function:
result = list.fold(parse_list, ([], []), !dyn_sources)
matching_sources = fst(result)
remaining_sources = snd(result)
# We store the remaining sources in dyn_sources
dyn_sources := remaining_sources
# If no source matched, we return an error
if list.length(matching_sources) == 0 then
"Error: no matching sources!"
else
# We stop all sources
list.iter(source.shutdown, matching_sources)
# And return
"Done!"
end
end
# Now we register the telnet commands:
server.register(namespace="dynamic_playlist",
description="Start a new dynamic playlist.",
usage="start <uri>",
"start",
create_playlist)
server.register(namespace="dynamic_playlist",
description="Stop a dynamic playlist.",
usage="stop <uri>",
"stop",
destroy_playlist)
</pre>
<div align="right">
<a href="scripts/dynamic_playlist.liq">
<img class="grab" src="./images/grab.png" alt="Grab the code!">
</a>
</div></p>
<p>
If you execute this code (add a <code>output.dummy(blank())</code> if you have
no other output..), you have two new telnet commands:
</p>
<ul>
<li>
<code>dynamic_playlist.start <uri></code></li>
<li>
<code>dynamic_playlist.stop <uri></code></li>
</ul>
<p>
which you can use to create/destroy dynamically your sources.
</p>
<p>
With more tweaking, you should be able to adapt these ideas to your
precise needs.
</p>
<p>
If you want to plug those sources into an existing output, you may
want to use an <code>input.harbor</code> in the main output and change the
<code>output.icecast</code> in the dynamic source creation to send everything to
this <code>input.harbor</code>. You can use the <code>%wav</code> format in this case to avoid
compressing/decompressing the data..
</p>
</div></div>
<div>
<div id="footer"> 2003-2011 Savonet team</div>
</div>
</div>
</body></html>
|