-updated liquidsoap scripts + library to be liquidsoap-beta2 compliant
This commit is contained in:
parent
022b013dd2
commit
3dc1380fab
|
@ -71,7 +71,7 @@ def output.icecast.lame(
|
||||||
~host="localhost",~port=8000,
|
~host="localhost",~port=8000,
|
||||||
~user="source",~password="hackme",
|
~user="source",~password="hackme",
|
||||||
~genre="Misc",~url="http://savonet.sf.net/",
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
~description="OCaml Radio!",~public=true,
|
~description="Liquidsoap Radio!",~public=true,
|
||||||
~dumpfile="",~mount="Use [name]",
|
~dumpfile="",~mount="Use [name]",
|
||||||
~name="Use [mount]",~protocol="http",
|
~name="Use [mount]",~protocol="http",
|
||||||
~lame="lame",~bitrate=128,~swap=false,
|
~lame="lame",~bitrate=128,~swap=false,
|
||||||
|
@ -130,7 +130,7 @@ def output.shoutcast.lame(
|
||||||
~host="localhost",~port=8000,
|
~host="localhost",~port=8000,
|
||||||
~user="source",~password="hackme",
|
~user="source",~password="hackme",
|
||||||
~genre="Misc",~url="http://savonet.sf.net/",
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
~description="OCaml Radio!",~public=true,
|
~description="Liquidsoap Radio!",~public=true,
|
||||||
~dumpfile="",~name="Use [mount]",~icy_reset=true,
|
~dumpfile="",~name="Use [mount]",~icy_reset=true,
|
||||||
~lame="lame",~aim="",~icq="",~irc="",
|
~lame="lame",~aim="",~icq="",~irc="",
|
||||||
~fallible=false,~on_start={()},~on_stop={()},
|
~fallible=false,~on_start={()},~on_stop={()},
|
||||||
|
@ -177,7 +177,7 @@ def output.icecast.flac(
|
||||||
~host="localhost",~port=8000,
|
~host="localhost",~port=8000,
|
||||||
~user="source",~password="hackme",
|
~user="source",~password="hackme",
|
||||||
~genre="Misc",~url="http://savonet.sf.net/",
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
~description="OCaml Radio!",~public=true,
|
~description="Liquidsoap Radio!",~public=true,
|
||||||
~dumpfile="",~mount="Use [name]",
|
~dumpfile="",~mount="Use [name]",
|
||||||
~name="Use [mount]",~protocol="http",
|
~name="Use [mount]",~protocol="http",
|
||||||
~flac="flac",~quality=6,
|
~flac="flac",~quality=6,
|
||||||
|
@ -240,7 +240,7 @@ def output.icecast.aacplusenc(
|
||||||
~host="localhost",~port=8000,
|
~host="localhost",~port=8000,
|
||||||
~user="source",~password="hackme",
|
~user="source",~password="hackme",
|
||||||
~genre="Misc",~url="http://savonet.sf.net/",
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
~description="OCaml Radio!",~public=true,
|
~description="Liquidsoap Radio!",~public=true,
|
||||||
~dumpfile="",~mount="Use [name]",
|
~dumpfile="",~mount="Use [name]",
|
||||||
~name="Use [mount]",~protocol="http",
|
~name="Use [mount]",~protocol="http",
|
||||||
~aacplusenc="aacplusenc",~bitrate=64,
|
~aacplusenc="aacplusenc",~bitrate=64,
|
||||||
|
@ -288,7 +288,7 @@ def output.shoutcast.aacplusenc(
|
||||||
~host="localhost",~port=8000,
|
~host="localhost",~port=8000,
|
||||||
~user="source",~password="hackme",
|
~user="source",~password="hackme",
|
||||||
~genre="Misc",~url="http://savonet.sf.net/",
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
~description="OCaml Radio!",~public=true,
|
~description="Liquidsoap Radio!",~public=true,
|
||||||
~fallible=false,~on_start={()},~on_stop={()},
|
~fallible=false,~on_start={()},~on_stop={()},
|
||||||
~dumpfile="",~name="Use [mount]",~icy_reset=true,
|
~dumpfile="",~name="Use [mount]",~icy_reset=true,
|
||||||
~aim="",~icq="",~irc="",~aacplusenc="aacplusenc",
|
~aim="",~icq="",~irc="",~aacplusenc="aacplusenc",
|
||||||
|
|
|
@ -28,8 +28,6 @@ def enable_external_flac_decoder() =
|
||||||
# If the value is not an int, this returns 0 and we are ok :)
|
# If the value is not an int, this returns 0 and we are ok :)
|
||||||
int_of_string(channels)
|
int_of_string(channels)
|
||||||
else
|
else
|
||||||
# Try to detect using mime test..
|
|
||||||
mime = get_mime(file)
|
|
||||||
if string.match(pattern="flac",file) then
|
if string.match(pattern="flac",file) then
|
||||||
# We do not know the number of audio channels
|
# We do not know the number of audio channels
|
||||||
# so setting to -1
|
# so setting to -1
|
||||||
|
@ -76,7 +74,7 @@ end
|
||||||
|
|
||||||
%ifdef add_oblivious_decoder
|
%ifdef add_oblivious_decoder
|
||||||
# Enable or disable external FAAD (AAC/AAC+/M4A) decoders.
|
# Enable or disable external FAAD (AAC/AAC+/M4A) decoders.
|
||||||
# Requires faad binary in the path for audio decoding and
|
# Requires faad binary in the path for audio decoding and
|
||||||
# metaflac binary for metadata. Does not work on Win32.
|
# metaflac binary for metadata. Does not work on Win32.
|
||||||
# Please note that built-in support for faad is available
|
# Please note that built-in support for faad is available
|
||||||
# in liquidsoap if compiled and should be preferred over
|
# in liquidsoap if compiled and should be preferred over
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
# BIG TODO:
|
||||||
|
# - Check for errors
|
||||||
|
# - Unregister radio and streams
|
||||||
|
|
||||||
|
# Register a radio on Liquidsoap Flows.
|
||||||
|
# @category Liquidsoap
|
||||||
|
# @param ~radio Name of the radio.
|
||||||
|
# @param ~website URL of the website of the radio.
|
||||||
|
# @param ~description Description of the radio.
|
||||||
|
# @param ~genre Genre of the radio (rock or rap or etc.).
|
||||||
|
# @param ~streams List of streams for the radio described by \
|
||||||
|
# a pair of strings consisting of the format of the stream \
|
||||||
|
# and the url of the stream. The format should be \
|
||||||
|
# of the form "ogg/128k" consisting of the codec and \
|
||||||
|
# the bitrate, separated by "/".
|
||||||
|
def register_flow(~server="",~user="default",~password="default",
|
||||||
|
~email="",~radio,~website,~description,~genre,
|
||||||
|
~streams,s)
|
||||||
|
|
||||||
|
# If the server is "", we get the server from sf.net
|
||||||
|
server =
|
||||||
|
if server == "" then
|
||||||
|
server = http.get("http://savonet.sourceforge.net/flows_server")
|
||||||
|
html_status = snd(fst(fst(fst(server))))
|
||||||
|
if html_status == 200 then
|
||||||
|
snd(server)
|
||||||
|
else
|
||||||
|
# If sf is down, we use the hardcoded server
|
||||||
|
"http://savonet.rastageeks.org/liqflows.py"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
server
|
||||||
|
end
|
||||||
|
log(level=4,"Flows server: #{server}")
|
||||||
|
|
||||||
|
# Initial variables
|
||||||
|
ping_period = 600. # Pinging period in seconds
|
||||||
|
|
||||||
|
# Fix default parameters
|
||||||
|
# and set request function.
|
||||||
|
base_params = [("v", "0.0"),
|
||||||
|
("user",user),
|
||||||
|
("password",password),
|
||||||
|
("email",email),
|
||||||
|
("radio",radio)]
|
||||||
|
def request(~cmd,~params) =
|
||||||
|
log = log(label=radio)
|
||||||
|
log(level=4,"Processing command #{cmd} with arguments:")
|
||||||
|
def log_arg(x) =
|
||||||
|
label = fst(x)
|
||||||
|
value = snd(x)
|
||||||
|
log(level=4," #{label}: #{value}")
|
||||||
|
end
|
||||||
|
list.iter(log_arg,params)
|
||||||
|
|
||||||
|
cmd = url.encode(cmd)
|
||||||
|
params = list.append(base_params,params)
|
||||||
|
def f(z) =
|
||||||
|
x = fst(z)
|
||||||
|
y = url.encode(snd(z))
|
||||||
|
"#{x}=#{y}"
|
||||||
|
end
|
||||||
|
params = string.concat(separator="&",list.map(f,params))
|
||||||
|
url = "#{server}?cmd=#{cmd}&#{params}"
|
||||||
|
|
||||||
|
# TODO: do something with errors!
|
||||||
|
answer = http.get(url)
|
||||||
|
x = fst(answer)
|
||||||
|
status = fst(x)
|
||||||
|
y = fst(status)
|
||||||
|
protocol = fst(y)
|
||||||
|
code = snd(y)
|
||||||
|
desc = snd(status)
|
||||||
|
headers = snd(x)
|
||||||
|
data = snd(answer)
|
||||||
|
log(level=4,"Response status: #{protocol} #{code} #{desc}")
|
||||||
|
log(level=4,"Response headers:")
|
||||||
|
list.iter(log_arg,headers)
|
||||||
|
log(level=4,"Response content: #{data}")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Register radio
|
||||||
|
params = [("radio_website",website),
|
||||||
|
("radio_description",description),
|
||||||
|
("radio_genre",genre)]
|
||||||
|
request(cmd="add radio",params=params)
|
||||||
|
|
||||||
|
# Ping
|
||||||
|
def ping() =
|
||||||
|
ignore(request(cmd="ping radio",params=[]))
|
||||||
|
ping_period
|
||||||
|
end
|
||||||
|
add_timeout(fast=false,ping_period,ping)
|
||||||
|
|
||||||
|
# Register streams
|
||||||
|
def register_stream(format_url)
|
||||||
|
format = fst(format_url);
|
||||||
|
url = snd(format_url);
|
||||||
|
params = [("stream_format",format),("stream_url",url)]
|
||||||
|
request(cmd="add stream",params=params)
|
||||||
|
end
|
||||||
|
request(cmd="clear streams",params=[])
|
||||||
|
list.iter(register_stream,streams)
|
||||||
|
|
||||||
|
# Metadata update
|
||||||
|
def metadata(m) =
|
||||||
|
artist = m["artist"]
|
||||||
|
title = m["title"]
|
||||||
|
params = [("m_title",title),("m_artist",artist)]
|
||||||
|
request(cmd="metadata",params=params)
|
||||||
|
end
|
||||||
|
on_metadata(metadata,s)
|
||||||
|
end
|
|
@ -1,15 +0,0 @@
|
||||||
# Launch with: screen -c interactive.screen
|
|
||||||
screen -t Liquidsoap liquidsoap --interactive 'set("log.file.path","/tmp/interactive.log") system("echo \"setenv PID #{getpid()}\" > /tmp/interactive.env")'
|
|
||||||
verbose
|
|
||||||
# Yeah, this is a trick
|
|
||||||
# to wait for interactive.env
|
|
||||||
# to be created
|
|
||||||
logfile /dev/null
|
|
||||||
log
|
|
||||||
source /tmp/interactive.env
|
|
||||||
screen -t Log tail --pid=$PID -f /tmp/interactive.log
|
|
||||||
split -v
|
|
||||||
select 0
|
|
||||||
focus
|
|
||||||
select 1
|
|
||||||
focus
|
|
|
@ -1,43 +0,0 @@
|
||||||
#!/sbin/runscript
|
|
||||||
|
|
||||||
user=liquidsoap
|
|
||||||
group=liquidsoap
|
|
||||||
prefix=/usr/local
|
|
||||||
exec_prefix=${prefix}
|
|
||||||
confdir=${prefix}/etc/liquidsoap
|
|
||||||
liquidsoap=${exec_prefix}/bin/liquidsoap
|
|
||||||
rundir=${prefix}/var/run/liquidsoap
|
|
||||||
|
|
||||||
depend() {
|
|
||||||
after net icecast
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
cd $confdir
|
|
||||||
for liq in *.liq ; do
|
|
||||||
if test $liq != '*.liq' ; then
|
|
||||||
ebegin "Starting $liq"
|
|
||||||
start-stop-daemon --start --quiet --pidfile $rundir/${liq%.liq}.pid \
|
|
||||||
--chuid $user:$group --exec $liquidsoap -- -d $confdir/$liq
|
|
||||||
eend $?
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
cd $rundir
|
|
||||||
for liq in *.pid ; do
|
|
||||||
if test $liq != '*.pid' ; then
|
|
||||||
ebegin "Stopping $liq"
|
|
||||||
start-stop-daemon --stop --quiet --pidfile $liq
|
|
||||||
eend $?
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
restart() {
|
|
||||||
svc_stop
|
|
||||||
einfo "Sleeping 4 seconds ..."
|
|
||||||
sleep 4
|
|
||||||
svc_start
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: liquidsoap
|
|
||||||
# Required-Start: $remote_fs $network $time
|
|
||||||
# Required-Stop: $remote_fs $network $time
|
|
||||||
# Should-Start:
|
|
||||||
# Should-Stop:
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: Starts the liquidsoap daemon
|
|
||||||
# Description:
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
user=liquidsoap
|
|
||||||
group=liquidsoap
|
|
||||||
prefix=/usr/local
|
|
||||||
exec_prefix=${prefix}
|
|
||||||
confdir=${prefix}/etc/liquidsoap
|
|
||||||
liquidsoap=${exec_prefix}/bin/liquidsoap
|
|
||||||
rundir=${prefix}/var/run/liquidsoap
|
|
||||||
|
|
||||||
# Test if $rundir exists
|
|
||||||
if [ ! -d $rundir ]; then
|
|
||||||
mkdir -p $rundir;
|
|
||||||
chown $user:$group $rundir
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
stop)
|
|
||||||
echo -n "Stopping channels: "
|
|
||||||
cd $rundir
|
|
||||||
for liq in *.pid ; do
|
|
||||||
if test $liq != '*.pid' ; then
|
|
||||||
echo -n "$liq "
|
|
||||||
start-stop-daemon --stop --quiet --pidfile $liq --retry 4
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "OK"
|
|
||||||
;;
|
|
||||||
|
|
||||||
start)
|
|
||||||
echo -n "Starting channels: "
|
|
||||||
cd $confdir
|
|
||||||
for liq in *.liq ; do
|
|
||||||
if test $liq != '*.liq' ; then
|
|
||||||
echo -n "$liq "
|
|
||||||
start-stop-daemon --start --quiet --pidfile $rundir/${liq%.liq}.pid \
|
|
||||||
--chuid $user:$group --exec $liquidsoap -- -d $confdir/$liq
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "OK"
|
|
||||||
;;
|
|
||||||
|
|
||||||
restart|force-reload)
|
|
||||||
$0 stop
|
|
||||||
$0 start
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 {start|stop|restart|force-reload}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
|
@ -1,15 +0,0 @@
|
||||||
/usr/local/var/log/liquidsoap/*.log {
|
|
||||||
compress
|
|
||||||
rotate 5
|
|
||||||
size 300k
|
|
||||||
missingok
|
|
||||||
notifempty
|
|
||||||
sharedscripts
|
|
||||||
postrotate
|
|
||||||
for liq in /usr/local/var/run/liquidsoap/*.pid ; do
|
|
||||||
if test $liq != '/usr/local/var/run/liquidsoap/*.pid' ; then
|
|
||||||
start-stop-daemon --stop --signal USR1 --quiet --pidfile $liq
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
endscript
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This script is called from liquidsoap for generating a file
|
|
||||||
# for "say:voice/text" URIs.
|
|
||||||
# Usage: liquidtts text output_file voice
|
|
||||||
|
|
||||||
echo $1 | /usr/bin/text2wave -f 44100 > $2.tmp.wav && /usr/bin/sox $2.tmp.wav -t wav -c 2 -r 44100 $2 2> /dev/null > /dev/null
|
|
||||||
return=$?
|
|
||||||
/bin/rm $2.tmp.wav
|
|
||||||
false $2 2> /dev/null > /dev/null
|
|
||||||
exit $return
|
|
|
@ -2,3 +2,4 @@
|
||||||
%include "externals.liq"
|
%include "externals.liq"
|
||||||
%include "shoutcast.liq"
|
%include "shoutcast.liq"
|
||||||
%include "lastfm.liq"
|
%include "lastfm.liq"
|
||||||
|
%include "flows.liq"
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
# @param ~on_stop Callback executed when outputting stops.
|
# @param ~on_stop Callback executed when outputting stops.
|
||||||
# @param ~on_connect Callback executed when connection starts.
|
# @param ~on_connect Callback executed when connection starts.
|
||||||
# @param ~on_disconnect Callback executed when connection stops.
|
# @param ~on_disconnect Callback executed when connection stops.
|
||||||
# @param ~icy_metadata Send new metadata using the ICY protocol. One of: "guess", "true", "false"
|
# @param ~icy_metadata Send new metadata using the ICY protocol. One of: "guess", "true", "false"
|
||||||
# @param ~format Format, e.g. "audio/ogg". When empty, the encoder is used to guess.
|
# @param ~format Format, e.g. "audio/ogg". When empty, the encoder is used to guess.
|
||||||
# @param e Endoding format. For shoutcast, should be mp3 or AAC(+).
|
# @param e Endoding format. For shoutcast, should be mp3 or AAC(+).
|
||||||
# @param s The source to output
|
# @param s The source to output
|
||||||
|
@ -24,7 +24,7 @@ def output.shoutcast(
|
||||||
~host="localhost",~port=8000,
|
~host="localhost",~port=8000,
|
||||||
~user="source",~password="hackme",
|
~user="source",~password="hackme",
|
||||||
~genre="Misc",~url="http://savonet.sf.net/",
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
~name="OCaml Radio!",~public=true, ~format="",
|
~name="Liquidsoap Radio!",~public=true, ~format="",
|
||||||
~dumpfile="", ~icy_metadata="guess",
|
~dumpfile="", ~icy_metadata="guess",
|
||||||
~on_connect={()}, ~on_disconnect={()},
|
~on_connect={()}, ~on_disconnect={()},
|
||||||
~aim="",~icq="",~irc="",~icy_reset=true,
|
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# This is the test for bug #403 from our old trac.
|
||||||
|
#
|
||||||
|
# Make a switch() declare itself ready and arrange to use it for the next
|
||||||
|
# frame where it isn't ready anymore.
|
||||||
|
#
|
||||||
|
# Two switches A and B
|
||||||
|
# A is only ready for a short period of time due to its predicates.
|
||||||
|
# B reselects at the end of a frame just before A becomes unavailable
|
||||||
|
# as a result, B has selected = A, attempts to stream it
|
||||||
|
# but A finds itself not ready anymore.
|
||||||
|
# In other words, B committed but A did not.
|
||||||
|
|
||||||
|
r = ref false
|
||||||
|
pred = { v=!r ; r:=false ; v }
|
||||||
|
add_timeout(2.,{ r := true ; (-1.) })
|
||||||
|
|
||||||
|
mixer = fallback(id="mixer", track_sensitive=false,
|
||||||
|
[at(pred, sine(duration=3.)), blank()])
|
||||||
|
|
||||||
|
output.dummy(mixer)
|
||||||
|
add_timeout(3.,{ print("TEST PASSED") ; shutdown() ; (-1.) })
|
|
@ -0,0 +1,10 @@
|
||||||
|
# In LS-268 we realized that an incorrect assumption had
|
||||||
|
# been made in code from LS-394, resulting in a crash in
|
||||||
|
# case of source re-awakening.
|
||||||
|
|
||||||
|
p = input.http("http://localhost:8000/nonexistent")
|
||||||
|
o = output.dummy(fallible=true,p)
|
||||||
|
|
||||||
|
add_timeout(2.,{ source.shutdown(o) ; (-1.) })
|
||||||
|
add_timeout(3.,{ output.dummy(fallible=true,p) ; (-1.) })
|
||||||
|
add_timeout(4.,{ shutdown() ; (-1.) })
|
|
@ -0,0 +1,11 @@
|
||||||
|
s = on_track(
|
||||||
|
fun(_)-> begin print("TEST PASSED") shutdown() end,
|
||||||
|
blank(duration=1.))
|
||||||
|
|
||||||
|
r = ref false
|
||||||
|
d = source.dynamic({ if !r then [s] else [] end })
|
||||||
|
|
||||||
|
output.dummy(mksafe(d))
|
||||||
|
|
||||||
|
add_timeout(2.,{r:=true;(-1.)})
|
||||||
|
add_timeout(4.,{print("TEST FAILED");shutdown();(-1.)})
|
|
@ -0,0 +1,15 @@
|
||||||
|
s1 = fail()
|
||||||
|
s2 = on_track(
|
||||||
|
fun(_)-> begin print("TEST PASSED") shutdown() end,
|
||||||
|
blank(duration=1.))
|
||||||
|
|
||||||
|
r = ref 0
|
||||||
|
d = source.dynamic({ if !r==1 then [s1]
|
||||||
|
elsif !r==2 then [s2]
|
||||||
|
else [] end })
|
||||||
|
|
||||||
|
output.dummy(mksafe(d))
|
||||||
|
|
||||||
|
add_timeout(2.,{r:=1;(-1.)})
|
||||||
|
add_timeout(3.,{r:=2;(-1.)})
|
||||||
|
add_timeout(5.,{print("TEST FAILED");shutdown();(-1.)})
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Scenario:
|
||||||
|
# Let foo start using q, then stop it, skip in q.
|
||||||
|
# When foo restarts it doesn't know that q isn't ready anymore,
|
||||||
|
# which can lead to a crash.
|
||||||
|
|
||||||
|
q = once(sine(duration=10.))
|
||||||
|
output.dummy(id="bar",mksafe(q))
|
||||||
|
output.dummy(id="foo",fallback([amplify(1.,q),blank(duration=1.)]))
|
||||||
|
|
||||||
|
def at(t,s)
|
||||||
|
add_timeout(t,{ignore(server.execute(s));(-1.)})
|
||||||
|
end
|
||||||
|
|
||||||
|
at(3.,"foo.stop")
|
||||||
|
at(4.,"bar.skip")
|
||||||
|
at(5.,"foo.start")
|
||||||
|
add_timeout(6.,{print("TEST PASSED");shutdown();(-1.)})
|
|
@ -0,0 +1,13 @@
|
||||||
|
# In LS-503 we realized that a source may throw an
|
||||||
|
# exception during output_get_ready call in the initial
|
||||||
|
# main phase. This code reproduces the issue by throwing
|
||||||
|
# an exception in output.icecast.
|
||||||
|
|
||||||
|
# Reopen stderr to /dev/null to
|
||||||
|
# disable printing expected exception
|
||||||
|
reopen.stderr("/dev/null")
|
||||||
|
|
||||||
|
p = input.http("http://localhost:8000/nonexistent")
|
||||||
|
o = output.icecast(%wav,fallible=true,host="nonexistent",
|
||||||
|
mount="test",p)
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
DISTFILES = Makefile $(wildcard *.liq) $(wildcard *.pl)
|
||||||
|
|
||||||
|
top_srcdir = ../..
|
||||||
|
include $(top_srcdir)/Makefile.rules
|
||||||
|
|
||||||
|
test:
|
||||||
|
@for i in $(wildcard *.liq) ; do \
|
||||||
|
echo -n "$$i... " ; $(top_srcdir)/src/liquidsoap -q - < ./$$i | head -n 1 ; \
|
||||||
|
done
|
||||||
|
@echo -n "type_errors.pl... " ; \
|
||||||
|
if (./type_errors.pl > /dev/null 2> /dev/null) ; then \
|
||||||
|
echo "TEST PASSED (check manually the prettiness of messages)" ; \
|
||||||
|
else \
|
||||||
|
echo "TEST FAILED" ; \
|
||||||
|
fi
|
|
@ -0,0 +1,43 @@
|
||||||
|
count = ref 1
|
||||||
|
fail = ref false
|
||||||
|
|
||||||
|
def echo(s)
|
||||||
|
# system("echo "^quote(s))
|
||||||
|
if s != string_of(!count) then
|
||||||
|
fail := true
|
||||||
|
end
|
||||||
|
count := !count + 1
|
||||||
|
()
|
||||||
|
end
|
||||||
|
|
||||||
|
def test(lbl,f)
|
||||||
|
if f() then echo(lbl) else echo("fail "^lbl) end
|
||||||
|
end
|
||||||
|
|
||||||
|
test("1",{ 1==1 })
|
||||||
|
test("2",{ 1+1==2 })
|
||||||
|
test("3",{ (-1)+2==1 })
|
||||||
|
test("4",{ (-1)+2 <= 3*2 })
|
||||||
|
test("5",{ true })
|
||||||
|
test("6",{ true and true })
|
||||||
|
test("7",{ 1==1 and 1==1 })
|
||||||
|
test("8",{ (1==1) and (1==1) })
|
||||||
|
test("9",{ true and (-1)+2 <= 3*2 })
|
||||||
|
|
||||||
|
l = [ ("bla",""), ("bli","x"), ("blo","xx"), ("blu","xxx"), ("dix","10") ]
|
||||||
|
echo(l["dix"])
|
||||||
|
test("11",{ 2 == list.length(string.split(separator="",l["blo"])) })
|
||||||
|
|
||||||
|
%ifdef foobarbaz
|
||||||
|
if = if is not a well-formed expression, and we do not care...
|
||||||
|
%endif
|
||||||
|
|
||||||
|
echo("1#{1+1}")
|
||||||
|
echo(string_of(int_of_float(float_of_string(default=13.,"blah"))))
|
||||||
|
|
||||||
|
f=fun(x)->x
|
||||||
|
# Checking that the following is not recursive:
|
||||||
|
f=fun(x)->f(x)
|
||||||
|
echo(string_of(f(14)))
|
||||||
|
|
||||||
|
if !fail then print("TEST FAILED") else print("TEST PASSED") end
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
use strict ;
|
||||||
|
|
||||||
|
my $liquidsoap = "../../src/liquidsoap";
|
||||||
|
die unless -f $liquidsoap ;
|
||||||
|
|
||||||
|
$liquidsoap = "$liquidsoap -c";
|
||||||
|
|
||||||
|
sub section {
|
||||||
|
print "\n*** $_[0] ***\n\n" ;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub incorrect {
|
||||||
|
my $expr = pop ;
|
||||||
|
print "Incorrect expression $expr...\n" ;
|
||||||
|
system "$liquidsoap '$expr'" ;
|
||||||
|
die unless (($?>>8)==1) ;
|
||||||
|
print "\n" ;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub correct {
|
||||||
|
my $expr = pop ;
|
||||||
|
print "Correct expression $expr...\n" ;
|
||||||
|
system "$liquidsoap -i '$expr'" ;
|
||||||
|
die unless (($?>>8)==0) ;
|
||||||
|
print "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
section("BASIC");
|
||||||
|
incorrect('[1]==["1"]');
|
||||||
|
incorrect('1==["1"]');
|
||||||
|
incorrect('1==(1,"1")');
|
||||||
|
# In some of those examples the type error could be reported for a
|
||||||
|
# sub-expression since we have location information.
|
||||||
|
# With the concise error, it's still pretty good currently.
|
||||||
|
incorrect('(1,1)==(1,"1")');
|
||||||
|
incorrect('(1,1)==("1",1)');
|
||||||
|
incorrect('1==request.create("")');
|
||||||
|
incorrect('fun(x)->x(snd(x))');
|
||||||
|
|
||||||
|
section("SUBTYPING");
|
||||||
|
incorrect('(1:unit)');
|
||||||
|
correct('((blank():source(1,1,1)):source(*,*,*))');
|
||||||
|
incorrect('((blank():source(*,*,*)):source(1,1,1))');
|
||||||
|
# Next one requires the inference of a subtype (fixed vs. variable arity)
|
||||||
|
correct('audio_to_stereo(add([]))');
|
||||||
|
|
||||||
|
section("CONSTRAINTS");
|
||||||
|
incorrect('"bl"+"a"');
|
||||||
|
incorrect('(fun(a,b)->a+b)==(fun(a,b)->a+b)');
|
||||||
|
incorrect('fun(x)->x(x)'); # TODO is it an accident that we get same varname
|
||||||
|
incorrect('def f(x) y=snd(x) y(x) end');
|
||||||
|
|
||||||
|
section("LET GENERALIZATION");
|
||||||
|
correct('def f(x) = y=x ; y end f(3)+snd(f((1,2)))');
|
||||||
|
incorrect('def f(x) = y=x ; y end f(3)+"3"');
|
||||||
|
|
||||||
|
section("ARGUMENTS");
|
||||||
|
# The errors should be about the type of the param, not of the function.
|
||||||
|
incorrect('1+"1"');
|
||||||
|
# Also, a special simple error is expected for obvious labelling mistakes.
|
||||||
|
incorrect('fallback(transitions=[],xxxxxxxxxxx=[])');
|
||||||
|
incorrect('fallback(transitions=[],transitions=[])');
|
||||||
|
|
||||||
|
section("FUNCTIONS");
|
||||||
|
incorrect('fallback(transitions=[fun(~l)->1])');
|
||||||
|
incorrect('fallback(transitions=[fun(~l=1)->1])');
|
||||||
|
incorrect('fallback(transitions=[fun(x,y=blank())->y])');
|
||||||
|
incorrect('fallback(transitions=[fun(x,y)->0])');
|
||||||
|
correct('f=fallback(transitions=[fun(x,y,a=2)->x])');
|
||||||
|
incorrect('fallback(transitions=[fun(x,y)->y+1])');
|
||||||
|
correct('x=fun(f)->f(3) y=x(fun(f,u="1")->u)');
|
||||||
|
|
||||||
|
section("CONTENT KIND");
|
||||||
|
incorrect('output.file(%vorbis(stereo),"foo",mean(blank()))');
|
||||||
|
incorrect('output.file(%vorbis(stereo),"foo",video.add_image(blank()))');
|
||||||
|
incorrect('def f(x) = output.file(%vorbis(stereo),"",x) output.file(%vorbis(mono),"",x) end');
|
||||||
|
incorrect('add([output.file(%vorbis(stereo),"",blank()),output.file(%vorbis(mono),"",blank())])');
|
||||||
|
incorrect('add([mean(blank()),audio_to_stereo(add([]))])');
|
||||||
|
|
||||||
|
print "Everything's good!\n" ;
|
|
@ -0,0 +1,112 @@
|
||||||
|
# Check these examples with: liquidsoap --no-libs -i -c typing.liq
|
||||||
|
|
||||||
|
# TODO Throughout this file, parsing locations displayed in error messages
|
||||||
|
# are often much too inaccurate.
|
||||||
|
|
||||||
|
# Check that some polymorphism is allowed.
|
||||||
|
# id : (string,'a)->'a
|
||||||
|
def id(a,b)
|
||||||
|
log(a)
|
||||||
|
b
|
||||||
|
end
|
||||||
|
ignore("bla"==id("bla","bla"))
|
||||||
|
ignore(0==id("zero",0))
|
||||||
|
|
||||||
|
# Reporting locations for the next error is non-trivial, because it is about
|
||||||
|
# an instantiation of the type of id. The deep error doesn't have relevant
|
||||||
|
# information about why the int should be a string, the outer one has.
|
||||||
|
# id(0,0)
|
||||||
|
|
||||||
|
# Polymorphism is limited to outer generalizations, this is not system F.
|
||||||
|
# apply : ((string)->'a)->'a
|
||||||
|
def apply(f)
|
||||||
|
f("bla")
|
||||||
|
# f is not polymorphic, the following is forbidden:
|
||||||
|
# f(0)
|
||||||
|
# f(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
# The level checks forbid abusive generalization.
|
||||||
|
# id' : ('a)->'a
|
||||||
|
def id'(x)
|
||||||
|
# If one isn't careful about levels/scoping, f2 gets the type ('a)->'b
|
||||||
|
# and so does twisted_id.
|
||||||
|
def f2(y)
|
||||||
|
x
|
||||||
|
end
|
||||||
|
f2(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
# More errors...
|
||||||
|
# 0=="0"
|
||||||
|
# [3,""]
|
||||||
|
|
||||||
|
# Subtyping, functions and lists.
|
||||||
|
f1 = fun () -> 3
|
||||||
|
f2 = fun (a=1) -> a
|
||||||
|
|
||||||
|
# This is OK, l1 is a list of elements of type f1.
|
||||||
|
l1 = [f1,f2]
|
||||||
|
list.iter(fun (f) -> log(string_of(f())), l1)
|
||||||
|
# Forbidden. Indeed, f1 doesn't accept any argument -- although f2 does.
|
||||||
|
# Here the error message may even be too detailed since it goes back to the
|
||||||
|
# definition of l1 and requires that f1 has type (int)->int.
|
||||||
|
# list.iter(fun (f) -> log(string_of(f(42))), l1)
|
||||||
|
|
||||||
|
# Actually, this is forbidden too, but the reason is more complex...
|
||||||
|
# The infered type for the function is ((int)->int)->unit,
|
||||||
|
# and (int)->int is not a subtype of (?int)->int.
|
||||||
|
# There's no most general answer here since (?int)->int is not a
|
||||||
|
# subtype of (int)->int either.
|
||||||
|
# list.iter(fun (f) -> log(string_of(f(42))), [f2])
|
||||||
|
|
||||||
|
# Unlike l1, this is not OK, since we don't leave open subtyping constraints
|
||||||
|
# while infering types.
|
||||||
|
# I hope we can make the inference smarter in the future, without obfuscating
|
||||||
|
# the error messages too much.
|
||||||
|
# The type error here shows the use of all the displayed positions:
|
||||||
|
# f1 has type t1, f2 has type t2, t1 should be <: t2
|
||||||
|
# l2 = [ f2, f1 ]
|
||||||
|
|
||||||
|
# An error where contravariance flips the roles of both sides..
|
||||||
|
# [fun (x) -> x+1, fun (y) -> y^"."]
|
||||||
|
|
||||||
|
# An error without much locations..
|
||||||
|
# TODO An explaination about the missing label would help a lot here.
|
||||||
|
# def f(f)
|
||||||
|
# f(output.icecast.vorbis)
|
||||||
|
# f(output.icecast.mp3)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# This causes an occur-check error.
|
||||||
|
# TODO The printing of the types breaks the sharing of one EVAR
|
||||||
|
# across two types. Here the sharing is actually the origin of the occur-check
|
||||||
|
# error. And it's not easy to understand..
|
||||||
|
# omega = fun (x) -> x(x)
|
||||||
|
|
||||||
|
# Now let's test ad-hoc polymorphism.
|
||||||
|
|
||||||
|
echo = fun(x) -> system("echo #{quote(string_of(x))}")
|
||||||
|
|
||||||
|
ignore("bla")
|
||||||
|
ignore((1,3.12))
|
||||||
|
ignore(1 + 1)
|
||||||
|
ignore(1. + 2.14)
|
||||||
|
|
||||||
|
# string is not a Num
|
||||||
|
# echo("bl"+"a")
|
||||||
|
|
||||||
|
ignore(1 <= 2)
|
||||||
|
ignore((1,2) == (1,3))
|
||||||
|
|
||||||
|
# float <> int
|
||||||
|
# echo(1 == 2.)
|
||||||
|
|
||||||
|
# source is not an Ord
|
||||||
|
# echo(blank()==blank())
|
||||||
|
|
||||||
|
def sum_eq(a,b)
|
||||||
|
a+b == a
|
||||||
|
end
|
||||||
|
|
||||||
|
print("TEST PASSED")
|
|
@ -0,0 +1,61 @@
|
||||||
|
# run this file through "liquidsoap -c -i"
|
||||||
|
# to see if pretty printing looks pretty enough
|
||||||
|
# for more checks, pass --twidth 78
|
||||||
|
|
||||||
|
x = (blank() : source(2,3,4))
|
||||||
|
pair = (x,x)
|
||||||
|
x = (x,x)
|
||||||
|
x = (x,x)
|
||||||
|
x = (x,x)
|
||||||
|
|
||||||
|
def output.shoutcast(
|
||||||
|
~id="output.shoutcast",~start=true,
|
||||||
|
~restart=false,~restart_delay=3,
|
||||||
|
~host="localhost",~port=8000,
|
||||||
|
~user="source",~password="hackme",
|
||||||
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
|
~name="OCaml Radio!",~public=true, ~format="",
|
||||||
|
~dumpfile="", ~icy_metadata="guess",
|
||||||
|
~on_connect={()}, ~on_disconnect={()},
|
||||||
|
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||||
|
~fallible=false,~on_start={()},~on_stop={()},
|
||||||
|
e,s)
|
||||||
|
=
|
||||||
|
42
|
||||||
|
end
|
||||||
|
|
||||||
|
x = (output.shoutcast,pair)
|
||||||
|
|
||||||
|
def output.shoutcast(
|
||||||
|
~id="output.shoutcast",~start=true,
|
||||||
|
~restart=false,~restart_delay=3,
|
||||||
|
~host="localhost",~port=8000,
|
||||||
|
~user="source",~password="hackme",
|
||||||
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
|
~name="OCaml Radio!",~public=true, ~format="",
|
||||||
|
~dumpfile="", ~icy_metadata="guess",
|
||||||
|
~on_connect={()}, ~on_disconnect={()},
|
||||||
|
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||||
|
~fallible=false,~on_start={()},~on_stop={()},
|
||||||
|
e,s)
|
||||||
|
=
|
||||||
|
(pair,42)
|
||||||
|
end
|
||||||
|
|
||||||
|
def output.shoutcast(
|
||||||
|
~id="output.shoutcast",~start=true,
|
||||||
|
~restart=false,~restart_delay=3,
|
||||||
|
~host="localhost",~port=8000,
|
||||||
|
~user="source",~password="hackme",
|
||||||
|
~genre="Misc",~url="http://savonet.sf.net/",
|
||||||
|
~name="OCaml Radio!",~public=true, ~format="",
|
||||||
|
~dumpfile="", ~icy_metadata="guess",
|
||||||
|
~on_connect={()}, ~on_disconnect={()},
|
||||||
|
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||||
|
~fallible=false,~on_start={()},~on_stop={()},
|
||||||
|
e,s)
|
||||||
|
=
|
||||||
|
(blank() : source(3,0,0))
|
||||||
|
end
|
||||||
|
|
||||||
|
x = (output.shoutcast,blank())
|
|
@ -97,41 +97,63 @@ def merge_tracks(s)
|
||||||
sequence(merge=true,[s])
|
sequence(merge=true,[s])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Default inputs and outpus
|
||||||
|
#
|
||||||
|
# They are called "prefered" but it's not a user preference,
|
||||||
|
# just a view of what's generally preferable among the available
|
||||||
|
# modules.
|
||||||
|
# It is important that input and output preferences are in the
|
||||||
|
# same order: the chosen I/O should work in the same clock, we don't
|
||||||
|
# want an ALSA input and OSS output. The only exception is AO:
|
||||||
|
# it is the default output after dummy, so the input will be a dummy
|
||||||
|
# when AO is used for output.
|
||||||
|
|
||||||
output.prefered=output.dummy
|
output.prefered=output.dummy
|
||||||
%ifdef output.oss
|
%ifdef output.ao
|
||||||
output.prefered=output.oss
|
output.prefered=output.ao
|
||||||
%endif
|
%endif
|
||||||
%ifdef output.alsa
|
%ifdef output.alsa
|
||||||
output.prefered=output.alsa
|
output.prefered=output.alsa
|
||||||
%endif
|
%endif
|
||||||
|
%ifdef output.oss
|
||||||
|
output.prefered=output.oss
|
||||||
|
%endif
|
||||||
|
%ifdef output.portaudio
|
||||||
|
output.prefered = output.portaudio
|
||||||
|
%endif
|
||||||
%ifdef output.pulseaudio
|
%ifdef output.pulseaudio
|
||||||
output.prefered=output.pulseaudio
|
output.prefered=output.pulseaudio
|
||||||
%endif
|
%endif
|
||||||
%ifdef output.ao
|
# Output to local audio card using the first available driver in
|
||||||
output.prefered=output.ao
|
# pulseaudio, portaudio, oss, alsa, ao, dummy.
|
||||||
%endif
|
|
||||||
# Output to local audio card using the first available driver in this list:
|
|
||||||
# ao, pulseaudio, alsa, oss, dummy
|
|
||||||
# @category Source / Output
|
# @category Source / Output
|
||||||
def output.prefered(~id="",s)
|
def output.prefered(~id="",~fallible=false,
|
||||||
output.prefered(id=id,s)
|
~on_start={()},~on_stop={()},~start=true,s)
|
||||||
|
output.prefered(id=id,fallible=fallible,
|
||||||
|
start=start,on_start=on_start,on_stop=on_stop,
|
||||||
|
s)
|
||||||
end
|
end
|
||||||
|
|
||||||
in = fun () -> blank()
|
def in(~id="",~start=true,~on_start={()},~on_stop={()},~fallible=false)
|
||||||
%ifdef input.oss
|
blank(id=id)
|
||||||
in = fun () -> input.oss(id="oss_mic")
|
end
|
||||||
%endif
|
|
||||||
%ifdef input.alsa
|
%ifdef input.alsa
|
||||||
in = fun () -> input.alsa(id="alsa_mic")
|
in = input.alsa
|
||||||
|
%endif
|
||||||
|
%ifdef input.oss
|
||||||
|
in = input.oss
|
||||||
%endif
|
%endif
|
||||||
%ifdef input.portaudio
|
%ifdef input.portaudio
|
||||||
in = fun () -> input.portaudio(id="pa_mic")
|
in = input.portaudio
|
||||||
%endif
|
%endif
|
||||||
# Create a source from the first available input driver in this list:
|
%ifdef input.pulseaudio
|
||||||
# portaudio, alsa, oss, blank.
|
in = input.pulseaudio
|
||||||
|
%endif
|
||||||
|
# Create a source from the first available input driver in
|
||||||
|
# pulseaudio, portaudio, oss, alsa, blank.
|
||||||
# @category Source / Input
|
# @category Source / Input
|
||||||
def in()
|
def in(~id="",~start=true,~on_start={()},~on_stop={()},~fallible=false)
|
||||||
in()
|
in(id=id,start=start,on_start=on_start,on_stop=on_stop,fallible=fallible)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Output a stream using the 'output.prefered' operator. The input source does
|
# Output a stream using the 'output.prefered' operator. The input source does
|
||||||
|
@ -362,6 +384,11 @@ def read(~hide=false)
|
||||||
s
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
file.mime_default = fun (_) -> ""
|
||||||
|
%ifdef file.mime
|
||||||
|
file.mime_default = file.mime
|
||||||
|
%endif
|
||||||
|
|
||||||
# Generic mime test. First try to use file.mime if it exist.
|
# Generic mime test. First try to use file.mime if it exist.
|
||||||
# Otherwise try to get the value using the file binary.
|
# Otherwise try to get the value using the file binary.
|
||||||
# Returns "" (empty string) if no value can be find.
|
# Returns "" (empty string) if no value can be find.
|
||||||
|
@ -376,15 +403,8 @@ def get_mime(file) =
|
||||||
""
|
""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
def mime_method(file) =
|
|
||||||
ret = ""
|
|
||||||
%ifdef file.mime
|
|
||||||
ret = file.mime(file)
|
|
||||||
%endif
|
|
||||||
ret
|
|
||||||
end
|
|
||||||
# First try mime method
|
# First try mime method
|
||||||
ret = mime_method(file)
|
ret = file.mime_default(file)
|
||||||
if ret != "" then
|
if ret != "" then
|
||||||
ret
|
ret
|
||||||
else
|
else
|
||||||
|
@ -403,8 +423,8 @@ end
|
||||||
|
|
||||||
# Creates a source that fails to produce anything.
|
# Creates a source that fails to produce anything.
|
||||||
# @category Source / Input
|
# @category Source / Input
|
||||||
def fail()
|
def fail(~id="")
|
||||||
fallback([])
|
fallback(id=id,[])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a source that plays only one track of the input source.
|
# Creates a source that plays only one track of the input source.
|
||||||
|
@ -677,6 +697,17 @@ def enable_replaygain_metadata(
|
||||||
add_metadata_resolver("replay_gain", replaygain_metadata)
|
add_metadata_resolver("replay_gain", replaygain_metadata)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Assign a new clock to the given source (and to other time-dependent
|
||||||
|
# sources) and return the source. It is a conveniency wrapper around
|
||||||
|
# clock.assign_new(), allowing more concise scripts in some cases.
|
||||||
|
# @category Liquidsoap
|
||||||
|
# @param ~sync Do not synchronize the clock on regular wallclock time, \
|
||||||
|
# but try to run as fast as possible (CPU burning mode).
|
||||||
|
def clock(~sync=true,~id="",s)
|
||||||
|
clock.assign_new(sync=sync,id=id,[s])
|
||||||
|
s
|
||||||
|
end
|
||||||
|
|
||||||
# Create a log of clock times for all the clocks initially present.
|
# Create a log of clock times for all the clocks initially present.
|
||||||
# The log is in a simple format which you can directly use with gnuplot.
|
# The log is in a simple format which you can directly use with gnuplot.
|
||||||
# @category Liquidsoap
|
# @category Liquidsoap
|
||||||
|
|
|
@ -14,7 +14,7 @@ output_shoutcast = false
|
||||||
# Logging settings #
|
# Logging settings #
|
||||||
###########################################
|
###########################################
|
||||||
log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"
|
log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"
|
||||||
log_level = 3
|
#log_level = 3
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
# Icecast Stream settings #
|
# Icecast Stream settings #
|
||||||
|
|
|
@ -53,11 +53,11 @@ s = map_metadata(append_title, s)
|
||||||
|
|
||||||
|
|
||||||
if output_sound_device then
|
if output_sound_device then
|
||||||
out_device = out(s)
|
ignore(out(s))
|
||||||
end
|
end
|
||||||
|
|
||||||
if output_icecast_mp3 then
|
if output_icecast_mp3 then
|
||||||
out_mp3 = output.icecast(%mp3,
|
ignore(output.icecast(%mp3,
|
||||||
host = icecast_host,
|
host = icecast_host,
|
||||||
port = icecast_port,
|
port = icecast_port,
|
||||||
password = icecast_pass,
|
password = icecast_pass,
|
||||||
|
@ -69,11 +69,12 @@ if output_icecast_mp3 then
|
||||||
description = icecast_description,
|
description = icecast_description,
|
||||||
genre = icecast_genre,
|
genre = icecast_genre,
|
||||||
s)
|
s)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
if output_icecast_vorbis then
|
if output_icecast_vorbis then
|
||||||
if output_icecast_vorbis_metadata then
|
if output_icecast_vorbis_metadata then
|
||||||
out_vorbis = output.icecast(%vorbis,
|
ignore(output.icecast(%vorbis,
|
||||||
host = icecast_host,
|
host = icecast_host,
|
||||||
port = icecast_port,
|
port = icecast_port,
|
||||||
password = icecast_pass,
|
password = icecast_pass,
|
||||||
|
@ -85,11 +86,12 @@ if output_icecast_vorbis then
|
||||||
description = icecast_description,
|
description = icecast_description,
|
||||||
genre = icecast_genre,
|
genre = icecast_genre,
|
||||||
s)
|
s)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
#remove metadata from ogg source and merge tracks to fix bug
|
#remove metadata from ogg source and merge tracks to fix bug
|
||||||
#with vlc and mplayer disconnecting at the end of every track
|
#with vlc and mplayer disconnecting at the end of every track
|
||||||
s = add(normalize=false, [amplify(0.00001, noise()),s])
|
s = add(normalize=false, [amplify(0.00001, noise()),s])
|
||||||
out_vorbis = output.icecast(%vorbis,
|
ignore(output.icecast(%vorbis,
|
||||||
host = icecast_host,
|
host = icecast_host,
|
||||||
port = icecast_port,
|
port = icecast_port,
|
||||||
password = icecast_pass,
|
password = icecast_pass,
|
||||||
|
@ -101,11 +103,12 @@ if output_icecast_vorbis then
|
||||||
description = icecast_description,
|
description = icecast_description,
|
||||||
genre = icecast_genre,
|
genre = icecast_genre,
|
||||||
s)
|
s)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if output_shoutcast then
|
if output_shoutcast then
|
||||||
out_shoutcast = output.shoutcast(%mp3,
|
ignore(output.shoutcast(%mp3,
|
||||||
host = shoutcast_host,
|
host = shoutcast_host,
|
||||||
port = shoutcast_port,
|
port = shoutcast_port,
|
||||||
password = shoutcast_pass,
|
password = shoutcast_pass,
|
||||||
|
@ -115,5 +118,6 @@ if output_shoutcast then
|
||||||
url = shoutcast_url,
|
url = shoutcast_url,
|
||||||
genre = shoutcast_genre,
|
genre = shoutcast_genre,
|
||||||
s)
|
s)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue