在 iOS 中播放 Avplayer 时移动滑块变得不稳定
Moving slider getting jumpy while playing Avplayer in iOS
我在 Avplayer 中播放 mp3 网址。它工作正常,我正在向 Slider 展示音频播放器的进度。在尝试向前移动滑块时,它变得神经质。但是音频搜索工作正常。只有滑块 UI 变得不稳定。
我的密码是
/* ----------------------------------------------------
Player setup
------------------------------------------------------ */
func playerSetup(url:String) {
do {
let audioURL = url
avPlayerItem = AVPlayerItem( url:NSURL( string:audioURL )! as URL )
avPlayer = AVPlayer(playerItem:avPlayerItem)
avPlayer?.rate = 1.0
avPlayer?.play()
self.sliderSetup()
self.timeObserverSetup()
}
}
/* ----------------------------------------------------
Slider setup
------------------------------------------------------ */
func sliderSetup() {
DispatchQueue.global(qos: .background).async {
let duration : CMTime = self.avPlayerItem!.asset.duration
let seconds : Float64 = CMTimeGetSeconds(duration)
DispatchQueue.main.async {
self.slider!.maximumValue = Float(seconds)
}
}
slider.isContinuous = false
slider!.minimumValue = 0
slider!.value = 0
slider.addTarget(self, action: #selector(MyViewController.playbackSliderValueChanged(_:event:)), for: .valueChanged)
}
/* ----------------------------------------------------
Avplayer Observer timer setup
------------------------------------------------------ */
func timeObserverSetup() {
let interval = CMTime(seconds: 0.05, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
timeObserver = avPlayer!.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { [weak self] elapsedTime in
// print("observer running")
self!.updateSlider(elapsedTime: elapsedTime)
})
}
/* ----------------------------------------------------
update slider with avplayer duration
------------------------------------------------------ */
func updateSlider(elapsedTime: CMTime) {
let playerDuration = playerItemDuration()
if CMTIME_IS_INVALID(playerDuration) {
slider.minimumValue = 0.0
return
}
let duration = Float(CMTimeGetSeconds(playerDuration))
if duration.isFinite && duration > 0 {
slider.minimumValue = 0.0
slider.maximumValue = duration
let time = Float(CMTimeGetSeconds(elapsedTime))
slider.setValue(time, animated: true)
}
}
/* ----------------------------------------------------
avplayeritem duration
------------------------------------------------------ */
private func playerItemDuration() -> CMTime {
let thePlayerItem = avPlayer?.currentItem
if thePlayerItem?.status == .readyToPlay {
return thePlayerItem!.duration
}
return CMTime.invalid
}
/* ----------------------------------------------------
Slider Action
------------------------------------------------------ */
@objc func playbackSliderValueChanged(_ playbackSlider:UISlider, event: UIEvent) {
DispatchQueue.main.async {
let seconds : Int64 = Int64(self.slider.value)
let targetTime:CMTime = CMTimeMake(value: seconds, timescale: 1)
self.avPlayer!.seek(to: targetTime)
if let touchEvent = event.allTouches?.first {
switch touchEvent.phase {
case .began:
self.removeTimerObserver()
self.pauseAudio()
break
case .moved:
break
case .ended:
self.timeObserverSetup()
self.playAudio()
break
default:
break
}
}
}
}
/* ----------------------------------------------------
Remove timer observer
------------------------------------------------------ */
func removeTimerObserver() {
if ((self.timeObserver) != nil) {
if self.avPlayer?.rate == 1.0 { // it is required as you have to check if player is playing
self.avPlayer?.removeTimeObserver(self.timeObserver as Any)
self.timeObserver = nil
}
}
}
我看过其他论坛,他们建议在开始滑动触摸时,我们可以删除时间观察器,然后滑动触摸结束我们可以添加观察器,所以,我遵循了。
但是,还是有问题。
有什么建议吗?
我已经找到问题了。
此问题是由于滑块低于 属性 而发生的。
slider.isContinuous = false
所以,这个我已经删除了,现在可以正常使用了。
我也是运行滑块动作方法DispatchQueue.main.async。所以,我改成了关注
/* ----------------------------------------------------
Slider Action
------------------------------------------------------ */
@objc func playbackSliderValueChanged(_ playbackSlider:UISlider, event: UIEvent) {
let seconds : Int64 = Int64(self.slider.value)
let targetTime:CMTime = CMTimeMake(value: seconds, timescale: 1)
self.avPlayer!.seek(to: targetTime)
if let touchEvent = event.allTouches?.first {
switch touchEvent.phase {
case .began:
self.removeTimerObserver()
self.pauseAudio()
break
case .moved:
break
case .ended:
self.timeObserverSetup()
self.playAudio()
break
default:
break
}
}
}
现在一切正常。
我在 Avplayer 中播放 mp3 网址。它工作正常,我正在向 Slider 展示音频播放器的进度。在尝试向前移动滑块时,它变得神经质。但是音频搜索工作正常。只有滑块 UI 变得不稳定。
我的密码是
/* ----------------------------------------------------
Player setup
------------------------------------------------------ */
func playerSetup(url:String) {
do {
let audioURL = url
avPlayerItem = AVPlayerItem( url:NSURL( string:audioURL )! as URL )
avPlayer = AVPlayer(playerItem:avPlayerItem)
avPlayer?.rate = 1.0
avPlayer?.play()
self.sliderSetup()
self.timeObserverSetup()
}
}
/* ----------------------------------------------------
Slider setup
------------------------------------------------------ */
func sliderSetup() {
DispatchQueue.global(qos: .background).async {
let duration : CMTime = self.avPlayerItem!.asset.duration
let seconds : Float64 = CMTimeGetSeconds(duration)
DispatchQueue.main.async {
self.slider!.maximumValue = Float(seconds)
}
}
slider.isContinuous = false
slider!.minimumValue = 0
slider!.value = 0
slider.addTarget(self, action: #selector(MyViewController.playbackSliderValueChanged(_:event:)), for: .valueChanged)
}
/* ----------------------------------------------------
Avplayer Observer timer setup
------------------------------------------------------ */
func timeObserverSetup() {
let interval = CMTime(seconds: 0.05, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
timeObserver = avPlayer!.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { [weak self] elapsedTime in
// print("observer running")
self!.updateSlider(elapsedTime: elapsedTime)
})
}
/* ----------------------------------------------------
update slider with avplayer duration
------------------------------------------------------ */
func updateSlider(elapsedTime: CMTime) {
let playerDuration = playerItemDuration()
if CMTIME_IS_INVALID(playerDuration) {
slider.minimumValue = 0.0
return
}
let duration = Float(CMTimeGetSeconds(playerDuration))
if duration.isFinite && duration > 0 {
slider.minimumValue = 0.0
slider.maximumValue = duration
let time = Float(CMTimeGetSeconds(elapsedTime))
slider.setValue(time, animated: true)
}
}
/* ----------------------------------------------------
avplayeritem duration
------------------------------------------------------ */
private func playerItemDuration() -> CMTime {
let thePlayerItem = avPlayer?.currentItem
if thePlayerItem?.status == .readyToPlay {
return thePlayerItem!.duration
}
return CMTime.invalid
}
/* ----------------------------------------------------
Slider Action
------------------------------------------------------ */
@objc func playbackSliderValueChanged(_ playbackSlider:UISlider, event: UIEvent) {
DispatchQueue.main.async {
let seconds : Int64 = Int64(self.slider.value)
let targetTime:CMTime = CMTimeMake(value: seconds, timescale: 1)
self.avPlayer!.seek(to: targetTime)
if let touchEvent = event.allTouches?.first {
switch touchEvent.phase {
case .began:
self.removeTimerObserver()
self.pauseAudio()
break
case .moved:
break
case .ended:
self.timeObserverSetup()
self.playAudio()
break
default:
break
}
}
}
}
/* ----------------------------------------------------
Remove timer observer
------------------------------------------------------ */
func removeTimerObserver() {
if ((self.timeObserver) != nil) {
if self.avPlayer?.rate == 1.0 { // it is required as you have to check if player is playing
self.avPlayer?.removeTimeObserver(self.timeObserver as Any)
self.timeObserver = nil
}
}
}
我看过其他论坛,他们建议在开始滑动触摸时,我们可以删除时间观察器,然后滑动触摸结束我们可以添加观察器,所以,我遵循了。
但是,还是有问题。
有什么建议吗?
我已经找到问题了。
此问题是由于滑块低于 属性 而发生的。
slider.isContinuous = false
所以,这个我已经删除了,现在可以正常使用了。
我也是运行滑块动作方法DispatchQueue.main.async。所以,我改成了关注
/* ----------------------------------------------------
Slider Action
------------------------------------------------------ */
@objc func playbackSliderValueChanged(_ playbackSlider:UISlider, event: UIEvent) {
let seconds : Int64 = Int64(self.slider.value)
let targetTime:CMTime = CMTimeMake(value: seconds, timescale: 1)
self.avPlayer!.seek(to: targetTime)
if let touchEvent = event.allTouches?.first {
switch touchEvent.phase {
case .began:
self.removeTimerObserver()
self.pauseAudio()
break
case .moved:
break
case .ended:
self.timeObserverSetup()
self.playAudio()
break
default:
break
}
}
}
现在一切正常。