I want to detect if my AVPlayer is buffering for the current location, so that I can show a loader or something. But I can\'t seem to find anything in the documentation for
Updated for Swift 4.2
var player : AVPlayer? = nil
let videoUrl = URL(string: "https://wolverine.raywenderlich.com/content/ios/tutorials/video_streaming/foxVillage.mp4")
self.player = AVPlayer(url: videoUrl!)
self.player?.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 600), queue: DispatchQueue.main, using: { time in
if self.player?.currentItem?.status == AVPlayerItem.Status.readyToPlay {
if let isPlaybackLikelyToKeepUp = self.player?.currentItem?.isPlaybackLikelyToKeepUp {
//do what ever you want with isPlaybackLikelyToKeepUp value, for example, show or hide a activity indicator.
//MBProgressHUD.hide(for: self.view, animated: true)
}
}
})
The accepted answer didn't work for me, I used the code below to show the loader efficiently.
Swift 3
//properties
var observer:Any!
var player:AVPlayer!
self.observer = self.player.addPeriodicTimeObserver(forInterval: CMTimeMake(1, 600), queue: DispatchQueue.main) {
[weak self] time in
if self?.player.currentItem?.status == AVPlayerItemStatus.readyToPlay {
if let isPlaybackLikelyToKeepUp = self?.player.currentItem?.isPlaybackLikelyToKeepUp {
//do what ever you want with isPlaybackLikelyToKeepUp value, for example, show or hide a activity indicator.
}
}
}
Swift 4 observations:
var playerItem: AVPlayerItem?
var playbackLikelyToKeepUpKeyPathObserver: NSKeyValueObservation?
var playbackBufferEmptyObserver: NSKeyValueObservation?
var playbackBufferFullObserver: NSKeyValueObservation?
private func observeBuffering() {
let playbackBufferEmptyKeyPath = \AVPlayerItem.playbackBufferEmpty
playbackBufferEmptyObserver = playerItem?.observe(playbackBufferEmptyKeyPath, options: [.new]) { [weak self] (_, _) in
// show buffering
}
let playbackLikelyToKeepUpKeyPath = \AVPlayerItem.playbackLikelyToKeepUp
playbackLikelyToKeepUpKeyPathObserver = playerItem?.observe(playbackLikelyToKeepUpKeyPath, options: [.new]) { [weak self] (_, _) in
// hide buffering
}
let playbackBufferFullKeyPath = \AVPlayerItem.playbackBufferFull
playbackBufferFullObserver = playerItem?.observe(playbackBufferFullKeyPath, options: [.new]) { [weak self] (_, _) in
// hide buffering
}
}
Observers need to be removed after we are done observing.
To remove these three observers just set playbackBufferEmptyObserver
, playbackLikelyToKeepUpKeyPathObserver
and playbackBufferFullObserver
to nil
.
No need to remove them manually (this is specific for observe<Value>(_ keyPath:, options:, changeHandler:)
method.
Solution for Xamarin inspired by Marco's answer
// KVO registrations
private void Initialize()
{
playbackBufferEmptyObserver?.Dispose();
playbackBufferEmptyObserver = (NSObject)playerItem.AddObserver("playbackBufferEmpty",
NSKeyValueObservingOptions.New,
AVPlayerItem_BufferUpdated);
playbackLikelyToKeepUpObserver?.Dispose();
playbackLikelyToKeepUpObserver = (NSObject)playerItem.AddObserver("playbackLikelyToKeepUp",
NSKeyValueObservingOptions.New,
AVPlayerItem_BufferUpdated);
playbackBufferFullObserver?.Dispose();
playbackBufferFullObserver = (NSObject)playerItem.AddObserver("playbackBufferFull",
NSKeyValueObservingOptions.New,
AVPlayerItem_BufferUpdated);
}
private void AVPlayerItem_BufferUpdated(NSObservedChange e)
{
ReportVideoBuffering();
}
private void ReportVideoBuffering()
{
// currentPlayerItem is the current AVPlayerItem of AVPlayer
var isBuffering = !currentPlayerItem.PlaybackLikelyToKeepUp;
// NOTE don't make "buffering" as one of your PlayerState.
// Treat it as a separate property instead. Learned this the hard way.
Buffering?.Invoke(this, new BufferingEventArgs(isBuffering));
}