Add immediate stop on hook and abort incomplete recordings

**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 <noreply@anthropic.com>
This commit is contained in:
2025-10-24 15:53:56 +07:00
parent 9ea6a5e3a6
commit 7e26373fe9

View File

@@ -228,8 +228,9 @@ class RotaryPhone:
# Play the sound with volume control # Play the sound with volume control
data = wf.readframes(CHUNK) data = wf.readframes(CHUNK)
while data: while data:
# For greeting sounds, stop if handset is hung up # For greeting sounds, stop immediately if handset is hung up
if check_hook_status and self.phone_status != "off_hook": if check_hook_status and GPIO.input(HOOK_PIN) != HOOK_PRESSED:
print("Handset hung up, stopping playback immediately")
break break
# Apply volume by converting to numpy array and scaling # Apply volume by converting to numpy array and scaling
@@ -259,6 +260,8 @@ class RotaryPhone:
print(f"Recording to {filename}") print(f"Recording to {filename}")
MIN_RECORDING_DURATION = 1.0 # Minimum 1 second to save recording
try: try:
# Use configured audio device # Use configured audio device
stream = self.audio.open( stream = self.audio.open(
@@ -276,9 +279,9 @@ class RotaryPhone:
# Record until handset is hung up or max time reached # Record until handset is hung up or max time reached
start_time = time.time() start_time = time.time()
while self.recording and (time.time() - start_time) < RECORD_SECONDS: 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: if GPIO.input(HOOK_PIN) != HOOK_PRESSED:
print("Handset hung up, stopping recording") print("Handset hung up, stopping recording immediately")
break break
try: try:
@@ -291,21 +294,33 @@ class RotaryPhone:
stream.stop_stream() stream.stop_stream()
stream.close() stream.close()
# Save the recording # Calculate recording duration
if frames: 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 = wave.open(filename, 'wb')
wf.setnchannels(CHANNELS) wf.setnchannels(CHANNELS)
wf.setsampwidth(self.audio.get_sample_size(FORMAT)) wf.setsampwidth(self.audio.get_sample_size(FORMAT))
wf.setframerate(RATE) wf.setframerate(RATE)
wf.writeframes(b''.join(frames)) wf.writeframes(b''.join(frames))
wf.close() wf.close()
duration = len(frames) * CHUNK / RATE
print(f"Recording saved: {filename} ({duration:.1f}s)") print(f"Recording saved: {filename} ({duration:.1f}s)")
else: 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: except Exception as e:
print(f"Recording error: {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.recording = False
self.current_recording = None self.current_recording = None