dandepeched
dandepeched

Reputation: 454

Use player controls on iOS lock screen for Remote Control application

I'm trying to implement player controls on iOS lock screen for my Remote Control application that controls Music Player on PC. So basically I need to control playback outside of iOS device. I've enabled Background Modes in capabilities (Audio) and tried to set MPRemoteCommandCenter lock screen controls, but they aren't shown. Here is code:

class RemoteCommandHandler: NSObject {
    static let shared = RemoteCommandHandler()

    private let player = AVPlayer()
    private let audioSession = AVAudioSession.sharedInstance()
    private let commandCenter = MPRemoteCommandCenter.shared()

    func initRemote() {
        //UIApplication.shared.beginReceivingRemoteControlEvents()

        do {
            if #available(iOS 10.0, *) {
                try audioSession.setCategory(.playback, mode: .default, options: [])
            } else {
                // Fallback on earlier versions
                try audioSession.setCategory(.playback)
            }
        } catch {
            NSLog("\(error)")
        }

        do {
            try audioSession.setActive(true)
            NSLog("AVSession is active")
        } catch {
            NSLog("\(error)")
        }

        setupRemoteTransportControls()
        setupNowPlaying()
    }

    func setupRemoteTransportControls() {
        commandCenter.togglePlayPauseCommand.isEnabled = true
        commandCenter.togglePlayPauseCommand.addTarget(self, action: #selector(controlPlayPause))
    }

    func setupNowPlaying() {
        var nowPlayingInfo = [String : Any]()
        nowPlayingInfo[MPMediaItemPropertyTitle] = NowPlayingInfo.getValue(.Title)

        if let image = UIImage(named: "DemoArtwork") {
            nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(image: image)
        }
        nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = TimeInterval(exactly: 10)
        nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = NowPlayingInfo.getDurationMs() / 1000
        nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0

        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
}

Is it even possible to do what I want? What I'm doing wrong?

Upvotes: 2

Views: 1789

Answers (1)

dandepeched
dandepeched

Reputation: 454

It looks like the only possible way to have controls on lock screen is to initiate playback of real audio file from your app. I did a workaround of very short silent file playback on app startup and now I have access to those controls.

Keep in mind that Background Mode (Audio) should be enabled in order to see controls while your app is not on the screen.

Another limitation is that Volume control is hard-wired to device volume, so you cannot change app volume separately.

Here is the minimal code to enable controls:

import MediaPlayer
import AVFoundation

class RemoteCommandHandler: NSObject {
    static let shared = RemoteCommandHandler()

    private var player: AVPlayer!
    private var playerItem: AVPlayerItem!
    private let audioSession = AVAudioSession.sharedInstance()
    private let commandCenter = MPRemoteCommandCenter.shared()

    func initRemote() {
        let sound = Bundle.main.path(forResource: "SilenceAAC", ofType: "m4a")
        playerItem = AVPlayerItem(url: URL(fileURLWithPath: sound!))
        player = AVPlayer(playerItem: playerItem)

        do {
            if #available(iOS 10.0, *) {
                try audioSession.setCategory(.playback, mode: .default, options: [])
            } else {
                // Fallback on earlier versions
                try audioSession.setCategory(.playback)
            }

            try audioSession.setActive(true)
            NSLog("AVSession is active - \(audioSession)")
        } catch {
            NSLog("\(error)")
        }

        setupNowPlaying()
        setupRemoteTransportControls()

        player.play()
    }

    func setupRemoteTransportControls() {
        commandCenter.togglePlayPauseCommand.addTarget(self, action: #selector(controlPlayPause))
    }

    func setupNowPlaying() {
        var nowPlayingInfo = [String : Any]()
        nowPlayingInfo[MPMediaItemPropertyTitle] = NowPlayingInfo.getValue(.Title)

        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
}

Upvotes: 2

Related Questions