mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-16 14:51:39 +00:00
* feat(ios): add Apple Watch voice turns * chore(ios): sync native i18n inventory * fix(ios): preserve Watch message label
47 lines
1.1 KiB
Swift
47 lines
1.1 KiB
Swift
import AVFAudio
|
|
import Observation
|
|
|
|
@MainActor
|
|
@Observable
|
|
final class WatchSpeechPlayback: NSObject {
|
|
private let synthesizer = AVSpeechSynthesizer()
|
|
private(set) var isSpeaking = false
|
|
|
|
override init() {
|
|
super.init()
|
|
self.synthesizer.delegate = self
|
|
}
|
|
|
|
func speak(_ text: String) {
|
|
self.stop()
|
|
self.isSpeaking = true
|
|
self.synthesizer.speak(AVSpeechUtterance(string: text))
|
|
}
|
|
|
|
func stop() {
|
|
guard self.isSpeaking || self.synthesizer.isSpeaking else { return }
|
|
self.synthesizer.stopSpeaking(at: .immediate)
|
|
self.isSpeaking = false
|
|
}
|
|
}
|
|
|
|
extension WatchSpeechPlayback: AVSpeechSynthesizerDelegate {
|
|
nonisolated func speechSynthesizer(
|
|
_: AVSpeechSynthesizer,
|
|
didFinish _: AVSpeechUtterance)
|
|
{
|
|
Task { @MainActor in
|
|
self.isSpeaking = false
|
|
}
|
|
}
|
|
|
|
nonisolated func speechSynthesizer(
|
|
_: AVSpeechSynthesizer,
|
|
didCancel _: AVSpeechUtterance)
|
|
{
|
|
Task { @MainActor in
|
|
self.isSpeaking = false
|
|
}
|
|
}
|
|
}
|