Why is AVPlayer not continuing to next song while in background?

一笑奈何 提交于 2019-12-06 12:43:40

问题


I have been streaming music from remote source using AVPlayer. I get URLs, use one to create an AVPlayerItem, which i then associate with my instance of AVPlayer. I add an observer to the item that I associate with the player to observe when the item finishes playing ( AVPlayerItemDidPlayToEndTimeNotification ). When the observer notifies me at the item end, I then create a new AVPlayerItem and do it all over again. This works well in the foreground AND in the background on iOS 9.2.

Problem: Since I have updated to iOS 9.3 this does not work in the background. Here is the relevant code:

var portionToBurffer = Double()
var player = AVPlayer()


func prepareAudioPlayer(songNSURL: NSURL, portionOfSongToBuffer: Double){

   self.portionToBuffer = portionOfSongToBuffer

   //create AVPlayerItem
   let createdItem = AVPlayerItem(URL: songNSURL)

   //Associate createdItem with AVPlayer
   player = AVPlayer(playerItem: createdItem)

   //Add item end observer
   NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: player.currentItem)

   //Use KVO to see how much is loaded
   player.currentItem?.addObserver(self, forKeyPath: "loadedTimeRanges", options: .New, context: nil)

}


override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "loadedTimeRanges" {
    if let loadedRangeAsNSValueArray = player.currentItem?.loadedTimeRanges {
        let loadedRangeAsCMTimeRange = loadedRangeAsNSValueArray[0].CMTimeRangeValue
        let endPointLoaded = CMTimeRangeGetEnd(loadedRangeAsCMTimeRange)
        let secondsLoaded = CMTimeGetSeconds(endPointLoaded)
        print("the endPointLoaded is \(secondsLoaded) and the duration is \(CMTimeGetSeconds((player.currentItem?.duration)!))")


        if secondsLoaded >= portionToBuffer  {
            player.currentItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
            player.play()
        }
    }
}
}



 func playerItemDidReachEnd(notification: NSNotification){
     recievedItemEndNotification()
 }





func recievedItemEndNotification() {
   //register background task
   bgTasker.registerBackgroundTask()

   if session.playlistSongIndex == session.playlistSongTitles.count-1 {
       session.playlistSongIndex = 0
   } else {
       session.playlistSongIndex += 1
   }

     prepareAudioPlayer(songURL: session.songURLs[session.playlistSongIndex], portionOfSongToBuffer: 30.00)

  }

I have set breakpoints to see that player.play() IS being called when in the background. When i print player.rate it reads 0.0. I have checked the property playbackLikelyToKeepUp of the AVPlayerItem and it is true. I have confirmed also that the new URL is successfully used to create the new AVPlayerItem and associated with the AVPlayer when the app is in the background. I have turned audio and airplay background capabilities on and I have even opened up a finite length background task (in code above as bgTasker.registerBackgroundTask). No idea what is going on.

I found THIS but i'm not sure it helps. Any advice would be great, thanks


回答1:


When the observer notifies me at the item end, I then create a new AVPlayerItem and do it all over again

But the problem is that meanwhile play stops, and the rule is that background playing is permitted only so long as you were playing in the foreground and continue to play in the background.

I would suggest using AVQueuePlayer instead of AVPlayer. This will allow you to enqueue the next item while the current item is still playing — and thus, we may hope, this will count as continuing to play.




回答2:


I encountered the similar problem, and I searched lots of websites on google, but didn't find the answer.

The Phenomenon

The problem of my app is that when I start play an audio, and turn the app to background, it will finish the playing of the current audio, and when playing the second audio, it will load some data, but then it stopped, if I turn the app to foreground, it will play the audio.

Solution

My solution is to add the following call.

UIApplication.shared.beginReceivingRemoteControlEvents()

So enable background audio capabilities is not enough, we need to begin receiving remote controller events.



来源:https://stackoverflow.com/questions/36348332/why-is-avplayer-not-continuing-to-next-song-while-in-background

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!