Skip to content

Commit f3cc7a5

Browse files
Port Enhancements from EA Release
1 parent 84fc18b commit f3cc7a5

File tree

15 files changed

+380
-295
lines changed

15 files changed

+380
-295
lines changed

deepgram/audio/microphone/microphone.py

Lines changed: 81 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class Microphone: # pylint: disable=too-many-instance-attributes
2222

2323
_logger: verboselogs.VerboseLogger
2424

25-
_audio: "pyaudio.PyAudio"
26-
_stream: "pyaudio.Stream"
25+
_audio: Optional["pyaudio.PyAudio"] = None
26+
_stream: Optional["pyaudio.Stream"] = None
2727

2828
_chunk: int
2929
_rate: int
@@ -145,77 +145,49 @@ def start(self) -> bool:
145145
self._asyncio_thread = None
146146
self._push_callback = self._push_callback_org
147147

148-
self._stream = self._audio.open(
149-
format=self._format,
150-
channels=self._channels,
151-
rate=self._rate,
152-
input=True,
153-
frames_per_buffer=self._chunk,
154-
input_device_index=self._input_device_index,
155-
stream_callback=self._callback,
156-
)
148+
if self._audio is not None:
149+
self._stream = self._audio.open(
150+
format=self._format,
151+
channels=self._channels,
152+
rate=self._rate,
153+
input=True,
154+
output=False,
155+
frames_per_buffer=self._chunk,
156+
input_device_index=self._input_device_index,
157+
stream_callback=self._callback,
158+
)
159+
160+
if self._stream is None:
161+
self._logger.error("start failed. No stream created.")
162+
self._logger.debug("Microphone.start LEAVE")
163+
return False
157164

158165
self._exit.clear()
159-
self._stream.start_stream()
166+
if self._stream is not None:
167+
self._stream.start_stream()
160168

161169
self._logger.notice("start succeeded")
162170
self._logger.debug("Microphone.start LEAVE")
163171
return True
164172

165-
def _callback(
166-
self, input_data, frame_count, time_info, status_flags
167-
): # pylint: disable=unused-argument
168-
"""
169-
The callback used to process data in callback mode.
170-
"""
171-
# dynamic import of pyaudio as not to force the requirements on the SDK (and users)
172-
import pyaudio # pylint: disable=import-outside-toplevel
173-
174-
self._logger.debug("Microphone._callback ENTER")
175-
176-
if self._exit.is_set():
177-
self._logger.info("exit is Set")
178-
self._logger.notice("_callback stopping...")
179-
self._logger.debug("Microphone._callback LEAVE")
180-
return None, pyaudio.paAbort
181-
182-
if input_data is None:
183-
self._logger.warning("input_data is None")
184-
self._logger.debug("Microphone._callback LEAVE")
185-
return None, pyaudio.paContinue
186-
187-
try:
188-
if self._is_muted:
189-
size = len(input_data)
190-
input_data = b"\x00" * size
191-
192-
self._push_callback(input_data)
193-
except Exception as e:
194-
self._logger.error("Error while sending: %s", str(e))
195-
self._logger.debug("Microphone._callback LEAVE")
196-
raise
197-
198-
self._logger.debug("Microphone._callback LEAVE")
199-
return input_data, pyaudio.paContinue
200-
201173
def mute(self) -> bool:
202174
"""
203175
mute - mutes the microphone stream
204176
205177
Returns:
206178
bool: True if the stream was muted, False otherwise
207179
"""
208-
self._logger.debug("Microphone.mute ENTER")
180+
self._logger.verbose("Microphone.mute ENTER")
209181

210182
if self._stream is None:
211183
self._logger.error("mute failed. Library not initialized.")
212-
self._logger.debug("Microphone.mute LEAVE")
184+
self._logger.verbose("Microphone.mute LEAVE")
213185
return False
214186

215187
self._is_muted = True
216188

217189
self._logger.notice("mute succeeded")
218-
self._logger.debug("Microphone.mute LEAVE")
190+
self._logger.verbose("Microphone.mute LEAVE")
219191
return True
220192

221193
def unmute(self) -> bool:
@@ -225,19 +197,42 @@ def unmute(self) -> bool:
225197
Returns:
226198
bool: True if the stream was unmuted, False otherwise
227199
"""
228-
self._logger.debug("Microphone.unmute ENTER")
200+
self._logger.verbose("Microphone.unmute ENTER")
229201

230202
if self._stream is None:
231203
self._logger.error("unmute failed. Library not initialized.")
232-
self._logger.debug("Microphone.unmute LEAVE")
204+
self._logger.verbose("Microphone.unmute LEAVE")
233205
return False
234206

235207
self._is_muted = False
236208

237209
self._logger.notice("unmute succeeded")
238-
self._logger.debug("Microphone.unmute LEAVE")
210+
self._logger.verbose("Microphone.unmute LEAVE")
239211
return True
240212

213+
def is_muted(self) -> bool:
214+
"""
215+
is_muted - returns the state of the stream
216+
217+
Args:
218+
None
219+
220+
Returns:
221+
True if the stream is muted, False otherwise
222+
"""
223+
self._logger.spam("Microphone.is_muted ENTER")
224+
225+
if self._stream is None:
226+
self._logger.spam("is_muted: stream is None")
227+
self._logger.spam("Microphone.is_muted LEAVE")
228+
return False
229+
230+
val = self._is_muted
231+
232+
self._logger.spam("is_muted: %s", val)
233+
self._logger.spam("Microphone.is_muted LEAVE")
234+
return val
235+
241236
def finish(self) -> bool:
242237
"""
243238
finish - stops the microphone stream
@@ -255,7 +250,6 @@ def finish(self) -> bool:
255250
self._logger.notice("stopping stream...")
256251
self._stream.stop_stream()
257252
self._stream.close()
258-
self._stream = None # type: ignore
259253
self._logger.notice("stream stopped")
260254

261255
# clean up the thread
@@ -265,13 +259,43 @@ def finish(self) -> bool:
265259
self._asyncio_thread
266260
is not None
267261
):
268-
self._logger.notice("stopping asyncio loop...")
262+
self._logger.notice("stopping _asyncio_loop...")
269263
self._asyncio_loop.call_soon_threadsafe(self._asyncio_loop.stop)
270264
self._asyncio_thread.join()
271-
self._asyncio_thread = None
272265
self._logger.notice("_asyncio_thread joined")
266+
self._stream = None
267+
self._asyncio_thread = None
273268

274269
self._logger.notice("finish succeeded")
275270
self._logger.debug("Microphone.finish LEAVE")
276271

277272
return True
273+
274+
def _callback(
275+
self, input_data, frame_count, time_info, status_flags
276+
): # pylint: disable=unused-argument
277+
"""
278+
The callback used to process data in callback mode.
279+
"""
280+
# dynamic import of pyaudio as not to force the requirements on the SDK (and users)
281+
import pyaudio # pylint: disable=import-outside-toplevel
282+
283+
if self._exit.is_set():
284+
self._logger.notice("_callback exit is Set. stopping...")
285+
return None, pyaudio.paAbort
286+
287+
if input_data is None:
288+
self._logger.warning("input_data is None")
289+
return None, pyaudio.paContinue
290+
291+
try:
292+
if self._is_muted:
293+
size = len(input_data)
294+
input_data = b"\x00" * size
295+
296+
self._push_callback(input_data)
297+
except Exception as e:
298+
self._logger.error("Error while sending: %s", str(e))
299+
raise
300+
301+
return input_data, pyaudio.paContinue

0 commit comments

Comments
 (0)