我正在尝试将
AVSpeechSynthesizer.write
的结果变成AsyncStream
。我想知道最干净的方法是什么来确保 AVSpeechSynthesizer
保持活动状态直到流完成
这是我最初编写的代码:
func toSpeachStream(utterance: AVSpeechUtterance) -> AsyncStream<AVAudioPCMBuffer> {
return AsyncStream { continuation in
let synthesizer = AVSpeechSynthesizer()
synthesizer.write(utterance, toBufferCallback: { buffer in
guard let buffer = buffer as? AVAudioPCMBuffer else {
return
}
continuation.yield(buffer)
if buffer.frameCapacity <= 1 { // Check if finished
continuation.finish()
}
})
}
}
这似乎不起作用。我认为问题在于
synthesizer
在 write
回调完成之前被销毁。结果是一个空流,我们永远等待
我当前的解决方案是保留对
AVSpeechSynthesizer
的引用,直到整个流被消耗,如下所示:
let synthesizer = AVSpeechSynthesizer()
for await buff in toSpeachStream(synthesizer, utterance) {
...
}
// Make sure the synthesizer stays alive until the stream is done
synthesizer.stopSpeaking(at: .immediate)
有更惯用的方法吗?我更喜欢保留简单的签名
toSpeachStream
您可以将语音合成器的实例化移出此函数。例如,我可能只编写一个返回
AsyncStream
作为 AVSpeechSynthesizer
: 的方法的函数
extension AVSpeechSynthesizer {
func buffers(for utterance: AVSpeechUtterance) -> AsyncStream<AVAudioPCMBuffer> {
AsyncStream { continuation in
write(utterance) { buffer in
guard let buffer = buffer as? AVAudioPCMBuffer else {
return
}
continuation.yield(buffer)
if buffer.frameCapacity <= 1 { // Check if finished
continuation.finish()
}
}
}
}
}
然后您可以实例化合成器,在其中迭代缓冲区,确保
AVSpeechSynthesizer
不会被释放,直到您完成异步序列的迭代:
func toSpeechStream(for utterance: AVSpeechUtterance) async {
let synthesizer = AVSpeechSynthesizer()
for await buffer in synthesizer.buffers(for: utterance) {
…
}
}