最近才發(fā)現(xiàn)惭嚣,其實系統(tǒng)已經(jīng)提供了語音轉成文字的API,于是立馬去試了一下缺亮。結果發(fā)現(xiàn)很不錯翁涤,速度也還可以。支持iOS10級以上的版本萌踱,需要麥克風權限和語音識別權限葵礼。下面來看看如何達到效果(沒有深入的理解,但是可以用了)并鸵。
一鸳粉、引入系統(tǒng)庫
import Speech
二、主要的類
-
SFSpeechRecognizer
聲音處理器
langugeSimple 要語音識別的語言簡稱园担,具體有哪些可以看上一篇語音閱讀
SFSpeechRecognizer(locale: Locale(identifier: langugeSimple))
這句會根據(jù)傳入的語言簡稱來返回一個聲音處理器届谈,如果不支持,怎會返回nil弯汰。更多細節(jié)可以查看官方文檔艰山。
通過下面的方法來得到語音識別的結果
// Recognize speech utterance with a request
// If request.shouldReportPartialResults is true, result handler will be called
// repeatedly with partial results, then finally with a final result or an error.
open func recognitionTask(with request: SFSpeechRecognitionRequest, resultHandler: @escaping (SFSpeechRecognitionResult?, Error?) -> Void) -> SFSpeechRecognitionTask
-
AVAudioEngine
專門用來處理聲音的數(shù)據(jù)
這里細節(jié)不在介紹了,直接上使用的代碼
lazy var audioEngine: AVAudioEngine = {
let audioEngine = AVAudioEngine()
audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: audioEngine.inputNode.outputFormat(forBus: 0)) { (buffer, audioTime) in
// 為語音識別請求對象添加一個AudioPCMBuffer咏闪,來獲取聲音數(shù)據(jù)
self.recognitionRequest.append(buffer)
}
return audioEngine
}()
-
SFSpeechAudioBufferRecognitionRequest
語音識別器
// 語音識別器
lazy var recognitionRequest: SFSpeechAudioBufferRecognitionRequest = {
let recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
return recognitionRequest
}()
-
SFSpeechRecognitionTask
語言識別任務管理器曙搬,啟用和關閉都要使用這個管理進行
public enum SFSpeechRecognitionTaskState : Int {
case starting // Speech processing (potentially including recording) has not yet begun
case running // Speech processing (potentially including recording) is running
case finishing // No more audio is being recorded, but more recognition results may arrive
case canceling // No more recognition reuslts will arrive, but recording may not have stopped yet
case completed // No more results will arrive, and recording is stopped.
}
二、完整的代碼
import UIKit
import Speech
enum LGSpeechType: Int {
case start
case stop
case finished
case authDenied
}
typealias LGSpeechBlock = (_ speechType: LGSpeechType, _ finalText: String?) -> Void
@available(iOS 10.0, *)
class LGSpeechManager: NSObject {
private var parentVc: UIViewController!
private var speechTask: SFSpeechRecognitionTask?
// 聲音處理器
private var speechRecognizer: SFSpeechRecognizer?
static let share = LGSpeechManager()
private var block: LGSpeechBlock?
// 語音識別器
lazy var recognitionRequest: SFSpeechAudioBufferRecognitionRequest = {
let recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
return recognitionRequest
}()
lazy var audioEngine: AVAudioEngine = {
let audioEngine = AVAudioEngine()
audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: audioEngine.inputNode.outputFormat(forBus: 0)) { (buffer, audioTime) in
// 為語音識別請求對象添加一個AudioPCMBuffer鸽嫂,來獲取聲音數(shù)據(jù)
self.recognitionRequest.append(buffer)
}
return audioEngine
}()
func lg_startSpeech(speechVc: UIViewController, langugeSimple: String, speechBlock: @escaping LGSpeechBlock) {
parentVc = speechVc
block = speechBlock
lg_checkmicroPhoneAuthorization { (microStatus) in
if microStatus {
self.lg_checkRecognizerAuthorization(recongStatus: { (recStatus) in
if recStatus {
// 初始化語音處理器的輸入模式 語音處理器準備就緒(會為一些audioEngine啟動時所必須的資源開辟內(nèi)存)
self.audioEngine.prepare()
if (self.speechTask?.state == .running) { // 如果當前進程狀態(tài)是進行中
// 停止語音識別
self.lg_stopDictating()
} else { // 進程狀態(tài)不在進行中
self.speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: langugeSimple))
guard (self.speechRecognizer != nil) else {
self.showAlert("抱歉织鲸,暫不支持當前地區(qū)使用語音輸入")
return
}
self.lg_setCallBack(type: .start, text: nil)
// 開啟語音識別
self.lg_startDictating()
}
} else {
self.showAlert("您已取消授權使用語音識別,如果需要使用語音識別功能溪胶,可以到設置中重新開啟搂擦!")
self.lg_setCallBack(type: .authDenied, text: nil)
}
})
} else {
//麥克風沒有授權
self.showAlert("您已取消授權使用麥克風,如果需要使用語音識別功能哗脖,可以到設置中重新開啟瀑踢!")
self.lg_setCallBack(type: .authDenied, text: nil)
}
}
}
}
@available(iOS 10.0, *)
extension LGSpeechManager: SFSpeechRecognitionTaskDelegate {
//判斷語音識別權限
private func lg_checkRecognizerAuthorization(recongStatus: @escaping (_ resType: Bool) -> Void) {
let authorStatus = SFSpeechRecognizer.authorizationStatus()
if authorStatus == .authorized {
recongStatus(true)
} else if authorStatus == .notDetermined {
SFSpeechRecognizer.requestAuthorization { (status) in
if status == .authorized {
recongStatus(true)
} else {
recongStatus(false )
}
}
} else {
recongStatus(false)
}
}
//檢測麥克風
private func lg_checkmicroPhoneAuthorization(authoStatus: @escaping (_ resultStatus: Bool) -> Void) {
let microPhoneStatus = AVCaptureDevice.authorizationStatus(for: .audio)
if microPhoneStatus == .authorized {
authoStatus(true)
} else if microPhoneStatus == .notDetermined {
AVCaptureDevice.requestAccess(for: .audio, completionHandler: {(res) in
if res {
authoStatus(true)
} else {
authoStatus(false)
}
})
} else {
authoStatus(false)
}
}
//開始進行
private func lg_startDictating() {
do {
try audioEngine.start()
speechTask = speechRecognizer!.recognitionTask(with: recognitionRequest) { (speechResult, error) in
// 識別結果,識別后的操作
if speechResult == nil {
return
}
self.lg_setCallBack(type: .finished, text: speechResult!.bestTranscription.formattedString)
}
} catch {
print(error)
self.lg_setCallBack(type: .finished, text: nil)
}
}
// 停止聲音處理器才避,停止語音識別請求進程
func lg_stopDictating() {
lg_setCallBack(type: .stop, text: nil)
audioEngine.stop()
recognitionRequest.endAudio()
speechTask?.cancel()
}
private func lg_setCallBack(type: LGSpeechType, text: String?) {
if block != nil {
block!(type, text)
}
}
private func showAlert(_ message: String) {
let alertVC = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let firstAction = UIAlertAction(title: "知道了", style: .default, handler: {(action) in
})
alertVC.addAction(firstAction)
parentVc.present(alertVC, animated: true, completion: nil)
}
}