iosarraysswiftavaudioplayeravqueueplayer

How to play a list of songs after pressing a button just once in Swift


I know how to make to play a single song play when you press a button on the screen but not an array of songs where one song automatically plays after a song finishes until all songs in the array are played.

Someone mentioned on using AVQueuePlayer but countless of us don't know how to implement. Can you guys provide a good sample code on how to use it?

I followed the code in this video to make a single song play when you tap a button - https://www.youtube.com/watch?v=2kflmGGMBOA

var myQueuePlayer: AVQueuePlayer?
var avItems: [AVPlayerItem] = []

func audio () {

    var items: [String] = ["one", "two", "three", "four", "five"]
    items.shuffle()

    for clip in items {
        guard let url = Bundle.main.url(forResource: clip, withExtension: ".mp3") else {
            // mp3 file not found in bundle - so crash!
            fatalError("Could not load \(clip).mp3")
        }
        avItems.append(AVPlayerItem(url: url))
        //button.isHidden = true
    }

}


@IBAction func didTapButton() {

    audio()
    if myQueuePlayer == nil {

        // instantiate the AVQueuePlayer with all avItems
        myQueuePlayer = AVQueuePlayer(items: avItems)
        print("pup1")
        print(myQueuePlayer!.rate)

    } else {

        // stop the player and remove all avItems
        myQueuePlayer?.removeAllItems()
        // add all avItems back to the player
        avItems.forEach {
                myQueuePlayer?.insert($0, after: nil)
            }

    }
    // seek to .zero (in case we added items back in)
    myQueuePlayer?.seek(to: .zero)
    // start playing
    myQueuePlayer?.play()

}

Solution

  • You really should have had no trouble finding this on your own, but here's a very simple example:

    import AVFoundation
    
    class TestAVQueuViewController: UIViewController {
    
        var myQueuePlayer: AVQueuePlayer?
        var avItems: [AVPlayerItem] = []
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // assuming I have 4 .mp3 files in the bundle, named:
            let mySongs: [String] = [
                "clip1", "clip2", "clip3", "clip4",
            ]
    
            for clip in mySongs {
                guard let url = Bundle.main.url(forResource: clip, withExtension: ".mp3") else {
                    // mp3 file not found in bundle - so crash!
                    fatalError("Could not load \(clip).mp3")
                }
                avItems.append(AVPlayerItem(url: url))
            }
    
        }
    
        @IBAction func didTap(_ sender: Any) {
            // if first time
            if myQueuePlayer == nil {
                // instantiate the AVQueuePlayer with all avItems
                myQueuePlayer = AVQueuePlayer(items: avItems)
            } else {
                // stop the player and remove all avItems
                myQueuePlayer?.removeAllItems()
                // add all avItems back to the player
                avItems.forEach {
                    myQueuePlayer?.insert($0, after: nil)
                }
            }
            // seek to .zero (in case we added items back in)
            myQueuePlayer?.seek(to: .zero)
            // start playing
            myQueuePlayer?.play()
        }
    
    }
    

    Edit

    Updated code to demonstrate playing clips on button tap, and re-starting the clips on further button taps.