mirror of
https://github.com/yattee/yattee.git
synced 2025-12-07 16:48:15 +00:00
Add retry mechanism for AVPlayer file load errors
Implemented automatic retry logic with exponential backoff (2, 4, 6 seconds) when file loading fails in AVPlayerBackend. Retries up to 3 times before showing error to user. Retry state is properly reset on successful loads. This matches the retry implementation added to MPVBackend in commit b6df73f9.
This commit is contained in:
@@ -110,6 +110,14 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
|
|
||||||
var controlsUpdates = false
|
var controlsUpdates = false
|
||||||
|
|
||||||
|
// Retry mechanism
|
||||||
|
private var retryCount = 0
|
||||||
|
private let maxRetries = 3
|
||||||
|
private var currentRetryStream: Stream?
|
||||||
|
private var currentRetryVideo: Video?
|
||||||
|
private var currentRetryPreservingTime = false
|
||||||
|
private var currentRetryUpgrading = false
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
addFrequentTimeObserver()
|
addFrequentTimeObserver()
|
||||||
addInfrequentTimeObserver()
|
addInfrequentTimeObserver()
|
||||||
@@ -151,6 +159,12 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
preservingTime: Bool,
|
preservingTime: Bool,
|
||||||
upgrading: Bool
|
upgrading: Bool
|
||||||
) {
|
) {
|
||||||
|
// Store stream and video for potential retries
|
||||||
|
currentRetryStream = stream
|
||||||
|
currentRetryVideo = video
|
||||||
|
currentRetryPreservingTime = preservingTime
|
||||||
|
currentRetryUpgrading = upgrading
|
||||||
|
|
||||||
isLoadingVideo = true
|
isLoadingVideo = true
|
||||||
|
|
||||||
if let url = stream.singleAssetURL {
|
if let url = stream.singleAssetURL {
|
||||||
@@ -265,9 +279,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
self?.insertPlayerItem(stream, for: video, preservingTime: preservingTime, upgrading: upgrading)
|
self?.insertPlayerItem(stream, for: video, preservingTime: preservingTime, upgrading: upgrading)
|
||||||
}
|
}
|
||||||
case .failed:
|
case .failed:
|
||||||
DispatchQueue.main.async { [weak self] in
|
self?.handleFileLoadError(error: error)
|
||||||
self?.model.playerError = error
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -528,6 +540,9 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
|
|
||||||
switch playerItem.status {
|
switch playerItem.status {
|
||||||
case .readyToPlay:
|
case .readyToPlay:
|
||||||
|
// Reset retry state on successful load
|
||||||
|
self.resetRetryState()
|
||||||
|
|
||||||
if self.model.activeBackend == .appleAVPlayer,
|
if self.model.activeBackend == .appleAVPlayer,
|
||||||
self.isAutoplaying(playerItem)
|
self.isAutoplaying(playerItem)
|
||||||
{
|
{
|
||||||
@@ -565,9 +580,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case .failed:
|
case .failed:
|
||||||
DispatchQueue.main.async {
|
self.handleFileLoadError(error: item.error)
|
||||||
self.model.playerError = item.error
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
@@ -836,4 +849,44 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
func setNeedsDrawing(_: Bool) {}
|
func setNeedsDrawing(_: Bool) {}
|
||||||
func setSize(_: Double, _: Double) {}
|
func setSize(_: Double, _: Double) {}
|
||||||
func setNeedsNetworkStateUpdates(_: Bool) {}
|
func setNeedsNetworkStateUpdates(_: Bool) {}
|
||||||
|
|
||||||
|
private func handleFileLoadError(error: Error?) {
|
||||||
|
guard let stream = currentRetryStream, let video = currentRetryVideo else {
|
||||||
|
// No stream info available, show error immediately
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.model.playerError = error
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if retryCount < maxRetries {
|
||||||
|
retryCount += 1
|
||||||
|
let delay = TimeInterval(retryCount * 2) // 2, 4, 6 seconds
|
||||||
|
|
||||||
|
logger.warning("File load failed. Retry attempt \(retryCount) of \(maxRetries) after \(delay) seconds...")
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
self.logger.info("Retrying file load (attempt \(self.retryCount))...")
|
||||||
|
self.playStream(stream, of: video, preservingTime: self.currentRetryPreservingTime, upgrading: self.currentRetryUpgrading)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// All retries exhausted, show error
|
||||||
|
logger.error("File load failed after \(maxRetries) retry attempts")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.model.playerError = error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset retry counter for next attempt
|
||||||
|
resetRetryState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func resetRetryState() {
|
||||||
|
retryCount = 0
|
||||||
|
currentRetryStream = nil
|
||||||
|
currentRetryVideo = nil
|
||||||
|
currentRetryPreservingTime = false
|
||||||
|
currentRetryUpgrading = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user