iOS10语音识别框架Speech详解

一 、前言

语音识别技术已经成为人工智能应用的一个重点,通过语音控制设备简单方便,在各个领域兴起了研究应用的热潮。

目前语音识别在智能家居、智能车载、智能客服机器人方面有广泛的应用,未来将会深入到学习、生活、工作的各个环节。国内外许多大公司都在倾力研究此技术,并不断推出实际产品。

说起语音识别功能,不得不提的就是最为经典的苹果iPhone 4S,以及由这部里程碑式的作品开启的siri语音助手。也正是由此,语音识别的智能技术在市场上开始被越来越多的用户了解、接受,赢得了很多用户的喜爱。

在移动产品的应用上也越来越广,各种第三方语音识别SDK也是层出不穷,例如科大讯飞、百度语音等。很多国产手机搭载的语音智能识别助手,都使用了科大讯飞的技术支持。2017年,小米首次也搭上了AI交互、语音识别的车,推出了"小爱同学"。

本篇博客将主要探讨iOS10中新引入的SpeechFramework框架。有了这个框架,iOS开发者可以十分容易的为自己的App添加语音识别功能,不需要再依赖于其他第三方的语音识别服务,并且,Apple的Siri应用的强大也证明了Apple的语音服务是足够强大的,不通过第三方,也大大增强了用户的安全性。

SpeechFramework的文档地址: https://developer.apple.com/documentation/speech

demo地址:https://github.com/Xcoder1011/SpeechTest

image.png

二 、Speech

简介

Perform speech recognition on live or prerecorded audio, and receive transcriptions, alternative interpretations, and confidence levels of the results.

对现场或预先录制的音频执行语音识别,并接收结果的转录,可替代的解释和置信度。

使用语音框架识别录制或现场音频中的语音。键盘的听写支持使用语音识别将音频内容翻译成文本; 这个框架提供了类似的行为,当然,您可以使用语音识别来处理识别口头命令或处理应用程序其他部分的文本口述。

您可以使用多种语言执行语音识别,但每个对象都使用一种语言。某些语言可以使用设备语音识别,但该框架还依赖于Apple的语音识别服务器。始终假设执行语音识别需要网络连接。SFSpeechRecognizer

要启动语音识别过程,请执行以下操作:

  1. 请求授权使用语音识别。

  2. 创建一个识别器。SFSpeechRecognizer

  3. 使用语音识别器对象的属性验证服务的可用性。

  4. 准备您的音频内容。

  5. 创建一个识别请求对象。SFSpeechRecognitionRequest

  • 创建的识别请求对象的类型取决于您是处理现有音频文件还是传入音频流。
  • 对于音频文件:SFSpeechURLRecognitionRequest
  • 对于音频流:SFSpeechAudioBufferRecognitionRequest
  1. 调用recognitionTask(with:delegate:)方法或者recognitionTask(with:resultHandler:)方法 开始识别。

初识一些类的概念

SFSpeechRecognizer:这个类是语音识别的操作类,用于语音识别用户权限的申请,语言环境的设置,语音模式的设置以及向Apple服务发送语音识别的请求。

SFSpeechRecognitionTask:这个类是语音识别服务请求任务类,每一个语音识别请求都可以抽象为一个SFSpeechRecognitionTask实例,其中SFSpeechRecognitionTaskDelegate协议中约定了许多请求任务过程中的监听方法。

SFSpeechRecognitionRequest:语音识别请求类,需要通过其子类来进行实例化。

SFSpeechURLRecognitionRequest:通过音频URL来创建语音识别请求。

SFSpeechAudioBufferRecognitionRequest:通过音频流来创建语音识别请求。

SFSpeechRecognitionResult:语音识别请求结果类。

SFTranscription:语音转换后的信息类,已识别语音的文本表示。

SFTranscriptionSegment:整个假设转录的一部分,语音转换中的音频节点类。

必需步骤

1.请求语音识别权限

  • 请求用户允许使用Apple的服务器执行语音识别。

语音识别过程涉及捕获用户语音的音频并将该数据发送到Apple的服务器进行处理。您捕获的音频构成敏感的用户数据,您必须尽一切努力保护它。在将数据通过网络发送到Apple的服务器之前,您还必须获得用户的许可。您使用Speech框架的API请求授权。

  • 将隐私密钥添加到Info.plist文件中

In Xcode, add the “Privacy - Speech Recognition Usage Description” key to your app’s Info.plist file.

description: "The application uses speech recognition to help you chat easily."

  • 首次申请授权

在使用Speech框架的API之前,必须调用该对象。该方法异步执行并将结果传递给您提供的块。使用该块确定用户是授予还是拒绝您的请求。

注意: 如果您不打算立即使用该功能,请勿请求访问语音识别。相反,请延迟请求,直到用户与使用此类功能的应用部分进行交互。

func requestAuthorization() {
        
        SFSpeechRecognizer.requestAuthorization { (status) in
            
            OperationQueue.main.addOperation {
                
                var isSpeakBtnEnabled = false
                
                switch status {
                    
                case .authorized :
                    
                    isSpeakBtnEnabled = true
                    
                case .notDetermined :
                    
                    isSpeakBtnEnabled = false
                    
                    self.speakBtn.setTitle("语音识别还没有经授权", for: .disabled)
                    
                case .denied :
                    
                    isSpeakBtnEnabled = false
                    
                    self.speakBtn.setTitle("用户拒绝访问语音识别", for: .disabled)
                    
                case .restricted :
                    
                    isSpeakBtnEnabled = false
                    
                    self.speakBtn.setTitle("语音识别不支持此设备", for: .disabled)
                }
                
                self.speakBtn.isEnabled = isSpeakBtnEnabled
            }
        }
    }

2. 创建语音识别器:SFSpeechRecognizer

用于检查语音识别服务的可用性以及启动语音识别过程的对象。

是一种用于管理语音识别过程中的中心对象。使用此对象:SFSpeechRecognizer

SFSpeechRecognizer:这个类是语音识别的操作类,用于语音识别用户权限的申请,语言环境的设置,语音模式的设置以及向Apple服务发送语音识别的请求。

1) 创建支持语音识别的语言环境的识别器。

let recognizer = SFSpeechRecognizer.init(locale: Locale.init(identifier: "zh-CN"))

Local:语音识别器的语言环境。

SFSpeechRecognizer.supportedLocales()可支持的语言列表:

  for value in SFSpeechRecognizer.supportedLocales() {
      print(value.description)
 }

/////

th-TH (fixed)
ca-ES (fixed)
fr-BE (fixed)
de-CH (fixed)
sk-SK (fixed)
en-ZA (fixed)
es-CL (fixed)
hi-IN (fixed)
zh-CN (fixed)
zh-TW (fixed)
da-DK (fixed)
hi-IN-translit (fixed)
el-GR (fixed)
he-IL (fixed)
pt-BR (fixed)
en-AE (fixed)
pt-PT (fixed)
fr-CH (fixed)
ro-RO (fixed)
vi-VN (fixed)
en-SA (fixed)
pl-PL (fixed)
es-US (fixed)
hi-Latn (fixed)
en-SG (fixed)
tr-TR (fixed)
hr-HR (fixed)
ko-KR (fixed)
uk-UA (fixed)
it-CH (fixed)
ar-SA (fixed)
id-ID (fixed)
en-IN (fixed)
es-ES (fixed)
de-AT (fixed)
en-IE (fixed)
cs-CZ (fixed)
es-CO (fixed)
zh-HK (fixed)
sv-SE (fixed)
en-PH (fixed)
en-ID (fixed)
en-CA (fixed)
nl-NL (fixed)
yue-CN (fixed)
en-NZ (fixed)
en-GB (fixed)
ja-JP (fixed)
it-IT (fixed)
ru-RU (fixed)
en-US (fixed)
ms-MY (fixed)
es-MX (fixed)
hu-HU (fixed)
fr-CA (fixed)
wuu-CN (fixed)
de-DE (fixed)
fr-FR (fixed)
fi-FI (fixed)
nb-NO (fixed)
nl-BE (fixed)
en-AU (fixed)

2)监控语音识别服务的可用性:SFSpeechRecognizerDelegate

设置识别器的代理,isAvailable: 指示语音识别器当前是否可用。

    //MARK: SFSpeechRecognizerDelegate
    // 监控语音识别的可用性
    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
        print("availabilityDidChange = \(available)")
        if available { //available: 指示语音识别器当前是否可用。
            self.speakBtn.isEnabled = true
        } else {
            self.speakBtn.isEnabled = false
        }
    }

3)api解释:


    // 查看可支持的语言环境
    open class func supportedLocales() -> Set<Locale>

    // 返回您应用的当前授权以执行语音识别状态
    open class func authorizationStatus() -> SFSpeechRecognizerAuthorizationStatus

    // 请求语音识别权限
    open class func requestAuthorization(_ handler: @escaping (SFSpeechRecognizerAuthorizationStatus) -> Swift.Void)

    // 如果不支持语言环境,则返回nil
    public convenience init?()  

    // 表示所请求的语音识别的类型
    // 如果SFSpeechRecognitionRequest对象中也进行了设置 则会覆盖这里的值
    open var defaultTaskHint: SFSpeechRecognitionTaskHint
    
     // 通过请求识别语音话语
     // 执行语音识别请求并将结果传递到指定的处理程序块。
    open func recognitionTask(with request: SFSpeechRecognitionRequest, resultHandler: @escaping (SFSpeechRecognitionResult?, Error?) -> Swift.Void) -> SFSpeechRecognitionTask

      // 高级API:识别与指定请求关联的音频源的语音,使用指定的委托来管理结果
    open func recognitionTask(with request: SFSpeechRecognitionRequest, delegate: SFSpeechRecognitionTaskDelegate) -> SFSpeechRecognitionTask

    // 要在其上执行识别任务处理程序和委托方法的队列
    // 默认为主队列
    open var queue: OperationQueue

3. 创建语音识别请求:SFSpeechRecognitionRequest

SFSpeechAudioBufferRecognitionRequest:

使用该对象在实时音频或一组现有音频缓冲区上执行语音识别。例如,使用此请求对象将音频从设备的麦克风路由到语音识别器。SFSpeechAudioBufferRecognitionRequest

请求对象最初不包含音频。在捕获音频时,调用append(_:)或将音频样本添加到请求对象,语音识别器会持续分析您附加的音频,仅在您调用方法时停止。

@available(iOS 10.0, *)
open class SFSpeechRecognitionRequest : NSObject {

    // 表示正在执行的语音识别类型的值。
    open var taskHint: SFSpeechRecognitionTaskHint

    
    // 如果为true,将报告每个话语的部分(非最终)结果
    // 指示是否要为每个话语返回中间结果。
    open var shouldReportPartialResults: Bool

    
    // 应该识别的一组短语,即使它们不在系统词汇表中
    open var contextualStrings: [String]

    
    // 识别请求: 可用于由开发人员识别接收者的字符串
    // 用于描述与语音识别请求关联的交互类型的标识符字符串。
    open var interactionIdentifier: String?
}

// 请求识别录制的音频文件中的语音。

@available(iOS 10.0, *)
open class SFSpeechURLRecognitionRequest : SFSpeechRecognitionRequest {

    
     // 请求从给定URL的音频文件中转录语音。
    public init(url URL: URL)

    
    open var url: URL { get }
}

// 从捕获的音频内容识别语音的请求,例如来自设备麦克风的音频。

@available(iOS 10.0, *)
open class SFSpeechAudioBufferRecognitionRequest : SFSpeechRecognitionRequest {

    // 获取最佳语音识别的首选音频格式。 
    open var nativeAudioFormat: AVAudioFormat { get }

    // 将PCM格式的音频添加到识别请求的末尾。
    open func append(_ audioPCMBuffer: AVAudioPCMBuffer)
 
   //  将音频附加到识别请求的末尾。
    open func appendAudioSampleBuffer(_ sampleBuffer: CMSampleBuffer)

    // 标记识别请求的音频输入结束。
    open func endAudio()
}

4. 语音识别任务:SFSpeechRecognitionTask

用于监视语音识别进度的任务对象。

使用对象确定语音识别任务的状态,取消正在进行的任务或发出任务结束的信号。

open class SFSpeechRecognitionTask : NSObject {

    // 语音识别任务的当前状态
    open var state: SFSpeechRecognitionTaskState { get }

     // 指示任务停止接受新音频(例如停止录音),但对已经缓冲的音频进行完整处理。
     // 这对基于URL的识别请求没有影响,这会立即有效地缓冲整个文件。
    open func finish()

    // 取消当前的语音识别任务。
    open func cancel()

    // 指定语音识别任务期间发生的错误。
    open var error: Error? { get }
}
  • SFSpeechRecognitionTaskDelegate:

该协议的方法为您提供了对语音识别过程的细粒度控制。具体来说,如果您想了解以下内容,请使用此协议:

当第一个语音发音在音频中时。

当语音识别器停止接受音频时。

语音识别过程结束或取消时。

当语音识别器产生潜在的转录时。

public protocol SFSpeechRecognitionTaskDelegate : NSObjectProtocol {

    // 当任务首次检测到源音频中的语音时
    optional public func speechRecognitionDidDetectSpeech(_ task: SFSpeechRecognitionTask)

    
    // 告诉代表可以使用假设的转录。
    optional public func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didHypothesizeTranscription transcription: SFTranscription)

    
    // 仅为最终识别话语而调用。将不再报道关于话语的事件
    optional public func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishRecognition recognitionResult: SFSpeechRecognitionResult)

    
    // 当任务不再接受新的音频输入时,即使最终处理正在进行,也告诉代理
    optional public func speechRecognitionTaskFinishedReadingAudio(_ task: SFSpeechRecognitionTask)

    
    // 告诉代理该任务已被取消。
    optional public func speechRecognitionTaskWasCancelled(_ task: SFSpeechRecognitionTask)

    
    // 完成对所有请求的话语的识别。
    optional public func speechRecognitionTask(_ task: SFSpeechRecognitionTask, didFinishSuccessfully successfully: Bool)
}

5. 语音识别结果:SFSpeechRecognitionResult

语音识别结果对象包含transcriptions当前话语中的一个或多个。每个转录都有一个置信度,表明它是正确的可能性。(您也可以直接获得最高评级的转录。)bestTranscription

bestTranscription:具有最高置信水平的转录
transcriptions:一系列潜在的转录,按置信度的降序排序。
isFinal:指示语音识别是否完整以及转录是否为最终。

  • SFTranscription

公认演讲的文字表示。
formattedString:整个话语,格式化为单个用户可显示的字符串。
segments:一系列转录片段,代表假设转录的部分

  • SFTranscriptionSegment

整个假设转录的一部分.

open class SFTranscriptionSegment : NSObject, NSCopying, NSSecureCoding {

   //  该转录片段中话语的字符串表示。
    open var substring: String { get }

  // 该转录片段子串的范围信息
    open var substringRange: NSRange { get }

    // 处理的音频流中段的开始时间
    open var timestamp: TimeInterval { get }

    // 用户说出段所代表的单词所花费的秒数,从话语的开头开始计算
    open var duration: TimeInterval { get }
    
    // 对该转录片段的识别准确性的置信水平 (0~1.0)
    open var confidence: Float { get }
    
    // 该转录片段中话语的一系列替代解释
    open var alternativeSubstrings: [String] { get }
}

三、Tips

  • Category:
  1. 只有简单音乐播放功能: AVAudioSessionCategoryPlayback
  2. 只是播放音乐,而不需要独占锁屏界面时,
try audioSession.setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)
  1. 常规录音: AVAudioSessionCategoryRecord
  2. 录音和播放同时进行时 : AVAudioSessionCategoryPlayAndRecord
  • AVAudioEngine:

    • 管理所有的音频节点(audio nodes)
    • 连接所有的音频节点使其运作形成链条(active chains)
    • 动态的获取(attach)和配置所有音频的节点。
    • 开启和停止API

  1. 有多种node,负责实现不同的功能,而AVAudioEngine在运行中可以自由组合、拆卸node,node经由它们各自的输入被连接到下一级的输出,从而可以灵活实现想要的效果
  2. AVAudioEngine实例化后默认有三个node,分别为inputNode、outputNode,这两个node不可以被detach,还有一个可选的mainMixerNode(混音)。
  3. inputNode、outputNode分别对应硬件的麦克风和扬声器,需要检查其采样率和声道数,若采样率为0,则不可用。

四 、总结

  • 处理由语音识别限制引起的故障:语音识别是基于网络的服务,单个设备可能在每天可以执行的识别数量方面受到限制,并且每个应用程序可能会根据其每天发出的请求数量进行全局限制。
  • 一分钟的音频持续时间限制:语音识别对电池寿命和网络使用造成相对较高的负担。为了最大限度地减轻这种负担,该框架会停止持续时间超过一分钟的语音识别任务 此限制类似于与键盘相关的听写限制。
  • 不要对私人或敏感信息进行语音识别:不要发送密码,健康或财务数据以及其他敏感语音进行识别。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容