1

On a screen inside my app I have both an AVAudioPlayer for music and an AVPlayer for videos. The user can swap out different songs and different videos but can only play one at a time. They can play either the audioPlayer or watch videos on the avPlayer.

I have MPRemoteCommandCenter that works fine for both when using pause/play/ff/rewind. The issue is I can't display the currentTime or duration for either on the lock screen. I tried this but it doesn't say where to put the code.

This is what I tried so that every time the user switches songs or videos I have all of the available data for the new items:

Audio-

do {        
    audioPlayer = try AVAudioPlayer(contentsOf: audioTrack)
    audioPlayer?.delegate = self
    audioPlayer?.prepareToPlay()
    audioPlayer?.play()
        
    setupNowPlayingForAudio()
        
} catch { 
}

func setupNowPlayingForAudio() {
    guard let audioPlayer = audioplayer else { return }
    
    var nowPlayingInfo = [String : Any]()
    nowPlayingInfo[MPMediaItemPropertyTitle] = "My App Name"
    
    nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = Float(audioPlayer.currentTime)
    nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = Float(audioPlayer.duration)
    nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = audioPlayer.rate

    MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}

Video-

playerStatusObserver = player?.observe(\.currentItem?.status, options: [.new, .old]) {

    switch (player.status) {
     case .readyToPlay:

         player?.play() 
         setupNowPlayingForVideo()
    }
}

func setupNowPlayingForVideo() {
    guard let player = player, let playerItem = player.currentItem else { return }
    
    var nowPlayingInfo = [String : Any]()
    nowPlayingInfo[MPMediaItemPropertyTitle] = "My App Name"
    
    nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playerItem.currentTime().seconds
    nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = playerItem.asset.duration.seconds
    nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.rate

    MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}

The MPRemoteCommandCenter is set in viewDidLoad along with the AVAudioSession

Lance Samaria
  • 17,576
  • 18
  • 108
  • 256

1 Answers1

0

I followed this answer which says that you have to add it to any pause/play/ff/rewind buttons, slider, and any observers that listen to the player playing/stopping. Here is the way that I did it. This works fine for me on the Lock Screen.

Here is where I used the below function for the AudioPlayer-

do {        
    audioPlayer = try AVAudioPlayer(contentsOf: audioTrack)
    // ... 
    audioPlayer?.play()

    setupNowPlaying(musicPlayer: audioPlayer)
        
} catch { }

func audioPlayerPausePlayButton() {
     // ...
     setupNowPlaying(musicPlayer: audioPlayer)
}

func audioPlayerFastFowardAndRewindButton() {
    // ... ff or rewind functions
    setupNowPlaying(musicPlayer: audioPlayer)
}

Here is where I used the below function for the AVPlayer-

playerStatusObserver = player?.observe(\.currentItem?.status, options: [.new, .old]) { // ...

    switch (player.status) {
     case .readyToPlay:

         // ... this should occur on the MainQueue
         self?.player?.play()
         self?.setupNowPlaying(videoPlayer: self?.player)
    }
}
// .. I also added it to any other observers that listen to the player stopping

func videoPlayerPausePlayButton() {
     // ...
     setupNowPlaying(videoPlayer: player)         
}

func videoPlayerFastFowardAndRewindButton() {
    // ...
    player?.seek(to: whateverSeekTime) { [weak self](_) in
        self?.setupNowPlaying(videoPlayer: self?.player)
    }
}

Dictionary values for the CommandCenter to show on the Lock Screen

func setupNowPlaying(musicPlayer: AVAudioPlayer? = nil, videoPlayer: AVPlayer? = nil) {
    
    var nowPlayingInfo = [String : Any]()
    
    // audio
    if let musicPlayer = musicPlayer, let musicUrl = musicPlayer.url {
        
        nowPlayingInfo[MPNowPlayingInfoPropertyAssetURL] = musicUrl
        nowPlayingInfo[MPMediaItemPropertyTitle] = musicUrl.lastPathComponent
        nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = MPNowPlayingInfoMediaType.audio.rawValue
        
        let currentTime: TimeInterval = musicPlayer.currentTime
        let musicCurrentTimeCMTime = CMTime(seconds: currentTime, preferredTimescale: 1000)
        nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(musicCurrentTimeCMTime)
        
        let musicDuration: TimeInterval = musicPlayer.duration
        let musicDurationCMTime = CMTime(seconds: musicDuration, preferredTimescale: 1000)
        nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = CMTimeGetSeconds(musicDurationCMTime)
        
        if musicPlayer.isPlaying {
            nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1
        } else {
            nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 0
        }
    }
    
    // video
    if let videoPlayer = videoPlayer, let currentItem = videoPlayer.currentItem {
        
        if let videoAsset = currentItem.asset as? AVURLAsset {
            let videoUrl = videoAsset.url
            nowPlayingInfo[MPNowPlayingInfoPropertyAssetURL] = videoUrl
            nowPlayingInfo[MPMediaItemPropertyTitle] = videoUrl.lastPathComponent
            nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = MPNowPlayingInfoMediaType.video.rawValue
        }
        
        if let videoDuration: CMTime = videoPlayer.currentItem?.duration {
            nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = CMTimeGetSeconds(videoDuration)
        }
        
        let videoCurrentTime: CMTime = videoPlayer.currentTime()
        let videoCurrentTimeAsSecs = CMTimeGetSeconds(videoCurrentTime)
        nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = videoCurrentTimeAsSecs
        
        print("videoCurrentTimeAsSecs: ", videoCurrentTimeAsSecs)
        
        if videoPlayer.isPlaying {
            nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1
        } else {
            nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 0
        }
    }
    
    nowPlayingInfo[MPMediaItemPropertyTitle] = "Your App Name"
    nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = false
    
    MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256