3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Swift5】AVSpeechSynthesizerとSFSpeechRecognizerを併用する際の注意点

Posted at

概要

iOSでは標準で音声合成と音声認識の機能を利用することが可能です。

  • 音声合成: AVSpeechSynthesizer
  • 音声認識: SFSpeechRecognizer

音声合成と音声認識を併用するケースはそこまで多くないと思いますが、一緒に利用する場合はハマりポイントがあるのでこの記事でメモします。

想定するケース

音声認識後に何らかの文字列を音声読み上げする場合を考えます。
イメージしやすいように、音声認識をして取得した結果を読み上げるだけのアプリを想定します。

  1. 音声認識を行い、話しかけられたテキストを取得する
  2. 取得した結果を音声で読み上げる

音声認識

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

情報が錯綜しているので不安はあるものの、同様の事象で悩まれている方の参考になれば幸いです。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?