fix(macos): fully stop Voice Wake runtime when disabled
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2.0.0-beta5 — Unreleased
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- macOS: Voice Wake now fully tears down the Speech pipeline when disabled (cancel pending restarts, drop stale callbacks) to avoid high CPU in the background.
|
||||||
|
|
||||||
## 2.0.0-beta4 — 2025-12-27
|
## 2.0.0-beta4 — 2025-12-27
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ actor VoiceWakeRuntime {
|
|||||||
private var listeningState: ListeningState = .idle
|
private var listeningState: ListeningState = .idle
|
||||||
private var overlayToken: UUID?
|
private var overlayToken: UUID?
|
||||||
private var activeTriggerEndTime: TimeInterval?
|
private var activeTriggerEndTime: TimeInterval?
|
||||||
|
private var scheduledRestartTask: Task<Void, Never>?
|
||||||
|
|
||||||
// Tunables
|
// Tunables
|
||||||
// Silence threshold once we've captured user speech (post-trigger).
|
// Silence threshold once we've captured user speech (post-trigger).
|
||||||
@@ -182,21 +183,19 @@ actor VoiceWakeRuntime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func stop(dismissOverlay: Bool = true) {
|
private func stop(dismissOverlay: Bool = true, cancelScheduledRestart: Bool = true) {
|
||||||
|
if cancelScheduledRestart {
|
||||||
|
self.scheduledRestartTask?.cancel()
|
||||||
|
self.scheduledRestartTask = nil
|
||||||
|
}
|
||||||
self.captureTask?.cancel()
|
self.captureTask?.cancel()
|
||||||
self.captureTask = nil
|
self.captureTask = nil
|
||||||
self.isCapturing = false
|
self.isCapturing = false
|
||||||
self.capturedTranscript = ""
|
self.capturedTranscript = ""
|
||||||
self.captureStartedAt = nil
|
self.captureStartedAt = nil
|
||||||
self.triggerChimePlayed = false
|
self.triggerChimePlayed = false
|
||||||
self.recognitionTask?.cancel()
|
self.haltRecognitionPipeline()
|
||||||
self.recognitionTask = nil
|
self.recognizer = nil
|
||||||
self.recognitionRequest?.endAudio()
|
|
||||||
self.recognitionRequest = nil
|
|
||||||
self.audioEngine?.inputNode.removeTap(onBus: 0)
|
|
||||||
self.audioEngine?.stop()
|
|
||||||
// Release the engine so we also release any audio session/resources when Voice Wake is disabled/stopped.
|
|
||||||
self.audioEngine = nil
|
|
||||||
self.currentConfig = nil
|
self.currentConfig = nil
|
||||||
self.listeningState = .idle
|
self.listeningState = .idle
|
||||||
self.activeTriggerEndTime = nil
|
self.activeTriggerEndTime = nil
|
||||||
@@ -425,7 +424,7 @@ actor VoiceWakeRuntime {
|
|||||||
private func restartRecognizer() {
|
private func restartRecognizer() {
|
||||||
// Restart the recognizer so we listen for the next trigger with a clean buffer.
|
// Restart the recognizer so we listen for the next trigger with a clean buffer.
|
||||||
let current = self.currentConfig
|
let current = self.currentConfig
|
||||||
self.stop(dismissOverlay: false)
|
self.stop(dismissOverlay: false, cancelScheduledRestart: false)
|
||||||
if let current {
|
if let current {
|
||||||
Task { await self.start(with: current) }
|
Task { await self.start(with: current) }
|
||||||
}
|
}
|
||||||
@@ -437,7 +436,8 @@ actor VoiceWakeRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func scheduleRestartRecognizer(delay: TimeInterval = 0.7) {
|
private func scheduleRestartRecognizer(delay: TimeInterval = 0.7) {
|
||||||
Task { [weak self] in
|
self.scheduledRestartTask?.cancel()
|
||||||
|
self.scheduledRestartTask = Task { [weak self] in
|
||||||
let nanos = UInt64(max(0, delay) * 1_000_000_000)
|
let nanos = UInt64(max(0, delay) * 1_000_000_000)
|
||||||
try? await Task.sleep(nanoseconds: nanos)
|
try? await Task.sleep(nanoseconds: nanos)
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
Reference in New Issue
Block a user