简体   繁体   中英

UISlider does not work correctly with AVPlayer

I use AVPlayer to play audio files. I have problems. UISlider does not work correctly, the slider should move as a progress view and when you click the stop the audio is played again

@IBAction func play(_ sender: Any) {

let url = URL(string: self.urlAudio[0])
let playerItem = AVPlayerItem(url: url!)
player = AVPlayer(playerItem:playerItem)
player.rate = 1.0;
player.play()


let duration : CMTime = playerItem.asset.duration
let seconds : Float64 = CMTimeGetSeconds(duration)

playbackSlider.maximumValue = Float(seconds)
playbackSlider.isContinuous = true
playbackSlider.tintColor = UIColor.green

playbackSlider.addTarget(self, action: #selector(ViewControllerAudioDetail.playbackSliderValueChanged(_:)), for: .valueChanged) 

if  soundChange == true{
    playChange.setImage(UIImage(named:"Pause.png"), for: UIControlState.normal)
    soundChange = false
    player.play()
} else {
    playChange.setImage(UIImage(named:"Play.png"), for: UIControlState.normal)
    soundChange = true
    player.pause()
}

}

func playbackSliderValueChanged(_ playbackSlider:UISlider){

let seconds : Int64 = Int64(playbackSlider.value)
let targetTime:CMTime = CMTimeMake(seconds, 1)

player.seek(to: targetTime)

}

when you click the stop the audio is played again

In order to toggle play and pause check if avplayer is already playing or not. If playing pause it else play it.

if player.rate == 0 {
    player.play()
    //change your button image
}
else {
   player.pause()
   //change your button image
}

the slider should move as a progress view

You can use AVPlayer's PeriodicTime Observer to update your slider progress

    let _ = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC)), queue: DispatchQueue.main) { [weak self] (time) in
         self?.audioPlayerSlider.value = Float(CMTimeGetSeconds(time)) / Float(totalDuration)
    }

PS:

Don't create player instance every time user taps on button. Create only when player is nil or you want to play a different track.

@IBAction func play(_ sender: Any) {
   if player == nil {
      let url = URL(string: self.urlAudio[0])
      let playerItem = AVPlayerItem(url: url!)
      player = AVPlayer(playerItem:playerItem)
      player.rate = 1.0;
   }
   if player.rate == 0 {
       player.play()
       //change your button image
   }
   else {
       player.pause()
       //change your button image
   }
}

EDIT:

I believe you are trying to find a way to scrub / seek to specific time of audio that AVPlayer is playing.

You can use AVPlayer's seek method to do that.

@IBAction func audioSliderDragged(_ sender: AnyObject) {
        let value = self.audioPlayerSlider.value
        let durationToSeek = Float(totalDuration) * value
        player.seek(to: CMTimeMakeWithSeconds(Float64(durationToSeek),player.currentItem!.duration.timescale)) { [weak self](state) in
          //do what is relevant to your app on seeing to particular offset            
      }
}

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