Respond to changes in a player's playback state.
Framework
- AVFoundation
Overview
AVPlayer
and AVPlayer
are dynamic objects whose states change frequently. A simple way to observe and respond to these state changes is to use key-value observing (KVO). With KVO, an object can register to observe another object’s state. When the observed object’s state changes, the observer is notified with details of the state change. (For more information about KVO, see Key-Value Observing Programming Guide.)
Observe the Player's State
One of the most important AVPlayer
properties to observe is status
. This property indicates whether the player item is ready for playback and generally available for use. When you first create a player item, its status
value is AVPlayer
, meaning its media hasn’t been loaded or been enqueued for playback. When you associate a player item with AVPlayer
, it immediately begins enqueuing the item’s media and preparing it for playback. The player item becomes ready for use when the status
value changes to AVPlayer
. The following example shows how you can observe this state change:
let url: URL = // Asset URL
var asset: AVAsset!
var player: AVPlayer!
var playerItem: AVPlayerItem!
// Key-value observing context
private var playerItemContext = 0
let requiredAssetKeys = [
"playable",
"hasProtectedContent"
]
func prepareToPlay() {
// Create the asset to play
asset = AVAsset(url: url)
// Create a new AVPlayerItem with the asset and an
// array of asset keys to be automatically loaded
playerItem = AVPlayerItem(asset: asset,
automaticallyLoadedAssetKeys: requiredAssetKeys)
// Register as an observer of the player item's status property
playerItem.addObserver(self,
forKeyPath: #keyPath(AVPlayerItem.status),
options: [.old, .new],
context: &playerItemContext)
// Associate the player item with the player
player = AVPlayer(playerItem: playerItem)
}
The prepare
method registers to observe the player item’s status
property using the add
method. Call this method before associating the player item with the player to make sure you capture all state changes to the item’s status
.
Respond to a State Change
To be notified of state changes, you implement the observe
method. This method is invoked whenever the status
value changes, giving you the chance to take some action:
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
// Only handle observations for the playerItemContext
guard context == &playerItemContext else {
super.observeValue(forKeyPath: keyPath,
of: object,
change: change,
context: context)
return
}
if keyPath == #keyPath(AVPlayerItem.status) {
let status: AVPlayerItemStatus
if let statusNumber = change?[.newKey] as? NSNumber {
status = AVPlayerItemStatus(rawValue: statusNumber.intValue)!
} else {
status = .unknown
}
// Switch over status value
switch status {
case .readyToPlay:
// Player item is ready to play.
case .failed:
// Player item failed. See error.
case .unknown:
// Player item is not yet ready.
}
}
}
The example retrieves the new status
value from the change dictionary and switches over its value. If the player item’s status
value is AVPlayer
, then it’s ready for use. If a problem is encountered while attempting to load the player item’s media, the status
value is AVPlayer
. If a failure occurred, you can retrieve the NSError
object providing the details of the failure by querying the player item’s error
property.