diff --git a/modules/base/models.py b/modules/base/models.py
index e062cf858c55aef1187e6aa6ea812022e06ed688..9f66f395bc33324f49542de6e128ca5eeada2bad 100644
--- a/modules/base/models.py
+++ b/modules/base/models.py
@@ -30,10 +30,9 @@ from sqlalchemy                         import BigInteger, Boolean, Column, Date
 from sqlalchemy.orm                     import relationship
 from sqlalchemy.ext.hybrid              import hybrid_property
 
-
-from modules.scheduling.types           import PlaylistType
 from modules.base.config                import AuraConfig
-from modules.base.utils                 import SimpleUtil, EngineUtil
+from modules.base.utils                 import SimpleUtil
+from modules.core.resources             import ResourceUtil
 
 
 
@@ -159,7 +158,6 @@ class Schedule(DB.Model, AuraDatabaseModel):
     schedule_fallback_id = Column(Integer)
     show_fallback_id = Column(Integer)
     station_fallback_id = Column(Integer)
-    fallback_state = PlaylistType.DEFAULT
     
     fadeouttimer = None # Used to fade-out the schedule, even when entries are longer
 
@@ -215,6 +213,27 @@ class Schedule(DB.Model, AuraDatabaseModel):
         return schedules
 
 
+    def get_playlist(self):
+        """
+        Returns the assigned playlist.
+        """
+        # TODO Refactor to avoid storing array of playlists.
+        if self.playlist and self.playlist[0]:
+            return self.playlist[0]
+        return None
+
+
+    def has_queued_entries(self):
+        """
+        Checks if entries of this timeslot have been queued at the engine.        
+        """
+        #TODO Make logic more transparent
+        if hasattr(self, "queued_entries"):
+            if len(self.queued_entries) > 0:    
+                return True
+        return False
+
+
     @hybrid_property
     def start_unix(self):
         """
@@ -256,7 +275,6 @@ class Schedule(DB.Model, AuraDatabaseModel):
 
             "show": {
                 "name": self.show_name,
-                "type": self.get_type(),
                 "host": self.show_hosts
             },
 
@@ -289,7 +307,6 @@ class Playlist(DB.Model, AuraDatabaseModel):
     # data
     playlist_id = Column(Integer, autoincrement=False)  # , ForeignKey("schedule.playlist_id"))
     show_name = Column(String(256))
-    fallback_type = Column(Integer)
     entry_count = Column(Integer)
 
 
@@ -490,8 +507,8 @@ class PlaylistEntry(DB.Model, AuraDatabaseModel):
     def volume(self):
         return 100 # FIXME Make DB Column
 
-    def get_type(self):
-        return EngineUtil.get_channel_type(self.uri)
+    def get_content_type(self):
+        return ResourceUtil.get_content_type(self.uri)
 
 
     def get_prev_entries(self):
diff --git a/modules/scheduling/calendar.py b/modules/scheduling/calendar.py
index 8d565888badb59fde18e7ad268a40b1b0fafe265..4d5efd73943dd55dd96e11dc7833c7476fb2adac 100644
--- a/modules/scheduling/calendar.py
+++ b/modules/scheduling/calendar.py
@@ -26,7 +26,7 @@ import logging
 
 from datetime import datetime
 
-from modules.scheduling.types import PlaylistType
+# from modules.scheduling.types import PlaylistType
 from modules.base.utils import SimpleUtil as SU
 from modules.base.models import Schedule, Playlist, PlaylistEntry, PlaylistEntryMetaData
 from modules.scheduling.calender_fetcher import CalendarFetcher
@@ -140,13 +140,22 @@ class AuraCalendarService(threading.Thread):
                 schedule_db = self.store_schedule(schedule)
 
                 # Store playlists to play
-                self.store_playlist(schedule_db, schedule_db.playlist_id, schedule["playlist"], PlaylistType.DEFAULT.id)
+                self.store_playlist(schedule_db, schedule_db.playlist_id, schedule["playlist"])
                 if schedule_db.schedule_fallback_id:
-                    self.store_playlist(schedule_db, schedule_db.schedule_fallback_id, schedule["schedule_fallback"], PlaylistType.TIMESLOT.id)
+                    self.store_playlist(schedule_db, schedule_db.schedule_fallback_id, schedule["schedule_fallback"])
                 if schedule_db.show_fallback_id:
-                    self.store_playlist(schedule_db, schedule_db.show_fallback_id, schedule["show_fallback"], PlaylistType.SHOW.id)
+                    self.store_playlist(schedule_db, schedule_db.show_fallback_id, schedule["show_fallback"])
                 if schedule_db.station_fallback_id:
-                    self.store_playlist(schedule_db, schedule_db.station_fallback_id, schedule["station_fallback"], PlaylistType.STATION.id)
+                    self.store_playlist(schedule_db, schedule_db.station_fallback_id, schedule["station_fallback"])
+
+
+                # self.store_playlist(schedule_db, schedule_db.playlist_id, schedule["playlist"], PlaylistType.DEFAULT.id)
+                # if schedule_db.schedule_fallback_id:
+                #     self.store_playlist(schedule_db, schedule_db.schedule_fallback_id, schedule["schedule_fallback"], PlaylistType.TIMESLOT.id)
+                # if schedule_db.show_fallback_id:
+                #     self.store_playlist(schedule_db, schedule_db.show_fallback_id, schedule["show_fallback"], PlaylistType.SHOW.id)
+                # if schedule_db.station_fallback_id:
+                #     self.store_playlist(schedule_db, schedule_db.station_fallback_id, schedule["station_fallback"], PlaylistType.STATION.id)
 
                 result.append(schedule_db)
 
@@ -203,12 +212,14 @@ class AuraCalendarService(threading.Thread):
 
 
 
-    def store_playlist(self, schedule_db, playlist_id, fetched_playlist, fallbackplaylist_type=0):
+    # def store_playlist(self, schedule_db, playlist_id, fetched_playlist, fallbackplaylist_type=0):
+    def store_playlist(self, schedule_db, playlist_id, fetched_playlist):
         """
         Stores the Playlist to the database.
         """
         if not playlist_id or not fetched_playlist:
-            self.logger.debug("Playlist type %s with ID '%s' is not available!" % (fallbackplaylist_type, playlist_id))
+            self.logger.debug(f"Playlist ID#{playlist_id} is not available!")
+            # self.logger.debug("Playlist type %s with ID '%s' is not available!" % (fallbackplaylist_type, playlist_id))
             return
             
         playlist_db = Playlist.select_playlist_for_schedule(schedule_db.schedule_start, playlist_id)
@@ -222,7 +233,7 @@ class AuraCalendarService(threading.Thread):
         playlist_db.playlist_id = playlist_id
         playlist_db.schedule_start = schedule_db.schedule_start
         playlist_db.show_name = schedule_db.show_name
-        playlist_db.fallback_type = fallbackplaylist_type
+        # playlist_db.fallback_type = fallbackplaylist_type
         if "entries" in fetched_playlist:
             playlist_db.entry_count = len(fetched_playlist["entries"])
         else:
diff --git a/modules/scheduling/fallback_manager.py b/modules/scheduling/fallback_manager.py
index 072a31a35fd4631cdb4514287790cd276aa31d3f..9abbc31d731e82d94fac11aefa4392032b32bd83 100644
--- a/modules/scheduling/fallback_manager.py
+++ b/modules/scheduling/fallback_manager.py
@@ -19,15 +19,34 @@
 
 
 
+import logging
 
-import os, os.path
-import random
+from enum                       import Enum
+from threading                  import Thread, Timer
+from datetime                   import datetime, timedelta
 
-from accessify                  import private, protected
-from modules.scheduling.types   import PlaylistType
-from modules.base.utils         import SimpleUtil, EngineUtil
+from modules.base.utils         import SimpleUtil as SU
 from modules.base.mail          import AuraMailer
-from modules.core.channels      import ChannelType
+from modules.core.resources     import ResourceClass
+from modules.core.engine        import Engine
+
+
+class FallbackType(Enum):
+    """
+    Types of playlists.
+    """
+    NONE        = { "id": 0, "name": "default" }    # No fallback active, default playout
+    SCHEDULE    = { "id": 1, "name": "schedule" }   # The first played when some default playlist fails
+    SHOW        = { "id": 2, "name": "show" }       # The second played when the timeslot fallback fails    
+    STATION     = { "id": 3, "name": "station" }    # The last played when everything else fails
+
+    @property
+    def id(self):
+        return self.value["id"]
+
+    def __str__(self):
+        return str(self.value["name"])
+
 
 
 class FallbackManager:
@@ -40,21 +59,16 @@ class FallbackManager:
         logger (AuraLogger):        The logger
         mail   (AuraMailer):        Mail service
         scheduler (AuraScheduler):  The scheduler
-        fallback_history (Dict):    Holds a 24h history of played, local tracks to avoid re-play
-        last_fallback (Integer):    Timestamp, when the last local file fallback was played
-        is_processing (Boolean):    Flag to avoid race-conditions, as Liquidsoap sends plenty of requests at once
-    """
-
+    """    
     config = None
     logger = None
     mailer = None
     scheduler = None
-    fallback_history = {}
-    last_fallback = 0
-    is_processing = False
+    message_timer = None
 
 
-    def __init__(self, config, logger, scheduler):
+    
+    def __init__(self, config, logger, scheduler, message_timer):
         """
         Constructor
 
@@ -65,162 +79,103 @@ class FallbackManager:
         self.logger = logger
         self.mailer = AuraMailer(self.config)
         self.scheduler = scheduler
-        self.logger = logger
+        # self.message_timer = message_timer
+        self.message_timer = []
 
 
     #
     #   PUBLIC METHODS
     #
 
-    def resolve_playlist(self, schedule):
+    def schedule_fallback_playlist(self, schedule, schedule_now=False):
         """
-        Resolves the (fallback) playlist for the given schedule in case of pro-active fallback scenarios.
-        
-        A resolved playlist represents the state how it would currently  be aired. For example the `FallbackManager` 
-        evaluated, that the actually planned playlist cannot be played for various reasons (e.g. entries n/a). 
-        Instead one of the fallback playlists should be played. If the method is called some time later,
-        it actually planned playlist might be valid, thus returned as the resolved playlist.
-
-        As long the adressed schedule is still within the scheduling window, the resolved playlist can
-        always change.
-
-        This method also updates `schedule.fallback_state` to the current fallback type (`PlaylistType`).
+        Evaluates the scheduled fallback and queues it using a timed thread.
 
         Args:
-            schedule (Schedule):    The schedule to resolve the playlist for
-        
-        Returns:
-            (Playlist):             The resolved playlist
+            schedule_now (Boolean): If `True` it is executed immediately
         """
-        playlist = None
-        type = None
-        self.logger.info("Resolving playlist for schedule #%s ..." % schedule.schedule_id)
-
-        if not self.validate_playlist(schedule, "playlist"):
-            if not self.validate_playlist(schedule, "schedule_fallback"):
-                if not self.validate_playlist(schedule, "show_fallback"):
-                    if not self.validate_playlist(schedule, "station_fallback"):
-                        self.logger.error(SimpleUtil.red("No (fallback) playlists for schedule #%s available - not even a single one!" % schedule.schedule_id))
-                        return None
-                    else:
-                        type = PlaylistType.STATION
-                        playlist = schedule.station_fallback
-                else:
-                    type = PlaylistType.TIMESLOT
-                    playlist = schedule.schedule_fallback
-            else:
-                type = PlaylistType.SHOW
-                playlist = schedule.show_fallback
-        else:
-            type = PlaylistType.DEFAULT
-            playlist = schedule.playlist
-
-        if type and type != PlaylistType.DEFAULT:
-            previous_type = schedule.fallback_state
-            if type == previous_type:
-                self.logger.info("Fallback state for schedule #%s is still '%s'" % (schedule.schedule_id, type))
-            else:
-                self.logger.warn("Detected fallback type switch from '%s' to '%s' is required for schedule %s." % (previous_type, type, str(schedule)))
-        
-        schedule.fallback_state = type
-        return playlist[0]
-
-
+        timer_start = None
+        timer_end = None
+        (fallback_type, playlist) = self.get_fallback_playlist(schedule)
+
+        if playlist:
+            self.logger.info(f"Resolved {fallback_type.value} fallback")
+
+            def do_schedule(entries):
+                self.logger.info(SU.cyan(f"=== set_fallback_playlist('{entries}') ==="))
+                self.scheduler.engine.player.start_fallback_playlist(entries)
+            def do_unschedule():
+                self.logger.info(SU.cyan("=== clear_fallback_playlist() ==="))
+                self.scheduler.engine.player.stop_fallback_playlist()
+
+            if schedule_now == True:
+                # Update queue immediately
+                thread = Thread(target = do_schedule, args = (playlist.entries,))
+                thread.start()
+            else:          
+                # Update queue at the beginning of the timeslot  
+                timer_start = FallbackCommandTimer(schedule.start_unix, do_schedule, playlist.entries)
+                self.message_timer.append(timer_start)
+                timer_start.start()
+
+            # Update fallback channel to be cleared at the end of the timeslot
+            timer_end = FallbackCommandTimer(schedule.end_unix, do_unschedule)
+            self.message_timer.append(timer_end)
+            timer_end.start()
+            return (timer_start, timer_end)
 
-    def handle_proactive_fallback(self, scheduler, playlist):
-        """
-        This is the 1st level strategy for fallback handling. When playlist entries are pre-rolled their 
-        state is validated. If any of them doesn't become "ready to play" in time, some fallback entries
-        are queued.
-        """
-        resolved_playlist = self.resolve_playlist(playlist.schedule)
-        if playlist != resolved_playlist:
-            self.logger.info("Switching from playlist #%s to fallback playlist #%s ..." % (playlist.playlist_id, resolved_playlist.playlist_id))
-            
-            # Destroy any existing queue timers
-            for entry in playlist.entries:
-                scheduler.stop_timer(entry.switchtimer)
-            self.logger.info("Stopped existing timers for entries")
-
-            # Queue the fallback playlist
-            scheduler.queue_playlist_entries(resolved_playlist.schedule, resolved_playlist.entries, False, True)
-            self.logger.info("Queued fallback playlist entries (Fallback type: %s)" % playlist.type)
         else:
-            self.logger.critical(SimpleUtil.red("For some strange reason the fallback playlist equals the currently failed one?!"))
+            msg = f"There is no schedule- or show-fallback defined for timeslot#{schedule.schedule_id}. "
+            msg += f"The station fallback will be used automatically."
+            self.logger.info(msg)
 
-        
 
 
-    def get_fallback_for(self, fallbackname):
+    def resolve_playlist(self, schedule):
         """
-        Retrieves a random fallback audio source for any of the types:
-            - timeslot/schedule
-            - show
-            - station
-        
-        Args:
-            fallbackname (String):      Fallback type
+        Retrieves the currently planned (fallback) playlist. If a normal playlist is available,
+        this one is returned. In case of station fallback no playlist is returned.
 
+        Args:
+            schedule (Schedule)
+        
         Returns:
-            (String):                   Absolute path to the file
+            (FallbackType, Playlist)
         """
-        file = ""
-        media_type = "PLAYLIST"
-        active_schedule, active_playlist = self.scheduler.get_active_playlist()
+        planned_playlist = None
+        fallback_type = None
 
-        # Block access to avoid race-conditions
-        if self.is_processing:
-            return None
+        if self.validate_playlist(schedule, "playlist"):
+            planned_playlist = schedule.get_playlist()
+            fallback_type = FallbackType.NONE
         else:
-            self.is_processing = True
-
-        # Get fallback track(s) by fallback-type
-        if fallbackname == "timeslot":
-            file = self.get_playlist_items(active_schedule, "schedule_fallback")
-
-        elif fallbackname == "show":
-            file = self.get_playlist_items(active_schedule, "show_fallback")
-
-        elif fallbackname == "station":
-            file = self.get_playlist_items(active_schedule, "station_fallback")
-
-            if not file:
-                media_type = "TRACK"
-                file = self.get_random_local_track()
-
-                if not file:
-                    self.logger.critical("Got no file for station fallback! Playing default test track, to play anything at all.")
-                    file = "../../test/content/ernie_mayne_sugar.mp3"
-                    media_type = "DEFAULT TRACK"
-        else:
-            file = ""
-            self.logger.critical("Should set next fallback file for " + fallbackname + ", but this fallback is unknown!")
-
-        if file:
-            # Send admin email to notify about the fallback state
-            if not active_playlist:
-                active_playlist = "-"
-            msg = "AURA ENGINE %s FALLBACK DETECTED!\n\n" % fallbackname
-            msg += "Expected, active Schedule: %s \n" % active_schedule
-            msg += "Expected, active Playlist: %s \n\n" % active_playlist
-            msg += "Providing FALLBACK-%s for %s '%s'\n\n" % (media_type, fallbackname, file)
-            msg += "Please review the schedules or contact your Aura Engine administrator."
-            self.mailer.send_admin_mail("CRITICAL - Detected fallback for %s" % fallbackname, msg)
-            self.logger.warn("Providing fallback %s: '%s'. Sent admin email about fallback state" % (media_type, file))
+            (fallback_type, planned_playlist) = self.get_fallback_playlist(schedule)            
 
-        self.is_processing = False
-        return file
+        return (fallback_type, planned_playlist)
 
 
 
-    def fallback_has_started(self, artist, title):
+    def get_fallback_playlist(self, schedule):
         """
-        Called when a fallback track has actually started playing
-        """
-        self.logger.info("Now playing: fallback track '%s - %s'." % (artist, title))
+        Retrieves the playlist to be used in a fallback scenario.
 
+        Args: 
+            schedule (Schedule)
 
+        Returns:
+            (Playlist)
+        """        
+        playlist = None
+        fallback_type = FallbackType.STATION
 
+        if self.validate_playlist(schedule, "schedule_fallback"):
+            playlist = schedule.schedule_fallback[0]
+            fallback_type = FallbackType.SCHEDULE
+        elif self.validate_playlist(schedule, "show_fallback"):
+            playlist = schedule.show_fallback[0]
+            fallback_type = FallbackType.SHOW
+
+        return (fallback_type, playlist)
 
 
 
@@ -229,10 +184,21 @@ class FallbackManager:
     #
 
 
-
     def validate_playlist(self, schedule, playlist_type):
         """
         Checks if a playlist is valid for play-out.
+
+        Following checks are done for all playlists:
+
+            - has one or more entries
+
+        Fallback playlists should either:
+                
+            - have filesystem entries only
+            - reference a recording of a previous playout of a show (also filesystem)
+        
+        Otherwise, if a fallback playlist contains Live or Stream entries,
+        the exact playout behaviour can hardly be predicted.
         """
         playlist = getattr(schedule, playlist_type)
         if playlist \
@@ -240,105 +206,116 @@ class FallbackManager:
             and playlist[0].entries \
             and len(playlist[0].entries) > 0:
 
-            return True
+            # Default playlist
+            if playlist_type == "playlist":
+                return True
+
+            # Fallback playlist
+            elif playlist[0].entries:
+                is_fs_only = True
+                for entry in playlist[0].entries:
+                    if entry.get_content_type() not in ResourceClass.FILE.types:
+                        self.logger.error(SU.red("Fallback playlist of type '%s' contains not only file-system entries! \
+                            Skipping fallback level..." % playlist_type))
+                        is_fs_only = False
+                        break                
+                return is_fs_only
+
         return False
 
 
 
-    def validate_entries(self, entries):
-        """
-        Checks if playlist entries are valid for play-out.
-        """
-        for entry in entries:
-            if entry.get_type() == ChannelType.FILESYSTEM:
-                audio_store = self.config.get("audiofolder")
-                filepath = EngineUtil.uri_to_filepath(audio_store, entry.source)
 
-                if not self.is_audio_file(filepath):
-                    self.logger.warn("Invalid filesystem path '%s' in entry '%s'" % (filepath, str(entry)))
-                    return False
-        return True
 
+class EngineCommandTimer(Timer):
+    """
+    Timer for timed executing of Engine commands.
+    """
+    timer_store = {}    
+    logger = logging.getLogger("AuraEngine")
+    timer_id = None
+    timer_type = None
+    param = None
+    diff = None
+    dt = None
 
 
-    def get_playlist_items(self, schedule, fallback_key):
+    def __init__(self, timer_type="BASE", due_time=None, func=None, param=None):
         """
-        Retrieves the list of tracks from a playlist defined by `fallback_key`.
+        Constructor
         """
-        playlist_files = ""
-
-        if hasattr(schedule, fallback_key):
-            playlist = getattr(schedule, fallback_key)
-            if len(playlist) > 0:
-                playlist = playlist[0]
-                if playlist and playlist.entries:
-                    for entry in playlist.entries:
-                        playlist_files += entry.source + "\n"
+        now_unix = Engine.engine_time()        
+        self.timer_type = timer_type       
+        self.timer_id = f"{timer_type}:{func.__name__}:{due_time}"
+                
+        diff = due_time - now_unix
+        if diff < 0.0:
+            msg = f"Trying to create timer in the past: {self.timer_id}"
+            self.logger.error(SU.red(msg))
+            raise Exception(msg)
+
+        self.diff = diff
+        self.dt = datetime.now() + timedelta(seconds=diff)
+        self.func = func
+        self.param = param
+
+        def wrapper_func(param=None):
+
+            # Remove from cache
+            self.logger.info(SU.green(f"Removing old timer with ID: {self.timer_id}"))
+            del EngineCommandTimer.timer_store[self.timer_id]            
+            # Call actual function
+            if param: func(param,) 
+            else: func()
+
+        Timer.__init__(self, diff, wrapper_func, (param,))       
+        self.update_cache()
+        self.logger.info(SU.green(f"Created command timer with ID: {self.timer_id}"))
+        
 
-        return playlist_files
+    
+    def update_cache(self):
+        """
+        Adds the instance to the cache and cancels any previously existing commands.
+        """
+        existing_command = None
+        if self.timer_id in EngineCommandTimer.timer_store:
+            existing_command = EngineCommandTimer.timer_store[self.timer_id]    
+        if existing_command:
+            self.logger.info(SU.green(f"Cancelling previous timer with ID: {self.timer_id}"))
+            existing_command.cancel()
+        EngineCommandTimer.timer_store[self.timer_id] = self
 
 
 
-    def get_random_local_track(self):
+    def print_active_timers(self):
         """
-        Retrieves a random audio track from the local station-fallback directory.
-
-        Returns:
-            (String):   Absolute path to an audio file
+        Prints a list of active timers to the log.
         """
-        dir = self.config.fallback_music_folder
-        files = os.listdir(dir)
-        audio_files = list(filter(lambda f: self.is_audio_file(os.path.join(dir, f)), files))
-        
-        if not dir or not audio_files:
-            self.logger.error("Folder 'fallback_music_folder = %s' is empty!" % dir)
-            return None
-
-        # If last played fallback is > 24 hours ago, ignore play history
-        # This should save used memory if the engine runs for a long time
-        if self.last_fallback < SimpleUtil.timestamp() - (60*60*24):
-            self.fallback_history = {}
-            self.logger.info("Cleared fallback history.")
-        self.last_fallback = SimpleUtil.timestamp()
-        
-        # Retrieve files which haven't been played yet
-        history = set(self.fallback_history.keys())
-        left_audio_files = list( set(audio_files) - (history) )
-        self.logger.info("Left fallback audio-files: %d/%d" % (len(left_audio_files), len(audio_files)))
-        
-        # If nothing left, clear history and start with all files again
-        if not len(left_audio_files):
-            self.fallback_history = {}
-            left_audio_files = audio_files
+        for id, timer in EngineCommandTimer.timer_store.values():
+            EngineCommandTimer.logger.info(str(timer))
 
-        # Select random track from directory
-        i = random.randint(0, len(left_audio_files)-1)
-        file = os.path.join(dir, left_audio_files[i])
 
-        # Store track in history, to avoid playing it multiple times
-        if file:
-            self.fallback_history[left_audio_files[i]] = SimpleUtil.timestamp()
 
-        return file
+    def __str__(self):
+        """
+        String represenation of the timer.
+        """
+        return f"[{self.timer_id}] COMMAND TIMER due at {str(self.dt)} (alive: {self.is_alive()})"
 
 
 
-    def is_audio_file(self, file):
-        """
-        Checks if the passed file is an audio file i.e. has a file-extension
-        known for audio files.
 
-        Args:
-            dir (String):  
-            file (File):   the file object.
 
-        Returns:
-            (Boolean):      True, if it's an audio file.
+class FallbackCommandTimer(EngineCommandTimer):
+    """
+    Timer for executing timed scheduling of fallback playlists.
+    """
+    def __init__(self, diff=None, func=None, param=None):
         """
-        audio_extensions = [".wav", ".flac", ".mp3", ".ogg", ".m4a"]
-        ext = os.path.splitext(file)[1]
+        Constructor
+        """        
+        super().__init__("FALLBACK", diff, func, param)
+        self.logger.info("Executing scheduled fallback playlist update '%s' in %s seconds..." % \
+            (str(func.__name__), str(diff)))
 
-        if os.path.isfile(file):
-            if any(ext in s for s in audio_extensions):
-                return True
-        return False
\ No newline at end of file
diff --git a/modules/scheduling/scheduler.py b/modules/scheduling/scheduler.py
index ecb22187878d2a88d763195e6bb229c9ec17546d..ee49e58de2d7545edec8ba40882eae72b5edba0b 100644
--- a/modules/scheduling/scheduler.py
+++ b/modules/scheduling/scheduler.py
@@ -26,16 +26,17 @@ import decimal
 import traceback
 import sqlalchemy
 
+from enum import Enum
 from operator import attrgetter
 from datetime import datetime, timedelta
 
-from modules.cli.redis.messenger import RedisMessenger
-
-from modules.base.utils                     import SimpleUtil, EngineUtil
+from modules.cli.redis.messenger            import RedisMessenger
+from modules.base.utils                     import SimpleUtil as SU
 from modules.base.models                    import AuraDatabaseModel, Schedule, Playlist
 from modules.base.exceptions                import NoActiveScheduleException, LoadSourceException
+from modules.core.engine                    import Engine
 from modules.core.channels                  import ChannelType, TransitionType, EntryPlayState
-from modules.scheduling.types               import EntryQueueState
+from modules.core.resources                 import ResourceClass, ResourceUtil
 from modules.scheduling.calendar            import AuraCalendarService
 from modules.scheduling.fallback_manager    import FallbackManager
 
@@ -54,6 +55,17 @@ def alchemyencoder(obj):
     else:
         return str(obj)
 
+
+class EntryQueueState(Enum):
+    """
+    Types of playlist entry behaviours.
+    """
+    OKAY = "ok"
+    CUT = "cut"
+    OUT_OF_SCHEDULE = "oos"
+
+
+
 class AuraScheduler(threading.Thread):
     """
     Aura Scheduler Class
@@ -65,7 +77,7 @@ class AuraScheduler(threading.Thread):
         config (AuraConfig):                    Holds the Engine Configuration
         logger:                                 The logger
         exit_event(threading.Event):            Used to exit the thread if requested
-        soundsystem:                            Virtual mixer
+        engine:                            Virtual mixer
         last_successful_fetch (datetime):       Stores the last time a fetch from Steering/Tank was successful
 
         programme:                              The current radio programme to be played as defined in the local engine database
@@ -78,7 +90,7 @@ class AuraScheduler(threading.Thread):
     config = None
     logger = None
     exit_event = None
-    soundsystem = None
+    engine = None
     last_successful_fetch = None
     programme = None
     message_timer = []
@@ -89,23 +101,23 @@ class AuraScheduler(threading.Thread):
 
 
 
-    def __init__(self, config, soundsystem, func_on_init):
+    def __init__(self, config, engine, func_on_init):
         """
         Constructor
 
         Args:
             config (AuraConfig):        Reads the engine configuration
-            soundsystem (SoundSystem):  The soundsystem to play the schedule on
+            engine (Engine):            The engine to play the schedule on
             func_on_init (Function):    The function to be called when the scheduler is initialized
         """
         self.config = config
         self.logger = logging.getLogger("AuraEngine")
 
         self.init_database()
-        self.fallback_manager = FallbackManager(config, self.logger, self)
+        self.fallback_manager = FallbackManager(config, self.logger, self, None)
         self.redismessenger = RedisMessenger(config)
-        self.soundsystem = soundsystem
-        self.soundsystem.scheduler = self
+        self.engine = engine
+        self.engine.scheduler = self
         self.is_soundsytem_init = False
 
         # Scheduler Initialization
@@ -142,7 +154,7 @@ class AuraScheduler(threading.Thread):
             try:
                 self.config.load_config()
                 seconds_to_wait = int(self.config.get("fetching_frequency"))
-                self.logger.info(SimpleUtil.cyan("== start fetching new schedules =="))
+                self.logger.info(SU.cyan("== start fetching new schedules =="))
                 next_time = str(datetime.now())
                 self.logger.info("Fetching new schedules every %ss. Next fetching at %ss." % (str(seconds_to_wait), next_time))
                 self.fetch_new_programme()
@@ -153,12 +165,12 @@ class AuraScheduler(threading.Thread):
                     if self.func_on_initialized:
                         self.func_on_initialized()
 
-                # The soundsystem is ready
+                # The engine is ready
                 if self.is_soundsytem_init:
                     self.queue_programme()
 
             except Exception as e:
-                self.logger.critical(SimpleUtil.red("Unhandled error while fetching & scheduling new programme! (%s)" % str(e)), e)
+                self.logger.critical(SU.red("Unhandled error while fetching & scheduling new programme! (%s)" % str(e)), e)
 
             self.clean_timer_queue()
             self.print_timer_queue()
@@ -179,7 +191,7 @@ class AuraScheduler(threading.Thread):
 
     def on_ready(self):
         """
-        Called when the soundsystem is ready.
+        Called when the engine is ready.
         """
         # self.queue_programme()
         self.logger.info(self.get_ascii_programme())
@@ -203,25 +215,33 @@ class AuraScheduler(threading.Thread):
         """
         sleep_offset = 10
         active_schedule = self.get_active_schedule()
+
+        # Schedule any available fallback playlist
+        if active_schedule:
+            self.fallback_manager.schedule_fallback_playlist(active_schedule, True)
+            # Queue the fade-out of the schedule
+            if not active_schedule.fadeouttimer:
+                self.queue_end_of_schedule(active_schedule, True)
+
         active_entry = self.get_active_entry()
         if not active_entry:
             raise NoActiveScheduleException
 
         # In case of a file-system source, we need to fast-foward to the current marker as per schedule
-        if active_entry.get_type() == ChannelType.FILESYSTEM:
+        if active_entry.get_content_type() in ResourceClass.FILE.types:
 
             # Calculate the seconds we have to fast-forward
-            now_unix = self.get_virtual_now()
+            now_unix = Engine.engine_time()
             seconds_to_seek = now_unix - active_entry.start_unix
 
             # If the seek exceeds the length of the current track, 
             # there's no need to do anything - the scheduler takes care of the rest
             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:
+            else:                
                 # Pre-roll and play active entry
-                self.soundsystem.preroll(active_entry)
-                self.soundsystem.play(active_entry, TransitionType.FADE)
+                self.engine.player.preroll(active_entry)
+                self.engine.player.play(active_entry, TransitionType.FADE)
 
                 # Check if this is the last item of the schedule
                 # if active_entry.end_unix > active_entry.playlist.schedule.end_unix:
@@ -230,30 +250,28 @@ class AuraScheduler(threading.Thread):
                 # Fast-forward to the scheduled position
                 if seconds_to_seek > 0:
                     # Without plenty of timeout (10s) the seek doesn't work
-                    seconds_to_seek += sleep_offset
-                    time.sleep(sleep_offset)
-                    self.logger.info("Going to fast-forward %s seconds" % seconds_to_seek)
-                    self.soundsystem.enable_transaction()
-                    response = self.soundsystem.playlist_seek(active_entry.channel, seconds_to_seek)
-                    self.soundsystem.disable_transaction()
-                    self.logger.info("Sound-system seek response: " + response)
-        
-        elif active_entry.get_type() == ChannelType.HTTP \
-            or active_entry.get_type() == ChannelType.HTTPS \
-            or active_entry.get_type() == ChannelType.LIVE:
+                    def async_cue_seek(seconds_to_seek):
+                        seconds_to_seek += sleep_offset
+                        time.sleep(sleep_offset)
+                        self.logger.info("Going to fast-forward %s seconds" % seconds_to_seek)
+                        response = self.engine.player.queue_seek(active_entry.channel, seconds_to_seek)
+                        self.logger.info("Sound-system seek response: " + response)
+
+                    thread = threading.Thread(target = async_cue_seek, args = (seconds_to_seek,))
+                    thread.start()                         
+
+        elif active_entry.get_content_type() in ResourceClass.STREAM.types \
+            or active_entry.get_content_type() in ResourceClass.LIVE.types:
 
             # Pre-roll and play active entry
-            self.soundsystem.preroll(active_entry)
-            self.soundsystem.play(active_entry, TransitionType.FADE)
+            self.engine.player.preroll(active_entry)
+            self.engine.player.play(active_entry, TransitionType.FADE)
 
             # self.queue_end_of_schedule(active_schedule, True)
 
         else:
             self.logger.critical("Unknown Entry Type: %s" % active_entry)
         
-        # Queue the fade-out of the schedule
-        if active_schedule and not active_schedule.fadeouttimer:
-            self.queue_end_of_schedule(active_schedule, True)
 
 
 
@@ -264,7 +282,7 @@ class AuraScheduler(threading.Thread):
         Returns:
             (PlaylistEntry): The track which is (or should) currently being played
         """
-        now_unix = self.get_virtual_now()
+        now_unix = Engine.engine_time()
 
         # Load programme if necessary
         if not self.programme:
@@ -273,14 +291,14 @@ class AuraScheduler(threading.Thread):
         # Check for current schedule
         current_schedule = self.get_active_schedule()
         if not current_schedule:
-            self.logger.warning(SimpleUtil.red("There's no active schedule"))
+            self.logger.warning(SU.red("There's no active schedule"))
             return None
 
         # Check for scheduled playlist
-        current_playlist = self.fallback_manager.resolve_playlist(current_schedule)
+        current_playlist = current_schedule.get_playlist()
         if not current_playlist:
-            msg = "There's no active playlist for a current schedule. Most likely the playlist was never available or finished before the end of the schedule."
-            self.logger.warning(SimpleUtil.red(msg))
+            msg = "There's no playlist assigned to the current schedule. Most likely a fallback will make things okay again."
+            self.logger.warning(SU.red(msg))
             return None
 
         # Iterate over playlist entries and store the current one
@@ -292,8 +310,8 @@ class AuraScheduler(threading.Thread):
       
         if not current_entry:
             # Nothing playing ... fallback will kick-in
-            msg = "There's no entry scheduled for playlist '%s' at %s" % (str(current_playlist), SimpleUtil.fmt_time(now_unix))
-            self.logger.warning(SimpleUtil.red(msg))
+            msg = "There's no entry scheduled for playlist '%s' at %s" % (str(current_playlist), SU.fmt_time(now_unix))
+            self.logger.warning(SU.red(msg))
             return None
 
         return current_entry
@@ -308,7 +326,7 @@ class AuraScheduler(threading.Thread):
             (Schedule): The current schedule
         """
         current_schedule = None
-        now_unix = self.get_virtual_now()
+        now_unix = Engine.engine_time()
 
         # Iterate over all schedules and find the one to be played right now
         if self.programme:
@@ -330,7 +348,7 @@ class AuraScheduler(threading.Thread):
         Returns:
             ([Schedule]): The next schedules
         """
-        now_unix = self.get_virtual_now()
+        now_unix = Engine.engine_time()
         next_schedules = []
 
         for schedule in self.programme:
@@ -351,8 +369,9 @@ class AuraScheduler(threading.Thread):
             (Playlist): The resolved playlist
         """
         schedule = self.get_active_schedule()
-        playlist = self.fallback_manager.resolve_playlist(schedule)
-        return playlist
+        if schedule:
+            return schedule.get_playlist()
+        return None
 
 
     # FIXME Review relevance.
@@ -390,7 +409,7 @@ class AuraScheduler(threading.Thread):
         message_queue = ""
         messages = sorted(self.message_timer, key=attrgetter('diff'))
         if not messages:
-            self.logger.warning(SimpleUtil.red("There's nothing in the Timer Queue!"))
+            self.logger.warning(SU.red("There's nothing in the Timer Queue!"))
         else:
             for msg in messages:
                 message_queue += str(msg)+"\n"
@@ -468,26 +487,26 @@ class AuraScheduler(threading.Thread):
         """
         active_schedule = self.get_active_schedule()
 
-        s = "\n\n   PLAYING NOW:"
+        s = "\n\n   SCHEDULED NOW:"
         s += "\n┌──────────────────────────────────────────────────────────────────────────────────────────────────────"
         if active_schedule:
             planned_playlist = None
             if active_schedule.playlist:
-                planned_playlist = active_schedule.playlist[0] # FIXME Improve model without list
-            resolved_playlist = self.fallback_manager.resolve_playlist(active_schedule)
+                planned_playlist = active_schedule.playlist[0]
+
+            (fallback_type, resolved_playlist) = self.fallback_manager.resolve_playlist(active_schedule)
 
-            s += "\n│   Playing schedule %s         " % active_schedule
+            s += "\n│   Playing timeslot %s         " % active_schedule
             if planned_playlist: 
                 if resolved_playlist and resolved_playlist.playlist_id != planned_playlist.playlist_id:
                     s += "\n│       └── Playlist %s         " % planned_playlist
                     s += "\n│       "
-                    s += SimpleUtil.red("↑↑↑ That's the originally planned playlist.") + ("Instead playing the fallback playlist below ↓↓↓")
+                    s += SU.red("↑↑↑ That's the originally planned playlist.") + ("Instead playing the fallback playlist below ↓↓↓")
 
             if resolved_playlist:                                  
                 if not planned_playlist:
-                    fallback_type = str(EngineUtil.get_playlist_type(resolved_playlist.fallback_type))
                     s += "\n│                         "
-                    s += SimpleUtil.red("No Playlist assigned to schedule. Instead playing the `%s` playlist below ↓↓↓" % SimpleUtil.cyan(fallback_type))
+                    s += SU.red("No playlist assigned to timeslot. Instead playing the `%s` playlist below ↓↓↓" % SU.cyan(str(fallback_type)))
 
                 s += "\n│       └── Playlist %s         " % resolved_playlist
 
@@ -503,7 +522,7 @@ class AuraScheduler(threading.Thread):
                 # Entry currently being played
                 if active_entry:
                     s += "\n│         └── Entry %s | %s         " % \
-                        (str(entry.entry_num+1), SimpleUtil.green("PLAYING > "+str(active_entry)))
+                        (str(active_entry.entry_num+1), SU.green("PLAYING > "+str(active_entry)))
 
                     # Open entries for current playlist
                     rest_of_playlist = active_entry.get_next_entries(False)
@@ -511,27 +530,27 @@ class AuraScheduler(threading.Thread):
                     s += self.build_playlist_string(entries)
                     
             else:
-                s += "\n│       └── %s" % (SimpleUtil.red("No active playlist. There should be at least some fallback playlist running..."))
+                s += "\n│       └── %s" % (SU.red("No active playlist. There should be at least some fallback playlist running..."))
         else:
             s += "\n│   Nothing.           "
         s += "\n└──────────────────────────────────────────────────────────────────────────────────────────────────────"
 
-        s += "\n   PLAYING NEXT:"
+        s += "\n   SCHEDULED NEXT:"
         s += "\n┌──────────────────────────────────────────────────────────────────────────────────────────────────────"
 
         next_schedules = self.get_next_schedules()
         if not next_schedules:
             s += "\n│   Nothing.         "
         else:
-            for schedule in next_schedules:
-                resolved_playlist = self.fallback_manager.resolve_playlist(schedule)
+            for schedule in next_schedules:        
+                (fallback_type, resolved_playlist) = self.fallback_manager.resolve_playlist(schedule)
                 if resolved_playlist:
-                    fallback_type = str(EngineUtil.get_playlist_type(resolved_playlist.fallback_type))
-                    s += "\n│   Queued schedule %s         " % schedule
-                    s += "\n│      └── Playlist %s         (Type: %s)" % (resolved_playlist, SimpleUtil.cyan(fallback_type))
+
+                    s += "\n│   Queued timeslot %s         " % schedule
+                    s += "\n│      └── Playlist %s         (Type: %s)" % (resolved_playlist, SU.cyan(str(fallback_type)))
                     if resolved_playlist.end_unix > schedule.end_unix:
                         s += "\n│          %s!              " % \
-                        (SimpleUtil.red("↑↑↑ Playlist #%s ends after Schedule #%s!" % (resolved_playlist.playlist_id, schedule.schedule_id)))
+                        (SU.red("↑↑↑ Playlist #%s ends after timeslot #%s!" % (resolved_playlist.playlist_id, schedule.schedule_id)))
                     
                     entries = self.preprocess_entries(resolved_playlist.entries, False)
                     s += self.build_playlist_string(entries)
@@ -551,7 +570,7 @@ class AuraScheduler(threading.Thread):
         for entry in entries:
             if entry.queue_state == EntryQueueState.OUT_OF_SCHEDULE and not is_out_of_schedule:
                 s += "\n│             %s" % \
-                    SimpleUtil.red("↓↓↓ These entries won't be played because they are out of schedule.")
+                    SU.red("↓↓↓ These entries won't be played because they are out of schedule.")
                 is_out_of_schedule = True
 
             s += self.build_entry_string("\n│         └── ", entry, is_out_of_schedule)
@@ -566,10 +585,10 @@ class AuraScheduler(threading.Thread):
         """
         s = ""
         if entry.queue_state == EntryQueueState.CUT:
-            s = "\n│             %s" % SimpleUtil.red("↓↓↓ This entry is going to be cut.")
+            s = "\n│             %s" % SU.red("↓↓↓ This entry is going to be cut.")
 
         if strike:
-            entry_str = SimpleUtil.strike(entry)
+            entry_str = SU.strike(entry)
         else:
             entry_str = str(entry)
 
@@ -583,17 +602,17 @@ class AuraScheduler(threading.Thread):
 #
 
 
-    def get_virtual_now(self):
-        """
-        Liquidsoap is slow in executing commands, therefore it's needed to schedule
-        actions by (n) seconds in advance, as defined in the configuration file by
-        the property `lqs_delay_offset`.
+    # def engine_time(self):
+    #     """
+    #     Liquidsoap is slow in executing commands, therefore it's needed to schedule
+    #     actions by (n) seconds in advance, as defined in the configuration file by
+    #     the property `lqs_delay_offset`.
 
-        Returns:
-            (Integer):  the Unix epoch timestamp including the offset
-        """
-        time_offset = int(self.config.lqs_delay_offset)
-        return SimpleUtil.timestamp() + time_offset
+    #     Returns:
+    #         (Integer):  the Unix epoch timestamp including the offset
+    #     """
+    #     time_offset = int(self.config.lqs_delay_offset)
+    #     return SU.timestamp() + time_offset
 
 
 
@@ -603,7 +622,7 @@ class AuraScheduler(threading.Thread):
         is defined by the config option `scheduling_window_end`. This value defines the seconds
         minus the actual start time of the schedule.
         """
-        now_unix = self.get_virtual_now()
+        now_unix = Engine.engine_time()
         len_before = len(schedules)
         window_start = self.config.get("scheduling_window_start")
         window_end = self.config.get("scheduling_window_end")
@@ -619,7 +638,7 @@ class AuraScheduler(threading.Thread):
         """
         Checks if the schedule is within the scheduling window.
         """
-        now_unix = self.get_virtual_now()
+        now_unix = Engine.engine_time()
         window_start = self.config.get("scheduling_window_start")
         window_end = self.config.get("scheduling_window_end")
 
@@ -644,14 +663,17 @@ class AuraScheduler(threading.Thread):
         # Queue the schedules, their playlists and entries
         if schedules:
             for next_schedule in schedules:
-                playlist = self.fallback_manager.resolve_playlist(next_schedule)
-                self.queue_playlist_entries(next_schedule, playlist.entries, False, True)
-                
+                # Schedule any available fallback playlist
+                self.fallback_manager.schedule_fallback_playlist(next_schedule, False)
+
+                if next_schedule.playlist:
+                    self.queue_playlist_entries(next_schedule, next_schedule.get_playlist().entries, False, True)
+                                
                 # Queue the fade-out of the schedule
                 if not next_schedule.fadeouttimer:
                     self.queue_end_of_schedule(next_schedule, True)
 
-        self.logger.info(SimpleUtil.green("Finished queuing programme."))
+        self.logger.info(SU.green("Finished queuing programme."))
 
 
 
@@ -664,7 +686,7 @@ class AuraScheduler(threading.Thread):
         
         # Queue the (rest of the) currently playing schedule upon startup
         if current_schedule:
-            current_playlist = self.fallback_manager.resolve_playlist(current_schedule)
+            current_playlist = current_schedule.get_playlist()
 
             if current_playlist:
                 active_entry = self.get_active_entry()
@@ -682,7 +704,9 @@ class AuraScheduler(threading.Thread):
                     self.queue_playlist_entries(current_schedule, rest_of_playlist, False, True)
 
                     # Store them for later reference
-                    current_schedule.queued_entries = rest_of_playlist
+                    current_schedule.queued_entries = [active_entry]
+                    if rest_of_playlist:
+                        current_schedule.queued_entries.append(rest_of_playlist)
 
 
 
@@ -711,8 +735,8 @@ class AuraScheduler(threading.Thread):
         for entry in clean_entries:
             if previous_entry == None or \
                 (previous_entry != None and \
-                 previous_entry.get_type() == entry.get_type() and \
-                 entry.get_type() == ChannelType.FILESYSTEM):
+                 previous_entry.get_content_type() == entry.get_content_type() and \
+                 entry.get_content_type() in ResourceClass.FILE.types):
                 
                 entry_groups[index].append(entry)
             else:
@@ -736,7 +760,7 @@ class AuraScheduler(threading.Thread):
                 schedule.queued_entries = clean_entries
 
         else:
-            self.logger.warn(SimpleUtil.red("Nothing to schedule ..."))
+            self.logger.warn(SU.red("Nothing to schedule ..."))
 
 
 
@@ -749,22 +773,22 @@ class AuraScheduler(threading.Thread):
             entries ([]): List of multiple filesystem entries, or a single entry of other types
         """
         play_timer = self.is_something_planned_at_time(entries[0].start_unix)
-        now_unix = self.get_virtual_now()
+        now_unix = Engine.engine_time()
         diff = entries[0].start_unix - now_unix
 
         # Play function to be called by timer
         def do_play(entries):
-            self.logger.info(SimpleUtil.cyan("=== play('%s') ===" % EngineUtil.get_entries_string(entries)))
+            self.logger.info(SU.cyan("=== play('%s') ===" % ResourceUtil.get_entries_string(entries)))
             transition_type = TransitionType.INSTANT
             if fade_in:
                 transition_type = TransitionType.FADE
 
             if entries[-1].status != EntryPlayState.READY:
-                self.logger.critical(SimpleUtil.red("PLAY: For some reason the entry/entries are not yet ready to be played (Entries: %s)" % EngineUtil.get_entries_string(entries)))
+                self.logger.critical(SU.red("PLAY: For some reason the entry/entries are not yet ready to be played (Entries: %s)" % ResourceUtil.get_entries_string(entries)))
                 # At this point it's too late to do any pro-active fallback handling. Is it? Wait for the silence detector to deal with it.
                 # TODO Observe the actual handling of this section and think about possible improvements.
 
-            self.soundsystem.play(entries[0], transition_type)
+            self.engine.player.play(entries[0], transition_type)
             self.logger.info(self.get_ascii_programme())
 
 
@@ -775,7 +799,7 @@ class AuraScheduler(threading.Thread):
                 self.stop_timer(play_timer)                
             else:
                 # If the playlist entries do not differ => reuse the old timer and do nothing
-                self.logger.debug("Playlist Entry %s is already scheduled - no new timer created." % EngineUtil.get_entries_string(entries))
+                self.logger.debug("Playlist Entry %s is already scheduled - no new timer created." % ResourceUtil.get_entries_string(entries))
                 return
         
         # If nothing is planned at given time, create a new timer
@@ -827,7 +851,7 @@ class AuraScheduler(threading.Thread):
 
             if entry.entry_start >= entry.playlist.schedule.schedule_end:
                 msg = "Filtered entry (%s) after end-of schedule (%s) ... SKIPPED" % (entry, entry.playlist.schedule)
-                self.logger.warn(SimpleUtil.red(msg))
+                self.logger.warning(SU.red(msg))
                 entry.queue_state = EntryQueueState.OUT_OF_SCHEDULE
             elif entry.end_unix > entry.playlist.schedule.end_unix:
                 entry.queue_state = EntryQueueState.CUT
@@ -843,7 +867,7 @@ class AuraScheduler(threading.Thread):
 
     def queue_end_of_schedule(self, schedule, fade_out):
         """
-        Queues a soundsystem action to stop/fade-out the given schedule.
+        Queues a engine action to stop/fade-out the given schedule.
 
         Args:
             schedule (PlaylistEntry):  The schedule
@@ -851,20 +875,21 @@ class AuraScheduler(threading.Thread):
         """
         schedule_end = schedule.schedule_end
         schedule_end_unix = schedule.end_unix
-        now_unix = self.get_virtual_now()
+        now_unix = Engine.engine_time()
         fade_out_time = 0
 
         # Stop function to be called when schedule ends
         def do_stop(schedule):
-            last_entry = schedule.queued_entries[-1] # FIXME sometimes an issue with startup queues
-            self.logger.info(SimpleUtil.cyan("=== stop('%s') ===" % str(last_entry.playlist.schedule)))
-            transition_type = TransitionType.INSTANT
-            if fade_out:
-                transition_type = TransitionType.FADE
-            self.soundsystem.stop(last_entry, transition_type)
+            if schedule.has_queued_entries():
+                last_entry = schedule.queued_entries[-1]
+                self.logger.info(SU.cyan("=== stop('%s') ===" % str(last_entry.playlist.schedule)))
+                transition_type = TransitionType.INSTANT
+                if fade_out:
+                    transition_type = TransitionType.FADE
+                self.engine.player.stop(last_entry, transition_type)
 
         if fade_out == True:
-            fade_out_time = int(round(float(self.config.get("fade_out_time")))) #FIXME Use float
+            fade_out_time = int(round(float(self.config.get("fade_out_time")))) #TODO Use float
         
         # Stop any existing fade-out timer
         if schedule.fadeouttimer:
@@ -899,26 +924,26 @@ class AuraScheduler(threading.Thread):
         self.last_successful_fetch = None
 
         if response is None:
-            msg = SimpleUtil.red("Trying to load programme from Engine Database, because AuraCalendarService returned an empty response.")
+            msg = SU.red("Trying to load programme from Engine Database, because AuraCalendarService returned an empty response.")
             self.logger.warning(msg)
         elif type(response) is list:
             self.programme = response
             if self.programme is not None and len(self.programme) > 0:
                 self.last_successful_fetch = datetime.now()
-                self.logger.info(SimpleUtil.green("Finished fetching current programme from API"))
+                self.logger.info(SU.green("Finished fetching current programme from API"))
             if len(self.programme) == 0:
                 self.logger.critical("Programme fetched from Steering/Tank has no entries!")
         elif response.startswith("fetching_aborted"):
-            msg = SimpleUtil.red("Trying to load programme from database only, because fetching was being aborted from AuraCalendarService! Reason: ")
+            msg = SU.red("Trying to load programme from database only, because fetching was being aborted from AuraCalendarService! Reason: ")
             self.logger.warning(msg + response[16:])
         else:
-            msg = SimpleUtil.red("Trying to load programme from database only, because of an unknown response from AuraCalendarService: " + response)
+            msg = SU.red("Trying to load programme from database only, because of an unknown response from AuraCalendarService: " + response)
             self.logger.warning(msg)
 
         # Always load latest programme from the database
         self.last_successful_fetch = lsf
         self.load_programme_from_db()
-        self.logger.info(SimpleUtil.green("Finished loading current programme from database (%s schedules)" % str(len(self.programme))))
+        self.logger.info(SU.green("Finished loading current programme from database (%s schedules)" % str(len(self.programme))))
         for schedule in self.programme:
             self.logger.debug("\tSchedule %s with Playlist %s" % (str(schedule), str(schedule.playlist)))
 
@@ -934,7 +959,7 @@ class AuraScheduler(threading.Thread):
         self.programme = Schedule.select_programme()
 
         if not self.programme:
-            self.logger.critical(SimpleUtil.red("Could not load programme from database. We are in big trouble my friend!"))
+            self.logger.critical(SU.red("Could not load programme from database. We are in big trouble my friend!"))
             return
 
 
@@ -977,23 +1002,23 @@ class AuraScheduler(threading.Thread):
             # Pre-roll function to be called by timer
             def do_preroll(entries):
                 try:
-                    if entries[0].get_type() == ChannelType.FILESYSTEM:
-                        self.logger.info(SimpleUtil.cyan("=== preroll_group('%s') ===" % EngineUtil.get_entries_string(entries)))
-                        self.soundsystem.preroll_group(entries)
+                    if entries[0].get_content_type() in ResourceClass.FILE.types:
+                        self.logger.info(SU.cyan("=== preroll_group('%s') ===" % ResourceUtil.get_entries_string(entries)))
+                        self.engine.player.preroll_group(entries, ChannelType.QUEUE)
                     else:
-                        self.logger.info(SimpleUtil.cyan("=== preroll('%s') ===" % EngineUtil.get_entries_string(entries)))
-                        self.soundsystem.preroll(entries[0])
+                        self.logger.info(SU.cyan("=== preroll('%s') ===" % ResourceUtil.get_entries_string(entries)))
+                        self.engine.player.preroll(entries[0])
                 except LoadSourceException as e:
-                    self.logger.critical(SimpleUtil.red("Could not pre-roll entries %s" % EngineUtil.get_entries_string(entries)), e)
+                    self.logger.critical(SU.red("Could not pre-roll entries %s" % ResourceUtil.get_entries_string(entries)), e)
 
-                    # Pro-active fallback handling, avoiding the need of the silence detector kicking-in.
-                    self.fallback_manager.handle_proactive_fallback(self, entries[0].playlist)
+                    # # Pro-active fallback handling, avoiding the need of the silence detector kicking-in.
+                    # self.fallback_manager.handle_proactive_fallback(self, entries[0].playlist)
 
                 if entries[-1].status != EntryPlayState.READY:
-                    self.logger.critical(SimpleUtil.red("Entries didn't reach 'ready' state during pre-rolling (Entries: %s)" % EngineUtil.get_entries_string(entries)))
+                    self.logger.critical(SU.red("Entries didn't reach 'ready' state during pre-rolling (Entries: %s)" % ResourceUtil.get_entries_string(entries)))
 
-                    # Pro-active fallback handling, avoiding the need of the silence detector kicking-in.
-                    self.fallback_manager.handle_proactive_fallback(self, entries[0].playlist)
+                    # # Pro-active fallback handling, avoiding the need of the silence detector kicking-in.
+                    # self.fallback_manager.handle_proactive_fallback(self, entries[0].playlist)
 
             loader_diff = diff - self.config.get("preroll_offset")
             loader = CallFunctionTimer(diff=loader_diff, func=do_preroll, param=param, fadein=fadein, fadeout=fadeout, switcher=False, loader=True)
@@ -1033,7 +1058,7 @@ class AuraScheduler(threading.Thread):
 
         # Remove it from message queue
         self.message_timer.remove(timer)
-        self.logger.info("Stopped %s timers for: %s" % (str(count), EngineUtil.get_entries_string(timer.entries)))
+        self.logger.info("Stopped %s timers for: %s" % (str(count), ResourceUtil.get_entries_string(timer.entries)))
 
 
 
@@ -1111,7 +1136,7 @@ class CallFunctionTimer(threading.Timer):
     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)))
+        self.logger.debug("Executing engine command '%s' in %s seconds..." % (str(func.__name__), str(diff)))
         threading.Timer.__init__(self, diff, func, (param,))
 
         if not fadein and not fadeout and not switcher and not loader \
@@ -1141,12 +1166,12 @@ class CallFunctionTimer(threading.Timer):
         status += " starting at " + str(self.dt)
 
         if self.fadein:
-            return status + " fading in entries '" + EngineUtil.get_entries_string(self.entries)
+            return status + " fading in entries '" + ResourceUtil.get_entries_string(self.entries)
         elif self.fadeout:
             return status + " fading out schedule '" + str(self.param)
         elif self.switcher:
-            return status + " switching to entries '" + EngineUtil.get_entries_string(self.entries)
+            return status + " switching to entries '" + ResourceUtil.get_entries_string(self.entries)
         elif self.loader:
-            return status + " pre-rolling entries '" + EngineUtil.get_entries_string(self.entries)
+            return status + " pre-rolling entries '" + ResourceUtil.get_entries_string(self.entries)
         else:
             return "CORRUPTED CallFunctionTimer around! How can that be?"