Search code examples
iosswiftavplayeravaudioplayer

playing the next audio file in a playlist when in a background state


I have this class that manages the playlist of audio, it works when the app is active (screen on). how can I get it to work when the app is in the background? At the moment, if I put the phone to sleep, the current track plays until the end but the notification does not invoke the method to play the next track.

what is the best way to get this working while the device is in background mode?

class AudioPlayer: ObservableObject {
    var nextTracks: [String]?
    var player: AVPlayer? {
        didSet {
            if let player = player {
                NotificationCenter.default.addObserver(self, selector: #selector(self.songFinished), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
            }
        }
    }
    func play(songId: String, nextSongs: [String]? = nil) {
        let url = SubsonicClient.shared.stream(id: songId)
        let asset = AVURLAsset(url: url)
        let item = AVPlayerItem(asset: asset)
        self.nextTracks = nextSongs
        self.player = AVPlayer(playerItem: item)
        self.player?.play()
    }
    @objc func songFinished() {
        if let id = nextTracks?.first {
            let url = SubsonicClient.shared.stream(id: id)
            nextTracks?.remove(at: 0)
            let asset = AVURLAsset(url: url)
            let item = AVPlayerItem(asset: asset)
            self.player = AVPlayer(playerItem: item)
            self.player?.play()
        }
    }
}

Solution

  • Here is my solution:

    class AudioPlayer: ObservableObject {
        var nextTracks: [String]?
        var queue: AVQueuePlayer?
        func play(songIds: [String]) {
            var assets = [AVPlayerItem]()
            songIds.forEach {
                let url = SubsonicClient.shared.stream(id: $0)
                let asset = AVURLAsset(url: url)
                let item = AVPlayerItem(asset: asset)
                assets.append(item)
            }
            self.queue = AVQueuePlayer(items: assets)
            self.queue?.play()
        }
    }