Keypath Archives — Now Playing Apps Let's build it together Sat, 21 Mar 2020 15:33:12 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.1 151952093 How to get media duration from your iOS video player (AVPlayer) https://nowplayingapps.com/how-to-get-media-duration-from-your-ios-video-player-avplayer/ Fri, 28 Sep 2018 19:20:33 +0000 https://nowplayingapps.com/?p=60 Building a video player to stream content is absolutely amazing, however your customer experience is only as good as how accurate the information that is presented to them. I have had challenges putting accurate data in front of the user, and here is how overcame this challenge when using AVPlayer in iOS apps.

The post How to get media duration from your iOS video player (AVPlayer) appeared first on Now Playing Apps.

]]>
Building a video player to stream content is absolutely amazing, however, your customer experience is only as good as how accurate the information that is presented to them. I have had challenges putting accurate data in front of the user, and here is how I overcame this challenge when using AVPlayer in iOS apps.

The problem

If you are developing a custom video player skin, chances you have to somehow show the overall duration of the current playing media. And using AVPlayerItem’s duration is the best way of doing this. And this is how duration is accessed.

(lldb) po playerItem!.duration.seconds
nan

However, when done this way after we start playing, we get this “nan” 🙁

What the… NaN

The problem here is we are trying to access the duration before AVPlayer gets a chance to download the content (or manifest if using a streaming protocol like HLS). And the solution is to wait for the right time.

So, when’s the right time?

Simple answer. When the content is ready. Or otherwise when AVPlayerItem.Status.readyToPlay. Let’s see it in code

let streamURL = "http://184.72.239.149/vod/smil:BigBuckBunny.smil/playlist.m3u8"
playerItem = AVPlayerItem(url: URL(string: streamURL)!)
player = AVPlayer(playerItem: playerItem)
        
playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.old, .new], context: nil)

and then observing like this:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    
    if keyPath == #keyPath(AVPlayerItem.status), let statusNumber = change?[.newKey] as? NSNumber {
        
        switch statusNumber.intValue {
        case AVPlayerItem.Status.readyToPlay.rawValue:
            let durationInSeconds = playerItem?.asset.duration.seconds ?? 0
            print("Ready to play. Duration (in seconds): \(durationInSeconds)")
        default: break
        }
    }
}

When you take this approach, make sure to remove the observer when you close the player or change playerItem inside the player

playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status))

It’s easier with Swift 4

With Swift 4, listening to changes like these are even easier. This is how:

observation = playerItem?.observe(\AVPlayerItem.status, changeHandler: { observedPlayerItem, change in
    if (observedPlayerItem.status == AVPlayerItem.Status.readyToPlay) {
        print("Current stream duration \(observedPlayerItem.duration.seconds)")
    }
})

It is easy to remove this observer, just assign it to nil. Here’s the link to the WWDC video

And that’s it! Happy streaming.

The post How to get media duration from your iOS video player (AVPlayer) appeared first on Now Playing Apps.

]]>
60