style(names): renaming attributes names for better clarity

This commit is contained in:
CarolinePascal
2025-08-06 19:46:22 +02:00
parent e2f3982e2c
commit eaeff78924
@@ -75,20 +75,20 @@ class PortAudioMicrophone(Microphone):
# Microphone index # Microphone index
self.microphone_index = config.microphone_index self.microphone_index = config.microphone_index
# Input audio stream process and events # Input audio recording process and events
self.stream_process = None self.record_process = None
self.stream_stop_event = process_Event() self.record_stop_event = process_Event()
self.stream_start_event = process_Event() self.record_start_event = process_Event()
self.stream_close_event = process_Event() self.record_close_event = process_Event()
self.stream_is_started_event = process_Event() self.record_is_started_event = process_Event()
# Thread/Process-safe concurrent queue to store the recorded/read audio # Process-safe concurrent queues to store the written/read audio
self.record_queue = None self.write_queue = process_Queue()
self.read_queue = None self.read_queue = process_Queue()
# Thread/Process to handle data reading and file writing in a separate thread/process (safely) # Thread/Process to handle data writing in a separate thread/process (safely)
self.record_thread = None self.write_thread = None
self.record_stop_event = None self.write_stop_event = None
self.logs = {} self.logs = {}
self._is_connected = False self._is_connected = False
@@ -199,34 +199,35 @@ class PortAudioMicrophone(Microphone):
raise DeviceAlreadyConnectedError(f"Microphone {self.microphone_index} is already connected.") raise DeviceAlreadyConnectedError(f"Microphone {self.microphone_index} is already connected.")
self._configure_capture_settings() self._configure_capture_settings()
# Create queues
self.record_queue = process_Queue() # Create or reset queues
self.write_queue = process_Queue()
self.read_queue = process_Queue() self.read_queue = process_Queue()
# Reset events # Reset events
self.stream_start_event.clear() self.record_start_event.clear()
self.stream_stop_event.clear() self.record_stop_event.clear()
self.stream_close_event.clear() self.record_close_event.clear()
self.stream_is_started_event.clear() self.record_is_started_event.clear()
# Create and run audio input stream process # Create and start an audio input stream with a recording callback
# Remark: this is done in a separate process so that audio recording is not impacted by the main thread CPU usage, especially the busy_wait function. # Remark: this is done in a separate process so that audio recording is not impacted by the main thread CPU usage, especially the busy_wait function.
self.stream_process = Process( self.record_process = Process(
target=self._run_audio_input_stream, target=self._record_process,
args=( args=(
self.microphone_index, self.microphone_index,
self.sample_rate, self.sample_rate,
self.channels, self.channels,
self.stream_start_event, self.record_start_event,
self.stream_stop_event, self.record_stop_event,
self.stream_close_event, self.record_close_event,
self.stream_is_started_event, self.record_is_started_event,
self.record_queue, self.write_queue,
self.read_queue, self.read_queue,
), ),
) )
self.stream_process.daemon = True self.record_process.daemon = True
self.stream_process.start() self.record_process.start()
self._is_connected = True self._is_connected = True
@@ -240,12 +241,12 @@ class PortAudioMicrophone(Microphone):
if self.is_recording: if self.is_recording:
self.stop_recording() self.stop_recording()
if self.stream_process is not None: if self.record_process is not None:
self.stream_close_event.set() self.record_close_event.set()
self.read_queue = None self.read_queue = None
self.record_queue = None self.write_queue = None
self.stream_process.terminate() # No time to wait self.record_process.terminate() # No time to wait
self.stream_process = None self.record_process = None
self.is_connected = False self.is_connected = False
def _read(self) -> np.ndarray: def _read(self) -> np.ndarray:
@@ -268,7 +269,7 @@ class PortAudioMicrophone(Microphone):
""" """
if not self.is_connected: if not self.is_connected:
raise DeviceNotConnectedError(f"Microphone {self.microphone_index} is not connected.") raise DeviceNotConnectedError(f"Microphone {self.microphone_index} is not connected.")
if not self.stream.active: if not self.is_recording:
raise RuntimeError(f"Microphone {self.microphone_index} is not recording.") raise RuntimeError(f"Microphone {self.microphone_index} is not recording.")
start_time = time.perf_counter() start_time = time.perf_counter()
@@ -284,19 +285,19 @@ class PortAudioMicrophone(Microphone):
return audio_readings return audio_readings
@staticmethod @staticmethod
def _run_audio_input_stream( def _record_process(
microphone_index, microphone_index,
sample_rate, sample_rate,
channels, channels,
stream_start_event, record_start_event,
stream_stop_event, record_stop_event,
stream_close_event, record_close_event,
is_started_event, record_is_started_event,
record_queue, write_queue,
read_queue, read_queue,
) -> None: ) -> None:
""" """
Process callback used to create an unpickable sounddevice audio input stream and start, stop and close it based on multiprocessing events. Process callback used to create an unpickable sounddevice audio input stream with a recording callback and start, stop and close it based on multiprocessing events.
""" """
channels_index = np.array(channels) - 1 channels_index = np.array(channels) - 1
@@ -310,7 +311,7 @@ class PortAudioMicrophone(Microphone):
# Slicing makes copy unnecessary # Slicing makes copy unnecessary
# Two separate queues are necessary because .get() also pops the data from the queue # Two separate queues are necessary because .get() also pops the data from the queue
# Remark: this also ensures that file-recorded data and chunk-audio data are the same. # Remark: this also ensures that file-recorded data and chunk-audio data are the same.
record_queue.put_nowait(indata[:, channels_index]) write_queue.put_nowait(indata[:, channels_index])
read_queue.put_nowait(indata[:, channels_index]) read_queue.put_nowait(indata[:, channels_index])
# Create the audio stream # Create the audio stream
@@ -326,15 +327,16 @@ class PortAudioMicrophone(Microphone):
) )
while True: while True:
start_flag = stream_start_event.wait(timeout=1.0) start_flag = record_start_event.wait(timeout=0.1)
if stream_close_event.is_set(): if record_close_event.is_set():
break break
elif not start_flag: elif not start_flag:
continue continue
stream.start() stream.start()
is_started_event.set() record_is_started_event.set()
stream_stop_event.wait() record_stop_event.wait()
stream.stop() # stream.stop() waits for all buffers to be processed stream.stop() # stream.stop() waits for all buffers to be processed
record_is_started_event.clear()
# Remark : stream.abort() flushes the buffers ! # Remark : stream.abort() flushes the buffers !
stream.close() stream.close()
@@ -347,7 +349,6 @@ class PortAudioMicrophone(Microphone):
) -> None: ) -> None:
""" """
Starts the recording of the microphone. If output_file is provided, the audio will be written to this file. Starts the recording of the microphone. If output_file is provided, the audio will be written to this file.
Remark: multiprocessing is implemented, but does not work well with sounddevice (launching delays, tricky memory sharing, sounddevice streams are not picklable (even with dill #pathos), etc.).
""" """
if not self.is_connected: if not self.is_connected:
raise DeviceNotConnectedError(f"Microphone {self.microphone_index} is not connected.") raise DeviceNotConnectedError(f"Microphone {self.microphone_index} is not connected.")
@@ -356,11 +357,10 @@ class PortAudioMicrophone(Microphone):
# Reset queues # Reset queues
self._clear_queue(self.read_queue) self._clear_queue(self.read_queue)
self._clear_queue(self.record_queue) self._clear_queue(self.write_queue)
# Reset events - stream_start_event is already cleared here # Reset stop event
self.stream_stop_event.clear() self.record_stop_event.clear()
self.stream_is_started_event.clear()
# Write recordings into a file if output_file is provided # Write recordings into a file if output_file is provided
if output_file is not None: if output_file is not None:
@@ -376,44 +376,44 @@ class PortAudioMicrophone(Microphone):
) )
if multiprocessing: if multiprocessing:
self.record_stop_event = process_Event() self.write_stop_event = process_Event()
self.record_thread = Process( self.write_thread = Process(
target=PortAudioMicrophone._record_loop, target=PortAudioMicrophone._write_loop,
args=( args=(
self.record_queue, self.write_queue,
self.record_stop_event, self.write_stop_event,
self.sample_rate, self.sample_rate,
self.channels, self.channels,
output_file, output_file,
), ),
) )
else: else:
self.record_stop_event = thread_Event() self.write_stop_event = thread_Event()
self.record_thread = Thread( self.write_thread = Thread(
target=PortAudioMicrophone._record_loop, target=PortAudioMicrophone._write_loop,
args=( args=(
self.record_queue, self.write_queue,
self.record_stop_event, self.write_stop_event,
self.sample_rate, self.sample_rate,
self.channels, self.channels,
output_file, output_file,
), ),
) )
self.record_thread.daemon = True self.write_thread.daemon = True
self.is_writing = True self.is_writing = True
if barrier is None: if barrier is None:
self.record_thread.start() self.write_thread.start()
self.stream_start_event.set() # Start the input audio stream process self.record_start_event.set() # Start the input audio stream process
self.stream_is_started_event.wait() # Wait for the input audio stream process to be actually started self.record_is_started_event.wait() # Wait for the input audio stream process to be actually started
if barrier is not None: if barrier is not None:
barrier.wait() # Wait for multiple input audio streams to be started at the same time barrier.wait() # Wait for multiple input audio streams to be started at the same time
self._clear_queue(self.read_queue) self._clear_queue(self.read_queue)
self._clear_queue(self.record_queue) self._clear_queue(self.write_queue)
if output_file is not None: if output_file is not None:
self.record_thread.start() self.write_thread.start()
self.is_recording = True self.is_recording = True
@@ -426,21 +426,21 @@ class PortAudioMicrophone(Microphone):
if not self.is_recording: if not self.is_recording:
raise DeviceNotRecordingError(f"Microphone {self.microphone_index} is not recording.") raise DeviceNotRecordingError(f"Microphone {self.microphone_index} is not recording.")
if self.stream_process is not None: if self.record_process is not None:
self.stream_start_event.clear() # Ensures the stream is not started again ! self.record_start_event.clear() # Ensures the stream is not started again !
self.stream_stop_event.set() self.record_stop_event.set()
self.is_recording = False self.is_recording = False
if self.record_thread is not None: if self.write_thread is not None:
self.record_queue.join() self.write_queue.join()
self.record_stop_event.set() self.write_stop_event.set()
self.record_thread.join() self.write_thread.join()
self.record_thread = None self.write_thread = None
self.record_stop_event = None self.write_stop_event = None
self.is_writing = False self.is_writing = False
@staticmethod @staticmethod
def _record_loop(queue, event: Event, sample_rate: int, channels: list[int], output_file: Path) -> None: def _write_loop(queue, event: Event, sample_rate: int, channels: list[int], output_file: Path) -> None:
""" """
Thread/Process-safe loop to write audio data into a file. Thread/Process-safe loop to write audio data into a file.
""" """