-updated liquidsoap scripts + library to be liquidsoap-beta2 compliant

This commit is contained in:
martin 2011-07-06 11:14:51 -04:00
parent 022b013dd2
commit 3dc1380fab
24 changed files with 593 additions and 192 deletions

View File

@ -71,7 +71,7 @@ def output.icecast.lame(
~host="localhost",~port=8000,
~user="source",~password="hackme",
~genre="Misc",~url="http://savonet.sf.net/",
~description="OCaml Radio!",~public=true,
~description="Liquidsoap Radio!",~public=true,
~dumpfile="",~mount="Use [name]",
~name="Use [mount]",~protocol="http",
~lame="lame",~bitrate=128,~swap=false,
@ -130,7 +130,7 @@ def output.shoutcast.lame(
~host="localhost",~port=8000,
~user="source",~password="hackme",
~genre="Misc",~url="http://savonet.sf.net/",
~description="OCaml Radio!",~public=true,
~description="Liquidsoap Radio!",~public=true,
~dumpfile="",~name="Use [mount]",~icy_reset=true,
~lame="lame",~aim="",~icq="",~irc="",
~fallible=false,~on_start={()},~on_stop={()},
@ -177,7 +177,7 @@ def output.icecast.flac(
~host="localhost",~port=8000,
~user="source",~password="hackme",
~genre="Misc",~url="http://savonet.sf.net/",
~description="OCaml Radio!",~public=true,
~description="Liquidsoap Radio!",~public=true,
~dumpfile="",~mount="Use [name]",
~name="Use [mount]",~protocol="http",
~flac="flac",~quality=6,
@ -240,7 +240,7 @@ def output.icecast.aacplusenc(
~host="localhost",~port=8000,
~user="source",~password="hackme",
~genre="Misc",~url="http://savonet.sf.net/",
~description="OCaml Radio!",~public=true,
~description="Liquidsoap Radio!",~public=true,
~dumpfile="",~mount="Use [name]",
~name="Use [mount]",~protocol="http",
~aacplusenc="aacplusenc",~bitrate=64,
@ -288,7 +288,7 @@ def output.shoutcast.aacplusenc(
~host="localhost",~port=8000,
~user="source",~password="hackme",
~genre="Misc",~url="http://savonet.sf.net/",
~description="OCaml Radio!",~public=true,
~description="Liquidsoap Radio!",~public=true,
~fallible=false,~on_start={()},~on_stop={()},
~dumpfile="",~name="Use [mount]",~icy_reset=true,
~aim="",~icq="",~irc="",~aacplusenc="aacplusenc",

View File

@ -28,8 +28,6 @@ def enable_external_flac_decoder() =
# If the value is not an int, this returns 0 and we are ok :)
int_of_string(channels)
else
# Try to detect using mime test..
mime = get_mime(file)
if string.match(pattern="flac",file) then
# We do not know the number of audio channels
# so setting to -1
@ -76,7 +74,7 @@ end
%ifdef add_oblivious_decoder
# 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.
# Please note that built-in support for faad is available
# in liquidsoap if compiled and should be preferred over

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -2,3 +2,4 @@
%include "externals.liq"
%include "shoutcast.liq"
%include "lastfm.liq"
%include "flows.liq"

View File

@ -14,7 +14,7 @@
# @param ~on_stop Callback executed when outputting stops.
# @param ~on_connect Callback executed when connection starts.
# @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 e Endoding format. For shoutcast, should be mp3 or AAC(+).
# @param s The source to output
@ -24,7 +24,7 @@ def output.shoutcast(
~host="localhost",~port=8000,
~user="source",~password="hackme",
~genre="Misc",~url="http://savonet.sf.net/",
~name="OCaml Radio!",~public=true, ~format="",
~name="Liquidsoap Radio!",~public=true, ~format="",
~dumpfile="", ~icy_metadata="guess",
~on_connect={()}, ~on_disconnect={()},
~aim="",~icq="",~irc="",~icy_reset=true,

View File

@ -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.) })

View File

@ -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.) })

View File

@ -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.)})

View File

@ -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.)})

View File

@ -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.)})

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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" ;

View File

@ -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")

View File

@ -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())

View File

@ -97,41 +97,63 @@ def merge_tracks(s)
sequence(merge=true,[s])
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
%ifdef output.oss
output.prefered=output.oss
%ifdef output.ao
output.prefered=output.ao
%endif
%ifdef output.alsa
output.prefered=output.alsa
%endif
%ifdef output.oss
output.prefered=output.oss
%endif
%ifdef output.portaudio
output.prefered = output.portaudio
%endif
%ifdef output.pulseaudio
output.prefered=output.pulseaudio
%endif
%ifdef output.ao
output.prefered=output.ao
%endif
# Output to local audio card using the first available driver in this list:
# ao, pulseaudio, alsa, oss, dummy
# Output to local audio card using the first available driver in
# pulseaudio, portaudio, oss, alsa, ao, dummy.
# @category Source / Output
def output.prefered(~id="",s)
output.prefered(id=id,s)
def output.prefered(~id="",~fallible=false,
~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
in = fun () -> blank()
%ifdef input.oss
in = fun () -> input.oss(id="oss_mic")
%endif
def in(~id="",~start=true,~on_start={()},~on_stop={()},~fallible=false)
blank(id=id)
end
%ifdef input.alsa
in = fun () -> input.alsa(id="alsa_mic")
in = input.alsa
%endif
%ifdef input.oss
in = input.oss
%endif
%ifdef input.portaudio
in = fun () -> input.portaudio(id="pa_mic")
in = input.portaudio
%endif
# Create a source from the first available input driver in this list:
# portaudio, alsa, oss, blank.
%ifdef input.pulseaudio
in = input.pulseaudio
%endif
# Create a source from the first available input driver in
# pulseaudio, portaudio, oss, alsa, blank.
# @category Source / Input
def in()
in()
def in(~id="",~start=true,~on_start={()},~on_stop={()},~fallible=false)
in(id=id,start=start,on_start=on_start,on_stop=on_stop,fallible=fallible)
end
# Output a stream using the 'output.prefered' operator. The input source does
@ -362,6 +384,11 @@ def read(~hide=false)
s
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.
# Otherwise try to get the value using the file binary.
# Returns "" (empty string) if no value can be find.
@ -376,15 +403,8 @@ def get_mime(file) =
""
end
end
def mime_method(file) =
ret = ""
%ifdef file.mime
ret = file.mime(file)
%endif
ret
end
# First try mime method
ret = mime_method(file)
ret = file.mime_default(file)
if ret != "" then
ret
else
@ -403,8 +423,8 @@ end
# Creates a source that fails to produce anything.
# @category Source / Input
def fail()
fallback([])
def fail(~id="")
fallback(id=id,[])
end
# 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)
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.
# The log is in a simple format which you can directly use with gnuplot.
# @category Liquidsoap

View File

@ -14,7 +14,7 @@ output_shoutcast = false
# Logging settings #
###########################################
log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"
log_level = 3
#log_level = 3
###########################################
# Icecast Stream settings #

View File

@ -53,11 +53,11 @@ s = map_metadata(append_title, s)
if output_sound_device then
out_device = out(s)
ignore(out(s))
end
if output_icecast_mp3 then
out_mp3 = output.icecast(%mp3,
ignore(output.icecast(%mp3,
host = icecast_host,
port = icecast_port,
password = icecast_pass,
@ -69,11 +69,12 @@ if output_icecast_mp3 then
description = icecast_description,
genre = icecast_genre,
s)
)
end
if output_icecast_vorbis then
if output_icecast_vorbis_metadata then
out_vorbis = output.icecast(%vorbis,
ignore(output.icecast(%vorbis,
host = icecast_host,
port = icecast_port,
password = icecast_pass,
@ -85,11 +86,12 @@ if output_icecast_vorbis then
description = icecast_description,
genre = icecast_genre,
s)
)
else
#remove metadata from ogg source and merge tracks to fix bug
#with vlc and mplayer disconnecting at the end of every track
s = add(normalize=false, [amplify(0.00001, noise()),s])
out_vorbis = output.icecast(%vorbis,
ignore(output.icecast(%vorbis,
host = icecast_host,
port = icecast_port,
password = icecast_pass,
@ -101,11 +103,12 @@ if output_icecast_vorbis then
description = icecast_description,
genre = icecast_genre,
s)
)
end
end
if output_shoutcast then
out_shoutcast = output.shoutcast(%mp3,
ignore(output.shoutcast(%mp3,
host = shoutcast_host,
port = shoutcast_port,
password = shoutcast_pass,
@ -115,5 +118,6 @@ if output_shoutcast then
url = shoutcast_url,
genre = shoutcast_genre,
s)
)
end