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
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