iOS 10 语音识别Speech Framework详解
最近做了一个项目,涉及到语音识别,使用的是iOS的speech Framework框架,在网上搜了很多资料,也看了很多博客,但介绍的不是很详细,正好项目做完,在这里给大家详解一下speech Framework的运用,使用的语言是Swift,文章结尾会给OC语言的网址,可以参照。
首先要做的准备,将开发的app版本设置为iOS 10,这是苹果在iOS 10 发布出来的时候新增的内容,低于这版本用不了,同时运行的设备系统也得保持在iOS 10 及以上。
废话不多说,先上代码。
语音识别需要用户给予权限,在info.plist文件中增加两个key:
NSMicrophoneUsageDescription
- 这个 key 用于指定录音设备授权信息。注意,只有在用户点击麦克风按钮时,这条信息才会显示。NSSpeechRecognitionUsageDescription
- 这个 key 用于指定语音识别授权信息。
这里就不做UI了,将机制写出来,大家可以根据自己的需要完善 。
import UIKit
import Speech // 引用的框架是Speech,需要遵循的协议有两个
class ViewController: UIViewController ,SFSpeechRecognizerDelegate, SFSpeechRecognitionTaskDelegate {
// 语音识别对象,这里直接给出识别语言(中文)
private let speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier: "zh_CN"))!
// 识别请求
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
// 识别任务
private var recognitionTask: SFSpeechRecognitionTask?
// 设备音频
private let audioSession = AVAudioSession.sharedInstance()
// 声音输入引擎
private let audioEngine = AVAudioEngine()
// 麦克风按钮是否可点,取决于用户权限
private var micButtonEnabled = false
// 语音识别结果
private var recordResult:String = ""
// 说话间隔时间
private var timer:Timer! override func viewDidLoad() {
super.viewDidLoad() speechRecognizer.delegate = self // 语音识别权限请求
SFSpeechRecognizer.requestAuthorization { (authStatus) in
switch authStatus {
case .authorized:
// 通过授权
self.micButtonEnabled = true
break
case .denied:
// 拒绝授权
self.micButtonEnabled = false
break
case .restricted:
// 权限受限制
self.micButtonEnabled = false
break
case .notDetermined:
// 权限不明确
self.micButtonEnabled = false
break
}
}
} // 这里就会出现一个问题,比如说用户同意了语音识别权限,麦克风按钮可点,返回桌面进入设置,找到本应用,关闭语音识别权限,然后再进入app,发现麦克风按钮还是可点的,这就尴尬啦,所以页面出现时还要判断当前权限
override func viewWillAppear(_ animated: Bool) {
// 获取当前语音识别权限
AVAudioSession.sharedInstance().requestRecordPermission { (permiss:Bool) in
self.micButtonEnabled = permiss
}
} // 开始语音识别(这是我们自己写的方法,在麦克风按钮事件中调用这个函数)
func startRecording(){
// 判断音声引擎是否在运行
if !audioEngine.isRunning {
recordResult = "" // 接收识别结果的String赋为空
recording()
}
} // 语音识别终止
func stopRecording(){
if (recognitionRequest != nil) {
recognitionRequest?.endAudio()
}
} // 语音识别详细内容
func recording() {
// 判断目前有无识别任务,取消之前所有任务
if recognitionTask != nil {
recognitionTask?.cancel()
recognitionTask = nil
}
do {
// 设置设备音频
try audioSession.setCategory(AVAudioSessionCategoryRecord) // 将音频设置为录音
try audioSession.setMode(AVAudioSessionModeMeasurement)
try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
} catch {
print("audioSession properties weren't set because of an error.")
}
// 初始化识别请求
recognitionRequest = SFSpeechAudioBufferRecognitionRequest() guard let inputNode = audioEngine.inputNode else {
fatalError("Audio engine has no input node")
} guard let recognitionRequest = recognitionRequest else {
fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
}
recognitionRequest.shouldReportPartialResults = true
// 登机语音识别任务
recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest, delegate: self) // 麦克风获取语音片断
let recordingFormat = inputNode.outputFormat(forBus: ) // 追加后续输入的语音
inputNode.installTap(onBus: , bufferSize: , 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.")
}
} /******* 以下都是代理方法 *******/ // 判断当前是否连接网络
func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
// 这里有两点不足,1:只有关闭或打开网络的操作时这个函数才执行,如果我一直不改变网络状态,这个函数等于没用。假设我点击语音按钮时判断available是否为true,false时弹出alert提示没网,那么设备没联网的状态下打开app且不改变网络状态,点击语音按钮就不会提示,这就需要程序员自己判断了。2:这个函数判断不了当前连接的网络是否有效,比如连了一个无效的wifi,available还是为true
} // 录音过程中获取到声音
func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didHypothesizeTranscription transcription: SFTranscription) {
// 这个代理方法非常重要,录音过程中检测到声音就会执行,比如说了话之后让他自动结束语音,就可以在此加上计时器timer。
if(timer != nil && timer.isValid){
timer.invalidate()
timer = nil
}
timer = Timer.scheduledTimer(withTimeInterval: , repeats: true, block: { (Timer) in
self.stopRecording()
})
//只要在说话,计时器就不会走,停止说话计时器开始走,停止2两秒不说话,则录音就会自动结束开始识别成文本,时间可以自己设置
} // 开始识别语音
func speechRecognitionTaskFinishedReadingAudio(_ task: SFSpeechRecognitionTask) {
// 将声音转成文字,这个函数里面可以什么都不用写
} // 录音结束之后的识别处理
func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishRecognition recognitionResult: SFSpeechRecognitionResult) {
print(recognitionResult) // 输出的是一个数组,里面是所有识别出来的结果
recordResult = recognitionResult.bestTranscription.formattedString // 获取最优的结果,这里看情况,不一定是你需要的那个,也可以做一个tableView,让用户自己选结果
} // 语音转文本结束
func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishSuccessfully successfully: Bool) {
// 语音识别结束后,在这里释放对象
audioEngine.stop()
audioEngine.inputNode?.removeTap(onBus: )
self.recognitionRequest = nil
self.recognitionTask = nil
do {
// 添加这个代码是因为涉及到文本转语音的需求。语音识别会让音频处于录音状态,这个时候要朗读文本的话根本没有声音,所以需要添加这个设置。
try audioSession.setCategory(AVAudioSessionCategoryAmbient)
}catch let error as NSError{
print(error.code)
}
if(timer != nil){
timer.invalidate()
timer = nil
}
// 在这里,大家拿到了recordResult,就可以做想做的事啦
}
}
这是比较完整的代理方法,网上还有另一种方法,我就直接复制粘贴过来了:
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 {
print("audioSession properties weren't set because of an error.")
} recognitionRequest = SFSpeechAudioBufferRecognitionRequest() guard let inputNode = audioEngine.inputNode else {
fatalError("Audio engine has no input node")
} guard let recognitionRequest = recognitionRequest else {
fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
} 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: ) self.recognitionRequest = nil
self.recognitionTask = nil self.microphoneButton.isEnabled = true
}
}) let recordingFormat = inputNode.outputFormat(forBus: )
inputNode.installTap(onBus: , bufferSize: , 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.")
} textView.text = "Say something, I'm listening!" }
两种方法之间识别结果都是一样的,但第二种方法比较死板,无法设置自动结束语音,适应不了更多需求。
以上就是我对Speech Framework的个人理解,希望对广大同行有所帮助。
最后再贴一个OC版本的连接,别人写的,也是第一种方法,可以一起参考一下:https://my.oschina.net/u/2340880/blog/751442
iOS 10 语音识别Speech Framework详解的更多相关文章
- iOS 开发之照片框架详解之二 —— PhotoKit 详解(下)
本文链接:http://kayosite.com/ios-development-and-detail-of-photo-framework-part-three.html 这里接着前文<iOS ...
- iOS 开发之照片框架详解
转载自:http://kayosite.com/ios-development-and-detail-of-photo-framework.html 一. 概要 在 iOS 设备中,照片和视频是相当重 ...
- iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)
转载自:http://kayosite.com/ios-development-and-detail-of-photo-framework-part-two.html 一. 概况 本文接着 iOS 开 ...
- iOS百度地图简单使用详解
iOS百度地图简单使用详解 百度地图 iOS SDK是一套基于iOS 5.0及以上版本设备的应用程序接口,不仅提供展示地图的基本接口,还提供POI检索.路径规划.地图标注.离线地图.定位.周边雷达等丰 ...
- iOS 视图控制器转场详解
iOS 视图控制器转场详解 前言的前言 唐巧前辈在微信公众号「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各项指标有了大幅度的增长,多谢唐巧前辈的推荐.有些人问我相关的问题 ...
- iOS 开发之照片框架详解(2)
一. 概况 本文接着 iOS 开发之照片框架详解,侧重介绍在前文中简单介绍过的 PhotoKit 及其与 ALAssetLibrary 的差异,以及如何基于 PhotoKit 与 AlAssetLib ...
- IOS数据库操作SQLite3使用详解(转)
iPhone中支持通过sqlite3来访问iPhone本地的数据库.具体使用方法如下1:添加开发包libsqlite3.0.dylib首先是设置项目文件,在项目中添加iPhone版的sqlite3的数 ...
- 《iOS 7 应用开发实战详解》
<iOS 7 应用开发实战详解> 基本信息 作者: 朱元波 管蕾 出版社:人民邮电出版社 ISBN:9787115343697 上架时间:2014-4-25 出版日期:2014 年5 ...
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
随机推荐
- WKWebView的使用与JS交互详细解读
前言: WKWebView 这是在iOS8.0之后增加的一个比UIWebView更加完善和强大的控件!看网上关于它的博客也是有许多的了,从各个方面总结一下这个WKWebView看网上说它主要是为了和J ...
- 网易云直播SDK使用总结
前言: 最近公司的项目中加入中直播这部分的功能,现在的直播平台真的很多很多,以前在朋友圈看到过这张图片,没办法一次性给大家看,就只能这样截成几张给大家看看.其实按照我自己的看法,现在的直播已经没办法做 ...
- [Kafka] - Kafka 安装介绍
Kafka是由LinkedIn公司开发的,之后贡献给Apache基金会,成为Apache的一个顶级项目,开发语言为Scala.提供了各种不同语言的API,具体参考Kafka的cwiki页面: Kafk ...
- TCP协议详解
TCP协议详解 一.TCP协议 1.TCP 通过以下方式提供可靠性: · ◆ 应用程序分割为TCP认为最合适发送的数据块.由TCP传递给IP的信息单位叫做报文段. · ◆ 当TCP发出一个报文段后 ...
- Debug和Release区别
VC下Debug和Release区别 最近写代码过程中,发现 Debug 下运行正常,Release 下就会出现问题,百思不得其解,而Release 下又无法进行调试,于是只能采用printf方式逐步 ...
- [Linux] PHP程序员玩转Linux系列-搭建代码开发环境
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 有些同学可能觉得我写的都是啥yum安装的,随便配置一下而已,没啥技术含量,我的目的 ...
- path和classpath的用途
1 path很明显是unix shell的环境变量,比如bash shell,输入一个命令,它会先去path指定的目录下查找是不是有该命令的可执行文件. 2 -classpath 只是用在下面这种不发 ...
- 归纳篇(一)CSS的position定位和float浮动
近期会更新一系列博客,对基础知识再度做个巩固和梳理. 一.position定位 (一):position的属性 1.absolute:生成绝对定位的元素,相对于最近一级定位不是static的父元素来进 ...
- 使用Bootstrap + Vue.js实现 添加删除数据
界面首先需要引入bootstrap的css和bootstrap的js文件,还有vue.js和jQuery.js才可以看见效果. 这里提供bootstrap的在线文件给大家引用: <!-- 最新版 ...
- http服务搭建
http服务器搭建 主配置文件在 /etc/httpd/conf/httpd.conf 安装http yum install httpd -y 启动http服务器 systemctl start ...