From beae1866bba72ad32de92c7890446e896bbd55e1 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Sat, 28 Jun 2025 01:49:20 -0400 Subject: [PATCH 1/2] Moved restore speech on prompt to existing temp interrupt speech command, Fenrir+kp_plus unbound now. --- config/keyboard/desktop.conf | 2 +- config/keyboard/laptop.conf | 2 +- config/settings/settings.conf | 4 +++- .../commands/onByteInput/15000-enable_temp_speech.py | 3 +++ .../commands/onKeyInput/15000-enable_temp_speech.py | 3 +++ .../commands/onScreenUpdate/66000-prompt_detector.py | 3 +++ src/fenrirscreenreader/core/outputManager.py | 4 ++++ src/fenrirscreenreader/fenrirVersion.py | 2 +- 8 files changed, 19 insertions(+), 4 deletions(-) diff --git a/config/keyboard/desktop.conf b/config/keyboard/desktop.conf index a4491cbd..cdca8d9e 100644 --- a/config/keyboard/desktop.conf +++ b/config/keyboard/desktop.conf @@ -74,7 +74,7 @@ KEY_FENRIR,KEY_0=bookmark_10 KEY_FENRIR,KEY_KPSLASH=set_window_application 2,KEY_FENRIR,KEY_KPSLASH=clear_window_application KEY_KPPLUS=progress_bar_monitor -KEY_FENRIR,KEY_KPPLUS=silence_until_prompt +#KEY_FENRIR,KEY_KPPLUS=silence_until_prompt KEY_FENRIR,KEY_F2=toggle_braille KEY_FENRIR,KEY_F3=toggle_sound KEY_FENRIR,KEY_F4=toggle_speech diff --git a/config/keyboard/laptop.conf b/config/keyboard/laptop.conf index 1927d49e..a00978e7 100644 --- a/config/keyboard/laptop.conf +++ b/config/keyboard/laptop.conf @@ -76,7 +76,7 @@ KEY_FENRIR,KEY_F3=toggle_sound KEY_FENRIR,KEY_F4=toggle_speech KEY_FENRIR,KEY_ENTER=temp_disable_speech KEY_FENRIR,KEY_SHIFT,KEY_P=progress_bar_monitor -KEY_FENRIR,KEY_SHIFT,KEY_ENTER=silence_until_prompt +#KEY_FENRIR,KEY_SHIFT,KEY_ENTER=silence_until_prompt KEY_FENRIR,KEY_SHIFT,KEY_CTRL,KEY_P=toggle_punctuation_level KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_ENTER=toggle_output diff --git a/config/settings/settings.conf b/config/settings/settings.conf index ba95a9d2..8da5925f 100644 --- a/config/settings/settings.conf +++ b/config/settings/settings.conf @@ -124,7 +124,9 @@ interruptOnKeyPressFilter= doubleTapTimeout=0.2 [general] -debugLevel=0 +# Debug levels: 0=DEACTIVE, 1=ERROR, 2=WARNING, 3=INFO (most verbose) +# For production use, WARNING (2) provides good balance of useful info without spam +debugLevel=2 # debugMode sets where the debug output should send to: # debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log) # debugMode=Print just prints on the screen diff --git a/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py b/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py index 3aa0bd90..07fa7865 100644 --- a/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py +++ b/src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py @@ -20,6 +20,9 @@ class command(): return self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(self.env['commandBuffer']['enableSpeechOnKeypress'])) self.env['commandBuffer']['enableSpeechOnKeypress'] = False + # Also disable prompt watching since speech was manually re-enabled + if 'silenceUntilPrompt' in self.env['commandBuffer']: + self.env['commandBuffer']['silenceUntilPrompt'] = False self.env['runtime']['outputManager'].presentText(_("speech enabled"), soundIcon='SpeechOn', interrupt=True) def setCallback(self, callback): diff --git a/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py b/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py index 20e662d3..00a5d9a5 100644 --- a/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py +++ b/src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py @@ -24,6 +24,9 @@ class command(): return self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(self.env['commandBuffer']['enableSpeechOnKeypress'])) self.env['commandBuffer']['enableSpeechOnKeypress'] = False + # Also disable prompt watching since speech was manually re-enabled + if 'silenceUntilPrompt' in self.env['commandBuffer']: + self.env['commandBuffer']['silenceUntilPrompt'] = False self.env['runtime']['outputManager'].presentText(_("speech enabled"), soundIcon='SpeechOn', interrupt=True) def setCallback(self, callback): diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py b/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py index d4d7db5d..28c981f9 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/66000-prompt_detector.py @@ -118,6 +118,9 @@ class command(): """Helper method to restore speech when prompt is detected""" # Disable silence mode self.env['commandBuffer']['silenceUntilPrompt'] = False + # Also disable the keypress-based speech restoration since we're enabling it now + if 'enableSpeechOnKeypress' in self.env['commandBuffer']: + self.env['commandBuffer']['enableSpeechOnKeypress'] = False # Re-enable speech self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', 'True') self.env['runtime']['outputManager'].presentText(_("Speech restored"), soundIcon='SpeechOn', interrupt=True) diff --git a/src/fenrirscreenreader/core/outputManager.py b/src/fenrirscreenreader/core/outputManager.py index a5469448..87a9868c 100644 --- a/src/fenrirscreenreader/core/outputManager.py +++ b/src/fenrirscreenreader/core/outputManager.py @@ -184,6 +184,10 @@ class outputManager(): if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'): self.presentText(_("speech temporary disabled"), soundIcon='SpeechOff', interrupt=True) self.env['commandBuffer']['enableSpeechOnKeypress'] = True + # Also enable prompt watching for automatic speech restoration + if 'silenceUntilPrompt' not in self.env['commandBuffer']: + self.env['commandBuffer']['silenceUntilPrompt'] = False + self.env['commandBuffer']['silenceUntilPrompt'] = True self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'))) self.interruptOutput() diff --git a/src/fenrirscreenreader/fenrirVersion.py b/src/fenrirscreenreader/fenrirVersion.py index 85085a53..8dd4884c 100644 --- a/src/fenrirscreenreader/fenrirVersion.py +++ b/src/fenrirscreenreader/fenrirVersion.py @@ -4,5 +4,5 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributers. -version = "2025.06.25" +version = "2025.06.28" codeName = "testing" From 4bcf82178e777d6ec2a67b7b6f2922409d6b3449 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Sat, 28 Jun 2025 22:52:21 -0400 Subject: [PATCH 2/2] Updated configure_pipewire script. A bit more code refactor. Preparing to start moving everything over to pep8 compliance. --- .../onScreenUpdate/65000-progress_detector.py | 17 +- src/fenrirscreenreader/core/screenManager.py | 17 +- .../core/settingsManager.py | 56 ++++++ tools/configure_pipewire.sh | 187 ++++-------------- 4 files changed, 116 insertions(+), 161 deletions(-) diff --git a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py index c4bb7481..a10101b7 100644 --- a/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py +++ b/src/fenrirscreenreader/commands/onScreenUpdate/65000-progress_detector.py @@ -76,18 +76,21 @@ class command(): # Note: Auto-disable on 100% completion removed to respect user settings # Pattern 1: Percentage (50%, 25.5%, etc.) + # Filter out common non-progress percentages (weather, system stats, etc.) percentMatch = re.search(r'(\d+(?:\.\d+)?)\s*%', text) if percentMatch: percentage = float(percentMatch.group(1)) # Only trigger on realistic progress percentages (0-100%) if 0 <= percentage <= 100: - self.env['runtime']['debug'].writeDebugOut("Found percentage: " + str(percentage), debug.debugLevel.INFO) - if percentage != self.env['commandBuffer']['lastProgressValue']: - self.env['runtime']['debug'].writeDebugOut("Playing tone for: " + str(percentage), debug.debugLevel.INFO) - self.playProgressTone(percentage) - self.env['commandBuffer']['lastProgressValue'] = percentage - self.env['commandBuffer']['lastProgressTime'] = currentTime - return + # Filter out weather/system stats that contain percentages + if not re.search(r'\b(?:humidity|cpu|memory|disk|usage|temp|weather|forecast)\b', text, re.IGNORECASE): + self.env['runtime']['debug'].writeDebugOut("Found percentage: " + str(percentage), debug.debugLevel.INFO) + if percentage != self.env['commandBuffer']['lastProgressValue']: + self.env['runtime']['debug'].writeDebugOut("Playing tone for: " + str(percentage), debug.debugLevel.INFO) + self.playProgressTone(percentage) + self.env['commandBuffer']['lastProgressValue'] = percentage + self.env['commandBuffer']['lastProgressTime'] = currentTime + return # Pattern 1b: Time/token activity (not percentage-based, so use single beep) timeMatch = re.search(r'(\d+)s\s', text) diff --git a/src/fenrirscreenreader/core/screenManager.py b/src/fenrirscreenreader/core/screenManager.py index 48f004b5..92239325 100644 --- a/src/fenrirscreenreader/core/screenManager.py +++ b/src/fenrirscreenreader/core/screenManager.py @@ -17,6 +17,8 @@ class screenManager(): self.currScreenText = '' self.colums = None self.rows = None + # Compile regex once for better performance + self._space_normalize_regex = re.compile(' +') def getRows(self): return self.rows def getColumns(self): @@ -124,11 +126,6 @@ class screenManager(): # This code detects and categorizes screen content changes to provide appropriate # speech feedback (typing echo vs incoming text vs screen updates) - # Pre-process screen text for comparison - collapse multiple spaces to single space - # This normalization prevents spurious diffs from spacing inconsistencies - oldScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['oldContentText'])) - newScreenText = re.sub(' +',' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['newContentText'])) - # Track whether this appears to be typing (user input) vs other screen changes typing = False diffList = [] @@ -137,6 +134,10 @@ class screenManager(): # Special case: Initial screen content (going from empty to populated) # This handles first screen load or TTY switch scenarios if self.env['screen']['newContentText'] != '' and self.env['screen']['oldContentText'] == '': + # Pre-process screen text for comparison - collapse multiple spaces to single space + # This normalization prevents spurious diffs from spacing inconsistencies + oldScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['oldContentText'])) + newScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['newContentText'])) if oldScreenText == '' and\ newScreenText != '': self.env['screen']['newDelta'] = newScreenText @@ -194,6 +195,12 @@ class screenManager(): # GENERAL SCREEN CHANGE DETECTION # Not typing - handle as line-by-line content change # This catches: incoming messages, screen updates, application output, etc. + + # Pre-process screen text for comparison - collapse multiple spaces to single space + # This normalization prevents spurious diffs from spacing inconsistencies + oldScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['oldContentText'])) + newScreenText = self._space_normalize_regex.sub(' ',self.env['runtime']['screenManager'].getWindowAreaInText(self.env['screen']['newContentText'])) + diff = self.differ.compare(oldScreenText.split('\n'),\ newScreenText.split('\n')) diffList = list(diff) diff --git a/src/fenrirscreenreader/core/settingsManager.py b/src/fenrirscreenreader/core/settingsManager.py index 0cad86b5..9ae333d0 100644 --- a/src/fenrirscreenreader/core/settingsManager.py +++ b/src/fenrirscreenreader/core/settingsManager.py @@ -234,15 +234,71 @@ class settingsManager(): elif isinstance(self.settings[section][setting], bool): if not value in ['True','False']: raise ValueError('could not convert string to bool: '+ value) + v = value == 'True' elif isinstance(self.settings[section][setting], int): v = int(value) elif isinstance(self.settings[section][setting], float): v = float(value) + + # Content validation for critical settings + self._validateSettingValue(section, setting, v) + self.settingArgDict[section][setting] = str(value) except Exception as e: print('settingsManager:setOptionArgDict:Datatype missmatch: '+ section + '#' + setting + '=' + value + ' Error:' + str(e)) #self.env['runtime']['debug'].writeDebugOut('settingsManager:setOptionArgDict:Datatype missmatch: '+ section + '#' + setting + '=' + value + ' Error:' + str(e), debug.debugLevel.ERROR) return + + def _validateSettingValue(self, section, setting, value): + """Validate setting values for critical screen reader functionality. + Only validates settings that could cause crashes or accessibility issues. + Invalid values raise ValueError which is caught by the calling method.""" + + # Speech settings validation - critical for accessibility + if section == 'speech': + if setting == 'rate': + if not (0.0 <= value <= 3.0): + raise ValueError(f'Speech rate must be between 0.0 and 3.0, got {value}') + elif setting == 'pitch': + if not (0.0 <= value <= 2.0): + raise ValueError(f'Speech pitch must be between 0.0 and 2.0, got {value}') + elif setting == 'volume': + if not (0.0 <= value <= 1.5): + raise ValueError(f'Speech volume must be between 0.0 and 1.5, got {value}') + elif setting == 'driver': + valid_drivers = ['speechdDriver', 'genericDriver', 'dummyDriver'] + if value not in valid_drivers: + raise ValueError(f'Invalid speech driver: {value}. Valid options: {valid_drivers}') + + # Sound settings validation + elif section == 'sound': + if setting == 'volume': + if not (0.0 <= value <= 1.5): + raise ValueError(f'Sound volume must be between 0.0 and 1.5, got {value}') + elif setting == 'driver': + valid_drivers = ['genericDriver', 'gstreamerDriver', 'dummyDriver'] + if value not in valid_drivers: + raise ValueError(f'Invalid sound driver: {value}. Valid options: {valid_drivers}') + + # Screen settings validation + elif section == 'screen': + if setting == 'driver': + valid_drivers = ['vcsaDriver', 'ptyDriver', 'dummyDriver'] + if value not in valid_drivers: + raise ValueError(f'Invalid screen driver: {value}. Valid options: {valid_drivers}') + + # Input settings validation + elif section == 'keyboard': + if setting == 'driver': + valid_drivers = ['evdevDriver', 'ptyDriver', 'atspiDriver', 'dummyDriver'] + if value not in valid_drivers: + raise ValueError(f'Invalid input driver: {value}. Valid options: {valid_drivers}') + + # General settings validation + elif section == 'general': + if setting == 'debugLevel': + if not (0 <= value <= 3): + raise ValueError(f'Debug level must be between 0 and 3, got {value}') def parseSettingArgs(self, settingArgs): for optionElem in settingArgs.split(';'): diff --git a/tools/configure_pipewire.sh b/tools/configure_pipewire.sh index 0f079da7..364b7e30 100755 --- a/tools/configure_pipewire.sh +++ b/tools/configure_pipewire.sh @@ -9,146 +9,26 @@ mkdir -p "$xdgPath/pipewire" mkdir -p "$xdgPath/wireplumber/main.lua.d" mkdir -p "$xdgPath/wireplumber/bluetooth.lua.d" -#create the file that tells the pipewire-pulse server to use a second socket located at /tmp/pulse.sock -# Warn user if we are going to overwrite an existing pipewire-pulse.conf -if [ -f "$xdgPath/pipewire/pipewire-pulse.conf" ]; then - read -p "This will replace the current file located at $xdgPath/pipewire/pipewire-pulse.conf, press enter to continue or control+c to abort. " continue +# Create drop-in configuration for PipeWire-Pulse console access +mkdir -p "$xdgPath/pipewire/pipewire-pulse.conf.d" +# Warn user if we are going to overwrite an existing fenrir console config +if [ -f "$xdgPath/pipewire/pipewire-pulse.conf.d/50-fenrir-console.conf" ]; then + read -p "This will replace the current file located at $xdgPath/pipewire/pipewire-pulse.conf.d/50-fenrir-console.conf, press enter to continue or control+c to abort. " continue fi -cat << "EOF" > "$xdgPath/pipewire/pipewire-pulse.conf" -# PulseAudio config file for PipeWire version "0.3.49" # -# -# Copy and edit this file in /etc/pipewire for system-wide changes -# or in ~/.config/pipewire for local changes. -# -# It is also possible to place a file with an updated section in -# /etc/pipewire/pipewire-pulse.conf.d/ for system-wide changes or in -# ~/.config/pipewire/pipewire-pulse.conf.d/ for local changes. -# - -context.properties = { - ## Configure properties in the system. - #mem.warn-mlock = false - #mem.allow-mlock = true - #mem.mlock-all = false - #log.level = 2 - - #default.clock.quantum-limit = 8192 -} - -context.spa-libs = { - audio.convert.* = audioconvert/libspa-audioconvert - support.* = support/libspa-support -} - -context.modules = [ - { name = libpipewire-module-rt - args = { - nice.level = -11 - #rt.prio = 88 - #rt.time.soft = -1 - #rt.time.hard = -1 - } - flags = [ ifexists nofail ] - } - { name = libpipewire-module-protocol-native } - { name = libpipewire-module-client-node } - { name = libpipewire-module-adapter } - { name = libpipewire-module-metadata } - - { name = libpipewire-module-protocol-pulse - args = { - # contents of pulse.properties can also be placed here - # to have config per server. - } - } -] - -# Extra modules can be loaded here. Setup in default.pa can be moved here -context.exec = [ - { path = "pactl" args = "load-module module-always-sink" } - { path = "pactl" args = "load-module module-switch-on-connect" } - #{ path = "/usr/bin/sh" args = "~/.config/pipewire/default.pw" } -] - -stream.properties = { - #node.latency = 1024/48000 - #node.autoconnect = true - #resample.quality = 4 - #channelmix.normalize = false - #channelmix.mix-lfe = false - #channelmix.upmix = true - #channelmix.upmix-method = simple # none, psd - #channelmix.lfe-cutoff = 120 - #channelmix.fc-cutoff = 6000 - #channelmix.rear-delay = 12.0 - #channelmix.stereo-widen = 0.1 - #channelmix.hilbert-taps = 0 -} +cat << "EOF" > "$xdgPath/pipewire/pipewire-pulse.conf.d/50-fenrir-console.conf" +# Fenrir console audio support +# Adds secondary socket for console applications like Fenrir pulse.properties = { # the addresses this server listens on server.address = [ "unix:native" - "unix:/tmp/pulse.sock" # absolute paths may be used - #"tcp:4713" # IPv4 and IPv6 on all addresses - #"tcp:[::]:9999" # IPv6 on all addresses - #"tcp:127.0.0.1:8888" # IPv4 on a single address - # - #{ address = "tcp:4713" # address - # max-clients = 64 # maximum number of clients - # listen-backlog = 32 # backlog in the server listen queue - # client.access = "restricted" # permissions for clients - #} + "unix:/tmp/pulse.sock" # console access socket ] - #pulse.min.req = 256/48000 # 5ms - #pulse.default.req = 960/48000 # 20 milliseconds - #pulse.min.frag = 256/48000 # 5ms - #pulse.default.frag = 96000/48000 # 2 seconds - #pulse.default.tlength = 96000/48000 # 2 seconds - #pulse.min.quantum = 256/48000 # 5ms - #pulse.default.format = F32 - #pulse.default.position = [ FL FR ] - # These overrides are only applied when running in a vm. - vm.overrides = { - pulse.min.quantum = 1024/48000 # 22ms - } } # client/stream specific properties pulse.rules = [ - { - matches = [ - { - # all keys must match the value. ~ starts regex. - #client.name = "Firefox" - #application.process.binary = "teams" - #application.name = "~speech-dispatcher.*" - } - ] - actions = { - update-props = { - #node.latency = 512/48000 - } - # Possible quirks:" - # force-s16-info forces sink and source info as S16 format - # remove-capture-dont-move removes the capture DONT_MOVE flag - #quirks = [ ] - } - } - { - # skype does not want to use devices that don't have an S16 sample format. - matches = [ - { application.process.binary = "teams" } - { application.process.binary = "skypeforlinux" } - ] - actions = { quirks = [ force-s16-info ] } - } - { - # firefox marks the capture streams as don't move and then they - # can't be moved with pavucontrol or other tools. - matches = [ { application.process.binary = "firefox" } ] - actions = { quirks = [ remove-capture-dont-move ] } - } { # speech dispatcher asks for too small latency and then underruns. matches = [ { application.name = "~speech-dispatcher*" } ] @@ -162,23 +42,27 @@ pulse.rules = [ ] EOF -#Creates the file that tells pipewire not to suspend any sinks for all devices. This makes sure audio doesn't die after switching to the console. -# Warn user if we are going to overwrite an existing 50-do-not-suspend.lua -if [ -f "$xdgPath/wireplumber/main.lua.d/50-do-not-suspend.lua" ]; then - read -p "This will replace the current file located at $xdgPath/wireplumber/main.lua.d/50-do-not-suspend.lua, press enter to continue or control+c to abort. " continue +# Create WirePlumber configuration to prevent audio device suspension on console switch +# Warn user if we are going to overwrite an existing 50-fenrir-no-suspend.lua +if [ -f "$xdgPath/wireplumber/main.lua.d/50-fenrir-no-suspend.lua" ]; then + read -p "This will replace the current file located at $xdgPath/wireplumber/main.lua.d/50-fenrir-no-suspend.lua, press enter to continue or control+c to abort. " continue fi -echo 'alsa_monitor.rules = { +cat << "EOF" > "$xdgPath/wireplumber/main.lua.d/50-fenrir-no-suspend.lua" +-- Fenrir console audio support +-- Prevents audio device suspension when switching to TTY console + +alsa_monitor.rules = { { matches = { { - { "device.name", "matches", "alsa_card.*" }, + { "device.name", "matches", "alsa_card.*" }, }, }, - apply_properties = { + apply_properties = { ["api.alsa.use-acp"] = true, ["api.acp.auto-profile"] = false, ["api.acp.auto-port"] = false, -["session.suspend-timeout-seconds"] = 0 + ["session.suspend-timeout-seconds"] = 0 }, }, { @@ -194,14 +78,19 @@ echo 'alsa_monitor.rules = { ["session.suspend-timeout-seconds"] = 0 }, }, -}' > $xdgPath/wireplumber/main.lua.d/50-do-not-suspend.lua +} +EOF -#Creates the file that disables the logind module for wireplumber which causes bluetooth to disconnect when switching tty -# Warn user if we are going to overwrite an existing 30-bluez-monitor.lua -if [ -f "$xdgPath/wireplumber/bluetooth.lua.d/30-bluez-monitor.lua" ]; then - read -p "This will replace the current file located at $xdgPath/wireplumber/bluetooth.lua.d/30-bluez-monitor.lua, press enter to continue or control+c to abort. " continue +# Create WirePlumber bluetooth configuration to prevent disconnection on TTY switch +# Warn user if we are going to overwrite an existing 30-fenrir-bluez.lua +if [ -f "$xdgPath/wireplumber/bluetooth.lua.d/30-fenrir-bluez.lua" ]; then + read -p "This will replace the current file located at $xdgPath/wireplumber/bluetooth.lua.d/30-fenrir-bluez.lua, press enter to continue or control+c to abort. " continue fi -echo 'bluez_monitor = {} +cat << "EOF" > "$xdgPath/wireplumber/bluetooth.lua.d/30-fenrir-bluez.lua" +-- Fenrir console audio support +-- Disables logind module to prevent bluetooth disconnection when switching TTY + +bluez_monitor = {} bluez_monitor.properties = {} bluez_monitor.rules = {} @@ -210,8 +99,8 @@ function bluez_monitor.enable() properties = bluez_monitor.properties, rules = bluez_monitor.rules, }) - -end' > $xdgPath/wireplumber/bluetooth.lua.d/30-bluez-monitor.lua +end +EOF echo "Please ensure that your user is added to the audio group." echo "If you have not yet done so, please run this script as root to write the client.conf file." @@ -220,12 +109,12 @@ else xdgPath="/root/.config" mkdir -p "$xdgPath/pulse" -# Warn user if we are going to overwrite an existing default.pa -if [ -f "$xdgPath/pulse/default.pa" ]; then - read -p "This will replace the current file located at $xdgPath/pulse/default.pa, press enter to continue or control+c to abort. " continue +# Warn user if we are going to overwrite an existing client.conf +if [ -f "$xdgPath/pulse/client.conf" ]; then + read -p "This will replace the current file located at $xdgPath/pulse/client.conf, press enter to continue or control+c to abort. " continue fi -cat << EOF > "$xdgPath/pulse/client.conf" +cat << "EOF" > "$xdgPath/pulse/client.conf" # This file is part of PulseAudio. # # PulseAudio is free software; you can redistribute it and/or modify