iOS 10 的 Speech 框架实现语音识别 (Swift)
什么都不说先上效果
早在2011年iPhone4s 的上,iOS 5系统就有了语音识别.
但有以下缺陷
需要- 弹出键盘
只支持实时语音
无法自定义录音
单一的输出结果
不开放
在 2016 年的 WWDC 上,Apple 终于开放了语音识别 Speech Recognition API,那就是 Speech 框架。事实上,Siri 的语音识别正是由 Speech Kit 提供支持。
超过50种语言获得支持
任何运行iOS10的设备都可用
加入用户授权使其更安全
可以转化音频文件和实时语音
下面通过一个语音转换为文本介绍Speech 框架的使用
##界面设计
首先,让我们来创建一个 iOS Single View Application 工程。然后在 Main.storyboard 上添加
UILabel用于标题
UITextView用于显示识别内容
UIButton 用于触发
下一步,连线 textView变量,Button变量和事件
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var speakerBtn: UIButton!
@IBAction func speakAction(_ sender: Any) {
}
##使用 Speech 框架
import这个框架,并遵循 SFSpeechRecognizerDelegate 协议。
##用户权限
在使用 Speech 框架进行语音识别之前,你必须先请求用户许可,原因是识别不仅发生在 iOS 设备本地,还需要依赖 Apple 的服务器。具体来说,所有音频数据都会被传输到苹果后台进行处理。因此需要获取用户的权限,其中包括用户必须允许应用使用的音频输入和语音识别权限。
//用于apple语言识别的变量
private let speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: "zh-CN"))
// MARK: - *** 获取用户权限 ***
func authRequest(){
speakerBtn.isEnabled = false
speechRecognizer?.delegate = self
SFSpeechRecognizer.requestAuthorization { (authStatus) in
var isBtnEndable = false
switch authStatus{
case.authorized:
isBtnEndable = true
case .denied:
isBtnEndable = false
print("User denied access to speech recognition")
case .restricted:
isBtnEndable = false
print("Speech recognition restricted on this device")
case .notDetermined:
isBtnEndable = false
}
OperationQueue.main.addOperation {
self.speakerBtn.isEnabled = isBtnEndable
}
}
}
创建一个区域标志符 (locale identifier) 为 zh-CN 的 SFSpeechRecognizer 实例,这时候语音识别就会知道用户录入的语种。简单说,这就是语音识别的处理对象。
在语音识别被激活之前,默认设置麦克风按钮为禁用状态。
然后,将语音识别的 delegate 设置为 ViewController 中的 self。
之后,就到了请求语音识别权限的阶段了,这时我们通过调用 SFSpeechRecognizer.requestAuthorization 来达到目的。
最后,检查验证状态,如果得到了授权,则启用麦克风按钮。否则,打印错误信息,继续禁用麦克风按钮。
你可能会认为,现在我们启动应用将会看到一个授权提示框,很遗憾你错了。运行应用带来的是崩溃。你可能会想问,这是为什么?
提供授权信息
Apple 要求应用为所有请求的权限提供自定义消息,对于语音权限的情况,我们必须为两个行为请求授权:
麦克风的使用
语音的识别
要自定义消息,你需要在 info.plist 文件中定义这些消息。
让我们打开 info.plist 文件的源代码。方法是在 info.plist 上点击右键。然后选择 Open As > Source Code。最后,复制下面的 XML 代码并将它们插入到 标签前。
NSMicrophoneUsageDescription
麦克风输入请求信息
NSSpeechRecognitionUsageDescription
语音识别请求信息
注意:务必在IPhone真机上运行测试,iOS 模拟器并不会连接 Mac 的麦克风。
处理语音识别
// 可以将识别请求的结果返回给你,它带来了极大的便利,必要时,可以取消或停止任务。
private var recognitionTask: SFSpeechRecognitionTask?
//对象用于处理语音识别请求,为语音识别提供音频输入
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
// 音频引擎 用于进行音频输入
private let audioEngine = AVAudioEngine()
// MARK: - *** 处理语音识别 ***
func startRecording(){
if recognitionTask != nil{
recognitionTask?.cancel()
recognitionTask = nil
}
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSessionCategoryRecord)
try audioSession.setMode(AVAudioSessionModeMeasurement)
try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
}catch{
fatalError("会话创建失败")
}
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
guard let inputNode = audioEngine.inputNode else {
fatalError("音频引擎 没有输入节点")
}
guard let recognitionRequest = recognitionRequest else {
fatalError("创建音频缓存失败")
}
//结果报告
recognitionRequest.shouldReportPartialResults = true
//开启授权任务
recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
var isFinal = false
if result != nil {
self.textView.text = result?.bestTranscription.formattedString
isFinal = (result?.isFinal)!
}
if error != nil || isFinal {
self.audioEngine.stop()
inputNode.removeTap(onBus: 0)
self.recognitionRequest = nil
self.recognitionTask = nil
self.speakerBtn.isEnabled = true
}
})
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
self.recognitionRequest?.append(buffer)
}
audioEngine.prepare()
do {
try audioEngine.start()
} catch {
print("audioEngine couldn't start because of an error.")
}
}
}
检查 recognitionTask 的运行状态,如果正在运行,取消任务。
创建一个 AVAudioSession 对象为音频录制做准备。这里我们将录音分类设置为 Record,模式设为 Measurement,然后启动。注意,设置这些属性有可能会抛出异常,因此你必须将其置于 try catch 语句中。
实例化 recognitionResquest。创建 SFSpeechAudioBufferRecognitionRequest 对象,然后我们就可以利用它将音频数据传输到 Apple 的服务器。
检查 audioEngine (你的设备)是否支持音频输入以录音。如果不支持,报一个 fatal error。
检查 recognitionRequest 对象是否已被实例化,并且值不为 nil。
告诉 recognitionRequest 不要等到录音完成才发送请求,而是在用户说话时一部分一部分发送语音识别数据。
在调用 speechRecognizer 的 recognitionTask 函数时开始识别。该函数有一个完成回调函数,每次识别引擎收到输入时都会调用它,在修改当前识别结果,亦或是取消或停止时,返回一个最终记录。
定义一个 boolean 变量来表示识别是否已结束。
倘若结果非空,则设置 textView.text 属性为结果中的最佳记录。同时若为最终结果,将 isFinal 置为 true。
如果请求没有错误或已经收到最终结果,停止 audioEngine (音频输入),recognitionRequest 和 recognitionTask。同时,将开始录音按钮的状态切换为可用。
向 recognitionRequest 添加一个音频输入。值得留意的是,在 recognitionTask 启动后再添加音频输入完全没有问题。Speech 框架会在添加了音频输入之后立即开始识别任务。
将 audioEngine 设为准备就绪状态,并启动引擎。
触发语音识别
在创建语音识别任务时,我们首先得确保语音识别的可用性,需要实现delegate 方法。如果语音识别不可用,或是改变了状态,应随之设置 按钮的enable ,我们通过扩展来实现代理
// MARK: - *** delegate ***
//这个方法会在按钮的可用性改变时被调用。如果语音识别可用,录音按钮也将被启用。
extension ViewController: SFSpeechRecognizerDelegate{
func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
if available {
speakerBtn.isEnabled = true
} else {
speakerBtn.isEnabled = false
}
}
}
最后,我们还需要更新一下 按钮的点击方法:
@IBAction func speakAction(_ sender: Any) {
if audioEngine.isRunning {
audioEngine.stop()
recognitionRequest?.endAudio()
speakerBtn.isEnabled = false
speakerBtn.setTitle("开始说话", for: .normal)
} else {
startRecording()
speakerBtn.setTitle("说完了", for: .normal)
}
}
Apple忠告
确保使用语音之别之前,通过UI界面告知用户
在涉及密码或者敏感信息时,请勿使用
在你操作识别结果之前,请先把结果展示给用户
Apple 对每台设备的识别有限制。详情未知,不过你可以尝试联系 Apple 获得更多信息。
Apple 对每个应用的识别也有限制。
如果你总是遭遇限制,务必联系 Apple,他们或许可以解决这个问题。
语音识别会消耗不少电量和流量。
语音识别每次只能持续大概一分钟。
欢迎打赏 点赞,收藏,关注博主
iOS 10 的 Speech 框架实现语音识别 (Swift)相关推荐
- iOS 10中不推荐使用UILocalNotification(UILocalNotification is deprecated in iOS 10)
It may be a question in advance but I wonder what to use instead of UILocalNotification in iOS 10. I ...
- 支持防骚扰的iOS 10来了,网络电话成受益者
今天,苹果正式推送iOS 10.作为第十代iOS,这次更新让人眼花缭乱:更强大的通知栏.更智能的Siri.更好玩的iMessage.更聪明的照片应用.作为第十代iOS,iOS 10前所未有的开放,部分 ...
- iOS 10来了!迎来黄金赛道的网络电话拼什么?
今天,苹果正式推送iOS 10.作为第十代iOS,这次更新让人眼花缭乱:更强大的通知栏.更智能的Siri.更好玩的iMessage.更聪明的照片应用.作为第十代iOS,iOS 10前所未有的开放,部分 ...
- iOS 语音识别,语音转文字的实现(Speech 框架的使用)
闲来无聊翻看苹果官方文档的时候看到一个 Speech 框架 ,之前并没有接触过这个框架,看了一下这个框架其实不大,于是决定研究一下. Speech API可让我们扩展和增强应用程序中的语音识别体验,而 ...
- iOS 10 SceneKit 新特性 – SceneKit 制作 3D 场景框架
来源:scauos(@大朕东) 链接:http://www.jianshu.com/p/b30785bb6c97 开头语: 今天的主题是探索iOS10 SceneKit的新功能,你可以观看今年WWDC ...
- 活久见的重构 - iOS 10 UserNotifications 框架解析
2019独角兽企业重金招聘Python工程师标准>>> TL;DR iOS 10 中以前杂乱的和通知相关的 API 都被统一了,现在开发者可以使用独立的 UserNotificati ...
- ios swift请求框架_使用Swift在iOS中创建二进制框架
ios swift请求框架 We all use a lot of frameworks in our daily development routine. We just type the magi ...
- 使用 Swift 在 iOS 10 中集成 Siri —— SiriKit 教程
使用 Swift 在 iOS 10 中集成 Siri -- SiriKit 教程 转载地址:http://swift.gg/2016/06/28/adding-siri-to-ios-10-apps- ...
- 使用 Swift 在 iOS 10 中集成 Siri —— SiriKit 教程(Part 1)
作者:Jameson Quave,原文链接,原文日期:2016-06-14 译者:Crystal Sun:校对:Cee:定稿:Channe 这篇教程写于 2016 年 6 月 13 日,使用 Xcod ...
最新文章
- python3+opencv生成不规则黑白mask
- c语言 临时文件作用,c语言函数mktemp()产生唯一临时文件名实例源码介绍
- 复现经典:《统计学习方法》第22章 无监督学习方法总结
- 活动执行手册_1-200家门店,标准化不等于手册!而是标准+训练+督导,缺一不可!...
- “十步一杀” 干掉你的职场压力
- DirectX 基础学习系列5 纹理映射
- 如何最快速的找到页面某一元素所绑定的点击事件,并查看js代码
- 分布式定时任务调度框架
- Ubuntu 18.04实现实时显示网速
- c语言知识点总结300字,大二学年自我总结300字 .doc
- CAD2006提示没有足够的权限来安装此产品
- MCU裸系统下快速平方根实现
- HTML5页面跳转的几种方法
- php自定义文件后缀名,显示文件扩展名 显示文件后缀名设置篇-DIV CSS网页开发准备...
- MATLAB 求解定积分和不定积分
- ZZULIOJ 1149: 组合三位数之二
- [埋坑系列] 基于QT/C++的杰瑞走迷宫小游戏 :1.大体构造
- HFSS学习笔记 21 扫频分析
- 2022年起重机司机(限桥式起重机)理论题库及答案
- 第8章 Drupal 主题系统( Drupal theme)(3) 模板文件