Search code examples
iosavfoundationavplayer

AVPlayerItemDidPlayToEndTimeNotification firing when out of buffer


I've noticed that AVPlayerItemDidPlayToEndTimeNotification is occasionally sent when the network is deactivated and the video cannot continue playing. This is despite the video not having completed.

This can be reproduced with the following code:

#import "ViewController.h"  
#import   

@interface ViewController ()  
@property AVPlayerItem *item;  
@property AVPlayer *player;  

@end  

@implementation ViewController  

- (void)viewDidLoad {  
    [super viewDidLoad];  

    NSURL *url = [NSURL URLWithString:@"https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8"];  
    self.item = [[AVPlayerItem alloc] initWithURL: url];  
    self.player = [[AVPlayer alloc] initWithPlayerItem:self.item];  


    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];  
    playerLayer.frame = self.view.bounds;  

    [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleNotification:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.item];  
    [self.view.layer addSublayer:playerLayer];  

    [self.player addObserver:self forKeyPath:@"status" options:0 context:nil];  

    [[AVAudioSession sharedInstance]  
     setCategory: AVAudioSessionCategoryPlayback  
     error: nil];  

    [self.player play];  

    NSLog(@"Playing");  
}  

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object  
                        change:(NSDictionary *)change context:(void *)context {  
    if (object == self.player && [keyPath isEqualToString:@"status"]) {  

    }  
}  

-(void)handleNotification:(NSNotification*)notification {  
    NSLog(@"%@", notification.name.debugDescription);  

    NSLog(@"HandleNotification called at:%lld seconds. Duration on player is:%lld seconds", self.player.currentTime.value/self.player.currentTime.timescale, self.item.duration.value/self.item.duration.timescale);  
}  


@end  

Reproduction steps are: 1. Run the app and let the video play for around 40s. 2. Kill the network on the device. AVPlayerItemDidPlayToEndTimeNotification is fired and written to the log.

Is there any reason why I should expect this to happen? And if so, how can I distinguish between an end of play event and a failure to continue playback due to lack of buffered content?


Solution

  • I found same issue from AVPlayer's notification. When AVPlayerItemFailedToPlayToEndTime is trigged, I check AVPlayerItem's position from the end.

    Code sample from ModernAVPlayer library: