简体   繁体   中英

AVPlayer : How to handle network interruptions

When using AVPlayer to play audio from an url it will discontinue to play when for example disconnecting from wifi.

[player play];

Does not resume the AVPlayer

player.rate // Value is 1.0

player.currentItem.isPlaybackLikelyToKeepUp // Value is YES

player.status // Value is AVPlayerStatusReadyToPlay

player.error // Value is nil

But the player is not playing any audio.

How do I handle a disconnect from AVPlayer, for reconnecting the AVPlayer and start playing again?

In order to handle network changes, you have to add an observer for AVPlayerItemFailedToPlayToEndTimeNotification .

- (void) playURL:(NSURL *)url
{
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:url];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemFailedToPlayToEndTime:) name:AVPlayerItemFailedToPlayToEndTimeNotification object:playerItem];
    self.player = [AVPlayer playerWithPlayerItem:playerItem];
    [self.player play];
}

- (void) playerItemFailedToPlayToEndTime:(NSNotification *)notification
{
    NSError *error = notification.userInfo[AVPlayerItemFailedToPlayToEndTimeErrorKey];
    // Handle error ...
}

You should add observer for AVPlayerItemPlaybackStalledNotification .

AVPlayerItemFailedToPlayToEndTimeNotification has no value for me on this problem.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackStalled:) name:AVPlayerItemPlaybackStalledNotification object:trackItem];

As the doc says, file-based playback does not continue if necessary streaming media wasn't delivered in a timely fashion over a network.

The notification's object is the AVPlayerItem instance whose playback was unable to continue because the necessary streaming media wasn't delivered in a timely fashion over a network. Playback of streaming media continues once a sufficient amount of data is delivered. File-based playback does not continue.

This explained why AVPlayer can resume HLS streams after network switch, but cannot do the same if I use AVPlayer to play TuneIn resources which is file-based.

Then the answer becomes simple.

- (void)playbackStalled:(NSNotification *)notification {
    if ([self isFileBased:streamUri]) {
        // Restart playback
        NSURL *url = [NSURL URLWithString:streamUri];
        AVPlayerItem *trackItem = [AVPlayerItem playerItemWithURL:url];
        AVPlayer *mediaPlayer = [AVPlayer playerWithPlayerItem:trackItem];
        [self registerObservers:trackItem player:mediaPlayer];
        [mediaPlayer play];
    }
}

Further reading on discussion of automaticallyWaitsToMinimizeStalling .

0xced's answer for Swift 3/4 :

var playerItem: AVPlayerItem?
var player: AVPlayer?

func instantiatePlayer(_ url: URL) {
    self.playerItem = AVPlayerItem(url: url)            
    self.player = AVPlayer(playerItem: self.playerItem)
        NotificationCenter.default.addObserver(self, selector: #selector(playerItemFailedToPlay(_:)), name: NSNotification.Name.AVPlayerItemFailedToPlayToEndTime, object: nil)
}

func playerItemFailedToPlay(_ notification: Notification) {
    let error = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? Error

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM