Search code examples
iosswiftavfoundationavqueueplayer

How to add new items to AVQueuePlayer currently playing with old items


Adding New Items To AVQueuePlayer Doesn't Play

I have scenarios where I'm streaming HLS audios from server. Initially I make an Array of AVPlayerItem. And initialise the AVQueuePlayer, And on button clicks it plays initial items very fine. But down the road when half of my items finishes playing I am trying to add more items at the end of list which doesn't play.

class ViewController: UIViewController, AVAudioPlayerDelegate{

let baseUrl = "********"

var player: AVQueuePlayer?
var items: [AVPlayerItem] = [];

let controller = AVPlayerViewController()

var counter = 0;

override func viewDidLoad() {
    super.viewDidLoad()
    
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(animationDidFinish(_:)),
                                           name: .AVPlayerItemDidPlayToEndTime,
                                           object: player?.items())
}

override func viewDidAppear(_ animated: Bool) {
    queueMaker()
}

@IBAction func btnTapped(_ sender: UIButton) {

    let player = AVQueuePlayer(items: self.items)
    let playerLayer = AVPlayerLayer(player: player)
    self.view.layer.addSublayer(playerLayer)
    player.play()    
}

@objc func animationDidFinish(_ notification: NSNotification) {
    print("HLS : AVQueuePlayer Item Finished Playing")
    counter += 1
    if ((items.count) - counter) < 4 {
        print("HLS : Adding More Items")
        addMoreItemsToQueue()
    }
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

func queueMaker() {
    
    let listOfAyahs: [String] = ["1/1.m3u8","2/2.m3u8","3/3.m3u8","4/4.m3u8","5/5.m3u8","6/6.m3u8","7/7.m3u8"]
    
    for item in listOfAyahs {
        let stringUrl = "\(self.baseUrl)\(item)"
        let url = URL(string: stringUrl)
        let item = AVPlayerItem(url: url!)
        items.append(item)
    }
}


func addMoreItemsToQueue() {
    
    let listOfAyahs: [String] = ["8/8.m3u8","9/9.m3u8","10/10.m3u8","11/11.m3u8","12/12.m3u8","13/13.m3u8","14/14.m3u8"]

    for item in listOfAyahs {
        let stringUrl = "\(self.baseUrl)\(item)"
        let url = URL(string: stringUrl)
        let item = AVPlayerItem(url: url!)
        items.append(item)
    }
  }
}    

Solution

  • You are initialising a AVQuePlayer with some items which is the base copy for the AVQuePlayer and later you are appending new AVPlayerItems to your items array, about which the AVQuePlayer is not aware of. So, update the following to function and it should work.

    @IBAction func btnTapped(_ sender: UIButton) {
        // UPDATE THE PLAYER's SCOPE TO GLOBAL
        player = AVQueuePlayer(items: self.items)
        let playerLayer = AVPlayerLayer(player: player)
        self.view.layer.addSublayer(playerLayer)
        player?.play()
    }
    

    And add replace insert items to the queue like this

    func addMoreItemsToQueue() {
    
      let listOfAyahs: [String] = ["8/8.m3u8","9/9.m3u8","10/10.m3u8","11/11.m3u8","12/12.m3u8","13/13.m3u8","14/14.m3u8"]
    
      var lastItem = self.player?.items().last
      for item in listOfAyahs {
            let stringUrl = "\(self.baseUrl)\(item)"
            let url = URL(string: stringUrl)
            let item = AVPlayerItem(url: url!)
            self.player?.insert(item, after: lastItem)
            lastItem = item
        }
    }
    

    Try and share the results.