Commit a5a5e72e authored by David Trattnig's avatar David Trattnig
Browse files

Finalized Engine Basics.

parent 89a80e42
......@@ -110,8 +110,8 @@ class Guru():
# getter
self.parser.add_argument("-pcs", "--print-connection-status", action="store_true", dest="get_connection_status", default=False, help="Prints the status of the connection to liquidsoap, pv and tank")
self.parser.add_argument("-gam", "--get-active-mixer", action="store_true", dest="get_active_mixer", default=False, help="Which mixer is activated?")
self.parser.add_argument("-pms", "--print-mixer-status", action="store_true", dest="get_mixer_status", default=False, help="Prints all mixer sources and their states")
self.parser.add_argument("-gam", "--get-active-mixer", action="store_true", dest="mixer_channels_selected",default=False, help="Which mixer channels are selected?")
self.parser.add_argument("-pms", "--print-mixer-status", action="store_true", dest="mixer_status", default=False, help="Prints all mixer sources and their states")
self.parser.add_argument("-pap", "--print-act-programme", action="store_true", dest="get_act_programme", default=False, help="Prints the actual Programme, the controller holds")
self.parser.add_argument("-s", "--status", action="store_true", dest="get_status", default=False, help="Returns the Engine Status as JSON")
......
......@@ -50,11 +50,11 @@ class Padavan:
if self.args.fetch_new_programme:
self.fetch_new_programme()
elif self.args.get_active_mixer:
self.get_active_mixer()
elif self.args.mixer_channels_selected:
self.mixer_channels_selected()
elif self.args.get_mixer_status:
self.get_mixer_status()
elif self.args.mixer_status:
self.mixer_status()
elif self.args.get_act_programme:
self.get_act_programme()
......@@ -275,9 +275,9 @@ class Padavan:
self.destroy_liquidsoap_communication()
# ------------------------------------------------------------------------------------------ #
def get_active_mixer(self):
def mixer_channels_selected(self):
self.init_liquidsoap_communication()
am = self.ss.get_active_mixer()
am = self.ss.mixer_channels_selected()
if len(am) == 0:
self.destroy_liquidsoap_communication()
......@@ -289,10 +289,10 @@ class Padavan:
self.destroy_liquidsoap_communication()
# ------------------------------------------------------------------------------------------ #
def get_mixer_status(self):
def mixer_status(self):
self.init_liquidsoap_communication()
status = self.ss.get_mixer_status()
status = self.ss.mixer_status()
for k, v in status.items():
self.stringreply += "source: " + k + "\t status: " + v + "\n"
......
This diff is collapsed.
......@@ -159,7 +159,7 @@ class Monitoring:
self.status["soundsystem"]["version"] = self.soundsystem.version()
self.status["soundsystem"]["uptime"] = self.soundsystem.uptime()
self.status["soundsystem"]["io"] = self.get_io_state()
self.status["soundsystem"]["mixer"] = self.soundsystem.get_mixer_status()
self.status["soundsystem"]["mixer"] = self.soundsystem.mixer_status()
#self.status["soundsystem"]["recorder"] = self.soundsystem.get_recorder_status()
self.soundsystem.disable_transaction(self.soundsystem.client)
......
......@@ -59,32 +59,24 @@ class PlayerStateService:
#
def set_active_entry(self, entry):
def add_to_history(self, entries):
"""
Saves the currently playing entry to the local cache.
Saves the currently pre-rolled [`Entry`] to the local cache.
"""
self.entry_history.pop()
self.entry_history.appendleft(entry)
msg = "Active entry history:\n"
msg += "\n" + str(self.entry_history[0])
msg += "\n" + str(self.entry_history[1])
msg += "\n" + str(self.entry_history[2])
self.logger.info(msg)
self.entry_history.appendleft(entries)
def get_active_entry(self):
def get_recent_entries(self):
"""
Retrieves the currently playing `Entry` from the local cache.
Retrieves the currently playing [`Entry`] from the local cache.
"""
return self.entry_history[0]
def store_trackservice_entry(self, source):
"""
Stores the given entry in the Track Service.
Stores the entry identified by the given source in the Track Service.
Args:
source (String): The URI of the currently playing source
......@@ -92,25 +84,42 @@ class PlayerStateService:
Raises:
(NoActiveEntryException): In case currently nothing is playing
"""
active_entry = self.get_active_entry()
found = False
entries = self.get_recent_entries()
if not active_entry:
if not entries:
raise NoActiveEntryException
if active_entry.source == source:
trackservice = TrackService(active_entry)
trackservice.store(add=True, commit=True)
for active_entry in entries:
if active_entry.source == source:
trackservice = TrackService(active_entry)
trackservice.store(add=True, commit=True)
active_entry.trackservice_id = trackservice.id
active_entry.store(add=False, commit=True)
active_entry.trackservice_id = trackservice.id
active_entry.store(add=False, commit=True)
self.logger.info("Stored active entry '%s' to TrackService as '%s'" % (active_entry, trackservice))
found = True
self.logger.info("Stored active entry '%s' to TrackService as '%s'" % (active_entry, trackservice))
else:
msg = "Active entry source '%s' != '%s' activated source." % (active_entry.source, source)
if not found:
msg = "Found no entry in the recent history which matches the given source '%s'" % (source)
self.logger.critical(SimpleUtil.red(msg))
def print_entry_history(self):
"""
Prints all recents entries of the history.
"""
msg = "Active entry history:\n"
for entries in self.entry_history:
msg += "["
for e in entries:
msg += "\n" + str(e)
msg += "]"
self.logger.info(msg)
# def adapt_trackservice_title(self, source):
# """
......
......@@ -423,7 +423,7 @@ class PlaylistEntry(DB.Model, AuraDatabaseModel):
entry_start = Column(DateTime)
queue_state = None # Assigned when entry is about to be queued
channel = None # Assigned when entry is actually played
state = None # Assigned when state changes
status = None # Assigned when state changes
# relationships
playlist = relationship("Playlist", uselist=False, back_populates="entries")
......@@ -720,7 +720,7 @@ class SingleEntry(DB.Model, AuraDatabaseModel):
queue_state = None # Assigned when entry is about to be queued
channel = None # Assigned when entry is actually played
state = None # Assigned when state changes
status = None # Assigned when state changes
@hybrid_property
......
......@@ -196,8 +196,8 @@ class AuraScheduler(threading.Thread):
if (seconds_to_seek + sleep_offset) > active_entry.duration:
self.logger.info("The FFWD [>>] range exceeds the length of the entry. Drink some tea and wait for the sound of the next entry.")
else:
# Load and play active entry
self.soundsystem.load(active_entry)
# Pre-roll and play active entry
self.soundsystem.preroll(active_entry)
self.soundsystem.play(active_entry, TransitionType.FADE)
# Check if this is the last item of the schedule
......@@ -219,8 +219,8 @@ class AuraScheduler(threading.Thread):
or active_entry.type == ChannelType.HTTPS \
or active_entry.type == ChannelType.LIVE:
# Load and play active entry
self.soundsystem.load(active_entry)
# Pre-roll and play active entry
self.soundsystem.preroll(active_entry)
self.soundsystem.play(active_entry, TransitionType.FADE)
self.queue_end_of_schedule(active_entry, True)
......@@ -558,7 +558,6 @@ class AuraScheduler(threading.Thread):
def queue_playlist_entries(self, entries, fade_in, fade_out):
"""
Creates Liquidsoap player commands for all playlist items to be executed at the scheduled time.
......@@ -571,58 +570,81 @@ class AuraScheduler(threading.Thread):
Returns:
(String): Formatted string to display playlist entries in log
"""
entry_groups = []
entry_groups.append([])
previous_entry = None
index = 0
# Mark entries which start after the end of their schedule or are cut
clean_entries = self.preprocess_entries(entries, True)
# Schedule function calls
# Group all filesystem entries, allowing them to be queued at once
for entry in clean_entries:
if previous_entry == None or \
(previous_entry != None and \
previous_entry.type == entry.type and \
entry.type == ChannelType.FILESYSTEM):
entry_groups[index].append(entry)
else:
index += 1
entry_groups.append([])
entry_groups[index].append(entry)
self.set_entry_timer(entry, fade_in, fade_out)
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)
# Check if it's the last item, which needs special handling
if entry == clean_entries[-1]:
if entries[-1] == clean_entries[-1]:
# The end of schedule is the actual end of the track
self.queue_end_of_schedule(entry, fade_out)
self.queue_end_of_schedule(entries[-1], fade_out)
def set_entry_timer(self, entry, fade_in, fade_out):
def set_entry_timer(self, entries, fade_in, fade_out):
"""
Creates timer for loading and playing an entry. Existing timers are
Creates timer for loading and playing one or multiple entries. Existing timers are
updated.
Args:
entries ([]): List of multiple filesystem entries, or a single entry of other types
"""
play_timer = self.is_something_planned_at_time(entry.start_unix)
play_timer = self.is_something_planned_at_time(entries[0].start_unix)
now_unix = self.get_virtual_now()
diff = entry.start_unix - now_unix
diff = entries[0].start_unix - now_unix
# Play function to be called by timer
def do_play(entry):
self.logger.info(SimpleUtil.cyan("=== play('%s') ===" % entry))
def do_play(entries):
self.logger.info(SimpleUtil.cyan("=== play('%s') ===" % EngineUtil.get_entries_string(entries)))
transition_type = TransitionType.INSTANT
if fade_in:
transition_type = TransitionType.FADE
if entry.status != EntryPlayState.READY:
self.logger.critical(SimpleUtil.red("PLAY: For some reason the entry is not yet ready or could not be loaded (Entry: %s)" % str(entry)))
if entries[-1].status != EntryPlayState.READY:
self.logger.critical(SimpleUtil.red("PLAY: For some reason the entry/entries is not yet ready or could not be loaded (Entries: %s)" % str(entries)))
# TODO Pro-active fallback handling here
self.soundsystem.play(entry, transition_type)
self.soundsystem.play(entries[0], transition_type)
self.logger.info(self.get_ascii_programme())
if play_timer:
# Check if the Playlist IDs are different
if play_timer.entry.entry_id != entry.entry_id:
if play_timer.entries[0].entry_id != entries[0].entry_id:
# If not, stop and remove the old timer, create a new one
self.stop_timer(play_timer)
else:
# If the playlists do not differ => reuse the old timer and do nothing
self.logger.info("Playlist Entry %s is already scheduled - no new timer created!" % entry)
self.logger.info("Playlist Entry %s is already scheduled - no new timer created!" % str(entries))
return
# If nothing is planned at given time, create a new timer
(entry.switchtimer, entry.loadtimer) = self.create_timer(diff, do_play, [entry], switcher=True)
(entries[0].switchtimer, entries[0].loadtimer) = self.create_timer(diff, do_play, [entries], switcher=True)
......@@ -750,7 +772,7 @@ class AuraScheduler(threading.Thread):
Checks for existing timers at the given time.
"""
for t in self.message_timer:
if t.entry.start_unix == given_time and (t.fade_in or t.switcher):
if t.entry[0].start_unix == given_time and (t.fade_in or t.switcher):
return t
return False
......@@ -775,12 +797,16 @@ class AuraScheduler(threading.Thread):
if switcher:
# Load function to be called by timer
def do_load(entry):
self.logger.info(SimpleUtil.cyan("=== load('%s') ===" % entry))
def do_load(entries):
try:
self.soundsystem.load(entry)
if entries[0].type == ChannelType.FILESYSTEM:
self.logger.info(SimpleUtil.cyan("=== preroll_group('%s') ===" % EngineUtil.get_entries_string(entries)))
self.soundsystem.preroll_group(entries)
else:
self.logger.info(SimpleUtil.cyan("=== preroll('%s') ===" % EngineUtil.get_entries_string(entries)))
self.soundsystem.preroll(entries[0])
except LoadSourceException as e:
self.logger("Could not load entry %s:" % str(entry), e)
self.logger("Could not load entries %s:" % EngineUtil.get_entries_string(entries), e)
# TODO Fallback logic here
loader_diff = diff - self.config.get("preload_offset")
......
......@@ -63,7 +63,7 @@ class ConnectionTester(AuraConfig):
def test_lqs_conn(self):
try:
lsc = soundsystem(self.config)
lsc.get_mixer_status()
lsc.mixer_status()
return True
except Exception as e:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment