防止 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
}
和管理标志一样。
我正在使用 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
}
和管理标志一样。