I've a SwiftUi app with a View in which I want to play a sequence of videos from remote. I've used an AVQueuePlayer.
At the end of any reproduction I want to play the next video after a defined pause from an array of pauses.
This code work only after the first played item, and then the observer not intercept nothing. Any suggestion?
struct ExercisesPlay: View {
@State var urls: [URL]
@State var pauses: [Int]
var player: AVQueuePlayer
@State var showToast: Bool = false
init(urls: [URL], pauses: [Int]) {
self.urls = urls
self.pauses = pauses
var array: [AVPlayerItem] = []
urls.forEach { URL in
array.append(AVPlayerItem(url: URL))
}
self.player = AVQueuePlayer(items: array)
}
var body: some View {
VideoPlayer(player:player)
.onAppear{
player.play()
addObserver()
}
.onDisappear{
removeObserver()
}
.toast(message: LocalizedStringKey("Pause").stringValue()!,
isShowing: self.$showToast, duration: Toast.long)
}
func addObserver() {
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue:nil ) { notif in
self.showToast.toggle()
if(!pauses.isEmpty){
print(player.currentItem)
player.pause()
DispatchQueue.main.asyncAfter(deadline: (.now() + DispatchTimeInterval.seconds(pauses.first!))) {
player.seek(to: .zero)
player.play()
pauses.remove(at: 0)
}
}
}
}
func removeObserver() {
NotificationCenter.default.removeObserver(self,name: .AVPlayerItemDidPlayToEndTime, object: nil)
}
}
The observer is only being added to the current item when the view appears.
You can add an observer to each item before passing them to the AVQueuePlayer. If you include a reference to the object, you can more easily remove the observer later.
urls.forEach { URL in
let item = AVPlayerItem(url: URL)
NotificationCenter.default.addObserver(self, selector: #selector(itemFinishedPlaying), name: .AVPlayerItemDidPlayToEndTime, object: item)
array.append(item)
}
In the selector method, you can do your setup and cleanup the observer.
@objc private func itemFinishedPlaying(_ notification: NSNotification) {
NotificationCenter.default.removeObserver(self, name: notification.name, object: notification.object)
// additional code you want to perform goes here
}
If you want to cleanup all of the observers when the view disappears, you can iterate through the queued items.
for item in player.items() {
NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: item)
}