Open1

iOS:AVAudioEngineのsetVoiceProcessingでエラーが発生する件

kabeyakabeya

iOSのAVAudioEngineを使って、マイク入力&音声合成でインとアウトの両方を使うアプリを作っています。

let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.playAndRecord, mode: .voiceChat)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)

こんな感じで、カテゴリを.playAndRecordにして、モードを.voiceChat(もしくは.videoChat)にするとマイク入力と、音声出力の両方ができます。

で、音声合成をAVSpeechSynthesizerで行う場合、AVAudioOutputNodesetVoiceProcessingEnabled(true)をすると、再生音量が大きくできるみたいなのです。
(ドキュメントとかに書いてあるわけではなく、やってみたら大きくなった)

これをやらないととても小さな声で再生するので聞き取れません。

class MyClass {
    private var audioEngine = AVAudioEngine()
    
    func doSomething() throws {
        let outputNode = self.audioEngine.outputNode
        try outputNode.setVoiceProcessingEnabled(true)
        // このあと何か音声合成する
    }
}

ですが、音が大きくなる反面、エラーをめちゃくちゃ出力するようになります。

throwing -1
  from AU (0x1068c61c0): auou/vpio/appl, render err: -1

このメッセージが実行中(AVAudioEngineがアクティブな間ずっと)Xcodeのログに出続けます。
(かつXcodeでデバッグ実行を止めると、このメッセージをどこかに出力しているのか、レインボーカーソルが回り続けて邪魔)

色々試したところ、ミキサーを追加してアウトプットに繋げばOKと分かりました。

    func doSomething() throws {
        let outputNode = self.audioEngine.outputNode
        try outputNode.setVoiceProcessingEnabled(true)

        let mainMixer = self.audioEngine.mainMixerNode
        let outputFormat = outputNode.outputFormat(forBus: 0)
        self.audioEngine.connect(mainMixer, to: outputNode, format: outputFormat)
        Thread.sleep(forTimeInterval: 1.0)
        // このあと何か音声合成する
    }

最後のsleepですが、これを入れないとタイミング依存か何かで、うまく行くときと行かないときがあります(1.0が良いかはちょっと分かっていません)。うまく行かないときはマイク入力ができません(出力もできないような気がしますが試してはいません)。

ちなみにconnectでインプットからミキサーに繋いでないのが気持ち悪い気もしますが、それをしたらマイク入力した音がアウトプットに出てくるので、今回の目的ではダメです。