概要
iOSでは標準で音声合成と音声認識の機能を利用することが可能です。
- 音声合成: AVSpeechSynthesizer
- 音声認識: SFSpeechRecognizer
音声合成と音声認識を併用するケースはそこまで多くないと思いますが、一緒に利用する場合はハマりポイントがあるのでこの記事でメモします。
想定するケース
音声認識後に何らかの文字列を音声読み上げする場合を考えます。
イメージしやすいように、音声認識をして取得した結果を読み上げるだけのアプリを想定します。
- 音声認識を行い、話しかけられたテキストを取得する
- 取得した結果を音声で読み上げる
音声認識
iOSで標準利用可能なSFSpeechRecognizerを利用して音声認識をします。
※iOS10から利用可能
公式Doc
https://developer.apple.com/documentation/speech/sfspeechrecognizer
下記のような実装で音声認識が可能です。(最低限イメージが持てるよう、かなり省略したものを載せています。実装する方は公式Docをご参照ください。)
import UIKit
import AVFoundation
import Speech
class SampleViewController: UIViewController {
private var audioEngine: AVAudioEngine!
private var recognitionReq: SFSpeechAudioBufferRecognitionRequest?
private var recognitionTask: SFSpeechRecognitionTask?
private var recognizedText = ""
private let synthesizer = AVSpeechSynthesizer()
~~~~
private func startRec() throws {
~~~~
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
let inputNode = audioEngine.inputNode
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 2048, format: recordingFormat) { (buffer, time) in
recognitionReq.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
recognitionTask = recognizer.recognitionTask(with: recognitionReq, resultHandler: { (result, error) in
if let error = error {
~~~
} else {
print(result.bestTranscription.formattedString))
}
})
}
音声合成
AVSpeechSynthesizerの利用法はこちらの記事で紹介しています。
https://qiita.com/maKunugi/items/dc9da201a663c8773c8c
併用した場合のハマりポイント
音声認識直後にAVSpeechSynthesizerのspaekメソッドを使って読み上げをしようとすると下記のエラーが発生し、読み上げが行われません。
2020-09-24 20:33:33.228313+0900 xxxxxxx[10895:2365580] [AXTTSCommon] Failure starting audio queue \M-3<…>
解決方法
AVSpeechSynthesizerのspeakメソッドを利用する際は、audioSession.setCategoryを指定することで解決しました。
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
この問題についてハマった際、ネット上の記事を探していると同様の事象についてのやりとりがあります。
ex
https://developer.apple.com/forums/thread/88030
ただし、ネット上の情報だと、
AVAudioSession.Category.playAndRecord
を指定するとうまくいくと記述されている情報が多いですが、自分の環境だと、このCategoryを設定してしまうと読み上げの音量が極端に小さくなってしまうという挙動を確認しました。
※調べきれていないですが、OSのバージョンによって挙動が変わる可能性もあります。
※iOS13, 14では「playback」を指定することで正常に動作することを確認しました (XCode12)
音声認識後に音量が小さくなってしまう事象はこの記事でも登場しています。
https://stackoverflow.com/questions/40639660/swift-3-using-speech-recognition-and-avfoundation-together
情報が錯綜しているので不安はあるものの、同様の事象で悩まれている方の参考になれば幸いです。