diff --git a/TODO b/TODO index 6dd38b3a..0a844c11 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,7 @@ ToDos in Priority order: Known Bugs: - some timing issues for some users that leads to an delay to read incomming messages - for some users fenrir eats the orca key +- dont break on non existing python-evdev event. - in special cases next word skipps a word, "word<12 spaces>word2<12 spaces>word3 (storm_dragon) - Fenrir key sometimes wents crazy? (maybe this is if fenrir key is released before other keys) - For example, in screen, it just tells me bell in window, but doesn't tell me which one. (southernprince) diff --git a/config/settings/settings.conf b/config/settings/settings.conf index 3d2b2a74..4eebfaa9 100644 --- a/config/settings/settings.conf +++ b/config/settings/settings.conf @@ -4,6 +4,7 @@ enabled=True # Select the driver used to play sounds, choices are generic and gstreamer. # Sox is the default. +#driver=gstreamer driver=generic # Sound themes. This is the pack of sounds used for sound alerts. diff --git a/src/fenrir/core/debug.py b/src/fenrir/core/debug.py index 7b4e511c..271c221b 100644 --- a/src/fenrir/core/debug.py +++ b/src/fenrir/core/debug.py @@ -47,7 +47,7 @@ class debug(): if not self._fileOpened: self.openDebugFile() if onAnyLevel: - msg = 'ANY '+ str(level) + str(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')) + msg = 'ANY '+ str(level) + ' ' + str(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')) else: msg = str(level) +' ' + str(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f') ) diff --git a/src/fenrir/core/settingsManager.py b/src/fenrir/core/settingsManager.py index 7ec44dfb..27c2e618 100644 --- a/src/fenrir/core/settingsManager.py +++ b/src/fenrir/core/settingsManager.py @@ -175,15 +175,18 @@ class settingsManager(): return value def loadDriver(self, driverName, driverType): - if self.env['runtime'][driverType] != None: - print('shutdown %s',driverType) - self.env['runtime'][driverType].shutdown(self.env) - spec = importlib.util.spec_from_file_location(driverName, os.path.dirname(os.path.realpath(__main__.__file__)) + "/" + driverType + '/' + driverName + '.py') - driver_mod = importlib.util.module_from_spec(spec) - spec.loader.exec_module(driver_mod) - self.env['runtime'][driverType] = driver_mod.driver() - self.env['runtime'][driverType].initialize(self.env) - + try: + if self.env['runtime'][driverType] != None: + self.env['runtime'][driverType].shutdown(self.env) + spec = importlib.util.spec_from_file_location(driverName, os.path.dirname(os.path.realpath(__main__.__file__)) + "/" + driverType + '/' + driverName + '.py') + driver_mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(driver_mod) + self.env['runtime'][driverType] = driver_mod.driver() + self.env['runtime'][driverType].initialize(self.env) + self.env['runtime']['debug'].writeDebugOut('Loading Driver ' + driverType +" OK",debug.debugLevel.INFO, onAnyLevel=True) + except Exception as e: + self.env['runtime'][driverType] = None + self.env['runtime']['debug'].writeDebugOut("Loading " + driverType + " Driver : "+ str(e), debug.debugLevel.ERROR) def shutdownDriver(self, driverType): if self.env['runtime'][driverType] == None: return diff --git a/src/fenrir/inputDriver/evdev.py b/src/fenrir/inputDriver/evdev.py index a2c3a301..15e60cae 100644 --- a/src/fenrir/inputDriver/evdev.py +++ b/src/fenrir/inputDriver/evdev.py @@ -4,11 +4,17 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -import evdev -import time -from evdev import InputDevice, UInput -from select import select +_evdevAvailable = False +_evdevAvailableError = '' +try: + import evdev + from evdev import InputDevice, UInput + _evdevAvailable = True +except Exception as e: + _evdevAvailableError = str(e) +import time +from select import select from core import inputEvent from core import debug @@ -16,19 +22,30 @@ class driver(): def __init__(self): self.iDevices = {} self.uDevices = {} - self.ledDevices = {} + self.ledDevices = {} + self._initialized = False def initialize(self, environment): - self.env = environment - self.getInputDevices() + self.env = environment + global _evdevAvailable + self._initialized = _evdevAvailable + if not self._initialized: + global _evdevAvailableError + self.env['runtime']['debug'].writeDebugOut('InputDriver: ' + _evdevAvailableError,debug.debugLevel.ERROR) + return + self.getInputDevices() def shutdown(self): pass def getInputEvent(self): + if not self._initialized: + time.sleep(0.005) # dont flood CPU + return None if not self.iDevices: return None if self.iDevices == {}: return None + event = None r, w, x = select(self.iDevices, [], [], self.env['runtime']['settingsManager'].getSettingAsFloat('screen', 'screenUpdateDelay')) if r != []: @@ -47,16 +64,24 @@ class driver(): return None def writeEventBuffer(self): + if not self._initialized: + return for iDevice, uDevice, event in self.env['input']['eventBuffer']: self.writeUInput(uDevice, event) def clearEventBuffer(self): + if not self._initialized: + return del self.env['input']['eventBuffer'][:] def writeUInput(self, uDevice, event): + if not self._initialized: + return uDevice.write_event(event) uDevice.syn() def getInputDevices(self): + if not self._initialized: + return deviceList = evdev.list_devices() readableDevices = [] for dev in deviceList: @@ -83,6 +108,8 @@ class driver(): self.ledDevices = {dev.fd: dev for dev in self.ledDevices if dev.name.upper() in self.env['runtime']['settingsManager'].getSetting('keyboard', 'device').upper().split(',')} def mapEvent(self, event): + if not self._initialized: + return None if not event: return None mEvent = inputEvent.inputEvent @@ -97,6 +124,8 @@ class driver(): return None def getLedState(self, led = 0): + if not self._initialized: + return None # 0 = Numlock # 1 = Capslock # 2 = Rollen @@ -108,6 +137,8 @@ class driver(): return led in dev.leds() return False def toggleLedState(self, led = 0): + if not self._initialized: + return None ledState = self.getLedState(led) for i in self.ledDevices: if ledState == 1: @@ -115,6 +146,8 @@ class driver(): else: self.ledDevices[i].set_led(led , 1) def grabDevices(self): + if not self._initialized: + return None # leve the old code until the new one is better tested # for fd in self.iDevices: # dev = self.iDevices[fd] @@ -137,6 +170,8 @@ class driver(): except Exception as e: self.env['runtime']['debug'].writeDebugOut('InputDriver evdev: grabing not possible: ' + str(e),debug.debugLevel.ERROR) def releaseDevices(self): + if not self._initialized: + return None for fd in self.iDevices: try: self.iDevices[fd].ungrab() @@ -154,7 +189,9 @@ class driver(): self.iDevices.clear() self.uDevices.clear() - def __del__(self): - self.releaseDevices() + def __del__(self): + if not self._initialized: + return None + self.releaseDevices() diff --git a/src/fenrir/soundDriver/dummy.py b/src/fenrir/soundDriver/dummy.py index 6c45bd35..499730d2 100644 --- a/src/fenrir/soundDriver/dummy.py +++ b/src/fenrir/soundDriver/dummy.py @@ -9,19 +9,30 @@ from core import debug class driver(): def __init__(self): self.volume = None + self._initialized = False def initialize(self, environment): self.env = environment def shutdown(self): + if not self._initialized: + return self.cancel() def playFrequence(self, frequence = 1000, duration = 0.3, adjustVolume = 0): + if not self._initialized: + return if interrupt: self.cancel() def playSoundFile(self, filePath, interrupt = True): + if not self._initialized: + return if interrupt: self.cancel() def cancel(self): - pass + if not self._initialized: + return def setCallback(self, callback): - pass + if not self._initialized: + return def setVolume(self, volume): + if not self._initialized: + return self.volume = volume diff --git a/src/fenrir/soundDriver/generic.py b/src/fenrir/soundDriver/generic.py index e0155531..cea0c168 100644 --- a/src/fenrir/soundDriver/generic.py +++ b/src/fenrir/soundDriver/generic.py @@ -14,6 +14,7 @@ class driver(): self.soundType = '' self.soundFileCommand = '' self.frequenceCommand = '' + self._initialized = False def initialize(self, environment): self.env = environment self.soundFileCommand = self.env['runtime']['settingsManager'].getSetting('sound', 'genericPlayFileCommand') @@ -22,9 +23,14 @@ class driver(): self.soundFileCommand = 'play -q -v fenrirVolume fenrirSoundFile' if self.frequenceCommand == '': self.frequenceCommand = 'play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence' + self._initialized = True def shutdown(self): + if not self._initialized: + return self.cancel() def playFrequence(self, frequence = 1000, duration = 0.3, adjustVolume = 0): + if not self._initialized: + return if interrupt: self.cancel() popenFrequenceCommand = self.frequenceCommand.replace('fenrirVolume', str(self.volume + adjustVolume )) @@ -33,6 +39,8 @@ class driver(): self.proc = subprocess.Popen(popenFrequenceCommand, shell=True) self.soundType = 'frequence' def playSoundFile(self, filePath, interrupt = True): + if not self._initialized: + return if interrupt: self.cancel() popenSoundFileCommand = self.soundFileCommand.replace('fenrirVolume', str(self.volume )) @@ -40,6 +48,8 @@ class driver(): self.proc = subprocess.Popen(popenSoundFileCommand, shell=True) self.soundType = 'file' def cancel(self): + if not self._initialized: + return if self.soundType == '': return if self.soundType == 'file': @@ -48,6 +58,9 @@ class driver(): self.proc.kill() self.soundType = '' def setCallback(self, callback): - pass + if not self._initialized: + return def setVolume(self, volume): + if not self._initialized: + return self.volume = volume diff --git a/src/fenrir/soundDriver/gstreamer.py b/src/fenrir/soundDriver/gstreamer.py index 8c607142..b7ed86a1 100644 --- a/src/fenrir/soundDriver/gstreamer.py +++ b/src/fenrir/soundDriver/gstreamer.py @@ -5,32 +5,35 @@ # By Chrys, Storm Dragon, and contributers. from core import debug -import gi import time, threading -from gi.repository import GLib + +_gstreamerAvailable = False try: + import gi + from gi.repository import GLib gi.require_version('Gst', '1.0') from gi.repository import Gst -except: + _gstreamerAvailable, args = Gst.init_check(None) +except Exception as e: _gstreamerAvailable = False -else: - _gstreamerAvailable, args = Gst.init_check(None) + _availableError = str(e) class driver: def __init__(self): - self._initialized = False self._source = None self._sink = None self.volume = 1 + self._initialized = False + def initialize(self, environment): - if self._initialized: - return - global _gstreamerAvailable - if not _gstreamerAvailable: - self.environment['runtime']['debug'].writeDebugOut('Gstreamer not available',debug.debugLevel.ERROR) - return self.env = environment + global _gstreamerAvailable + self._initialized = _gstreamerAvailable + if not self._initialized: + global _availableError + self.environment['runtime']['debug'].writeDebugOut('Gstreamer not available ' + _availableError,debug.debugLevel.ERROR) + return self._player = Gst.ElementFactory.make('playbin', 'player') bus = self._player.get_bus() bus.add_signal_watch() @@ -46,21 +49,19 @@ class driver: self._pipeline.add(self._source) self._pipeline.add(self._sink) self._source.link(self._sink) - - self._initialized = True self.mainloop = GLib.MainLoop() self.thread = threading.Thread(target=self.mainloop.run) self.thread.start() + def shutdown(self): - global _gstreamerAvailable - if not _gstreamerAvailable: + if not self._initialized: return self.cancel() self.mainloop.quit() - self._initialized = False - _gstreamerAvailable = False def _onPlayerMessage(self, bus, message): + if not self._initialized: + return if message.type == Gst.MessageType.EOS: self._player.set_state(Gst.State.NULL) elif message.type == Gst.MessageType.ERROR: @@ -69,6 +70,8 @@ class driver: self.env['runtime']['debug'].writeDebugOut('GSTREAMER: _onPlayerMessage'+ str(error) + str(info),debug.debugLevel.WARNING) def _onPipelineMessage(self, bus, message): + if not self._initialized: + return if message.type == Gst.MessageType.EOS: self._pipeline.set_state(Gst.State.NULL) elif message.type == Gst.MessageType.ERROR: @@ -77,15 +80,21 @@ class driver: self.env['runtime']['debug'].writeDebugOut('GSTREAMER: _onPipelineMessage'+ str(error) + str(info),debug.debugLevel.WARNING) def _onTimeout(self, element): + if not self._initialized: + return element.set_state(Gst.State.NULL) def playSoundFile(self, fileName, interrupt=True): + if not self._initialized: + return if interrupt: self.cancel() self._player.set_property('uri', 'file://%s' % fileName) self._player.set_state(Gst.State.PLAYING) def playFrequence(self, frequence, duration, adjustVolume, interrupt=True): + if not self._initialized: + return if interrupt: self.cancel() self._source.set_property('volume', tone.volume) @@ -96,8 +105,7 @@ class driver: GLib.timeout_add(duration, self._onTimeout, self._pipeline) def cancel(self, element=None): - global _gstreamerAvailable - if not _gstreamerAvailable: + if not self._initialized: return if element: element.set_state(Gst.State.NULL) @@ -105,6 +113,8 @@ class driver: self._player.set_state(Gst.State.NULL) self._pipeline.set_state(Gst.State.NULL) def setVolume(self, volume): + if not self._initialized: + return self.volume = volume