Player lifecycle
To create your project and initialize the player instance, see Creating the player.
Creating a player
There are several ways to create a player instance. You can:
- Create a player from a URL.
- Create a player from a player item initialized from a URL.
- Creating a player from a player item initialized from an OTVAVURLAsset.
- Create a player and set the player item
Attaching a player to UIView
Before playing a stream, the player must be attached to a UIView to get the audio and video rendered.
Playing a stream
Play a stream that has been set by calling:
player.play() /* https://developer.apple.com/documentation/avfoundation/avplayer/1386726-play */
or
player.rate = 1.0 /* https://developer.apple.com/documentation/avfoundation/avplayer/1388846-rate */
or
player.playImmediately(atRate: 1.0) /* https://developer.apple.com/documentation/avfoundation/avplayer/1643480-playimmediately */
Pausing a playback
Pause the playback by calling:
player.pause() /* https://developer.apple.com/documentation/avfoundation/avplayer/1387895-pause */
or
player.rate = 0.0 /* https://developer.apple.com/documentation/avfoundation/avplayer/1388846-rate */
Seeking through a playback stream
You can seek through a playback stream.
For more information, see the Apple document Seeking Through Media.
Observing the playback time
You can use the following code to observe the currentTime change and handle the UI about the time update in the closure.
// You need to retain the instance timeObserverToken to make sure the closure can be called.
timeObserverToken = player.addPeriodicTimeObserver(forInterval: time, queue: .main) {
[weak self] time in
// update player UI for time update
}
// You also need to remove the observer when it's not used:
player.removeTimeObserver(timeObserverToken)
timeObserverToken = nil
For more information, see the Apple document Observing the Playback Time.
Changing streams
The playback stream can be changed by calling:
let playerItem = OTVAVPlayerItem(url: assetURL)
player.replaceCurrentItem(with: playerItem)
Stopping playback
Playback can be stopped by calling:
player.replaceCurrentItem(with: nil)
Observing player errors using the OTVAVFoundationErrors notification
When OTVAVPlayer and OTVAVPlayerItem encounter an error when initiating or playing content it produces a notification using the "OTVAVFoundationErrors" notification.
/// Notification when OTVAVPlayer or OTVAVPlayerItem encounters an error.
/// which gives the statusCode, domain and message for the error encounted.
public let OTVAVFoundationErrors = Notification.Name("otvAVFoundationErrors")
There are two types of of OTVAVFoundationErrors which are encountered, OTVAVPlayer and OTVAVPlayerItem errors
/**
`OTVAVFoundationError` is an enum that represent they type of OTVAfoundation type either, OTVAVPlayer or OTVAVPlayerItem
*/
public enum OTVAVFoundationError: Int {
// AVPlayerError
case otvAVPlayer = 1101
// AVPlayerItemError
case otvAVPlayerItem = 1102
}
Listening to OTVAVFoundationErrors can be done by first registering to listen to the notification
NotificationCenter.default.addObserver(self, selector: #selector(opyPlayerErrorsReturned), name: OTVAVFoundationErrors, object: nil)
The user must then filter on the type of OTVAVFoundationError returned, which as mentioned above is either 'otvAVPlayer' or 'otvAVPlayerItem' and then using the information returned from the userInfo object of the notification. The userInfo object is a dictionary containing 3 keys, statusCode, domain and message.
@objc func opyPlayerErrorsReturned(_ notification: NSNotification) {
if let error = notification.object as? OTVAVFoundationError, let userInfo = notification.userInfo {
let statusCode = userInfo["statusCode"]
let domain = userInfo["domain"]
let messsage = userInfo["message"]
switch error {
case .otvAVPlayer:
print("OTVAVPlayer errror:: Status code = ", statusCode, " domain = ", domain, " message = ", messsage)
case .otvAVPlayerItem:
print("OTVAVPlayerItem errror:: Status code = ", statusCode, " domain = ", domain, " message = ", messsage)
@unknown default:
NSLog("Unexpected OPY error: \(error)")
}
}
}
In the case of otvAVPlayerItem errors, the errors returned are that of AVPlayerItem error codes returned during playback when the item fails to play or the item status changes to failed state.
Observing player errors using the AVPlayerItemNewErrorLogEntry notification
To listen to AVPlayerItemNewErrorLogEntry for the content being played is by creating a notification observer on 'AVPlayerItemNewErrorLogEntry' using the OTVAVPlayerItem of the content being played.
NotificationCenter.default.addObserver(self, selector: #selector(handleAVPlayerItemErrorLog),
name: NSNotification.Name.AVPlayerItemNewErrorLogEntry,
object: self.playerItem)
This notification is triggered every time the player item encounters a media error of any kind. You can filter on last error log event using the code below
private func latestPlayerItemErrorLogEvent() -> AVPlayerItemErrorLogEvent? {
guard let item = playerItem, let errorLog = item.errorLog() else {
return nil
}
return errorLog.events.last
}
An example of how to handle the information returned from the 'AVPlayerItemNewErrorLogEntry' notification. All errors returned through this notification are from AVFoundation only and they do not contain any OPYPlayback errors.
@objc func handleAVPlayerItemErrorLog(notification: Notification) {
if let statusCode = latestPlayerItemErrorLogEvent()?.errorStatusCode, let message = latestPlayerItemErrorLogEvent()?.errorComment, let domain = latestPlayerItemErrorLogEvent()?.errorDomain {
print("The status code is: ", statusCode, " the error domain is: ", domain, " the error message is: ", message)
}
}