iOS элементы управления звуком на экране блокировки не обновляют время до нажатия кнопки - PullRequest
0 голосов
/ 05 марта 2020

Я создаю приложение для воспроизведения аудио, которое загружает mp3-файлы с URL. Я хочу получить функциональность iOS блокировки экрана и реализовал MPNowPlayingInfoCenter и MPRemoteCommandCenter, как вы увидите ниже. По какой-то причине временная позиция и продолжительность не будут обновляться, пока я не нажму одну из кнопок ПОСЛЕ воспроизведения звука (завершена буферизация). Как я могу получить время для автоматического обновления, как только будет воспроизводиться mp3?

    func playNewProgram() {
        let currentUrl: URL? = (player.currentItem?.asset as? AVURLAsset)?.url

        guard program?.playLink != currentUrl else {
            return
        }

        guard let url = program?.playLink else {
            return
        }

        let item = AVPlayerItem(url: url)
        self.player.replaceCurrentItem(with: item)
        audioPos = 0

        playAudio()
    }

    func resetPlayer() {
        guard let url = program?.playLink else {
            return
        }

        let item = AVPlayerItem(url: url)
        self.player.replaceCurrentItem(with: item)

        audioPos = 0
        player.pause()
        playerPaused = true
    }

    func togglePlayPause() {
        pausePlayer(!playerPaused)
    }

    func pausePlayer(_ pause: Bool) {

        playerPaused = pause

        if playerPaused {
            player.pause()
        }
        else {
            // This allows the audio to be played while the phone is on silent
            playAudio()
        }
    }

    func playAudio() {
        playerPaused = false

        do {
            try AVAudioSession.sharedInstance().setCategory(.playback)
        } catch(let error) {
            print(error.localizedDescription)
        }

        player.play()

        updateLockScreen(with: self.program)
    }


    func sliderEditingChanged(editingStarted: Bool) {

        if editingStarted {
            // Set a flag stating that we're seeking so the slider doesn't get updated by the periodic time observer on the player
            seeking = true
            pausePlayer(true)
        }
        // Do the seek if we're finished
        if !editingStarted {
            let targetTime = CMTime(seconds: audioPos * audioDuration,
                                    preferredTimescale: 600)
            player.seek(to: targetTime) { _ in
                // Now the seek is finished, resume normal operation
                self.seeking = false
                self.pausePlayer(false)
            }
        }
    }


    func goForward30() {

        if let currentTime = player.currentItem?.currentTime(), let duration = player.currentItem?.duration {

            var newTime = CMTimeGetSeconds(currentTime) + 30
            if newTime >= CMTimeGetSeconds(duration) {
                newTime = CMTimeGetSeconds(duration)
            }

            player.seek(to: CMTime(value: CMTimeValue(newTime * 600), timescale: 600)) { _ in

                self.updateLockScreen(with: self.program)
            }

            if !playerPaused {
                player.pause()
                playAudio()
            }
        }
    }


    func goBackward15() {

        if let currentTime = player.currentItem?.currentTime() {

            var newTime = CMTimeGetSeconds(currentTime) - 15
            if newTime <= 0 {
                newTime = 0
            }

            player.seek(to: CMTime(value: CMTimeValue(newTime * 600), timescale: 600)) { _ in

                self.updateLockScreen(with: self.program)
            }

            if !playerPaused {
                 player.pause()
                 playAudio()
             }
        }
    }



    // MARK: - MPMediaPlayer
    func setupRemoteCommandCenter() {

        let commandCenter = MPRemoteCommandCenter.shared()

        // MARK: Play
        commandCenter.playCommand.addTarget { event in
            self.togglePlayPause()
            return .success
        }

        // MARK: Pause
        commandCenter.pauseCommand.addTarget { event in
            self.togglePlayPause()
            return .success
        }


        // MARK: Skip
        func skipBackward(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
            guard let command = event.command as? MPSkipIntervalCommand else {
                return .noSuchContent
            }

            goBackward15()

            return .success
        }

        let skipBackwardCommand = commandCenter.skipBackwardCommand
        skipBackwardCommand.isEnabled = true
        skipBackwardCommand.addTarget(handler: skipBackward)
        skipBackwardCommand.preferredIntervals = [-15]


        func skipForward(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
            guard let command = event.command as? MPSkipIntervalCommand else {
                return .noSuchContent
            }

            goForward30()

            return .success
        }

        let skipForwardCommand = commandCenter.skipForwardCommand
        skipForwardCommand.isEnabled = true
        skipForwardCommand.addTarget(handler: skipForward)
        skipForwardCommand.preferredIntervals = [30]
    }


    func updateLockScreen(with program: ProgramData?) {

        // Define Now Playing Info
        var nowPlayingInfo = [String : Any]()

        nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0

        if let artist = program?.series {
            nowPlayingInfo[MPMediaItemPropertyArtist] = artist
        }

        if let title = program?.title {
            nowPlayingInfo[MPMediaItemPropertyTitle] = title
        }

        // Shows LIVE label instead of slider
//        nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = true

        nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = audioDuration
        nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = audioPos * audioDuration

        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
...