Skip to content
Snippets Groups Projects
Commit 19c407f8 authored by David Trattnig's avatar David Trattnig
Browse files

Improved timer behaviour and schedule updates.

parent 608b898e
No related branches found
No related tags found
No related merge requests found
......@@ -138,24 +138,27 @@ class AuraScheduler(threading.Thread):
3. Queues all playlists of the programm, if the soundssystem is ready to accept commands.
"""
while not self.exit_event.is_set():
seconds_to_wait = int(self.config.get("fetching_frequency"))
next_time = datetime.datetime.now() + datetime.timedelta(seconds=seconds_to_wait)
self.logger.info("Fetch new programmes every %ss. Next fetching in %ss." % (str(seconds_to_wait), str(next_time)))
self.fetch_new_programme()
# The Scheduler is ready
if not self.is_initialized:
self.is_initialized = True
if self.func_on_initialized:
self.func_on_initialized()
# The SoundSystem is ready
if self.soundsystem.is_ready():
self.queue_programme()
try:
seconds_to_wait = int(self.config.get("fetching_frequency"))
next_time = datetime.datetime.now() + datetime.timedelta(seconds=seconds_to_wait)
self.logger.info("Fetch new programmes every %ss. Next fetching in %ss." % (str(seconds_to_wait), str(next_time)))
self.fetch_new_programme()
# The scheduler is ready
if not self.is_initialized:
self.is_initialized = True
if self.func_on_initialized:
self.func_on_initialized()
# The soundsystem is ready
if self.soundsystem.is_ready():
self.queue_programme()
except Exception as e:
self.logger.critical(SimpleUtil.red("Unhandled error while fetching & scheduling new programme! (%s)" % str(e)), e)
self.print_message_queue()
self.exit_event.wait(seconds_to_wait)
self.logger.info(SimpleUtil.cyan("== start fetching new schedules =="))
......@@ -242,7 +245,6 @@ class AuraScheduler(threading.Thread):
# Load programme if necessary
if not self.programme:
self.logger.info("Next track requested: Need to load programme from database first.")
self.load_programme_from_db()
# Check for scheduled playlist
......@@ -590,19 +592,23 @@ class AuraScheduler(threading.Thread):
index += 1
entry_groups.append([])
entry_groups[index].append(entry)
previous_entry = entry
self.logger.info("Built %s entry group(s)" % len(entry_groups))
# Schedule function calls
for entries in entry_groups:
self.set_entry_timer(entries, fade_in, fade_out)
if len(clean_entries) > 0 and len(entry_groups) > 0:
for entries in entry_groups:
if not isinstance(entries, list):
raise ValueError("Invalid Entry Group: %s" % str(entries))
self.set_entry_timer(entries, fade_in, fade_out)
# Check if it's the last item, which needs special handling
if entries[-1] == clean_entries[-1]:
# The end of schedule is the actual end of the track
self.queue_end_of_schedule(entries[-1], fade_out)
# Check if it's the last item, which needs special handling
if entries[-1] == clean_entries[-1]:
# The end of schedule is the actual end of the track
self.queue_end_of_schedule(entries[-1], fade_out)
else:
self.logger.warn(SimpleUtil.red("Nothing to schedule..."))
......@@ -635,7 +641,7 @@ class AuraScheduler(threading.Thread):
if play_timer:
# Check if the Playlist IDs are different
if play_timer.entries[0].entry_id != entries[0].entry_id:
if play_timer.entries[0].playlist.playlist_id == entries[0].playlist.playlist_id:
# If not, stop and remove the old timer, create a new one
self.stop_timer(play_timer)
else:
......@@ -644,7 +650,7 @@ class AuraScheduler(threading.Thread):
return
# If nothing is planned at given time, create a new timer
(entries[0].switchtimer, entries[0].loadtimer) = self.create_timer(diff, do_play, [entries], switcher=True)
(entries[0].switchtimer, entries[0].loadtimer) = self.create_timer(diff, do_play, entries, switcher=True)
......@@ -762,7 +768,7 @@ class AuraScheduler(threading.Thread):
self.programme = Schedule.select_programme()
if not self.programme:
self.logger.critical("Could not load programme from database. We are in big trouble my friend!")
self.logger.critical(SimpleUtil.red("Could not load programme from database. We are in big trouble my friend!"))
return
......@@ -772,32 +778,34 @@ class AuraScheduler(threading.Thread):
Checks for existing timers at the given time.
"""
for t in self.message_timer:
if t.entry[0].start_unix == given_time and (t.fade_in or t.switcher):
if t.entries[0].start_unix == given_time and (t.fadein or t.switcher):
return t
return False
def create_timer(self, diff, func, parameters, fadein=False, fadeout=False, switcher=False):
def create_timer(self, diff, func, entries, fadein=False, fadeout=False, switcher=False):
"""
Creates a new timer for timed execution of mixer commands.
Args:
diff (Integer): The difference in seconds from now, when the call should happen
func (Function): The function to call
parameters ([]): The function parameters
entries ([]): The entries to be scheduled
"""
if not fadein and not fadeout and not switcher or fadein and fadeout or fadein and switcher or fadeout and switcher:
raise Exception("You have to call me with either fadein=true, fadeout=true or switcher=True")
raise ValueError("You have to call me with either fadein=true, fadeout=true or switcher=True")
if not isinstance(entries, list):
raise ValueError("No list of entries passed!")
t = CallFunctionTimer(diff, func, parameters, fadein, fadeout, switcher)
t = CallFunctionTimer(diff=diff, func=func, param=entries, fadein=fadein, fadeout=fadeout, switcher=switcher)
self.message_timer.append(t)
t.start()
if switcher:
# Load function to be called by timer
def do_load(entries):
# Pre-roll function to be called by timer
def do_preroll(entries):
try:
if entries[0].type == ChannelType.FILESYSTEM:
self.logger.info(SimpleUtil.cyan("=== preroll_group('%s') ===" % EngineUtil.get_entries_string(entries)))
......@@ -810,7 +818,7 @@ class AuraScheduler(threading.Thread):
# TODO Fallback logic here
loader_diff = diff - self.config.get("preload_offset")
loader = CallFunctionTimer(loader_diff, do_load, parameters, fadein, fadeout, switcher)
loader = CallFunctionTimer(diff=loader_diff, func=do_preroll, param=entries, fadein=fadein, fadeout=fadeout, switcher=False, loader=True)
self.message_timer.append(loader)
loader.start()
return (t, loader)
......@@ -827,22 +835,26 @@ class AuraScheduler(threading.Thread):
timer (Timer): The timer to stop.
"""
timer.cancel()
count = 1
if timer.entry.loadtimer is not None:
timer.entry.loadtimer.cancel()
self.message_timer.remove(timer.entry.loadtimer)
if timer.entries[0].loadtimer is not None:
timer.entries[0].loadtimer.cancel()
self.message_timer.remove(timer.entries[0].loadtimer)
count += 1
if timer.entry.fadeintimer is not None:
timer.entry.fadeintimer.cancel()
self.message_timer.remove(timer.entry.fadeintimer)
# if timer.entries[0].fadeintimer is not None:
# timer.entries[0].fadeintimer.cancel()
# self.message_timer.remove(timer.entries[0].fadeintimer)
# count += 1
if timer.entry.fadeouttimer is not None:
timer.entry.fadeouttimer.cancel()
self.message_timer.remove(timer.entry.fadeouttimer)
if timer.entries[0].fadeouttimer is not None:
timer.entries[0].fadeouttimer.cancel()
self.message_timer.remove(timer.entries[0].fadeouttimer)
count += 1
# Remove it from message queue
self.message_timer.remove(timer)
self.logger.info("Removed timer for " + str(timer.entry))
self.logger.info("Removed %s timers for: %s" % (str(count), EngineUtil.get_entries_string(timer.entries)))
......@@ -909,29 +921,30 @@ class AuraScheduler(threading.Thread):
class CallFunctionTimer(threading.Timer):
logger = None
param = None
entry = None
entries = None
diff = None
fadein = False
fadeout = False
switcher = False
loader = False
def __init__(self, diff, func, param, fadein=False, fadeout=False, switcher=False, loader=False):
def __init__(self, diff=None, func=None, param=None, fadein=False, fadeout=False, switcher=False, loader=False):
self.logger = logging.getLogger("AuraEngine")
self.logger.debug("Executing soundsystem command '%s' in %s seconds..." % (str(func.__name__), str(diff)))
threading.Timer.__init__(self, diff, func, args=param)
threading.Timer.__init__(self, diff, func, param)
if not fadein and not fadeout and not switcher and not loader \
or fadein and fadeout \
or fadein and switcher \
or fadeout and switcher:
raise Exception("You have to create me with either fadein=true, fadeout=true or switcher=True")
raise Exception("You have to create me with either fadein=True, fadeout=True or switcher=True")
self.diff = diff
self.func = func
self.param = param
self.entry = param[0]
self.entries = param
self.fadein = fadein
self.fadeout = fadeout
self.switcher = switcher
......@@ -942,13 +955,17 @@ class CallFunctionTimer(threading.Timer):
"""
String represenation of the timer.
"""
status = "Timer (Alive: %s)" % self.is_alive()
time_start = SimpleUtil.fmt_time(SimpleUtil.timestamp() + self.diff)
status += " starting in " + str(self.diff) + "s (" + time_start + ") "
if self.fadein:
return "CallFunctionTimer starting in " + str(self.diff) + "s fading in source '" + str(self.entry)
return status + " fading in entries '" + EngineUtil.get_entries_string(self.entries)
elif self.fadeout:
return "CallFunctionTimer starting in " + str(self.diff) + "s fading out source '" + str(self.entry)
return status + " fading out schedule '" + str(self.entries[0].playlist.schedule)
elif self.switcher:
return "CallFunctionTimer starting in " + str(self.diff) + "s switching to source '" + str(self.entry)
return status + " switching to entries '" + EngineUtil.get_entries_string(self.entries)
elif self.loader:
return "CallFunctionTimer starting in " + str(self.diff) + "s loading source '" + str(self.entry)
return status + " pre-rolling entries '" + EngineUtil.get_entries_string(self.entries)
else:
return "CORRUPTED CallFunctionTimer around! How can that be?"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment