防止 AVPlayer 一次播放多个曲目的最佳方法

Best way to prevent AVPlayer playing more than one track at a time

我正在使用 AVPlayer 播放流式音频,并希望防止它一次播放多个音轨。最好的方法是什么?我的方法完全是程序化的——我不使用故事板。当 url 被发送到 ViewController(VC,委托)时,它会设置播放器的一个新实例——我认为这是问题所在,但我不是当然。谢谢

 //this routine returns the url from control to the VC (delegate)
  func selectedAudio(_ audioUrl:String?) {
    if let urlString = audioUrl {
      setupPlayer(urlString)
    }
  }

    //single button which toggles between play/pause
  func playOrPauseTouched() {
    if isPlaying  {
      pausePlayer()
    } else {
      playPlayer()
    }
  }

  func playPlayer() {
    if player == nil || selectedTrackName != currentTrackLabel.text{
      if let urlString = selectedAudioUrl {
        setupPlayer(urlString)
        currentTrackLabel.text = "Playing: \(selectedTrackName ?? "")"
      }
    }
    player?.play()
    isPlaying = true
    playPauseButton.setImage(UIImage(named: "pause"), for: .normal)
    activityIndicatorView.startAnimating()
  }

  func pausePlayer() {
    player?.pause()
    isPlaying = false
    playPauseButton.setImage(UIImage(named: "play"), for: .normal)
  }

  func setupPlayer(_ urlString:String) {
    if let url = URL(string:urlString) {
      player = AVPlayer(url: url)
      let playerLayer = AVPlayerLayer(player: player)
      player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
      let interval = CMTime(value: 1, timescale: 5) //gives smooth thumb movement w/short clips
      player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { (progressTime) in
        let seconds = CMTimeGetSeconds(progressTime)
        let secondsString = String(format: "%02d", Int(seconds.truncatingRemainder(dividingBy: 60)))
        let minutesString = String(format: "%02d", Int(seconds / 60))
        self.currentTimeLabel.text = "\(minutesString):\(secondsString)"
        if let duration = self.player?.currentItem?.duration {
          let durationSeconds = CMTimeGetSeconds(duration)
          self.audioSlider.value = Float(seconds / durationSeconds)
        }
      })
    }
  }

我的意见是使用 KVO,它会通知您 AVPlayerItem 的当前状态。

意味着您将获得 state,这将帮助您识别当前项目正在播放、推送、缓冲或完成播放。

所以你应该拿一个 flag 来处理你当前的项目 state

例如

  • 在播放项目时将标志设置为真
  • 当项目完成播放时将标志设置为 false。
  • 当您点击播放另一个项目的按钮时,然后检查 if flag == false 之类的标志,然后开始播放另一个项目,否则不会。

第二种方式:

像下面那样使用 NotificationCenter

NotificationCenter.default.addObserver(self, selector: Selector(("playerDidFinishPlaying:")), 
       name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)

及以下项目播放完毕后自动调用

func playerDidFinishPlaying(note: NSNotification) {
    print("Item finished playing ")
   // Set flag here 
}

和管理标志一样。