2

再生が終了したらコールバックを送信する AVAudioPlayerNode オブジェクトがあります。そのコールバックはアプリ内の他の多くの関数をトリガーし、そのうちの 1 つが礼儀の stop() メッセージを送信します。何らかの理由で、AVAudioPlayerNode が終了した瞬間に stop() を呼び出すと、クラッシュが発生します。ここのコードでは、(アプリケーション全体を含めるのではなく) 効果を示すために AVAudioPlayerNode がただちに stop を呼び出すように省略しています。崩れているのがよくわかります。理由がわかりません。a) ノードがまだ再生中で、stop() がノードを停止するか、b) 再生が終了し、stop を無視できるかのいずれかです。

私の推測では、これはファイル バッファの最後にあるエッジ ケースであり、バッファが残っていないあいまいな状態にありますが、技術的にはまだ再生中です。おそらく、stop() を呼び出して残りのバッファをフラッシュしようとして、それらが空になるのでしょうか?

func testAVAudioPlayerNode(){
    let testBundle = Bundle(for: type(of: self))
    let url = URL(fileURLWithPath: testBundle.path(forResource: "19_lyrics_1", ofType: "m4a")!)
    let player = AVAudioPlayerNode()
    let engine = AVAudioEngine()
    let format = engine.mainMixerNode.outputFormat(forBus: 0)
    engine.attach(player)
    engine.connect(player, to: engine.mainMixerNode, format: format)
    let delegate = FakePlayMonitorDelegate()
    do {
        let audioFile = try AVAudioFile(forReading: url)
        let length = audioFile.length
        player.scheduleFile(audioFile, at: nil, completionCallbackType: AVAudioPlayerNodeCompletionCallbackType.dataPlayedBack, completionHandler: {(completionType) in
            print("playing = \(player.isPlaying)")
            player.stop()
        })
        try engine.start()
        let expectation = self.expectation(description: "playback")
        delegate.expectation = expectation
        player.play()
        self.waitForExpectations(timeout: 6.0, handler: nil)
    } catch {

    }
}
4

1 に答える 1

2

私の場合、メインスレッドからメソッドを呼び出すと.stop()(別のものを使用できます)、問題が解決しました。

DispatchQueue.main.async {
    player.stop()
}

デッドロックになる可能性があります。completionHandlerは、シリアル キューであるバックグラウンド キューから呼び出されることに気付きました。これを「レンダリング キュー」と呼びましょう。メソッド.stop()は「レンダリング キュー」で何らかの作業を行おうとしているようですが、現時点では「レンダリング キュー」はcompletionHandler.

デッドロックのスクリーンショット

于 2021-01-21T16:16:41.710 に答える