I'm building a music player in my iOS app, using AVPlayer
. I listen to changes for the AVPlayer.status
property like this, to know when audio is ready to be played:
player.currentItem!.addObserver(self, forKeyPath: "status", options: .New, context: nil)
And when the status is .ReadyToPlay
I automatically start playback:
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if (keyPath == "status") {
if let currentItem = self.player?.currentItem {
let status = currentItem.status
if (status == .ReadyToPlay) {
self.play()
}
}
}
}
}
Works great. The problem, however, is that if I start playing music in my app, pause the music and then leave the app and start playing music in, for example, Spotify, the AVPlayer
's status property seems to be changed to .ReadyToPlay
again the next time my app comes to the foreground, which causes the observer to fire, which in turn causes the music to start playing again.
I assume that something happens with the AVPlayer instance when the app gets focus again, which causes the status property to change/refresh.
How do I prevent this behaviour?
This seems like expected behavior. If you want to ensure that you only begin playback the first time the AVPlayerItem
status changes, remove the observer after calling play()
.
One caveat here is that you should already be removing the observer when the currentItem
is changed on the player, so you will need to use an additional flag to track whether you are observing the existing currentItem
.
The owner of the player would keep track of state
var isObservingCurrentItem = false
And update/check that state when you add the observer
if currentItem = player.currentItem where isObservingCurrentItem {
currentItem.removeObserver(self, forKeyPath:"status")
}
player.currentItem!.addObserver(self, forKeyPath: "status", options: .New, context: nil)
isObservingCurrentItem = true
Then you can safely remove the observer once the player is ready to play
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if let object = object,
keyPath = keyPath,
currentItem = self.player?.currentItem,
status = currentItem.status
where status == .ReadyToPlay {
self.play()
object.removeObserver(self, forKeyPath:keyPath)
isObservingCurrentItem = false
}
}