Forked from
AURA / engine
1704 commits behind, 24 commits ahead of the upstream repository.
-
Gottfried Gaisbauer authoredGottfried Gaisbauer authored
playd.liq 9.94 KiB
#!/usr/bin/liquidsoap
#set("log.stdout", true)
inst = if argv(1) != "" then string_of(argv(1)) else 'playd' end
instance = ref inst
%include "readini.liq"
inifile = '/etc/aura/aura.ini'
ini = read_ini(inifile)
# send alive
ignore(system('#{list.assoc("install_dir", ini)}/modules/liquidsoap/helpers/message.py -c #{!instance} -t sayAlive'))
# send alive frequently
exec_at(freq=20., pred={true}, {ignore(system('#{list.assoc("install_dir", ini)}/modules/liquidsoap/helpers/message.py -c #{!instance} -t sayAlive'))})
# set current playlist
ignore(system('#{list.assoc("install_dir", ini)}/modules/liquidsoap/helpers/message.py -c #{!instance} --task=setState -n playlistcurrent -v ""'))
# load data from ini file
#daemongroup = list.assoc("daemongroup", ini)
#daemonuser = list.assoc("daemonuser", ini)
socketdir = list.assoc("socketdir", ini)
# ALSA settings
use_alsa = list.assoc("use_alsa", ini)
alsa_buffer = int_of_string(list.assoc("alsa_buffer", ini))
alsa_periods = int_of_string(list.assoc("alsa_periods", ini))
# set player i/o devices
player_input = list.assoc("input_device", ini)
#player_second_input = list.assoc("player_second")
player_output = list.assoc("output_device", ini)
# fallback settings
fallback_audio_folder = list.assoc("fallback_audio_folder", ini)
fallback_max_blank = float_of_string(list.assoc("fallback_max_blank", ini))
fallback_min_noise = float_of_string(list.assoc("fallback_min_noise", ini))
fallback_threshold = float_of_string(list.assoc("fallback_threshold", ini))
# channel names from config
channelnames = ref string.split(separator=',', list.assoc("channels", ini))
# alsa settings
# buffer - decrease latency: eg. alsa_buffer="2024"
set("alsa.alsa_buffer", alsa_buffer)
set("alsa.periods", alsa_periods)
# enable socketserver
set("server.socket", true)
set("server.socket.path", socketdir^"/<script>.sock")
set("server.telnet", true)
set("server.telnet.port", 1234)
# enable daemon
#set("init.daemon", true)
#set("init.daemon.change_user.group", daemongroup)
#set("init.daemon.change_user.user", daemonuser)
#set("init.daemon.pidfile.path", socketdir^"/<script>.pid")
#set("init.daemon.pidfile.perms", 0o666)
# set logging
set("log.file",true)
set("log.file.path", list.assoc("logdir", ini)^"/<script>.log")
set("log.file.perms",0o640)
set("log.level", 10)
# allowed mime types
set("playlists.mime_types.xml",["text/xml","application/xml","application/xspf+xml"])
# load functions
# dir = list.assoc("install_dir", ini)
%include "library.liq"
%include "playlist.liq"
# Der input wie oben definiert
def get_input()
def get_input()
if use_alsa == "y" then
if player_input == "soundcard" then
print("autodetect device")
input.alsa(id="sound_input", fallible=true, clock_safe=false)
else
print("manual set device: "^player_input)
input.alsa(id="sound_input", fallible=true, clock_safe=false, device=player_input)
end
else
input.pulseaudio(id="sound_input")
end
end
def get_fallback()
if fallback_audio_folder != "" then
print("fallbackfolder chosen: "^fallback_audio_folder)
playlist.safe("/var/audio/fallback/music.flac")
#playlist.safe(fallback_audio_folder)
else
blank(duration=20.0)
end
end
if player_input == "" then
blank(duration=0.1) # wait...
else
# start silence detector on input alsa and set a fallback
fallback(track_sensitive=false,
[ strip_blank(max_blank=fallback_max_blank, min_noise=fallback_min_noise, threshold=fallback_threshold, get_input()),
get_fallback() ]
)
end
end
playlistrunning = ref false
playlist_recorded = playlist.xml(id='playlist', on_done=fun() -> begin ignore(system('#{list.assoc("install_dir", ini)}/modules/soundengine/helpers/message.py -c #{!instance} --task=setState -n playlistcurrent -v ""')) ignore(server.execute('mixer.select 0 false')) end, 'none')
# Die Source aus der Playlist
recorded = snd(playlist_recorded)
# Skippen erlauben
add_skip_command(recorded)
# Funktion zum laden einer neuen Playlist
playlist_funcs = fst(playlist_recorded)
# Flush functions
flush_recorded = snd(fst(playlist_funcs))
# Reload function
reload_recorded = fst(fst(playlist_funcs))
#up funtction
move_recorded = fst(fst(snd(playlist_funcs)))
#insert funtction
insert_recorded = fst(snd(fst(snd(playlist_funcs))))
# remove function
remove_recorded = snd(snd(fst(snd(playlist_funcs))))
#push function
push_recorded = snd(snd(snd(playlist_funcs)))
#show playlist function
data_recorded = fst(snd(snd(playlist_funcs)))
# create playlist source with smart crossfade
playlist = fallback(id="common", track_sensitive=false, [
switch(transitions =
[crossfade,crossfade],
[
( {!playlistrunning == true}, recorded ), # play the playlist
( {!playlistrunning == false}, get_input() )
]
),
if fallback_audio_folder != "" then
playlist.safe(fallback_audio_folder)
else
blank(duration=20.0)
end
])
# method to dynamicaly create a channel
def addChannel (ret, el, ~base="ch")
equeue = request.equeue(id = base^el) # create the equeue request
# add a seek function to the channel
server.register(namespace="ch"^el,
description="Seek to a relative position",
usage="seek <duration>",
"seek",fun (x) -> begin seek_track(equeue, x) end)
# append and return the list
list.append(ret,[equeue])
end
channels = addChannel([], '1', base='auto')
channels = addChannel(channels, '2', base='auto')
channels = list.fold(addChannel, channels, !channelnames)
mixer = mix(id = "mixer", list.append([playlist], channels))
#ignore(s) # testing
# User may load a XML-Playlist
#server.register(namespace='playlist',
# description="Load Playlist",
# usage="load <uri>",
# "load",fun (p) -> begin
# reload_recorded(skip=0, uri=p)
# end
#)
# Register the seek function
server.register(namespace='playlist',
description="Seek to a relative position",
usage="seek <duration>",
"seek",fun (x) -> begin seek_track(recorded, x) end
)
# The play function
server.register(namespace='playlist',
description="Play recorded files",
usage="play",
"play",fun (x) -> if !playlistrunning == true then
message('playlist', false, 'Playlist already playing', get_task_number ('play'), '01', level="info", type="user")
else
ignore(server.execute('mixer.select 0 true'))
playlistrunning := true
message('playlist', true, 'Start playing' , get_task_number ('play'), '00')
end
)
# Flush current playlist
server.register(namespace='playlist',
description="Flush recorded playlist",
usage="flush",
"flush",fun (s) -> begin flush_recorded() end)
# The remove function
server.register(namespace='playlist',
description="Remove item from playlist",
usage="remove <pos>",
"remove",fun (p) -> begin remove_recorded(int_of_string(p)) end)
# Let the user move up or down a track
server.register(namespace='playlist',
description="Move an item up or down",
usage="move <from> <to>",
"move",fun (p) -> begin
params=string.split(separator=" ",p)
src=if list.length(params)>0 then (int_of_string(list.nth(params,0))+0) else 0 end
target=if list.length(params)>1 then (int_of_string(list.nth(params,1))+0) else 0 end
move_recorded(src, target)
end
)
# Insert an entry
server.register(namespace='playlist',
description="Add an entry",
usage="insert <pos> <uri> [<title> <time>]",
"insert",fun (p) -> begin
params=string.split(separator=" ",p)
pos=if list.length(params)>0 then list.nth(params,0) else '' end
uri=if list.length(params)>1 then list.nth(params,1) else '' end
title=if list.length(params)>2 then list.nth(params,2) else '' end
time=if list.length(params)>3 then list.nth(params,3) else '' end
insert_recorded(pos=pos, title=title,time=time,uri)
end
)
# Insert a track on top of playlist
server.register(namespace='playlist',
description="Push an item to top and play immediately",
usage="push <pos>",
"push",fun (p) -> begin
params=string.split(separator=" ",p)
pos=if list.length(params)>0 then int_of_string(list.nth(params,0)) else 0 end
push_recorded(pos)
end
)
# Show metadata
server.register(namespace='playlist',
description="Show remaining playlist data in json format",
usage="data",
"data",fun (s) -> begin
playlist = data_recorded()
json_of(compact=true, playlist)
end
)
# Pause/stop playlist
server.register(namespace='playlist',
description="Pause playing recorded files",
usage="pause",
"pause", fun (x) -> if !playlistrunning == false then
message('playlist', false, 'Playlist already stopped', get_task_number ('pause'), '01', level="info", type="user")
else
playlistrunning := false
ignore(server.execute('playlist.skip'))
ignore(system('#{list.assoc("install_dir", ini)}/modules/soundengine/helpers/message.py -c #{!instance} --task=setState -n playlistcurrent -v ""'))
message('playlist', true, 'Playlist stopped', get_task_number ('pause'), '00')
end
)
# get remaining time
server.register(namespace='playlist',
description="Remaining time",
usage = "remaining",
"remaining", fun(x) -> string_of(source.remaining(recorded))
)
#streamm = single("/var/audio/fallback/music.flac")
#ignore(streamm) # testing
# Alsa output
if use_alsa == "y" then
if player_output == 'soundcard' then
output.alsa(id="player", fallible=true, mixer)
else
output.alsa(id="player", fallible=true, device=player_output, mixer)
end
else
output.pulseaudio(id="player", mixer)
end
# %include "stream.liq"