6
votes

I am streaming audio by using AVPlayer. It is working well. But Now i need to make a slider to move audio forward and backward, like typical music player. I used the function seekToTime which works great with local audio file. But when i stream song from web url, the function stops audio when I forward slider with a large range.

My guess is that the song is being downloaded and if i move slider forward with large range then may be system has not downloaded the song data packets for that time, so it halts player.

Lets say i just hit a button to stream song but now i move slider immediately at 0 to 100th second. In this case system is not working and stops the player. Due to lack of data packets for that time.

Has anyone know how to overcome this problem or is there any other approach. I am using SWIFT for development. I am up to use any library as well if it would work in swift. This is my function:

func forward () {
    timeGap = slider.value
    let preferredTimeScale : Int32 = 1
    let targetTime : CMTime = CMTimeMake(timeGap, preferredTimeScale)

    player.seekToTime(targetTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)

}

Thanks in advance.

1

1 Answers

9
votes

This answer is heavily based on this one : https://stackoverflow.com/a/7195954/765298 . Any and all credit should go there as this is merely a translation to swift.

You are right to assume that when seeking far forward to a part that has not been buffered yet the player stops. The thing is it still buffers the data, but doesn't start automatically when it is ready. So, to rephrase the linked answer to swift :

To setup your observers :

player.currentItem?.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .New, context: nil)
player.currentItem?.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .New, context: nil)

Note, that in order to be able to observe values, the passed self needs to inherit from NSObject.

And to handle them :

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

    guard keyPath != nil else { // a safety precaution
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
        return
    }

    switch keyPath! {
        case "playbackBufferEmpty" :
            if player.currentItem!.playbackBufferEmpty {
                print("no buffer")
                // do something here to inform the user that the file is buffering
            }

        case "playbackLikelyToKeepUp" :
            if player.currentItem!.playbackLikelyToKeepUp {
                self.player.play()
                // remove the buffering inidcator if you added it
            }
    }
}

You can also get information about avaiable time ranges from the currently playing AVPlayerItem (you can acces it via player.currentItem if you haven't created it yourself). This enables you to indicate to user which parts of the file are ready to go.

As always you can read some more in the docs : AVPlayerItem and AVPlayer

To read more about key-value observing (KVO) : here