Воспроизведение/пауза и прошедшее время не обновляются должным образом в командном центре iOS

У меня есть видеоплеер, который может воспроизводиться из командного центра iOS и экрана блокировки. Когда я переключаю кнопку воспроизведения/паузы в своем приложении, она должна обновить кнопку воспроизведения/паузы в командном центре (MPRemoteCommandCenter), обновив nowPlayingInfo (MPNowPlayingInfoCenter). Я не уверен, почему он не обновляется.

Например, если я ставлю видео на паузу с помощью пользовательской кнопки в своем приложении, в командном центре по-прежнему отображается кнопка паузы (это означает, что видео все еще воспроизводится, что неверно).

введите описание изображения здесь

Вот как я обновляю nowPlayingInfo:

func updateMPNowPlayingInforCenterMetadata() {
    guard video != nil else {
        nowPlayingInfoCenter.nowPlayingInfo = nil
        return
    }

    var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()

    let image: UIImage
    if let placeholderLocalURL = video.placeholderLocalURL, let placeholderImage = UIImage(contentsOfFile: placeholderLocalURL.path) {
        image = placeholderImage
    } else {
        image = UIImage()
    }

    let artwork = MPMediaItemArtwork(boundsSize: image.size, requestHandler: { _ -> UIImage in
        return image
    })

    nowPlayingInfo[MPMediaItemPropertyTitle] = video.title
    nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = video.creator?.name ?? " "
    nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork

    nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = Float(video.duration)
    nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = Float(currentTime) // CMTimeGetSeconds(player.currentItem!.currentTime())
    nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.rate
    nowPlayingInfo[MPNowPlayingInfoPropertyDefaultPlaybackRate] = player.rate

    nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo

    if player.rate == 0.0 {
        state = .paused
    } else {
        state = .playing
    }
}

С KVO, когда меняется rate игрока, я вызываю эту функцию:

// MARK: - Key-Value Observing Method

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard context == &assetPlaybackManagerKVOContext else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }

    } else if keyPath == #keyPath(AVPlayer.rate) {
        updateMPNowPlayingInforCenterMetadata()
    }
}

Есть предположения?

ОБНОВИТЬ

Я нашел решение, но не идеальное в моем случае. Итак, в моем приложении у меня есть 2 контроллера представления. Назовем их FeedVC и PlayerVC. Итак, у FeedVC есть AVPlayer, которые всегда играют, но приглушены. Если вы нажмете на один из них, то будет создан PlayerVC и воспроизводится полное видео. Если я приостановлю AVPlayer в FeedVC перед тем, как перейти к PlayerVC, то кнопка "воспроизведение/пауза" в NowPlayingInfoCenter будет работать отлично!

Есть ли способ заставить это работать без необходимости приостанавливать видео в FeedVC?

Еще одна проблема заключается в том, что elapsed time продолжает считать, если я не приостанавливаю игроков в FeedVC. Кажется, что если играют несколько игроков, кнопка воспроизведения/паузы и прошедшее время отображаются неправильно.


person JEL    schedule 07.04.2017    source источник
comment
Я понял тебя, чувак, просто дай мне время вернуться домой, и я покажу тебе свое решение.   -  person Brandon A    schedule 11.04.2017
comment
Я также столкнулся с той же проблемой. Вы нашли решение для этого   -  person Aslam    schedule 10.09.2019


Ответы (1)


Когда вы устанавливаете словарь для nowPlayingInfo, вам нужно правильно установить значение MPNowPlayingInfoPropertyPlaybackRate. MPNowPlayingInfoCenter ожидает значение 1.0 (воспроизведение) или 0.0 (не воспроизведение) в качестве объекта Double, обернутого в объект NSNumber. Ниже вы найдете код того, как я устанавливаю nowPlayingInfo в своем проекте.

func setNowPlayingMediaWith(song: SUSong, currentTime: Double?) {

    var playingInfo:[String: Any] = [:]

    if let title = song.title {
        playingInfo[MPMediaItemPropertyTitle] = title
    }

    if let songID = song.id {
        playingInfo[MPMediaItemPropertyPersistentID] = songID
    }
    if let artist = song.artist, let artistName = artist.name {
        playingInfo[MPMediaItemPropertyArtist] = artistName
    }

    if let album = song.album, let albumTitle = album.title {
        var artwork:MPMediaItemArtwork? = nil
        if let album = song.album, let artworkData = album.artwork {
            artwork = MPMediaItemArtwork(boundsSize: Constants.Library.Albums.thumbSize, requestHandler: { (size) -> UIImage in
                return UIImage(data: artworkData as Data)!
            })
        }
        if artwork != nil {
            playingInfo[MPMediaItemPropertyArtwork] = artwork!
        }
        playingInfo[MPMediaItemPropertyAlbumTitle] = albumTitle
    }

    var rate:Double = 0.0
    if let time = currentTime {
        playingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = time
        playingInfo[MPMediaItemPropertyPlaybackDuration] = song.duration
        rate = 1.0
    }
    playingInfo[MPNowPlayingInfoPropertyPlaybackRate] = NSNumber(value: rate)
    playingInfo[MPNowPlayingInfoPropertyMediaType] = NSNumber(value: MPNowPlayingInfoMediaType.audio.rawValue)
    MPNowPlayingInfoCenter.default().nowPlayingInfo = playingInfo
}

В этом методе я передаю song, которые в данный момент загружены моим плеером. Всякий раз, когда пользователь выбирает воспроизведение или паузу, я вызываю setNowPlayingMediaWith(song:currentTime:), чтобы обновить консоль управления устройством.

Я отслеживаю currentTime (Double) как свойство моего плеера. Если передается currentTime, это означает, что мы должны играть, поэтому установите MPNowPlayingInfoPropertyPlaybackRate на 1.0, а MPNowPlayingInfoPropertyElapsedPlaybackTime на currentTime. Это установит текущее время для автоматического запуска воспроизведения в консоли управления устройством.

Аналогично, если currentTime не пройдено, значит, мы остановились или приостановились. В этом случае мы устанавливаем MPNowPlayingInfoPropertyPlaybackRate на 0.0 и не включаем MPNowPlayingInfoPropertyElapsedPlaybackTime.

Загрузите мое приложение, чтобы увидеть его в действии.


EDIT (ответ на комментарии)

"Есть ли способ заставить это работать, не приостанавливая видео в FeedVC"

Не видя вашего кода, трудно дать вам определенный ответ. Однако было бы разумно приостановить любой текущий медиафайл перед запуском медиафайла PlayerVC.


"прошедшее время продолжает отсчитываться"

Прошедшее время будет отсчитывать прошедшее время на основе свойства NSTimer на NowPlayingInfoCenter. Этот таймер остановится только тогда, когда значение таймера достигнет значения, установленного в MPMediaItemPropertyPlaybackDuration, или когда вы обновите файл MPNowPlayingInfoPropertyElapsedPlaybackTime.

Мое предложение состоит в том, чтобы написать метод, который "очищает" NowPlayingInfoCenter. Этот метод должен установить для всех значений ключей значение 0.0 или nil соответственно. Вызывайте этот метод «очистить» каждый раз перед воспроизведением мультимедиа в PlayerVC. Затем, как только вы начнете играть с PlayerVC, установите значения ключа NowPlayingInfoCenter, как в методе, который я вставил в свой ответ, чтобы установить новые значения для новых воспроизводимых носителей.

person Brandon A    schedule 10.04.2017
comment
Разве мой код не делает это автоматически с nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.rate и nowPlayingInfo[MPNowPlayingInfoPropertyDefaultPlaybackRate] = player.rate? - person JEL; 11.04.2017
comment
Кроме того, я получил это из примера кода Apple: developer.apple.com/library/content/samplecode/ - person JEL; 11.04.2017
comment
Я обновлю свой ответ позже сегодня вечером. Я на работе и у меня нет персонального компьютера. Но я сделал это в личном проекте, и он отлично работает. Я думал, что все пошло так, как описано выше, но я обновлю это сегодня вечером. - person Brandon A; 11.04.2017
comment
Хорошо конечно, спасибо! Пожалуйста, также взгляните на мое обновление, потому что я также упоминаю, что elapsed time, похоже, не работает должным образом. - person JEL; 11.04.2017
comment
@JEL Я обновил свой ответ. Пожалуйста, дайте мне знать, если это поможет вам. Если нет, мы можем поговорить в чате, и я могу провести вас через это. - person Brandon A; 11.04.2017
comment
Я получаю текущее время игрока с помощью CMTimeGetSeconds(player.currentTime()), но это не возвращает nil. Поэтому с вашей функцией, когда вы решите передать nil параметру currentTime: Double? или нет? По сути, с CMTimeGetSeconds(player.currentTime()) это означает, что я никогда не прохожу nil - person JEL; 11.04.2017
comment
Это не работает для меня, я попытался установить currentTime на nil, когда приостанавливаю видео только для проверки, но кнопка воспроизведения/паузы не меняется правильно. Я все еще думаю, что это из-за того, что другие AVPlayer играют в другом контроллере представления. - person JEL; 12.04.2017
comment
Имейте в виду, что это не 100% копирование и вставка. Это именно то, что я сделал в своем проекте. Например, у вас не будет SUSong. Можете ли вы вставить свой код, чтобы я мог видеть, что вы делаете? - person Brandon A; 12.04.2017
comment
Да, я понимаю, что это не копирование/вставка :) Быстрый вопрос, вы запускали тест, в котором AVPlayer всегда играет в другом контроллере представления - аналогично тому, что я сказал в Update моего вопроса? - person JEL; 12.04.2017
comment
Вы видели мой предыдущий комментарий и вопрос выше? ^^ - person JEL; 17.04.2017
comment
@JEL Та же проблема возникает у меня с экземпляром AVPlayer и экземпляром AVPlayerViewController. К счастью, в AVPlayerViewController есть возможность установить для updateNowPlayingInfoCenter значение false. - person Aodh; 26.07.2017