1
votes

I am using AVPlayer to stream some live HTTP audio, not AVAudioPlayer which does not support live HTTP audio streaming, the question is, how do I get the status of current playback? For example:

Tap Play Button -> [Loading] -> [Playing] Tap Pause Button -> [Paused]

I need to show a spinner when loading, show a pause button when playing and show a play button when paused, I know I can observe the 'status' and 'rate' properties of AVPlayer:

rate: the current rate of playback. 0.0 means “stopped”, 1.0 means “play at the natural rate of the current item”.

status: Indicates whether the player can be used for playback.

AVPlayerStatusUnknown,
AVPlayerStatusReadyToPlay,
AVPlayerStatusFailed

so there is no way to indicate the audio is "LOADING", and after the status changes to AVPlayerStatusReadyToPlay, it still takes some time to have the audio playing(maybe because it is a live audio).

But anyway, how do I get the correct status of current playback? I know there is an AudioStream from Matt, but it does not support HTTP Live audio.

Thanks very much!

2
I might be missing something in your question but the time between calling [avPlayer start] and the rate going to 1.0 is the "loading" period. Set your own internal state to 'loading' as soon as you call [start] and then set it to 'playing' as soon as the rate goes to 1.0.SteveB

2 Answers

3
votes

I used

    [self.mPlayerItem addObserver:self 
                   forKeyPath:kStatusKey 
                      options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                      context:AVPlayerDemoPlaybackViewControllerStatusObservationContext];

to monitor the status key ("status"). Then I created the player

[self setPlayer:[AVPlayer playerWithPlayerItem:self.mPlayerItem]];  

And in the observeValueForKeyPath

    if (context == AVPlayerDemoPlaybackViewControllerStatusObservationContext)
{        
    AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
    switch (status)
    {
            /* Indicates that the status of the player is not yet known because 
             it has not tried to load new media resources for playback */
        case AVPlayerStatusUnknown:
        {
            [lblvalidation setText:@"Loading..."];

            NSLog(@"AVPlayerStatusUnknown");
        }
            break;

        case AVPlayerStatusReadyToPlay:
        {
            /* Once the AVPlayerItem becomes ready to play, i.e. 
             [playerItem status] == AVPlayerItemStatusReadyToPlay,
             its duration can be fetched from the item. */

            NSLog(@"AVPlayerStatusReadyToPlay");

            [self.player play];
            [lblvalidation setText:@"Playing..."];
        }
            break;

        case AVPlayerStatusFailed:
        {
            [lblvalidation setText:@"Error..."];
            NSLog(@"AVPlayerStatusFailed");
        }
            break;
    }
}

this works for me... I hope it help for you.

1
votes

Updated for Swift 2:

 private var AVPlayerDemoPlaybackViewControllerStatusObservationContext = 0

Add observer:

player.currentItem!.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: &AVPlayerDemoPlaybackViewControllerStatusObservationContext)

Observer

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {

    if context == &AVPlayerDemoPlaybackViewControllerStatusObservationContext {
        if let change = change as? [String: Int]
        {
            let status = change[NSKeyValueChangeNewKey]!

            switch status {
            case AVPlayerStatus.Unknown.rawValue:
                print("The status of the player is not yet known because it has not tried to load new media resources for playback")

            case AVPlayerStatus.ReadyToPlay.rawValue:
                self.playButtonPressed(playButton)
                print("The player is Ready to Play")

            case AVPlayerStatus.Failed.rawValue:
                print("The player failed to load the video")

            default:
                print("Other status")
            }
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }

}