Я использую AVPlayer, и иногда проигрыватель останавливается в случайном порядке. Я наблюдаю \.timeControlStatus
, но единственный ответ я получаю .paused
. Я также наблюдаю \.isPlaybackLikelyToKeepUp
, \.isPlaybackBufferEmpty
и \.isPlaybackBufferFull
, но для них ничего не срабатывает. Однако, используя Notification.Name.AVPlayerItemPlaybackStalled
, я получаю оператор печати с надписью «остановлен».
Хотя \.rate
срабатывает, когда проигрыватель делает паузу, это срабатывает до срабатывания .AVPlayerItemPlaybackStalled
, иногда \.timeControlStatus .paused
срабатывает после .AVPlayerItemPlaybackStalled
и игрок просто сидит там.
Что мне делать, когда .AVPlayerItemPlaybackStalled
запускается, а игрок сидит в режиме паузы?
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 ***
}