- Fix an accidental unmute bug in audioassist

- Code cleanup
This commit is contained in:
trigg 2024-07-08 16:20:52 +01:00
parent ce0c1aece3
commit 062e8b102f
2 changed files with 29 additions and 20 deletions

View file

@ -11,5 +11,5 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Entry point for Discover Overlay""" """Entry point for Discover Overlay"""
from .discover_overlay import * from .discover_overlay import entrypoint
entrypoint() entrypoint()

View file

@ -11,19 +11,19 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
"""A class to assist with reading pulseaudio changes""" """A class to assist with reading pulseaudio changes"""
import os
import logging import logging
import signal from contextlib import suppress
from threading import Thread
import asyncio
import pulsectl_asyncio import pulsectl_asyncio
import pulsectl import pulsectl
from contextlib import suppress
import asyncio
from threading import Thread, Event
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class DiscoverAudioAssist: class DiscoverAudioAssist:
"""Class to assist with reading volume levels from pulseaudio"""
def __init__(self, discover): def __init__(self, discover):
self.thread = None self.thread = None
@ -33,21 +33,25 @@ class DiscoverAudioAssist:
self.discover = discover self.discover = discover
# Keep last known state (or None) so that we don't repeatedly send messages for every little PA/PW signal # Keep last known state (or None) so that we don't repeatedly
# send messages for every little PA/PW signal
self.last_set_mute = None self.last_set_mute = None
self.last_set_deaf = None self.last_set_deaf = None
def set_enabled(self, enabled): def set_enabled(self, enabled):
"""Enable or Disable the functioning of this class"""
self.enabled = enabled self.enabled = enabled
if enabled: if enabled:
self.start() self.start()
def set_devices(self, sink, source): def set_devices(self, sink, source):
"""Set the names of the sink and source devices that we are monitoring"""
# Changed devices from client # Changed devices from client
self.source = source self.source = source
self.sink = sink self.sink = sink
def start(self): def start(self):
"""Start the the watcher in another thread"""
if not self.enabled: if not self.enabled:
return return
if not self.thread: if not self.thread:
@ -55,34 +59,33 @@ class DiscoverAudioAssist:
self.thread.start() self.thread.start()
def thread_loop(self): def thread_loop(self):
# Start an asyncio specific thread. Not the prettiest but I'm not rewriting from ground up for one feature """Start the event loop"""
log.info("Starting Audio subsystem assistance") log.info("Starting Audio subsystem assistance")
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
loop.run_until_complete(self.pulse_loop()) loop.run_until_complete(self.pulse_loop())
log.info("Stopped Audio subsystem assistance") log.info("Stopped Audio subsystem assistance")
async def listen(self): async def listen(self):
# Async to connect to pulse and listen for events """Async to connect to pulse and listen for events"""
try: try:
async with pulsectl_asyncio.PulseAsync('Discover-Monitor') as pulse: async with pulsectl_asyncio.PulseAsync('Discover-Monitor') as pulse:
await self.get_device_details(pulse) await self.get_device_details(pulse)
async for event in pulse.subscribe_events('all'): async for event in pulse.subscribe_events('all'):
await self.print_events(pulse, event) await self.handle_events(pulse, event)
except (pulsectl.pulsectl.PulseDisconnected): except pulsectl.pulsectl.PulseDisconnected:
log.info("Pulse has gone away") log.info("Pulse has gone away")
except (pulsectl.pulsectl.PulseError): except pulsectl.pulsectl.PulseError:
log.info("Pulse error") log.info("Pulse error")
async def pulse_loop(self): async def pulse_loop(self):
# Prep before connecting to pulse """Listen on event loop"""
loop = asyncio.get_event_loop() # loop = asyncio.get_event_loop()
listen_task = asyncio.create_task(self.listen()) listen_task = asyncio.create_task(self.listen())
with suppress(asyncio.CancelledError): with suppress(asyncio.CancelledError):
await listen_task await listen_task
async def get_device_details(self, pulse): async def get_device_details(self, pulse):
# Decant information about our chosen devices """Decant information about our chosen devices into function calls back to overlay"""
# Feed this back to client to change deaf/mute state
mute = None mute = None
deaf = None deaf = None
for sink in await pulse.sink_list(): for sink in await pulse.sink_list():
@ -98,22 +101,28 @@ class DiscoverAudioAssist:
self.last_set_mute = None self.last_set_mute = None
# At this point mute is undefined state # At this point mute is undefined state
# Setting mute/unmute while deafened will unset deafened
# deafened implies muted
if deaf or self.last_set_deaf:
return
for source in await pulse.source_list(): for source in await pulse.source_list():
if source.description == self.source: if source.description == self.source:
if source.mute == 1 or source.volume.values[0] == 0.0: if source.mute == 1 or source.volume.values[0] == 0.0:
mute = True mute = True
elif sink.mute == 0: elif source.mute == 0:
mute = False mute = False
if mute != self.last_set_mute: if mute != self.last_set_mute:
self.last_set_mute = mute self.last_set_mute = mute
self.discover.set_mute_async(mute) self.discover.set_mute_async(mute)
async def print_events(self, pulse, ev): async def handle_events(self, pulse, ev):
""" `Sink` and `Source` events are fired for changes to output and inputs
`Server` is fired when default sink or source changes."""
if not self.enabled: if not self.enabled:
return return
# Sink and Source events are fired for changes to output and ints
# Server is fired when default sink or source changes.
match ev.facility: match ev.facility:
case 'sink': case 'sink':
await self.get_device_details(pulse) await self.get_device_details(pulse)