Browse Source

fix: revert start sound to Tink and eliminate 10s silence recovery freeze on Option tap

main
Ali Alavi 1 week ago
parent
commit
98fe53a47d
  1. 27
      src/AppDelegate.swift

27
src/AppDelegate.swift

@ -204,7 +204,7 @@ public final class AppDelegate: NSObject, NSApplicationDelegate {
do {
try audioRecorder.startRecording()
playSystemSound(name: "Hero")
playSystemSound(name: "Tink")
statusBarController.updateIcon(state: .recording)
statusBarController.buildMenu(isRecording: true)
HUDOverlayController.shared.show(state: .recording(level: 0.1, isLagging: false, pingQuality: PingMonitor.shared.currentQuality))
@ -217,7 +217,8 @@ public final class AppDelegate: NSObject, NSApplicationDelegate {
}
private func hasAudibleSpeech(pcmData: Data) -> Bool {
guard pcmData.count >= 3200 else { return false }
// Less than 0.25s of audio is just a momentary key tap/click
guard pcmData.count >= 8000 else { return false }
var sumSquares: Double = 0
var peak: Int16 = 0
let count = pcmData.count / 2
@ -232,7 +233,8 @@ public final class AppDelegate: NSObject, NSApplicationDelegate {
}
}
let rms = sqrt(sumSquares / Double(count))
return peak > 1500 && rms > 0.010
// Raised thresholds: filter out mechanical keyclicks and keyboard taps
return peak > 2500 && rms > 0.015
}
public func stopRecording() {
@ -243,10 +245,10 @@ public final class AppDelegate: NSObject, NSApplicationDelegate {
let pcmData = audioRecorder.stopRecording()
self.lastRecordedAudio = pcmData
// Fast-path: If user did NOT speak (silence / short ambient hold), dismiss immediately with ZERO delay!
// Fast-path: If user tapped key or did NOT speak (silence / keyclick), dismiss immediately with ZERO delay!
let hasSpeech = hasAudibleSpeech(pcmData: pcmData)
if !hasSpeech && !InputBoxManager.shared.hasStreamedText {
print("AppDelegate: No audible speech detected. Immediate dismissal without freeze.")
if (!hasSpeech && !InputBoxManager.shared.hasStreamedText) || pcmData.count < 8000 {
print("AppDelegate: Short tap or silence detected. Immediate 0ms dismissal.")
activeSession?.cancel()
activeSession = nil
isBusyFinalizing = false
@ -308,12 +310,21 @@ public final class AppDelegate: NSObject, NSApplicationDelegate {
print("Soniox primary finalize error:", error)
}
// Strict Silence Gating: If server cleanly finished with empty text and no network drop,
// it was just silence/key tap. Dismiss immediately with zero freeze!
if rawText.isEmpty && !isNetworkError && !self.isNetworkDegraded {
print("AppDelegate: Server cleanly returned empty text for silence. Immediate dismissal.")
self.isBusyFinalizing = false
HUDOverlayController.shared.hide()
return
}
let hasSpeech = hasAudibleSpeech(pcmData: self.lastRecordedAudio)
let isTruncated = hasSpeech && self.lastRecordedAudio.count > 64000 && rawText.count < 10
let needsRetry = (isNetworkError || self.isNetworkDegraded || isTruncated || rawText.isEmpty) && hasSpeech && self.lastRecordedAudio.count > 16000
let needsRetry = (isNetworkError || self.isNetworkDegraded || isTruncated) && hasSpeech && self.lastRecordedAudio.count > 24000
if needsRetry {
let reason = isNetworkError ? "WebSocket network error" : (isTruncated ? "Truncated transcript (\(rawText.count) chars for \(self.lastRecordedAudio.count) bytes)" : "Empty transcript for audible speech")
let reason = isNetworkError ? "WebSocket network error" : "Truncated transcript (\(rawText.count) chars for \(self.lastRecordedAudio.count) bytes)"
startSmartAudioRecovery(pcmData: self.lastRecordedAudio, reason: reason)
return
}

Loading…
Cancel
Save