-1

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()

}

1 Answers1

0

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.

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Thank You Don, really helpful! I put the code you put in viewDidAppear in the IBaction section of my button so that when a person clicks, they hear the list of songs. My trouble now is that when you click more than once, an error pops up "Exception NSException * "An AVPlayerItem cannot be associated with more than one instance of AVPlayer" 0x00006000024c1170", any recommendations? Sorry I'm not good with iOS, your help means the world to me. – Yumel Hernandez Jun 15 '20 at 18:37
  • @YumelHernandez - disable the button while your songs are playing. – DonMag Jun 15 '20 at 19:42
  • Thank you! I have a last question, I hope I'm not being annoying you are adding incredible value. After I do all of that, then the audio won't play more than once. So when a person clicks the button for a second+ time none of the songs play, I want the array of songs to play again if a person taps on the button again. How do I go about doing that? I tried a lot of methods including "myQueuePlayer?.seek(to: CMTime.zero)" but nothing. – Yumel Hernandez Jun 16 '20 at 00:41
  • @YumelHernandez - please take a moment to take the [tour]. Stack Overflow is not a "please write my code for me" site. Ask a question... if you get an answer, mark it "Accepted." If you have other questions, post new questions. Nobody can have any idea what you want to do, so asking "how do I do [this]" followed by "how do I do my next thing" followed by "how do I do my next thing" gets annoying, and folks will be less inclined to offer help. By the way, I have never used `AVQueuePlayer` -- this code was from simple, easy searching. – DonMag Jun 16 '20 at 02:30