AVSpeechSynthesizer 检测语音何时结束
AVSpeechSynthesizer detect when the speech is finished
我只是不知道该怎么做...
我在这里和 google 搜索,人们谈论 AVSpeechSynthesizerDelegate,但我无法使用它。
我想在演讲结束时运行一个函数。
我怎样才能做到这一点?如果一定要用delegate,怎么办?
我这样试过:
func speechSynthesizer(synthesizer: AVSpeechSynthesizer, didFinishSpeechUtterance utterance: AVSpeechUtterance) {
falando = false
print("FINISHED")
}
这是我在开发人员的文档上找到的功能之一,虽然讲了讲,但没有打印任何内容。
我试着把 Class A : AVSpeechSynthesizerDelegate 那么我会做 Speech.delegate = self (语音是 A 的一个属性,属于 AVSpeechSynthesizer 类型)但它说 A 不符合协议NSObjectProtocol.
如何在演讲结束后立即运行执行某些功能(甚至打印)?
谢谢!
A does not conform to protocol NSObjectProtocol
表示你的class必须继承自NSObject,你可以阅读更多相关内容here.
现在我不知道你是如何构建你的代码的,但这个小例子似乎对我有用。首先是一个非常简单的 class ,它包含 AVSpeechSynthesizer
:
class Speaker: NSObject {
let synth = AVSpeechSynthesizer()
override init() {
super.init()
synth.delegate = self
}
func speak(_ string: String) {
let utterance = AVSpeechUtterance(string: string)
synth.speakUtterance(utterance)
}
}
注意我在这里设置委托(在 init
方法中)并注意它必须继承自 NSObject
以使编译器满意(非常重要!)
然后是实际的委托方法:
extension Speaker: AVSpeechSynthesizerDelegate {
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
print("all done")
}
}
最后,我可以在这里使用 class,就像这样:
class ViewController: UIViewController {
let speaker = Speaker()
@IBAction func buttonTapped(sender: UIButton) {
speaker.speak("Hello world")
}
}
奖励我
all done
在 AVSpeechSynthesizer
停止说话时在我的控制台中。
希望对你有所帮助。
更新
所以,时间过去了,@case-silva 在下面的评论中询问是否有实际示例,@dima-gershman 建议直接在 ViewController
中使用 AVSpeectSynthesizer
。
为了兼顾两者,我在这里制作了一个简单的 ViewController
示例,其中包含 UITextField
和 UIButton
。
流量为:
- 您在文本字段中输入一些文本(如果没有,将设置默认值)
- 你按下按钮
- 按钮被禁用并且背景颜色被更改(抱歉,这是我能想到的最好的:))
- 语音结束后,按钮启用,文本字段被清除,背景颜色再次更改。
这是它的样子
一个简单的UIViewController
例子
import UIKit
import AVFoundation
class ViewController: UIViewController {
//MARK: Outlets
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var speakButton: UIButton!
let synth = AVSpeechSynthesizer()
override func viewDidLoad() {
super.viewDidLoad()
synth.delegate = self
}
@IBAction func speakButtonTapped(_ sender: UIButton) {
//We're ready to start speaking, disable UI while we're speaking
view.backgroundColor = .darkGray
speakButton.isEnabled = false
let inputText = textField.text ?? ""
let textToSpeak = inputText.isEmpty ? "Please enter some text" : inputText
let speakUtterance = AVSpeechUtterance(string: textToSpeak)
synth.speak(speakUtterance)
}
}
extension ViewController: AVSpeechSynthesizerDelegate {
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
//Speaking is done, enable speech UI for next round
speakButton.isEnabled = true
view.backgroundColor = .lightGray
textField.text = ""
}
}
希望能给你一个线索案例。
// import AVFoundation
import AVFoundation
// Adhere to AVSpeechSynthesizerDelegate
class GetDirectionsViewController: UIViewController, AVSpeechSynthesizerDelegate {
// define a speech session
let speechsynthesizer = AVSpeechSynthesizer()
// set the delegate
speechsynthesizer.delegate = self
// Implement didFinish.
// This is called when speechsynthesizer completes speech
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
print("Speech finished")
}
// Done!
函数viewDidAppear
仅作为示例使用,相同的代码可以根据需要放在任何地方:
class MyViewController: UIViewController, AVSpeechSynthesizerDelegate {
var synth = AVSpeechSynthesizer()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// make sure to set the delegate before "speaking"
synth.delegate = self
let utterance = AVSpeechUtterance(string: "Hello world!")
synth.speak(utterance)
}
// will be called when speech did finish
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
// do something useful here ...
}
}
SwiftUI
创建一个继承自 NSObject 和 ObservableObject 的 Speaker class。
internal class Speaker: NSObject, ObservableObject {
internal var errorDescription: String? = nil
private let synthesizer: AVSpeechSynthesizer = AVSpeechSynthesizer()
@Published var isSpeaking: Bool = false
@Published var isShowingSpeakingErrorAlert: Bool = false
override init() {
super.init()
self.synthesizer.delegate = self
}
internal func speak(_ text: String, language: String) {
do {
let utterance = AVSpeechUtterance(string: text)
utterance.voice = AVSpeechSynthesisVoice(language: language)
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
self.synthesizer.speak(utterance)
} catch let error {
self.errorDescription = error.localizedDescription
isShowingSpeakingErrorAlert.toggle()
}
}
internal func stop() {
self.synthesizer.stopSpeaking(at: .immediate)
}
}
扩展它并实现必要的委托方法。
extension Speaker: AVSpeechSynthesizerDelegate {
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
self.isSpeaking = true
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
self.isSpeaking = false
try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
self.isSpeaking = false
try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
}
}
使用 StateObject 包装器将 Speaker 添加到必要的视图。
struct ContentView: View {
let text: String = "Hello World!"
@StateObject var speaker: Speaker = Speaker()
var body: some View {
HStack {
Text(text)
Spacer()
Button(action: {
if self.speaker.isSpeaking {
speaker.stop()
} else {
speaker.speak(text, language: "en-US")
}
}) {
Image(systemName: self.speaker.isSpeaking ? "stop.circle" : "speaker.wave.2.circle")
.resizable()
.frame(width: 30, height: 30)
}
.buttonStyle(BorderlessButtonStyle())
.alert(isPresented: $speaker.isShowingSpeakingErrorAlert) {
Alert(title: Text("Pronunciation error", comment: "Pronunciation error alert title."), message: Text(speaker.errorDescription ?? ""))
}
}
.padding()
}
}
我制作了应用程序并为我找到了这个解决方案。
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer,
willSpeakRangeOfSpeechString characterRange: NSRange,
utterance: AVSpeechUtterance) {
progress = Float(characterRange.location + characterRange.length)
/ Float(utterance.speechString.count)
speechCount = Float(utterance.speechString.count)
self.soundSliderView.setValue(progress, animated: true)
}
完成后可以使用“进度值”
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
if progress >= 1.0 {
// finis playing with end speaking
} else {
// finis playing with stopping
}
}
我只是不知道该怎么做...
我在这里和 google 搜索,人们谈论 AVSpeechSynthesizerDelegate,但我无法使用它。
我想在演讲结束时运行一个函数。
我怎样才能做到这一点?如果一定要用delegate,怎么办?
我这样试过:
func speechSynthesizer(synthesizer: AVSpeechSynthesizer, didFinishSpeechUtterance utterance: AVSpeechUtterance) {
falando = false
print("FINISHED")
}
这是我在开发人员的文档上找到的功能之一,虽然讲了讲,但没有打印任何内容。
我试着把 Class A : AVSpeechSynthesizerDelegate 那么我会做 Speech.delegate = self (语音是 A 的一个属性,属于 AVSpeechSynthesizer 类型)但它说 A 不符合协议NSObjectProtocol.
如何在演讲结束后立即运行执行某些功能(甚至打印)?
谢谢!
A does not conform to protocol NSObjectProtocol
表示你的class必须继承自NSObject,你可以阅读更多相关内容here.
现在我不知道你是如何构建你的代码的,但这个小例子似乎对我有用。首先是一个非常简单的 class ,它包含 AVSpeechSynthesizer
:
class Speaker: NSObject {
let synth = AVSpeechSynthesizer()
override init() {
super.init()
synth.delegate = self
}
func speak(_ string: String) {
let utterance = AVSpeechUtterance(string: string)
synth.speakUtterance(utterance)
}
}
注意我在这里设置委托(在 init
方法中)并注意它必须继承自 NSObject
以使编译器满意(非常重要!)
然后是实际的委托方法:
extension Speaker: AVSpeechSynthesizerDelegate {
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
print("all done")
}
}
最后,我可以在这里使用 class,就像这样:
class ViewController: UIViewController {
let speaker = Speaker()
@IBAction func buttonTapped(sender: UIButton) {
speaker.speak("Hello world")
}
}
奖励我
all done
在 AVSpeechSynthesizer
停止说话时在我的控制台中。
希望对你有所帮助。
更新
所以,时间过去了,@case-silva 在下面的评论中询问是否有实际示例,@dima-gershman 建议直接在 ViewController
中使用 AVSpeectSynthesizer
。
为了兼顾两者,我在这里制作了一个简单的 ViewController
示例,其中包含 UITextField
和 UIButton
。
流量为:
- 您在文本字段中输入一些文本(如果没有,将设置默认值)
- 你按下按钮
- 按钮被禁用并且背景颜色被更改(抱歉,这是我能想到的最好的:))
- 语音结束后,按钮启用,文本字段被清除,背景颜色再次更改。
这是它的样子
一个简单的UIViewController
例子
import UIKit
import AVFoundation
class ViewController: UIViewController {
//MARK: Outlets
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var speakButton: UIButton!
let synth = AVSpeechSynthesizer()
override func viewDidLoad() {
super.viewDidLoad()
synth.delegate = self
}
@IBAction func speakButtonTapped(_ sender: UIButton) {
//We're ready to start speaking, disable UI while we're speaking
view.backgroundColor = .darkGray
speakButton.isEnabled = false
let inputText = textField.text ?? ""
let textToSpeak = inputText.isEmpty ? "Please enter some text" : inputText
let speakUtterance = AVSpeechUtterance(string: textToSpeak)
synth.speak(speakUtterance)
}
}
extension ViewController: AVSpeechSynthesizerDelegate {
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
//Speaking is done, enable speech UI for next round
speakButton.isEnabled = true
view.backgroundColor = .lightGray
textField.text = ""
}
}
希望能给你一个线索案例。
// import AVFoundation
import AVFoundation
// Adhere to AVSpeechSynthesizerDelegate
class GetDirectionsViewController: UIViewController, AVSpeechSynthesizerDelegate {
// define a speech session
let speechsynthesizer = AVSpeechSynthesizer()
// set the delegate
speechsynthesizer.delegate = self
// Implement didFinish.
// This is called when speechsynthesizer completes speech
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
print("Speech finished")
}
// Done!
函数viewDidAppear
仅作为示例使用,相同的代码可以根据需要放在任何地方:
class MyViewController: UIViewController, AVSpeechSynthesizerDelegate {
var synth = AVSpeechSynthesizer()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// make sure to set the delegate before "speaking"
synth.delegate = self
let utterance = AVSpeechUtterance(string: "Hello world!")
synth.speak(utterance)
}
// will be called when speech did finish
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
// do something useful here ...
}
}
SwiftUI
创建一个继承自 NSObject 和 ObservableObject 的 Speaker class。
internal class Speaker: NSObject, ObservableObject {
internal var errorDescription: String? = nil
private let synthesizer: AVSpeechSynthesizer = AVSpeechSynthesizer()
@Published var isSpeaking: Bool = false
@Published var isShowingSpeakingErrorAlert: Bool = false
override init() {
super.init()
self.synthesizer.delegate = self
}
internal func speak(_ text: String, language: String) {
do {
let utterance = AVSpeechUtterance(string: text)
utterance.voice = AVSpeechSynthesisVoice(language: language)
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
self.synthesizer.speak(utterance)
} catch let error {
self.errorDescription = error.localizedDescription
isShowingSpeakingErrorAlert.toggle()
}
}
internal func stop() {
self.synthesizer.stopSpeaking(at: .immediate)
}
}
扩展它并实现必要的委托方法。
extension Speaker: AVSpeechSynthesizerDelegate {
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
self.isSpeaking = true
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
self.isSpeaking = false
try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
self.isSpeaking = false
try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
}
}
使用 StateObject 包装器将 Speaker 添加到必要的视图。
struct ContentView: View {
let text: String = "Hello World!"
@StateObject var speaker: Speaker = Speaker()
var body: some View {
HStack {
Text(text)
Spacer()
Button(action: {
if self.speaker.isSpeaking {
speaker.stop()
} else {
speaker.speak(text, language: "en-US")
}
}) {
Image(systemName: self.speaker.isSpeaking ? "stop.circle" : "speaker.wave.2.circle")
.resizable()
.frame(width: 30, height: 30)
}
.buttonStyle(BorderlessButtonStyle())
.alert(isPresented: $speaker.isShowingSpeakingErrorAlert) {
Alert(title: Text("Pronunciation error", comment: "Pronunciation error alert title."), message: Text(speaker.errorDescription ?? ""))
}
}
.padding()
}
}
我制作了应用程序并为我找到了这个解决方案。
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer,
willSpeakRangeOfSpeechString characterRange: NSRange,
utterance: AVSpeechUtterance) {
progress = Float(characterRange.location + characterRange.length)
/ Float(utterance.speechString.count)
speechCount = Float(utterance.speechString.count)
self.soundSliderView.setValue(progress, animated: true)
}
完成后可以使用“进度值”
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
if progress >= 1.0 {
// finis playing with end speaking
} else {
// finis playing with stopping
}
}