1

How can I get AvPlayer to work like AvAudioPlayer. What I mean is, I cannot seem to get duration to work at all. Here is what I need to convert to AvPlayer:

import UIKit
import AVKit
import AVFoundation


class ModalViewController: UIViewController {

    var audioPlayer = AVAudioPlayer()
    let varSend = VarSend.sharedInstance
    var timer:NSTimer!
    var toggleState = 2


    @IBOutlet weak var slider: UISlider!
    @IBOutlet weak var sermonImage: UIImageView!
    @IBOutlet weak var sermont: UILabel!
    @IBOutlet weak var sermond: UILabel!
    @IBOutlet weak var sermonE: UILabel!
    @IBOutlet weak var sermonL: UILabel!
    @IBOutlet weak var play: UIButton!
    @IBOutlet var layer: UIView!


    override func viewDidLoad() {

        super.viewDidLoad()
        let url = varSend.url
        print("Setting up.")



        do {
           let data1 =  NSData(contentsOfURL: NSURL(string:url)!)
            audioPlayer = try AVAudioPlayer(data: data1!)
            audioPlayer.prepareToPlay()
            audioPlayer.volume = 1.0
            audioPlayer.play()
        } catch {
            print("Error getting the audio file")
        }



        slider.maximumValue = Float(audioPlayer.duration)
        timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("updateSlider"), userInfo: nil, repeats: true)
        slider.setThumbImage(UIImage(named: "circle"), forState: .Normal)
        slider.setThumbImage(UIImage(named: "circle"), forState: .Highlighted)


        let title = varSend.sermonName
        self.sermont.text = title

        let date = varSend.sermonDate
        self.sermond.text = date

        let image = varSend.sermonPic

        ImageLoader.sharedLoader.imageForUrl(image, completionHandler:{(image: UIImage?, url: String) in
            self.sermonImage.image = image!
        })
    }

    @IBAction func ChangeAudioTime(sender: AnyObject) {
        audioPlayer.stop()
        audioPlayer.currentTime = NSTimeInterval(slider.value)
        audioPlayer.prepareToPlay()
        audioPlayer.volume = 1.0
        audioPlayer.play()

    }



    func updateSlider() {
        slider.value = Float(audioPlayer.currentTime)
        let currentTime = Int(audioPlayer.currentTime)
        let minutes = currentTime / 60
        let seconds = currentTime - minutes * 60
        let con = Int(audioPlayer.duration)
        let currentItem = con - currentTime
        let minutesU = Int(currentItem / 60)
        let secondsU = Int(currentItem % 60)
        sermonE.text = NSString(format: "%02d:%02d", minutes,seconds) as String
        let timeLeft = NSString(format: "%02d:%02d", minutesU,secondsU) as String
        sermonL.text = "-\(timeLeft)"

        if currentItem == 1 {
            //audioPlayer.pause()
            toggleState = 1
            print(toggleState)
            play.setImage(UIImage(named:"play.png"),forState:UIControlState.Normal)
        }
    }


    @IBAction func playPauseButton(sender: AnyObject) {
        let playBtn = sender as! UIButton
        if toggleState == 1 {
            audioPlayer.play()
            toggleState = 2
            playBtn.setImage(UIImage(named:"pause.png"),forState:UIControlState.Normal)

        } else {
            audioPlayer.pause()
            toggleState = 1
            playBtn.setImage(UIImage(named:"play.png"),forState:UIControlState.Normal)
        }
    }


    @IBAction func play(sender: AnyObject) {
        audioPlayer.play()
    }

    @IBAction func pause(sender: AnyObject) {
        audioPlayer.pause()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func close(sender: AnyObject) {
       self.dismissViewControllerAnimated(true, completion: nil)
        audioPlayer.stop()
    }

}

And here is what I have tried already:

import UIKit
import Alamofire
import SwiftyJSON
import AVKit
import AVFoundation
import CoreMedia

class test: UIViewController {
    var audioPlayer:AVPlayer!
    var playerItem:AVPlayerItem!

   var timer:NSTimer!

    @IBOutlet weak var sermonE: UILabel!
    @IBOutlet weak var sermonL: UILabel!
    @IBOutlet weak var slider: UISlider!

    override func viewDidLoad() {
        super.viewDidLoad()


        //let playerItem:AVPlayerItem!;
        let playerURL = "example.com"
        let steamingURL:NSURL = NSURL(string:playerURL)!
        audioPlayer = AVPlayer(URL: steamingURL)


         timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("updateSlider"), userInfo: nil, repeats: true)






    }

     func updateSlider() {
        let item = audioPlayer?.currentItem

            let durationInSeconds = CMTimeGetSeconds(item!.duration)
        print(durationInSeconds)

    }

    @IBAction func ChangeAudioTime(sender: AnyObject) {

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }




    @IBAction func Play(sender: AnyObject) {
        audioPlayer.play()
    }

}

I have been searching for days and Apple's docs are very hard to make out. I even tried

self.player.currentItem.asset.duration

from: How to get Duration from AVPlayer (Not AVAudioPlayer)?

Any help would be much appreciated.

Community
  • 1
  • 1
Barrett
  • 323
  • 5
  • 11
  • Are you playing the video from a HTTP Live stream? – Xcoder Feb 15 '16 at 11:03
  • 1
    What value are you getting for the duration? There is a chance, that when you ask for the duration from the AVPlayerItem that it has not been loaded yet. If that is the case you might try first creating an AVAsset and using func loadValuesAsynchronouslyForKeys(keys: [String], completionHandler handler: (() -> Void)?) where keys = ["duration"]. Then in your completion handler you can be sure that the duration has been loaded and is ready to use. – Jonathan Feb 26 '16 at 16:13
  • I will give it a try. And this is what I get for the duration "2350.02775510204". – Barrett Feb 28 '16 at 05:22

1 Answers1

1

Swift 2.0

loadedTimeRanges The array contains NSValue objects containing a CMTimeRange value indicating the times ranges for which the player item has media data readily available. The time ranges returned may be discontinuous.

So I call myplayer.getCurrentTrackDuration every 1 second and noticed that when I'm streaming I got the correct final duration after 3-4 second.

extension AVPlayer {
 //run this every 1 second of streaming (or use KVO)
 //In Http stream the duration it going to increase and probably finallize near to 7% of the total duration of the song 
 func getCurrentTrackDuration () -> Float64 {
    guard let currentItem = self.currentItem else { return 0.0 }
    guard currentItem.loadedTimeRanges.count > 0 else { return 0.0 }

    let timeInSecond = CMTimeGetSeconds((currentItem.loadedTimeRanges[0].CMTimeRangeValue).duration);

    return timeInSecond >= 0.0 ? timeInSecond : 0.0
 }
}
iluvatar_GR
  • 1,017
  • 13
  • 19