【问题标题】:AVSpeechSynthesizer detect when the speech is finishedAVSpeechSynthesizer 检测语音何时结束
【发布时间】:2016-09-29 00:27:56
【问题描述】:

我只是不知道该怎么做......

我在这里和谷歌搜索,人们谈到了 AVSpeechSynthesizerDelegate,但我无法使用它。

我想在演讲结束时运行一个函数。

我怎样才能做到这一点?如果我必须使用委托,我应该怎么做?

我试过这样:

func speechSynthesizer(synthesizer: AVSpeechSynthesizer, didFinishSpeechUtterance utterance: AVSpeechUtterance) {
    falando = false
    print("FINISHED")
}

这是我在开发者文档中找到的功能之一,虽然演讲被告知并没有打印出来。

我试图把 Class A : AVSpeechSynthesizerDelegate 所以我会做 Speech.delegate = self (Speech 是 A 的一个属性,类型为 AVSpeechSynthesizer)但它说 A 不符合协议 NSObjectProtocol。

演讲结束后如何运行某些功能(甚至是打印)?

谢谢!

【问题讨论】:

    标签: ios swift avspeechsynthesizer


    【解决方案1】:

    A does not conform to protocol NSObjectProtocol 表示你的类必须继承自 NSObject,你可以阅读更多关于它的信息here

    现在我不知道您是如何构建代码的,但这个小示例似乎对我有用。首先是一个包含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 ViewController: UIViewController {
        let speaker = Speaker()
    
        @IBAction func buttonTapped(sender: UIButton) {
            speaker.speak("Hello world")
        }
    }
    

    这奖励了我

    全部完成

    AVSpeechSynthesizer 停止讲话时在我的控制台中。

    希望对你有所帮助。

    更新

    所以,时间过去了,@case-silva 下面的 cmets 询问是否有实际示例,@dima-gershman 建议直接在ViewController 中使用AVSpeectSynthesizer

    为了适应这两种情况,我在这里用UITextFieldUIButton 做了一个简单的ViewController 示例。

    流程是:

    1. 您在文本字段中输入了一些文本(如果没有,将设置默认值)
    2. 你按下按钮
    3. 按钮被禁用并且背景颜色发生了变化(抱歉,这是我能想到的最好的方法:))
    4. 语音完成后,按钮启用,文本字段被清除,背景颜色再次更改。

    这是它的外观

    一个简单的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 = ""
        }
    }
    

    希望能给你一个线索案例。

    【讨论】:

    • @pbodsk 这个类Speaker 工作正常,但我假设如果人们想要检测语音何时结束——他们想做一些有用的事情。所以我建议要么为 Speaker 的一些 callback 块提供一个占位符 OR 直接在需要发言的类中实现 AVSpeechSynthesizerDelegate (比如你的视图控制器)。
    • @DimaGershman 我现在的情况是,当扬声器的演讲结束时,我确实需要在 ViewController 中执行有意义的操作。您能否举一个使用扬声器的回调块的示例?
    • 是的,现在有了更新的答案,您可以看到如何使用 AVSpeechSynthesizer 并通过委托执行有意义的操作的示例。 (感谢@pbodsk 更新!)
    • 谢谢,这是对完成委托的最好解释
    【解决方案2】:
    // 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!
    

    【讨论】:

      【解决方案3】:

      函数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 ...
          }
      }
      

      【讨论】:

        【解决方案4】:

        SwiftUI

        创建一个继承自 NSObjectObservableObjectSpeaker 类。

        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()
            }
        }
        

        【讨论】:

          【解决方案5】:

          我制作应用程序并为我找到了这个解决方案。

          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
                  }
           }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多