@@ -16,6 +16,8 @@ def __init__(self):
1616 except ImportError :
1717 raise ImportError ("To use DefaultAudioInterface you must install pyaudio." )
1818 self .pyaudio = pyaudio
19+ self .should_stop = threading .Event ()
20+ self .output_thread = None
1921
2022 def start (self , input_callback : Callable [[bytes ], None ]):
2123 # Audio input is using callbacks from pyaudio which we simply pass through.
@@ -24,7 +26,7 @@ def start(self, input_callback: Callable[[bytes], None]):
2426 # Audio output is buffered so we can handle interruptions.
2527 # Start a separate thread to handle writing to the output stream.
2628 self .output_queue : queue .Queue [bytes ] = queue .Queue ()
27- self .should_stop = threading . Event ()
29+ self .should_stop . clear () # Reset the event in case start is called multiple times
2830 self .output_thread = threading .Thread (target = self ._output_thread )
2931
3032 self .p = self .pyaudio .PyAudio ()
@@ -50,11 +52,15 @@ def start(self, input_callback: Callable[[bytes], None]):
5052
5153 def stop (self ):
5254 self .should_stop .set ()
53- self .output_thread .join ()
54- self .in_stream .stop_stream ()
55- self .in_stream .close ()
56- self .out_stream .close ()
57- self .p .terminate ()
55+ if self .output_thread and self .output_thread .is_alive ():
56+ self .output_thread .join ()
57+ if hasattr (self , 'in_stream' ):
58+ self .in_stream .stop_stream ()
59+ self .in_stream .close ()
60+ if hasattr (self , 'out_stream' ):
61+ self .out_stream .close ()
62+ if hasattr (self , 'p' ):
63+ self .p .terminate ()
5864
5965 def output (self , audio : bytes ):
6066 self .output_queue .put (audio )
@@ -94,6 +100,8 @@ def __init__(self):
94100 except ImportError :
95101 raise ImportError ("To use AsyncDefaultAudioInterface you must install pyaudio." )
96102 self .pyaudio = pyaudio
103+ self .should_stop = asyncio .Event ()
104+ self .output_task = None
97105
98106 async def start (self , input_callback : Callable [[bytes ], Awaitable [None ]]):
99107 # Audio input is using callbacks from pyaudio which we adapt to async
@@ -102,7 +110,7 @@ async def start(self, input_callback: Callable[[bytes], Awaitable[None]]):
102110 # Audio output is buffered so we can handle interruptions.
103111 # Start a separate task to handle writing to the output stream.
104112 self .output_queue : asyncio .Queue [bytes ] = asyncio .Queue ()
105- self .should_stop = asyncio . Event ()
113+ self .should_stop . clear () # Reset the event in case start is called multiple times
106114
107115 self .p = self .pyaudio .PyAudio ()
108116 self .in_stream = self .p .open (
@@ -128,11 +136,15 @@ async def start(self, input_callback: Callable[[bytes], Awaitable[None]]):
128136
129137 async def stop (self ):
130138 self .should_stop .set ()
131- await self .output_task
132- self .in_stream .stop_stream ()
133- self .in_stream .close ()
134- self .out_stream .close ()
135- self .p .terminate ()
139+ if self .output_task and not self .output_task .done ():
140+ await self .output_task
141+ if hasattr (self , 'in_stream' ):
142+ self .in_stream .stop_stream ()
143+ self .in_stream .close ()
144+ if hasattr (self , 'out_stream' ):
145+ self .out_stream .close ()
146+ if hasattr (self , 'p' ):
147+ self .p .terminate ()
136148
137149 async def output (self , audio : bytes ):
138150 await self .output_queue .put (audio )
0 commit comments