From cc72c813bfaa38369cd13dea0eebeec50689c164 Mon Sep 17 00:00:00 2001 From: CarolinePascal Date: Sun, 2 Nov 2025 17:48:44 +0100 Subject: [PATCH] fix(process init timeout): adding proper support when waiting for record process initialization --- .../microphones/portaudio/microphone_portaudio.py | 10 +++++++--- src/lerobot/microphones/touchlab/sensor_touchlab.py | 11 ++++++++--- src/lerobot/scripts/lerobot_record.py | 6 +++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/lerobot/microphones/portaudio/microphone_portaudio.py b/src/lerobot/microphones/portaudio/microphone_portaudio.py index 95414ae5c..eb6a9827d 100644 --- a/src/lerobot/microphones/portaudio/microphone_portaudio.py +++ b/src/lerobot/microphones/portaudio/microphone_portaudio.py @@ -269,12 +269,14 @@ class PortAudioMicrophone(Microphone): # 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. + process_init_event = process_Event() self.record_process = Process( target=self._record_process, args=( self.microphone_index, self.sample_rate, self.channels, + process_init_event, self.record_start_event, self.record_stop_event, self.record_close_event, @@ -288,10 +290,10 @@ class PortAudioMicrophone(Microphone): self.record_process.daemon = True self.record_process.start() - time.sleep( - 0.1 + is_init = process_init_event.wait( + timeout=5.0 ) # Wait for the recording process to be started, and to potentially raise an error on failure. - if not self.is_connected: + if not self.is_connected or not is_init: raise RuntimeError(f"Error connecting microphone {self.microphone_index}.") logger.info(f"{self} connected.") @@ -348,6 +350,7 @@ class PortAudioMicrophone(Microphone): microphone_index, sample_rate, channels, + process_init_event, record_start_event, record_stop_event, record_close_event, @@ -386,6 +389,7 @@ class PortAudioMicrophone(Microphone): # never_drop_input=True, # Disabled as it generates an error for some devices callback=audio_callback, ) + process_init_event.set() while True: start_flag = record_start_event.wait(timeout=0.1) diff --git a/src/lerobot/microphones/touchlab/sensor_touchlab.py b/src/lerobot/microphones/touchlab/sensor_touchlab.py index f9b979908..c2547be70 100644 --- a/src/lerobot/microphones/touchlab/sensor_touchlab.py +++ b/src/lerobot/microphones/touchlab/sensor_touchlab.py @@ -173,12 +173,14 @@ class TouchLabSensor(Microphone): # 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. + process_init_event = process_Event() self.record_process = Process( target=self._record_process, args=( self.sensor_port, self.baud_rate, self.channels, + process_init_event, self.record_start_event, self.record_stop_event, self.record_close_event, @@ -191,10 +193,10 @@ class TouchLabSensor(Microphone): self.record_process.daemon = True self.record_process.start() - time.sleep( - 0.1 + is_init = process_init_event.wait( + timeout=5.0 ) # Wait for the recording process to be started, and to potentially raise an error on failure. - if not self.is_connected: + if not self.is_connected or not is_init: raise RuntimeError(f"Error connecting sensor connected to {self.sensor_port}.") logger.info(f"{self} connected.") @@ -204,6 +206,7 @@ class TouchLabSensor(Microphone): sensor_port, baud_rate, channels, + process_init_event, record_start_event, record_stop_event, record_close_event, @@ -233,6 +236,8 @@ class TouchLabSensor(Microphone): write_queue.put_nowait(indata[:, channels_index]) read_shared_array.write(local_read_shared_array, indata[:, channels_index]) + process_init_event.set() + while True: start_flag = record_start_event.wait(timeout=0.1) if record_close_event.is_set(): diff --git a/src/lerobot/scripts/lerobot_record.py b/src/lerobot/scripts/lerobot_record.py index 6d94f7c72..93795c0b3 100644 --- a/src/lerobot/scripts/lerobot_record.py +++ b/src/lerobot/scripts/lerobot_record.py @@ -355,7 +355,11 @@ def record_loop( async_microphones_start_recording(robot.microphones) # Fill audio buffers if needed - if robot.microphones and (policy is not None or dataset is not None): + if ( + robot.microphones + and (policy is not None or dataset is not None) + and DEFAULT_INITIAL_AUDIO_BUFFER_DURATION > 0.0 + ): # This initial wait might be longer than the audio chunk duration to # (1) ensure that the audio buffers are filled with enough data # (2) add additional initial samples to the dataset in case of variable audio chunk duration during training