Eventlet interaction?
Hello, I am getting a hang in the audio playback\recording (need to CTRL-C) with playrec() when I monkey_patch with eventlet. Running RPI4 on Raspberry Pi OS 5.10 utilizing I2S codec device. Code works fine without the monkey_patch.
Example:
import eventlet
eventlet.monkey_patch()
import numpy as np
import sounddevice as sd
def pr():
z = np.zeros(48000)
sd.default.device = 2
rec = sd.playrec(z, 48000, channels=2, blocking=True)
print(rec)
if __name__ == "__main__":
pr()
Trace on CTRL-C:
(venv) pi@raspberrypi:~/ProdTestSys0 $ /home/pi/py0/venv/bin/python /home/pi/py0/sc0.py
^CTraceback (most recent call last):
File "/home/pi/py0/sc0.py", line 16, in <module>
pr()
File "/home/pi/py0/sc0.py", line 11, in pr
rec = sd.playrec(z, 48000, channels=2, blocking=True)
File "/home/pi/py0/venv/lib/python3.7/site-packages/sounddevice.py", line 371, in playrec
**kwargs)
File "/home/pi/py0/venv/lib/python3.7/site-packages/sounddevice.py", line 2583, in start_stream
self.wait()
File "/home/pi/py0/venv/lib/python3.7/site-packages/sounddevice.py", line 2592, in wait
self.event.wait()
File "/usr/lib/python3.7/threading.py", line 552, in wait
signaled = self._cond.wait(timeout)
File "/usr/lib/python3.7/threading.py", line 296, in wait
waiter.acquire()
File "/home/pi/py0/venv/lib/python3.7/site-packages/eventlet/semaphore.py", line 120, in acquire
hubs.get_hub().switch()
File "/home/pi/py0/venv/lib/python3.7/site-packages/eventlet/hubs/hub.py", line 313, in switch
return self.greenlet.switch()
File "/home/pi/py0/venv/lib/python3.7/site-packages/eventlet/hubs/hub.py", line 365, in run
self.wait(sleep_time)
File "/home/pi/py0/venv/lib/python3.7/site-packages/eventlet/hubs/poll.py", line 77, in wait
time.sleep(seconds)
KeyboardInterrupt
Thanks for the report!
The problem seems to be that this line never finishes:
https://github.com/spatialaudio/python-sounddevice/blob/d353fbf6c751a7a91169c614df8f905f2c55821c/sounddevice.py#L2598
... even though this line is called:
https://github.com/spatialaudio/python-sounddevice/blob/d353fbf6c751a7a91169c614df8f905f2c55821c/sounddevice.py#L2568
So it looks like eventlet.monkey_patch() somehow messes with threading.Event.
But this seems to only happen with the thread created by PortAudio, there's no problem when using "normal" Python threads.
Other than that, I don't know what exactly is going wrong nor how to fix it ...
Could you please create an issue at the eventlet project, maybe they can help?
There is a similar-sounding issue: https://github.com/eventlet/eventlet/issues/395
There it is suggested to use eventlet.monkey_patch(thread=False) which seems to make your example work!
I will put up something over at the Eventlet issues page. I am not sure of the ramifications of using thread=False; this code is being used in a larger code base which utilizes Flask & Flask-SocketIO which would likely not appreciate that change I imagine. As a short term workaround I have taken out the blocking and have put a hard sleep for the duration of the playrec with a bit extra for good measure. This is obviously not ideal and I might try to make my own stream implementation of playrec.
I might try to make my own stream implementation of
playrec
That's exactly what I would suggest as a work-around.
I'm not sure if if there is anything we can do on the sounddevice side to fix the root of the problem, though.