Change default sample rate to 48kHz and add validation

Changes:
- Update default sample rate from 44.1kHz to 48kHz (more professional standard)
- Add sample rate validation in play_sound_file()
- Display clear warning when uploaded file doesn't match configured rate
- Update default sound generation (dial tone & beep) to use configured RATE
- Prevent playback of incompatible sample rates (avoids ALSA errors)

Error Handling:
- Check file sample rate before attempting playback
- Print warning with actual vs expected sample rate
- Return False and skip playback if mismatch detected
- User-friendly error message with resampling instructions

This fixes the "Invalid sample rate" error when playing files with
non-matching sample rates. Users must now resample their audio files
to match the configured rate (default 48kHz).

To resample audio files:
ffmpeg -i input.wav -ar 48000 output.wav

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-27 12:55:13 +07:00
parent fbe9bb2f9a
commit 52b8348a03
2 changed files with 21 additions and 15 deletions

View File

@@ -11,7 +11,7 @@
"chunk_size": 1024,
"format": "paInt16",
"channels": 1,
"sample_rate": 44100,
"sample_rate": 48000,
"max_record_seconds": 300
},
"paths": {

View File

@@ -354,35 +354,33 @@ class RotaryPhone:
def generate_default_dialtone(self):
"""Generate a classic dial tone (350Hz + 440Hz) and save as default"""
print("Generating default dial tone...")
print(f"Generating default dial tone at {RATE}Hz...")
duration = 3
sample_rate = 44100
t = np.linspace(0, duration, int(sample_rate * duration), False)
t = np.linspace(0, duration, int(RATE * duration), False)
# Generate two frequencies and combine them
tone1 = np.sin(2 * np.pi * 350 * t)
tone2 = np.sin(2 * np.pi * 440 * t)
tone = (tone1 + tone2) / 2
# Convert to 16-bit PCM
tone = (tone * 32767).astype(np.int16)
# Save as WAV file
wf = wave.open(DIALTONE_FILE, 'wb')
wf.setnchannels(1)
wf.setsampwidth(2) # 16-bit
wf.setframerate(sample_rate)
wf.setframerate(RATE)
wf.writeframes(tone.tobytes())
wf.close()
print(f"Default dial tone saved to {DIALTONE_FILE}")
print(f"Default dial tone saved to {DIALTONE_FILE} ({RATE}Hz, 16-bit)")
def generate_default_beep(self):
"""Generate a simple beep tone (1000Hz) to indicate recording start"""
print("Generating default beep sound...")
print(f"Generating default beep sound at {RATE}Hz...")
beep_file = os.path.join(SOUNDS_DIR, "beep.wav")
duration = 0.5 # Half second beep
sample_rate = 44100
t = np.linspace(0, duration, int(sample_rate * duration), False)
t = np.linspace(0, duration, int(RATE * duration), False)
# Generate 1000Hz tone
frequency = 1000
@@ -395,10 +393,10 @@ class RotaryPhone:
wf = wave.open(beep_file, 'wb')
wf.setnchannels(1)
wf.setsampwidth(2) # 16-bit
wf.setframerate(sample_rate)
wf.setframerate(RATE)
wf.writeframes(tone.tobytes())
wf.close()
print(f"Default beep sound saved to {beep_file}")
print(f"Default beep sound saved to {beep_file} ({RATE}Hz, 16-bit)")
def play_sound_file(self, filepath, check_hook_status=True):
"""Play a WAV file with volume control
@@ -417,11 +415,19 @@ class RotaryPhone:
try:
wf = wave.open(filepath, 'rb')
# Check sample rate compatibility
file_rate = wf.getframerate()
if file_rate != RATE:
print(f"WARNING: File sample rate ({file_rate}Hz) doesn't match configured rate ({RATE}Hz)")
print(f"Audio may not play correctly. Please resample the file to {RATE}Hz")
wf.close()
return False
# Use configured audio device
stream = self.audio.open(
format=self.audio.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
rate=file_rate,
output=True,
output_device_index=AUDIO_DEVICE_INDEX,
frames_per_buffer=CHUNK