This file is indexed.

/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 &lt;uri&gt;",
                "start",
                create_playlist)
server.register(namespace="dynamic_playlist",
                description="Stop a dynamic playlist.",
                usage="stop &lt;uri&gt;",
                "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 &lt;uri&gt;</code></li>
<li>
<code>dynamic_playlist.stop &lt;uri&gt;</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>