Detect When iOS AVPlayer Finishes Buffering Using Swift
This is based on the article “Detect when audio playback begins with AVPlayer in iOS” we published back in 2014. Plenty has changed in the iOS SDK since then, but the general technique here still applies. We’ve updated the code to use Swift 3, and added a sample Xcode project you can download.
In the Call of the Land app, we have an animation timed to begin when audio playback starts. We use the iOS SDK AVFoundation framework AVPlayer for audio playback, so naturally our first instinct was to observe some property or notification on the AVPlayer object to start the animation.
The status property seemed a likely candidate, whose possible values are defined in the AVPlayerItemStatus enum:
public enum AVPlayerItemStatus : Int { case unknown case readyToPlay case failed }
The AVPlayerItemStatusReadyToPlay status seemed promising, but it did not take long to realize that being ready to play and actually playing are different. The “Ready to Play” state change happens before the audio is actually heard, and there can be a noticeable delay while the player initializes and buffers. Responding to the actual start of playback was going to require a different approach.
After a fair amount of research, and a whole bunch of experimentation, we came across the addBoundaryTimeObserver(forTimes:queue:using:) method on AVPlayer.
As per Apple’s documentation, this method
Requests invocation of a block when specified times are traversed during normal playback.
Not exactly an obvious solution, but we figured if we could set up a boundary time to execute a block at the start of playback – specifically after 1/3 of a second of playback – we’d have a way to start our animation in time with the audible playback:
let times = [NSValue(time:CMTimeMake(1,3))] _ = self.player.addBoundaryTimeObserver(forTimes: times, queue: DispatchQueue.main, using: { [weak self] time in self?.audioImage.startAnimating() })
Groovy!
Download our sample iOS AVPlayer audio animation Xcode project for a complete working Swift 3 example of how to detect when the iOS AVPlayer finishes buffering.