如何处理AVPlayer .AVPlayerItemPlaybackStalled通知 [英] How to handle AVPlayer .AVPlayerItemPlaybackStalled Notification
问题描述
我正在使用AVPlayer,有时播放器会随机暂停.我正在观察\.timeControlStatus
,但得到的唯一响应是.paused
.我还观察到\.isPlaybackLikelyToKeepUp
,\.isPlaybackBufferEmpty
和\.isPlaybackBufferFull
,但这些都不会触发.但是,使用Notification.Name.AVPlayerItemPlaybackStalled
时,我确实得到了一条打印文字,上面写着"stalled".
I'm using AVPlayer and sometimes the player randomly pauses. I'm observing \.timeControlStatus
but the only response I get .paused
. I'm also observing \.isPlaybackLikelyToKeepUp
, \.isPlaybackBufferEmpty
, and \.isPlaybackBufferFull
but nothing fires for those. However using Notification.Name.AVPlayerItemPlaybackStalled
I do get a print statement that says "stalled".
即使\.rate
在玩家暂停时触发,也要在.AVPlayerItemPlaybackStalled
触发前触发,有时\.timeControlStatus .paused
在.AVPlayerItemPlaybackStalled
之后触发,而玩家只是坐在那里.
Even though \.rate
fires when the the player pauses, that fires before .AVPlayerItemPlaybackStalled
fires, sometimes \.timeControlStatus .paused
fires after .AVPlayerItemPlaybackStalled
and the player just sits there.
.AVPlayerItemPlaybackStalled
运行并且播放器坐在暂停状态后该怎么办?
What should I do once .AVPlayerItemPlaybackStalled
runs and the player is sitting paused?
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemPlaybackStalled(_:)),
name: NSNotification.Name.AVPlayerItemPlaybackStalled,
object: playerItem)
@objc fileprivate func playerItemPlaybackStalled(_ notification: Notification) {
print("playerItemPlaybackStalled")
}
这是我的完整代码:
let player = AVPlayer()
player.automaticallyWaitsToMinimizeStalling = false
playerLayer = AVPlayerLayer(player: player)
playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
// add KVO observers and NotificationCenter observers
// playerItem keys are already loaded
playerItem.preferredForwardBufferDuration = TimeInterval(1.0)
player.replaceCurrentItem(with: playerItem)
playerStatusObserver = player?.observe(\.currentItem?.status, options: [.new, .old]) { [weak self] (player, change) in
switch (player.status) {
case .readyToPlay:
DispatchQueue.main.async {
// play video
}
case .failed, .unknown:
print("Video Failed to Play")
@unknown default:
break
}
}
playerRateObserver = player?.observe(\.rate, options: [.new, .old], changeHandler: { [weak self](player, change) in
if player.rate == 1 {
DispatchQueue.main.async {
// if player isn't playing play it
}
} else {
DispatchQueue.main.async {
// is player is playing pause it
}
}
})
playerTimeControlStatusObserver = player?.observe(\.timeControlStatus, options: [.new, .old]) { [weak self](player, change) in
switch (player.timeControlStatus) {
case .playing:
DispatchQueue.main.async { [weak self] in
// if player isn't playing pay it
}
case .paused:
print("timeControlStatus is paused") // *** SOMETIMES PRINTS after .AVPlayerItemPlaybackStalled runs***
case .waitingToPlayAtSpecifiedRate:
print("timeControlStatus- .waitingToPlayAtSpecifiedRate")
if let reason = player.reasonForWaitingToPlay {
switch reason {
case .evaluatingBufferingRate:
print("timeControlStatus- .evaluatingBufferingRate") // never prints
case .toMinimizeStalls:
print("timeControlStatus- .toMinimizeStalls") // never prints
case .noItemToPlay:
print("timeControlStatus- .noItemToPlay") // never prints
default:
print("Unknown \(reason)")
}
}
@unknown default:
break
}
}
playbackLikelyToKeepUpObserver = player?.currentItem?.observe(\.isPlaybackLikelyToKeepUp, options: [.old, .new]) { (playerItem, change) in
print("isPlaybackLikelyToKeepUp") // never prints
}
playbackBufferEmptyObserver = player?.currentItem?.observe(\.isPlaybackBufferEmpty, options: [.old, .new]) { (playerItem, change) in
print("isPlaybackBufferEmpty") // never prints
}
playbackBufferFullObserver = player?.currentItem?.observe(\.isPlaybackBufferFull, options: [.old, .new]) { (playerItem, change) in
print("isPlaybackBufferFull") // never prints
}
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidReachEnd(_:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: playerItem)
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemFailedToPlayToEndTime(_:)),
name: .AVPlayerItemFailedToPlayToEndTime,
object: playerItem)
NotificationCenter.default.addObserver(self, selector: #selector(playerItemNewError(_:)),
name: .AVPlayerItemNewErrorLogEntry,
object: playerItem)
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemPlaybackStalled(_:)),
name: NSNotification.Name.AVPlayerItemPlaybackStalled,
object: playerItem)
@objc func playerItemDidReachEnd(_ notification: Notification) {
// show replay button
}
@objc func playerItemFailedToPlayToEndTime(_ notification: Notification) {
print("playerItemFailedToPlayToEndTime") // never prints
if let error = notification.userInfo?["AVPlayerItemFailedToPlayToEndTime"] as? Error {
print(error.localizedDescription) // never prints
}
}
@objc func playerItemNewError(_ notification: Notification) {
print("playerItemNewErrorLogEntry") // never prints
}
@objc func playerItemPlaybackStalled(_ notification: Notification) {
print("playerItemPlaybackStalled") // *** PRINTS ***
}
推荐答案
我在此处找到了答案.基本上在停滞的通知中,我检查缓冲区是否已满.如果没有,我从链接中运行代码.
I found the answer here. Basically inside the stalled notification I check to see if the buffer is full or not. If not I run the code from the link.
这篇关于如何处理AVPlayer .AVPlayerItemPlaybackStalled通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!