rhasspy / wyoming-snd-external

Wyoming protocol server that calls an external program to play audio
MIT License
12 stars 10 forks source link

enhancement request , if multiple clients send requests concurrently one will fail #9

Open sdetweil opened 2 hours ago

sdetweil commented 2 hours ago

this player assumes only one play request at a time, but allows multiple to be processed at the event level.
(my test config client sends two wav files back to back on two sep connections)

should queue them up to play (as aplay has to be stopped/started for each) and inform the requestor as appropriate requestor may be waiting for 'Played' event which may not come depending on the error or may come, even if not actually played

really need a queue of queues
   each upper level queue represents a client connection
           each lower queue has a list of things with buffers, with last being the 'end' status (from the AudioStop event)
    the handler pulls from upper to get lower queue (block if empty)
          starts aplay/processor
           then pulls that lower queue,  (block if empty)
                   until 'end' found
                        writes buffer to processor stdin
                        await flush
           sends eof
           ends processor
           sends 'Played' event back to client
   repeat    
sdetweil commented 2 hours ago

existing log

    | DEBUG:root:Namespace(program='aplay -D plughw:0,8 -r 22050 -c 1 -f S16_LE -t raw', rate=22050, width=2, channels=1, samples_per_chunk=1024, uri='tcp://0.0.0.0:10601', debug=True, log_format='%(levelname)s:%(name)s:%(message)s')
playback_1      | INFO:root:Ready
playback_1      | DEBUG:root:Client connected: 228226895143759
playback_1      | DEBUG:root:Running ['aplay', '-D', 'plughw:0,8', '-r', '22050', '-c', '1', '-f', 'S16_LE', '-t', 'raw']
playback_1      | Playing raw data 'stdin' : Signed 16 bit Little Endian, Rate 22050 Hz, Mono
playback_1      | DEBUG:root:Client connected: 228227566383113
playback_1      | DEBUG:root:Running ['aplay', '-D', 'plughw:0,8', '-r', '22050', '-c', '1', '-f', 'S16_LE', '-t', 'raw']
playback_1      | aplay: main:831: audio open error: Device or resource busy   <==== trying to play before prior finishes
playback_1      | ERROR:asyncio:Task exception was never retrieved
playback_1      | future: <Task finished name='Task-9' coro=<AsyncEventHandler.run() done, defined at /app/.venv/lib/python3.11/site-packages/wyoming/server.py:28> exception=BrokenPipeError()>
playback_1      | Traceback (most recent call last):
playback_1      |   File "/app/.venv/lib/python3.11/site-packages/wyoming/server.py", line 38, in run
playback_1      |     await self.disconnect()
playback_1      |   File "/app/wyoming_snd_external/__main__.py", line 132, in disconnect
playback_1      |     await self._stop_proc()
playback_1      |   File "/app/wyoming_snd_external/__main__.py", line 127, in _stop_proc
playback_1      |     await self._proc.stdin.wait_closed()
playback_1      |   File "/usr/local/lib/python3.11/asyncio/streams.py", line 364, in wait_closed
playback_1      |     await self._protocol._get_close_waiter(self)
playback_1      | BrokenPipeError