Fix race condition with the player queue

This commit is contained in:
ronaldheft 2022-08-31 23:15:25 -04:00
parent defd895995
commit 6257c6488b

View file

@ -195,36 +195,48 @@ class AudioPlayer: NSObject {
private func setupQueueItemStatusObserver() { private func setupQueueItemStatusObserver() {
self.queueItemStatusObserver?.invalidate() self.queueItemStatusObserver?.invalidate()
self.queueItemStatusObserver = self.audioPlayer.currentItem?.observe(\.status, options: [.new, .old], changeHandler: { (playerItem, change) in let status = self.audioPlayer.currentItem?.status.rawValue ?? -1
guard let playbackSession = self.getPlaybackSession() else {
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.failed.rawValue), object: nil) NSLog("queueStatusObserver: Setting up status=\(status)")
return // First item already loaded, we need to fire manually
} if status == 1, let playerItem = self.audioPlayer.currentItem {
if (playerItem.status == .readyToPlay) { self.handleQueueItemStatus(playerItem: playerItem)
NSLog("queueStatusObserver: Current Item Ready to play. PlayWhenReady: \(self.playWhenReady)") }
self.updateNowPlaying() // Now listen for future updates
self.queueItemStatusObserver = self.audioPlayer.currentItem?.observe(\.status, options: [.new, .old], changeHandler: { playerItem, change in
// Seek the player before initializing, so a currentTime of 0 does not appear in MediaProgress / session self.handleQueueItemStatus(playerItem: playerItem)
let firstReady = self.status < 0
if firstReady || self.playWhenReady {
self.seek(playbackSession.currentTime, from: "queueItemStatusObserver")
}
// Mark the player as ready
self.status = 0
// Start the player, if requested
if self.playWhenReady {
self.playWhenReady = false
self.play()
}
} else if (playerItem.status == .failed) {
NSLog("queueStatusObserver: FAILED \(playerItem.error?.localizedDescription ?? "")")
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.failed.rawValue), object: nil)
}
}) })
} }
private func handleQueueItemStatus(playerItem: AVPlayerItem) {
NSLog("queueStatusObserver: Current item status changed")
guard let playbackSession = self.getPlaybackSession() else {
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.failed.rawValue), object: nil)
return
}
if (playerItem.status == .readyToPlay) {
NSLog("queueStatusObserver: Current Item Ready to play. PlayWhenReady: \(self.playWhenReady)")
// Seek the player before initializing, so a currentTime of 0 does not appear in MediaProgress / session
let firstReady = self.status < 0
if firstReady || self.playWhenReady {
self.seek(playbackSession.currentTime, from: "queueItemStatusObserver")
}
// Mark the player as ready
self.status = 0
// Start the player, if requested
if self.playWhenReady {
self.playWhenReady = false
self.play()
}
} else if (playerItem.status == .failed) {
NSLog("queueStatusObserver: FAILED \(playerItem.error?.localizedDescription ?? "")")
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.failed.rawValue), object: nil)
}
}
private func startPausedTimer() { private func startPausedTimer() {
guard self.pausedTimer == nil else { return } guard self.pausedTimer == nil else { return }
self.queue.async { self.queue.async {