How to play multiple Audio Files simultaneously using AVPlayer?

后端 未结 1 815
情歌与酒
情歌与酒 2020-12-17 07:20

I am trying to play multiple audio files using 2 AVPlayer instances, but one of the player stops for a fraction of a second rather than playing all audio files simultaneousl

相关标签:
1条回答
  • 2020-12-17 07:58

    You would be better off using AVAudioPlayerNode, AVAudioMixerNode, AVAudioEngine. Using these classes you won't have problems like you have right now. It's also not that difficult to set up.

    You can check out my gist, in order to play the sounds in your Playgrounds you would need to put audio files into Resources folder in Project Navigator: https://gist.github.com/standinga/24342d23acfe70dc08cbcc994895f32b

    The code works without stopping background audio when top sounds are triggered.

    Here's also the same code:

    import AVFoundation
    import PlaygroundSupport
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    class AudioPlayer {
    var backgroundAudioFile:AVAudioFile
    var topAudioFiles: [AVAudioFile] = []
    var engine:AVAudioEngine
    var backgroundAudioNode: AVAudioPlayerNode
    var topAudioAudioNodes = [AVAudioPlayerNode]()
    var mixer: AVAudioMixerNode
    var timer: Timer!
    var urls: [URL] = []
    
    init (_ url: URL, urls: [URL] = []) {
        backgroundAudioFile = try! AVAudioFile(forReading: url)
        topAudioFiles = urls.map { try! AVAudioFile(forReading: $0) }
    
        engine = AVAudioEngine()
        mixer = AVAudioMixerNode()
    
        engine.attach(mixer)
        engine.connect(mixer, to: engine.outputNode, format: nil)
        self.urls = urls
        backgroundAudioNode = AVAudioPlayerNode()
        for _ in topAudioFiles {
            topAudioAudioNodes += [AVAudioPlayerNode()]
        }
    }
    
    func start() {
        engine.attach(backgroundAudioNode)
        engine.connect(backgroundAudioNode, to: mixer, format: nil)
        backgroundAudioNode.scheduleFile(backgroundAudioFile, at: nil, completionHandler: nil)
    
        try! engine.start()
        backgroundAudioNode.play()
    
        for node in topAudioAudioNodes {
            engine.attach(node)
            engine.connect(node, to: mixer, format: nil)
            try! engine.start()
        }
    // simulate rescheduling files played on top of background audio
        DispatchQueue.global().async { [unowned self] in
            for i in 0..<1000 {
            sleep(2)
            let index = i % self.topAudioAudioNodes.count
            let node = self.topAudioAudioNodes[index]
            node.scheduleFile(self.topAudioFiles[index], at: nil, completionHandler: nil)
            node.play()
            }
        }
        }
    }
    
    let bundle = Bundle.main
    let beepLow = bundle.url(forResource: "beeplow", withExtension: "wav")!
    let beepMid = bundle.url(forResource: "beepmid", withExtension: "wav")!
    let backgroundAudio = bundle.url(forResource: "backgroundAudio", withExtension: "wav")!
    let audioPlayer = AudioPlayer(backgroundAudio, urls: [beepLow, beepMid])
    audioPlayer.start()
    
    0 讨论(0)
提交回复
热议问题