How can I check if my AVPlayer is buffering?
You can observe the values of your player.currentItem
:
playerItem.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .New, context: nil)
playerItem.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .New, context: nil)
playerItem.addObserver(self, forKeyPath: "playbackBufferFull", options: .New, context: nil)
then
override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if object is AVPlayerItem {
switch keyPath {
case "playbackBufferEmpty":
// Show loader
case "playbackLikelyToKeepUp":
// Hide loader
case "playbackBufferFull":
// Hide loader
}
}
}
Check AVPlayer buffering and playing state
This seems similar to a question I answered here: https://stackoverflow.com/a/42148482/5100819
The approach we used to update the UI when the AVPlayer finishes buffering and starts actual audible playback would likely do the job. We used a boundary time to execute a block at the start of playback – specifically after 1/3 of a second of playback – to update the UI at roughly the same time as audio is heard:
let times = [NSValue(time:CMTimeMake(1,3))]
_ = self.player.addBoundaryTimeObserver(forTimes: times, queue: DispatchQueue.main, using: {
[weak self] time in
// Code to update the UI goes here, e.g.
activityIndicator.stopAnimating()
})
I have a little more detail on the approach (and a sample Xcode project) on our company blog: http://www.artermobilize.com/blog/2017/02/09/detect-when-ios-avplayer-finishes-buffering-using-swift/
How to know when AVPlayerItem is buffered to the end of a song
I found a pretty good solution to this problem that can be seen below. The proposed solution written in the question didn't really work well because the preferredForwardBufferDuration is set to 0 by default which pretty much makes the solution not viable.
The following the code works pretty well. I call it every second on a timer.
auto theLoadedRanges = self.currentItem.loadedTimeRanges;
CMTime theTotalBufferedDuration = kCMTimeZero;
for( NSValue* theRangeValue in theLoadedRanges )
{
auto theRange = [theRangeValue CMTimeRangeValue];
theTotalBufferedDuration = CMTimeAdd( theTotalBufferedDuration, theRange.duration );
}
auto theDuration = CMTimeGetSeconds( self.currentItem.duration );
if( theDuration > 0 )
{
float thePercent = CMTimeGetSeconds( theTotalBufferedDuration ) / theDuration;
if( thePercent >= 0.99f )
{
// Fully buffered
}
}
Is it possible to pause and resume buffering of AVPlayer?
Yes it is possible to some extent!
You can use the playerItem's preferredForwardBufferDuration
property to decide how much duration from the current playing time the player should prefetch. But sadly, this is only available from iOS version 10.
Macro to check system version:
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
You can now set how much duration you want to prefetch (in seconds).
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
NSTimeInterval interval = 1; // set to 0 for default duration.
_player.currentItem.preferredForwardBufferDuration = interval;
_player.automaticallyWaitsToMinimizeStalling = YES;
}
automaticallyWaitsToMinimizeStalling
is another property which enables the autoplay
or autowait
feature in avplayer. Because the player is likely to stall frequently if the preferredForwardBufferDuration
is set to a smaller duration.
You can also use the playeritem's canUseNetworkResourcesForLiveStreamingWhilePaused
property to set if the player should continue or pause buffering when the player is in pause state. This is available from iOS 9 onwards.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0")) {
_player.currentItem.canUseNetworkResourcesForLiveStreamingWhilePaused = NO;
}
The condition check for the system version is very important. You can
use the macro mentioned above to do this. Otherwise the app will
crash.
UPDATE - swift:
if #available(iOS 10.0, *) {
player.currentItem?.preferredForwardBufferDuration = TimeInterval(1)
player.automaticallyWaitsToMinimizeStalling = true;
}
iOS AVPlayer cancel buffering
So the correct answer is @Che with:
If you will call [self.player replaceCurrentItemWithPlayerItem:nil];
buffering stops. – Che Oct 13 at 14:36
and you do so on the observer listening for the status update from the playerWithPlayerItem. Thanks All!
Related Topics
Launching Viber App via Url Scheme on iOS
Rotating a View in Layoutsubviews
How to Set Image in Tabbar Not Tint Color in iOS
How to Get Navigation Based Template Functionality in Swift Programming
Swift Uicolor Initializer - Compiler Error Only When Targeting Iphone5S
Catch an Exception for Invalid User Input in Swift
How to Cache or Preload Sklabelnode Font
Downloading Uiimage via Alamofireimage
Which Is the Best Way to Estimate Measure of Photographed Things
Uitableviewcells with Uibutton Overlaps While Scrolling
Getting Back a Date from a String
Xcode Process Launch Failed: Security
Z-Index Issue on iOS Safari & Chrome
How to Limit an iOS App Only to 4 Inch Screen Devices
What's the Equivalent of the Uisplitviewcontroller in Swiftui