Python sound delay

Hello.
I’ve been looking into customizing my Linux environment more recently and I was curious if there were any options for playing sound effects when pressing keys on my keyboard. I couldn’t find any options I really trusted so I decided to make my own via python as it’s built into my Linux system. I got the code to work, technically. The issue is that when pressing many keys in a short timeframe, the sound has a small delay and when typing quickly over a short period of time the program outright crashes for some reason.

from pynput.keyboard import *
from playsound import playsound

def press_on(key):
    print('press ON: {}'.format(key))
    playsound("keyboard_click.mp3", block=False)

def press_off(key):
    print('press OFF: {}'.format(key))
    if key == Key.esc:
        return False

with Listener(on_press = press_on, on_release = press_off) as listener:
    listener.join()

print is just to visually see it recognizing my key strokes, and the text has no delay at all between key strokes and displaying to the console. Below is the output I get after the program crashes. This happened when running a typing test at about 80 words per minute. First the sound is very responsive, then it stops playing altogether, then after a couple of seconds the program crashes.

(python:66069): GStreamer-CRITICAL **: 15:14:32.456: gst_poll_get_read_gpollfd: assertion 'set != NULL' failed
press OFF: Key.backspace
press ON: Key.backspace

(python:66069): GStreamer-CRITICAL **: 15:14:32.580: gst_poll_get_read_gpollfd: assertion 'set != NULL' failed

(python:66069): GStreamer-CRITICAL **: 15:14:32.585: gst_poll_get_read_gpollfd: assertion 'set != NULL' failed
press OFF: Key.backspace
press ON: 's'

(python:66069): GStreamer-CRITICAL **: 15:14:32.732: gst_poll_get_read_gpollfd: assertion 'set != NULL' failed
Unhandled exception in listener callback
Traceback (most recent call last):
  File "/usr/lib/python3.12/site-packages/pynput/_util/__init__.py", line 229, in inner
  File "/usr/lib/python3.12/site-packages/pynput/_util/xorg.py", line 470, in _handler
  File "/usr/lib/python3.12/site-packages/pynput/keyboard/_xorg.py", line 578, in _handle
  File "/usr/lib/python3.12/site-packages/pynput/_util/__init__.py", line 145, in inner
  File "/home/unknownvan/games/gamepart2/py/keytest.txt", line 6, in press_on
  File "/usr/lib/python3.12/site-packages/playsound.py", line 180, in _playsoundNix
playsound.PlaysoundException: playbin.set_state returned <enum GST_STATE_CHANGE_FAILURE of type Gst.StateChangeReturn>
Traceback (most recent call last):
  File "/home/unknownvan/games/gamepart2/py/keytest.txt", line 14, in <module>
    listener.join()
  File "/usr/lib/python3.12/site-packages/pynput/_util/__init__.py", line 281, in join
    six.reraise(exc_type, exc_value, exc_traceback)
  File "/usr/lib/python3.12/site-packages/six.py", line 718, in reraise
    raise value.with_traceback(tb)
  File "/usr/lib/python3.12/site-packages/pynput/_util/__init__.py", line 229, in inner
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pynput/_util/xorg.py", line 470, in _handler
    self._handle(self._display_stop, event)
  File "/usr/lib/python3.12/site-packages/pynput/keyboard/_xorg.py", line 578, in _handle
    self.on_press(key)
  File "/usr/lib/python3.12/site-packages/pynput/_util/__init__.py", line 145, in inner
    if f(*args) is False:
       ^^^^^^^^
  File "/home/unknownvan/games/gamepart2/py/keytest.txt", line 6, in press_on
    playsound("keyboard_click.mp3", block=False)
  File "/usr/lib/python3.12/site-packages/playsound.py", line 180, in _playsoundNix
    raise PlaysoundException(
playsound.PlaysoundException: playbin.set_state returned <enum GST_STATE_CHANGE_FAILURE of type Gst.StateChangeReturn>

Maybe playsound isn’t the proper library to use in this situation? Or maybe I need to load the audio into memory some way instead of constantly reading from the file? I haven’t been able to figure out how to do that, though. Any help is appreciated.

I expect that you overflowed some internal state in playsound.
You would need to limit the number of sounds playing at the same time to a reasonable number.

Maybe you can use a background thread to play the sound and make sure that it only plays sounds one-by-one.