5

I am handling audio playback using AVAudioEngine and AVAudioPlayerNode in my app, and I want to implement remote controls. Background audio is configured and working.

Control center controls work, but the play/pause button does not update when I play/pause the music from inside the app. I am testing on a real device.

Control center screenshot

Here is my AVAudioSession setup code:

func setupAudioSession() {

    UIApplication.shared.beginReceivingRemoteControlEvents()

    do {
        try AVAudioSession.sharedInstance().setActive(true)
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
    } catch let sessionError {
        print("Failed to activate session:", sessionError)
    }
}

MPRemoteCommandCenter setup:

func setupRemoteControl() {

    let commandCenter = MPRemoteCommandCenter.shared()

    commandCenter.playCommand.isEnabled = true
    commandCenter.playCommand.addTarget { (_) -> MPRemoteCommandHandlerStatus in
        self.audioPlayerNode.play()
        return .success
    }

    commandCenter.pauseCommand.isEnabled = true
    commandCenter.pauseCommand.addTarget { (_) -> MPRemoteCommandHandlerStatus in
        self.audioPlayerNode.pause()
        return .success
    }
}

Lock screen controls - never appeared.

anton
  • 181
  • 1
  • 6
  • @matt edited the question – anton Apr 19 '18 at 16:28
  • @matt yes, everything is playing in the background just fine. Background modes are configured. Maybe some AVAudioEngine special setup I am missing? – anton Apr 19 '18 at 16:34
  • @matt Sure, I can play/pause audio from control center. But the play button icon in control center wouldn't update from "pause icon" to "play icon" if i would go inside my app and pause the audio calling AVaudioPlayerNode.pause() for example, same thing happens in reverse – anton Apr 19 '18 at 16:52

1 Answers1

8

So here is the solution to my problem, I was starting my AVAudioEngine together with its setup function called from viewDidLoad(), that was the issue, and i used .play()/.pause() methods on my AVAudioPlayerNode to manipulate the audio, however AVAudioPlayerNode does not emit master audio, outputNode of AVAudioEngine does.

So whenever you want to play/pause audio from inside your app or from command center, if you are using AVAudioEngine to handle audio in you application, don’t forget to call .stop()/.start() methods on your AVAudioEngine. Lock screen controls should show up and play/pause buttons should update properly in command center/lock screen even without a single property set to MPNowPlayingInfoCenter.default().nowPlayingInfo.

MPRemoteCommandCenter setup:

func setupRemoteControl() {

    let commandCenter = MPRemoteCommandCenter.shared()

    commandCenter.playCommand.isEnabled = true
    commandCenter.playCommand.addTarget { (_) -> MPRemoteCommandHandlerStatus in
        try? self.audioEngine.start()
        return .success
    }

    commandCenter.pauseCommand.isEnabled = true
    commandCenter.pauseCommand.addTarget { (_) -> MPRemoteCommandHandlerStatus in
        self.audioEngine.stop()
        return .success
    }
}
anton
  • 181
  • 1
  • 6
  • 1
    Please note that if you will be accessing the play/pause command multiple times, it is better to use the AVAudioEngine's pause() method instead of stop(). – Taiwosam May 15 '19 at 16:01
  • Thank you!!! Had been trying to figure this out for ages. I had just been pausing the individual notes, and not the whole engine. – Muindor Apr 04 '21 at 21:00
  • Thank you sweet @anton! I'm using AudioKit, which uses AVAudioEngine and AVAudioPlayerNode, and could not get the UI controls to sync up with MPRemoteCommandCenter. This worked like a charm! I sunk so many hours into trying to figure out why this was happening. – rtoken Jul 31 '23 at 21:19
  • Update: this is causing problems when pausing from the lock screen while the app is in the background. 5 seconds or so after pausing, when I try to resume/play again, the app crashes due to the AVAudioEngine not running. In my `playAudio()` command, I do try to start the engine if it's not already running, but that fails. Any ideas? P.S. If I keep everything in the foreground: no problems. – rtoken Aug 01 '23 at 00:09