3

出力デバイスのサンプル レートに基づいて生成される任意のトーンを再生する必要があります。音声を聞くには、有線または無線のヘッドフォンを接続する必要があります。

最新のヘッドフォンは 44100 または 48000 のネイティブ サンプル レートを持つことができるためAVAudioPlayerNode、別のAVAudioFormat. 何もしなくても、オーディオが歪んで聞こえ始めます。ただし、、、、またはをしようとすると、さまざまなデッドロックに直面していattachます。ヘッドフォンを初めて切り替えようとすると実行がロックされることがあります(同時に2つのヘッドフォンが接続されており、SRが44100の汎用ヘッドセットとSRが48000のAirpodsがあります)、まれに、2番目にフリーズします試す。detachconnectdisconnectNodeOutput

これが私のコードです:

private let engine = AVAudioEngine()

private let audioUnit = MyAudioUnit()

init() {
    let audioSession = AVAudioSession.sharedInstance()
    let sampleRate = audioSession.sampleRate
    format = AVAudioFormat(
        commonFormat: .pcmFormatFloat32,
        sampleRate: sampleRate,
        channels: AVAudioChannelCount(audioSession.outputNumberOfChannels),
        interleaved: false
    )!

    engine.attach(audioUnit)
    engine.connect(
        audioUnit,
        to: engine.mainMixerNode,
        format: format
    )

    NotificationCenter.default.addObserver(
        self,
        selector: #selector(self.handleInterruption),
        name: Notification.Name.AVAudioEngineConfigurationChange,
        object: engine
    )
}

@objc
private func handleInterruption(_ notification: Notification) {
    DispatchQueue.main.async {
        let audioSession = AVAudioSession.sharedInstance()
        let sampleRate = audioSession.sampleRate
        self.format = AVAudioFormat(
            commonFormat: .pcmFormatFloat32,
            sampleRate: sampleRate,
            channels: AVAudioChannelCount(audioSession.outputNumberOfChannels),
            interleaved: false
        )!

        self.engine.detach(self.audioUnit)
        self.engine.attach(self.audioUnit)
        self.engine.connect(
            self.audioUnit,
            to: self.engine.mainMixerNode,
            format: self.format
        )
    }
}

// method called on main thread only
// BTW, using audioUnit.stop() instead of pause() would also introduce a deadlock
func setActive(_ active: Bool) {
    ...

    if active {
        try! engine.start()
        audioUnit.play()
    } else {
        audioUnit.pause()
        engine.stop()
        engine.reset()
    }
}

「再接続」するために多数のバリアントを試しましたAVAudioEngineが、それらはすべて次のデッドロックに陥りました。

ここに画像の説明を入力

ここに画像の説明を入力

バックグラウンドスレッドに残そうとしましたが、問題ありません。アプリがもう一度使用しようとするとすぐにAVAudioEngine、すべてが動かなくなります。

AVAudioPlayerNodeでは、サンプル レートを更新するためにを再接続する適切な方法はありますか? それとも、ヘッドフォンのネイティブ サンプル レートに依存せず、静的サンプル レートでオーディオ サウンドを正常に鳴らすことは可能でしょうか? 前もって感謝します!

4

1 に答える 1