Skip to content

Commit

Permalink
fix: Handle AVPlayer.currentItem.status error (#1336)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrien-coye authored Dec 6, 2024
2 parents b37650e + 5353cdd commit f67e99f
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 5 deletions.
21 changes: 21 additions & 0 deletions kDrive/UI/Controller/Files/Preview/PreviewViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import AVFoundation
import FloatingPanel
import InfomaniakCore
import InfomaniakDI
Expand Down Expand Up @@ -451,6 +452,8 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
let file = previewFiles[index]
if ConvertedType.documentTypes.contains(file.convertedType) {
handleOfficePreviewError(error, previewIndex: index)
} else if file.convertedType == .audio {
handleAudioPreviewError(error, previewIndex: index)
}

// We have to delay reload because errorWhilePreviewing can be called when the collectionView requests a new cell in
Expand All @@ -460,6 +463,19 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
}
}

func handleAudioPreviewError(_ error: Error, previewIndex: Int) {
let file = previewFiles[previewIndex]

guard let avError = error as? AVError,
avError.code == .fileFormatNotRecognized else {
return
}

previewErrors[file.id] = PreviewError(fileId: file.id, downloadError: nil)
guard file.isLocalVersionOlderThanRemote else { return }
downloadFile(at: IndexPath(item: previewIndex, section: 0))
}

func handleOfficePreviewError(_ error: Error, previewIndex: Int) {
let file = previewFiles[previewIndex]

Expand Down Expand Up @@ -526,6 +542,10 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
return
}

downloadFile(at: indexPath)
}

private func downloadFile(at indexPath: IndexPath) {
DownloadQueue.instance.temporaryDownload(
file: currentFile,
userId: accountManager.currentUserId,
Expand Down Expand Up @@ -558,6 +578,7 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
} else {
(collectionView.cellForItem(at: indexPath) as? DownloadingPreviewCollectionViewCell)?
.previewDownloadTask?.cancel()
previewErrors[currentFile.id] = nil
collectionView.endEditing(true)
collectionView.reloadItems(at: [indexPath])
updateNavigationBar()
Expand Down
33 changes: 28 additions & 5 deletions kDrive/UI/View/Files/Preview/AudioCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Combine
import InfomaniakCore
import kDriveCore
import kDriveResources
import Kingfisher
import MediaPlayer
import UIKit

Expand All @@ -39,6 +40,7 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {
public lazy var singleTrackPlayer = SingleTrackPlayer(driveFileManager: driveFileManager)

private var cancellables = Set<AnyCancellable>()
private var thumbnailDownloadTask: Kingfisher.DownloadTask?

override func awakeFromNib() {
super.awakeFromNib()
Expand Down Expand Up @@ -77,6 +79,7 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {

override func prepareForReuse() {
super.prepareForReuse()
thumbnailDownloadTask?.cancel()
setControls(enabled: false)
singleTrackPlayer.reset()
songTitleLabel.text = ""
Expand All @@ -91,12 +94,12 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {
Task { @MainActor in
await singleTrackPlayer.setup(with: frozenFile)
setControls(enabled: true)
setupObservation()
setupObservationFor(frozenFile: frozenFile)
}
}

/// Setup data flow
@MainActor func setupObservation() {
@MainActor func setupObservationFor(frozenFile: File) {
cancellables.forEach { $0.cancel() }
cancellables.removeAll()

Expand Down Expand Up @@ -153,9 +156,15 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {
.onCurrentTrackMetadata
.receive(on: DispatchQueue.main)
.sink { metadata in
self.artworkImageView.image = metadata.artwork ?? KDriveResourcesAsset.music.image
self.artistNameLabel.text = metadata.artist
self.songTitleLabel.text = metadata.title
self.handleMetadata(metadata, file: frozenFile)
}
.store(in: &cancellables)

singleTrackPlayer
.onItemError
.receive(on: DispatchQueue.main)
.sink { error in
self.previewDelegate?.errorWhilePreviewing(fileId: frozenFile.id, error: error)
}
.store(in: &cancellables)
}
Expand All @@ -167,6 +176,20 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {
iconHeightConstraint.constant = isPortrait ? 254 : 120
}

func handleMetadata(_ metadata: MediaMetadata, file: File) {
if let artwork = metadata.artwork {
artworkImageView.image = artwork
} else {
artworkImageView.image = KDriveResourcesAsset.music.image
thumbnailDownloadTask = file.getThumbnail { thumbnail, isThumbnailAvailable in
guard isThumbnailAvailable else { return }
self.artworkImageView.image = thumbnail
}
}
artistNameLabel.text = metadata.artist
songTitleLabel.text = metadata.title
}

@objc func rotated() {
setUpPlayButtons()
}
Expand Down
15 changes: 15 additions & 0 deletions kDriveCore/AudioPlayer/SingleTrackPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public final class SingleTrackPlayer: Pausable {
private var timeObserver: Any?
private var rateObserver: NSKeyValueObservation?
private var statusObserver: NSKeyValueObservation?
private var currentItemStatusObserver: NSKeyValueObservation?
private var isInterrupted = false

// MARK: Data flow
Expand All @@ -56,6 +57,7 @@ public final class SingleTrackPlayer: Pausable {
public let onPositionChange = PassthroughSubject<Float, Never>()
public let onPositionMaximumChange = PassthroughSubject<Float, Never>()
public let onCurrentTrackMetadata = PassthroughSubject<MediaMetadata, Never>()
public let onItemError = PassthroughSubject<Error, Never>()

var player: AVPlayer?

Expand Down Expand Up @@ -113,6 +115,10 @@ public final class SingleTrackPlayer: Pausable {
self.player = AVPlayer(playerItem: AVPlayerItem(asset: asset))
await self.setMetaData(from: asset.commonMetadata, playableFileName: playableFile.name)
self.setUpObservers()

self.currentItemStatusObserver = self.player?.observe(\.currentItem?.status) { _, _ in
self.handleItemStatusChange()
}
}
}
} else {
Expand Down Expand Up @@ -223,6 +229,12 @@ public final class SingleTrackPlayer: Pausable {
}
}

private func handleItemStatusChange() {
guard let error = player?.currentItem?.error else { return }

onItemError.send(error)
}

// MARK: - Observation

private func setUpObservers() {
Expand Down Expand Up @@ -271,6 +283,9 @@ public final class SingleTrackPlayer: Pausable {
statusObserver?.invalidate()
statusObserver = nil

currentItemStatusObserver?.invalidate()
currentItemStatusObserver = nil

removeAllRemoteControlEvents()
}

Expand Down

0 comments on commit f67e99f

Please sign in to comment.