From aac89d9938044019a5d2868ede3db02606fa908b Mon Sep 17 00:00:00 2001 From: Filip Darmanovic Date: Sun, 14 Mar 2021 14:14:00 +0100 Subject: [PATCH] Made the listener more robust to pulseaudio restarts Sometimes when I boot up my laptop, pulseaudio can't detect the devices properly. I run `pulseaudio -k` to restart it, but this changes the device ids and crashes the listener. Now this should work without any action from the user. --- README.md | 9 ++++-- micmute_listener_pa.py | 68 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 624c760..5a34f8c 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,17 @@ ## Installation 1. Make sure `BRIGHTNESS_FILE_PATH` in set_micmute_led.c corresponds to the LED file path on your system. -2. Run `./install.sh` +2. Make sure `mic_name` in micmute_listener_pa.py corresponds to your mic device name. This name can be found within the sources printed out when the client is started. (This will be made more user-friendly with upcoming releases) +3. Run `./install.sh` ## Running -If you have systemd and want to enable the script as soon as you log in, run `systemctl --user enable micmute_listener_pa.service`. +### With systemd +If you want to enable the script as soon as you log in, run `systemctl --user enable micmute_listener_pa.service`. To start the service immediately, run `systemctl --user start micmute_listener_pa.service`. +### Without systemd +Simply run `~/.local/bin/micmute_listener_pa.py &` after installation. For starting the client at boot, look up your distro's individual way to achieve this. + ## Contributions I'm very intrested in your opinions in terms of the architecture of this service. If you have suggestions on how to avoid SETUID or make the whole thing cleaner or more secure, please start a discussion! \ No newline at end of file diff --git a/micmute_listener_pa.py b/micmute_listener_pa.py index 48bd0a9..2e0e3ce 100755 --- a/micmute_listener_pa.py +++ b/micmute_listener_pa.py @@ -2,30 +2,72 @@ import pulsectl import os -pulse = pulsectl.Pulse('my-client-name') +import sys +import signal +pulse = pulsectl.Pulse('micmute-listener') + +# TODO: Read this from an external config file +mic_name = 'alsa_input.pci-0000_04_00.6.analog-stereo' active_index = 1 # This is the index of the source pulse_event = None -with pulsectl.Pulse('event-printer') as pulse: +def shutdown(signum, frame): + print('Shutting down client...') + pulse.disconnect() + quit(0) + +def find_mic_index(): + global active_index + + for source in pulse.source_list(): + if(source.name == mic_name): + active_index = int(source.index) + print('Mic index set: %d' % (active_index)) + return + + raise RuntimeError('Could not find a device corresponding to %s!' % (mic_name)) + +def catch_events(ev): + print('Pulse event:', ev) + global pulse_event + pulse_event = ev + ### Raise PulseLoopStop for event_listen() to return before timeout (if any) + raise pulsectl.PulseLoopStop + +def set_led_value(value): + os.system("/usr/local/bin/set_micmute_led " + str(value)) + +def init(): + pulse.connect(wait= True) + #print('Event types:', pulsectl.PulseEventTypeEnum) #print('Event facilities:', pulsectl.PulseEventFacilityEnum) #print('Event masks:', pulsectl.PulseEventMaskEnum) - #print('Source list:', pulse.source_list()) - - def print_events(ev): - #print('Pulse event:', ev) - global pulse_event - pulse_event = ev - ### Raise PulseLoopStop for event_listen() to return before timeout (if any) - raise pulsectl.PulseLoopStop + print('Source list:', pulse.source_list()) + + find_mic_index() + init_led_value = 0 if pulse.source_info(active_index).mute == 1 else 1 + set_led_value(init_led_value) pulse.event_mask_set('all') - pulse.event_callback_set(print_events) + pulse.event_callback_set(catch_events) + + +if __name__ == '__main__': + print('Starting the micmute listener...') + signal.signal(signal.SIGINT, shutdown) + init() while True: - pulse.event_listen() + try: + pulse.event_listen() + except pulsectl.pulsectl.PulseDisconnected: + # TODO: check the docu, maybe this isn't the best way to restart the connection + print('PulseAudio disconnected! Attempting to reconnect...', file=sys.stderr) + init() + continue if pulse_event.index == active_index: led_value = 0 if pulse.source_info(active_index).mute == 1 else 1 - os.system("/usr/local/bin/set_micmute_led " + str(led_value)) \ No newline at end of file + set_led_value(led_value) \ No newline at end of file