         info[MPMediaItemPropertyAlbumTitle] = album ?? ""
         info[MPMediaItemPropertyArtist] = artist ?? ""
         if let artwork = artwork {
-            info[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: artwork.size) { _ in artwork }
+            info[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: artwork.size) { (size) in artwork }
         }
         update()
     }
 
-    func update() {
+    private func update() {
         info[MPMediaItemPropertyPlaybackDuration] = player?.duration ?? 0
         info[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player?.currentTime ?? 0
         MPNowPlayingInfoCenter.default().nowPlayingInfo = info
     }
 
-    func callout() {
-        callback?(player)
-    }
-
-    private func registerControlEvents() {
+    private func handleControlEvents() {
         let center = MPRemoteCommandCenter.shared()
         center.pauseCommand.isEnabled = true
         center.playCommand.isEnabled = true


    static let sharedInstance = AudioPlayer()

    private let session: AVAudioSession = {
        let session = AVAudioSession.sharedInstance()
        try? session.setCategory(AVAudioSessionCategoryPlayback)
        return session
    }()
    private var commands: [Any] = []
    private var player: AVAudioPlayer?
    private var info: [String: Any] = [:]
    private var timer: Timer?
    private var callback: ((_ player: AVAudioPlayer?) -> Void)?

    func start() {
        try? session.setActive(true)
        UIApplication.shared.beginReceivingRemoteControlEvents()
        registerControlEvents()
        if UIApplication.shared.applicationState == .active {
            scheduleTimer()
        }
        addObservers()
    }

    func stop() {
        invalidateTimer()
        player?.stop()
        player = nil
        info.removeAll()
        MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
        deregisterControlEvents()
        UIApplication.shared.endReceivingRemoteControlEvents()
        try? session.setActive(false)
    }

    func play(data: Data, time: Date, _ eventCallback: ((_ player: AVAudioPlayer?) -> Void)? = nil) {

        center.likeCommand.isEnabled = false
        center.dislikeCommand.isEnabled = false
        center.bookmarkCommand.isEnabled = false
        center.pauseCommand.addTarget { [unowned self] _ in
            guard let player = self.player else { return .noActionableNowPlayingItem }
            player.pause()
            self.update()
            return .success
        }
        center.playCommand.addTarget { [unowned self] _ in
            guard let player = self.player else { return .noActionableNowPlayingItem }
            player.play()
            self.update()
            return .success
        }
    }

    private func handleNotifications() {
        let center = NotificationCenter.default
        center.addObserver(forName: Notification.Name.UIApplicationWillEnterForeground, object: nil, queue: nil) { [unowned self] (notification) in
            self.scheduleTimer()
        }
        center.addObserver(forName: Notification.Name.UIApplicationDidEnterBackground, object: nil, queue: nil) { [unowned self] (notification) in
            self.invalidateTimer()
        }
        center.addObserver(forName: Notification.Name.AVAudioSessionInterruption, object: nil, queue: nil) { [unowned self] (notification) in
            guard let userInfo = notification.userInfo else { return }
            guard let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt else { return }
            guard let type = AVAudioSessionInterruptionType(rawValue: typeValue) else { return }
            switch type {
            case .began:
                break
            case .ended:
                try? AVAudioSession.sharedInstance().setActive(true)
                self.player?.play()
            }
        }
        center.addObserver(forName: Notification.Name.AVAudioSessionSilenceSecondaryAudioHint, object: nil, queue: nil) { [unowned self] (notification) in
            guard let userInfo = notification.userInfo else { return }
            guard let typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey] as? UInt else { return }
            guard let type = AVAudioSessionSilenceSecondaryAudioHintType(rawValue: typeValue) else { return }
            switch type {
            case .begin:
                self.player?.pause()
                break
            case .end:
                self.player?.play()
                break
            }
        }
    }

    private func scheduleTimer() {
