在 2016 年的 WWDC 上,Apple 终于开放了语音识别 Speech Recognition API,那就是 Speech 框架。事实上,Siri 的语音识别正是由 Speech Kit 提供支持。超过50种语言获得支持、任何运行iOS10的设备都可用、加入用户授权使其更安全、可以转化音频文件和实时语音 。 现在阿里、腾讯、科大讯飞都有相关的语音识别框架、超过时长都会收费的、集成相关框架、调用相关api还是非常简单的,这里主要讲的是iOS自带语音识别框架Speech的使用。
iOS语音识别步骤
录音和语音识别都是用户的隐私权限,所以需要用户授权打开麦克风(实时语音)和音频识别权限,所以要在info.plist文件中添加相关key:(Privacy - Microphone Usage Description、Privacy - Speech Recognition Usage Description)
<key>NSMicrophoneUsageDescription</key><string>App需要您的同意,才能访问麦克风</string><key>NSSpeechRecognitionUsageDescription</key><string>App需要您的同意,才能使用语音识别技术</string>
override func viewDidLoad() {super.viewDidLoad()//获取用户权限SFSpeechRecognizer.requestAuthorization { (authStatus : SFSpeechRecognizerAuthorizationStatus) inDispatchQueue.main.async(execute: {switch authStatus {case .notDetermined:self.titleL.text = "语音识别未授权"breakcase .denied:self.titleL.text = "用户未授权使用语音识别"breakcase .restricted:self.titleL.text = "语音识别在这台设备上受到限制"breakcase .authorized:self.titleL.text = "可以开始录音了"self.btnClickEnabled = truebreak}})}}
本地音频文件识别
比如像微信支付宝一些搜索框中就是先录音,然后再识别音频文件转为文字进行搜索,这个相对用的比较多。关于录音上篇文章已经写过了,这里不再赘述。这里主要讲录音后的音频文件如何识别。 本地语音文件识别还是很简单的,获取音频文件路径url,通过这个url录音创建识别请求对象,音频识别对象通过该请求去执行识别任务后即可获得识别后的文字。 具体相关代码:
//本地语音文件识别(录音后,识别录音文件)@IBAction func leftBtnClick(_ sender: UIButton) {let local = NSLocale(localeIdentifier: "zh_CN")//获取本地录音文件路劲let url = Bundle.main.url(forResource: "recordAudio.wav", withExtension: nil)if url == nil {return}let localRecognizer = SFSpeechRecognizer(locale: local as Locale)!let rqs = SFSpeechURLRecognitionRequest(url: url!)
// recordUrl = [NSURL URLWithString:[NSTemporaryDirectory() stringByAppendingString:@"selfRecord.pcm"]]localRecognizer.recognitionTask(with: rqs) { (result, error) inif (error != nil) {print("语音识别解析失败,%@",error!);}else{self.titleL.text = result!.bestTranscription.formattedString}}}
实时语音识别
实时语音识别就像Siri一样可以变说话边转文字,类似于语言同步翻译,虽然一遍的开发中用到的很少,但还是有必要了解一下。实时语音需要开启麦克风,所以需要不能用模拟器测试。 实时语音识别需要用到音频引擎这个关键类AVAudioEngine
,用于生成和处理音频信号并执行音频输入和输出,功能十分强大。 具体相关代码:
//初始化一些成员变量
class ViewController: UIViewController {var btnClickEnabled = false//按钮是否可以点击var speechRecognizer : SFSpeechRecognizer?//音频识别器var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?//对象用于处理语音识别请求,为语音识别提供音频输入var recognitionTask : SFSpeechRecognitionTask? //可以将识别请求的结果返回给你,它带来了极大的便利,必要时,可以取消或停止任务。lazy var audioEngine = AVAudioEngine()// 音频引擎 用于进行音频输入}//初始化语音识别对象
override func viewDidLoad() {super.viewDidLoad()//用于apple语言识别的变量speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-CN"))speechRecognizer?.delegate = (self as SFSpeechRecognizerDelegate);}//开始录音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 : AVAudioInputNode = audioEngine.inputNode else {fatalError("音频引擎 没有输入节点")}guard let recognitionRequest = recognitionRequest else {fatalError("创建音频缓存失败")}//结果报告recognitionRequest.shouldReportPartialResults = true//开启授权任务recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) invar isFinal = falseguard result == nil else {self.titleL.text = result?.bestTranscription.formattedString//判断语言是否处理完成isFinal = (result?.isFinal)!return}guard error == nil && isFinal == false else{// 停止声音处理器引擎self.audioEngine.stop()inputNode.removeTap(onBus: 0)//停止语音识别请求进程self.recognitionRequest?.endAudio()self.recognitionRequest = nilself.recognitionTask?.cancel()self.recognitionTask = nil//按钮可以点击self.btnClickEnabled = truereturn}})// 初始化语音处理器的输入模式let recordingFormat = inputNode.outputFormat(forBus: 0)inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in// 为语音识别请求对象添加一个AudioPCMBuffer,来获取声音数据self.recognitionRequest?.append(buffer)}// 语音处理器准备就绪(会为一些audioEngine启动时所必须的资源开辟内存)audioEngine.prepare()do {//启动识别try audioEngine.start()} catch {print("audioEngine couldn't start because of an error.")}}//停止录音func endRecording(){audioEngine.stop()recognitionRequest?.endAudio()}//语音实时识别
extension UIViewController : SFSpeechRecognizerDelegate{//当语音识别器的可用性发生更改时通知代理。如果语音识别可用,录音按钮也将被启用。public func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {if available {btnClickEnabled = true} else {btnClickEnabled = false}}
}//按钮点击事件控制@IBAction func rightBtnClick(_ sender: UIButton) {if btnClickEnabled {if audioEngine.isRunning {//结束语言识别endRecording()sender.setTitle("开始语言识别", for: .normal)} else {self.titleL.text = ""startRecording()sender.setTitle("结束语言识别", for: .normal)}}}
Apple忠告: 确保使用语音之别之前,通过UI界面告知用户 在涉及密码或者敏感信息时,请勿使用 在你操作识别结果之前,请先把结果展示给用户 Apple 对每台设备的识别有限制。详情未知,不过你可以尝试联系 Apple 获得更多信息 Apple 对每个应用的识别也有限制 如果你总是遭遇限制,务必联系 Apple,他们或许可以解决这个问题 语音识别会消耗不少电量和流量 语音识别每次只能持续大概一分钟
相关demo : iOS语音识别 参考:wwdc2016/Speech Recognition API