From 7e26373fe98835493ab2ac4ec1ef848e0afef9c9 Mon Sep 17 00:00:00 2001 From: grabowski Date: Fri, 24 Oct 2025 15:53:56 +0700 Subject: [PATCH] Add immediate stop on hook and abort incomplete recordings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Immediate Hook Detection:** - Playback now checks GPIO pin directly instead of status variable - Recording checks GPIO pin in every loop iteration - Both stop immediately when handset is placed back on hook - No delays or waiting for status updates **Abort Incomplete Recordings:** - Added minimum recording duration (1 second) - Recordings shorter than 1 second are automatically deleted - Aborted recordings (hook hung up during recording) are not saved - Failed recordings are cleaned up automatically - Prevents saving empty or accidental recordings **Behavior:** - Pick up handset → Greeting plays - Hang up during greeting → Greeting stops immediately, no recording - Hang up during recording < 1s → Recording aborted, file deleted - Hang up during recording > 1s → Recording saved normally - Clean state after each hang up, ready for next call 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- rotary_phone_web.py | 49 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/rotary_phone_web.py b/rotary_phone_web.py index 1eb4377..416c058 100644 --- a/rotary_phone_web.py +++ b/rotary_phone_web.py @@ -228,8 +228,9 @@ class RotaryPhone: # Play the sound with volume control data = wf.readframes(CHUNK) while data: - # For greeting sounds, stop if handset is hung up - if check_hook_status and self.phone_status != "off_hook": + # For greeting sounds, stop immediately if handset is hung up + if check_hook_status and GPIO.input(HOOK_PIN) != HOOK_PRESSED: + print("Handset hung up, stopping playback immediately") break # Apply volume by converting to numpy array and scaling @@ -256,9 +257,11 @@ class RotaryPhone: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = os.path.join(OUTPUT_DIR, f"recording_{timestamp}.wav") self.current_recording = filename - + print(f"Recording to {filename}") - + + MIN_RECORDING_DURATION = 1.0 # Minimum 1 second to save recording + try: # Use configured audio device stream = self.audio.open( @@ -269,44 +272,56 @@ class RotaryPhone: input_device_index=AUDIO_DEVICE_INDEX, frames_per_buffer=CHUNK ) - + frames = [] self.recording = True - + # Record until handset is hung up or max time reached start_time = time.time() while self.recording and (time.time() - start_time) < RECORD_SECONDS: - # Check if handset is still off hook + # Check if handset is still off hook - immediate detection if GPIO.input(HOOK_PIN) != HOOK_PRESSED: - print("Handset hung up, stopping recording") + print("Handset hung up, stopping recording immediately") break - + try: data = stream.read(CHUNK, exception_on_overflow=False) frames.append(data) except Exception as e: print(f"Error reading audio: {e}") break - + stream.stop_stream() stream.close() - - # Save the recording - if frames: + + # Calculate recording duration + duration = len(frames) * CHUNK / RATE if frames else 0 + + # Only save if recording is long enough + if frames and duration >= MIN_RECORDING_DURATION: wf = wave.open(filename, 'wb') wf.setnchannels(CHANNELS) wf.setsampwidth(self.audio.get_sample_size(FORMAT)) wf.setframerate(RATE) wf.writeframes(b''.join(frames)) wf.close() - duration = len(frames) * CHUNK / RATE print(f"Recording saved: {filename} ({duration:.1f}s)") else: - print("No audio recorded") - + # Delete aborted/too short recording + if os.path.exists(filename): + os.remove(filename) + print(f"Recording aborted or too short ({duration:.1f}s), not saved") + except Exception as e: print(f"Recording error: {e}") - + # Clean up failed recording file + if os.path.exists(filename): + try: + os.remove(filename) + print(f"Cleaned up failed recording: {filename}") + except: + pass + self.recording = False self.current_recording = None