MPMusicPlayerController slow to respond when systemMusicPlayer, fast when application
Asked Answered
V

4

6

I have a music app that uses the MPMusicPlayerController.

I originally wrote it using the systemMusicPlayer option under iOS 9. I had some trouble with the player not shutting down correctly under certain circumstances so I switched to the appplicationMusicPlayer (see Quitting app causes error "Message from debugger: Terminated due to signal 9")

However, as an application player, I can't get a lot of the benefits like control center handling, bluetooth data display, etc.

So, I switched back to the systemMusicPlayer. I have also changed to Xcode 9.2 and a compile target of iOS 10.3.

Now when I run my app, it can take several seconds for it to respond to controls like play/pause or next/previous. My whole UI is painfully unresponsive.

I tried switching back to applicationMusicPlayer, recompiled, and sure enough - the UI is at normal speed.

So now I'm in a crappy position - with systemMusicPlayer, the app is barely usable, but with applicationMusicPlayer I lose a ton of capabilities.

This seems directly related to either iOS 11.2.2 on my iPhone, or something to do with targeting iOS 10.3+

Does anyone have any information about what is going on and how to fix it

EDIT: I created a very basic player and it seems to work fine in either mode, so now I'm puzzled - I'll be testing other MP commands to see what the issue is but since even my UI slows down I'm not sure.

EDIT 2: I believe I've found the culprit to be NotificationCenter, and also getting States from the MPMusicPlayerController. I've updated my sample code below which shows the problem. Once running, clicking the 'next' button will be slow sometimes, but clicking 'previous' can cause delays of up to two seconds!!

Here is the basic code if you want to create a simple player. Be sure to add three buttons in the storyboard and connect them accordingly.

//
//  ViewController.swift
//  junkplayer
//

import UIKit
import MediaPlayer

let notificationCenter = NotificationCenter.default

let myMP:MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
//let myMP:MPMusicPlayerController = MPMusicPlayerController.applicationMusicPlayer()

class ViewController: UIViewController {
    @IBOutlet weak var xxx: UIButton!
    @IBOutlet weak var nextbut: UIButton!
    @IBOutlet weak var prevbut: UIButton!
    var qrySongs = MPMediaQuery()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        myMP.repeatMode = MPMusicRepeatMode.none
        myMP.shuffleMode = MPMusicShuffleMode.off
        myMP.prepareToPlay()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        stopMPNotifications()
        startMPNotifications()
    }

    @IBAction func nextbut(_ sender: Any) {
        myMP.skipToNextItem()
    }
    @IBAction func prevbut(_ sender: Any) {
        myMP.skipToPreviousItem()
    }
    @IBAction func playbut(_ sender: UIButton) {
        qrySongs = MPMediaQuery.songs()
        myMP.setQueue(with: qrySongs)

        myMP.play()
    }
    func startMPNotifications(){
        notificationCenter.addObserver(self, selector: #selector(showNowPlaying), name: .MPMusicPlayerControllerNowPlayingItemDidChange, object: myMP)
        notificationCenter.addObserver(self, selector: #selector(handlePlayState), name: .MPMusicPlayerControllerPlaybackStateDidChange, object: myMP)
        myMP.beginGeneratingPlaybackNotifications()
    }
    func stopMPNotifications(){
        notificationCenter.removeObserver(self, name: .MPMusicPlayerControllerPlaybackStateDidChange, object: myMP)
        notificationCenter.removeObserver(self, name: .MPMusicPlayerControllerNowPlayingItemDidChange, object: myMP)
        myMP.endGeneratingPlaybackNotifications()
    }
    @objc func handlePlayState(){
        if myMP.playbackState == .playing {
            print("handlePlayState playback state = playing")
        }else{
            print("handlePlayState playback state NOT playing")
        }
        print("handlePlayState going to shownowplaying")
        showNowPlaying()
    }
    @objc func showNowPlaying(){
        if myMP.nowPlayingItem != nil {
            print("shownowplaying nowplaying not null")
        }
    }
}
Verleneverlie answered 17/1, 2018 at 21:37 Comment(3)
Confirmed. I am experiencing the same issue on iOS 11 with my music player app (which uses systemMusicPlayer). I have another app that does not have these lags/delays and it is using applicationMusicPlayer. I am also an Apple Music subscriber, but have all my music set to auto-download to my iOS devices. Sorry, but I have no workaround yet.Lepton
I am also trying to make an app and systemMusicPlayer makes the app lag very bad but queueplayer does not give controlsCircumscribe
Same issue here...Hangup
H
1

The app seems to lock up once you start playing, but if you swipe up to show the Control Centre then dismiss it, the app starts working fine immediately.

Holston answered 5/2, 2018 at 21:3 Comment(0)
T
0

I am having the same problem. I think it’s something wrong with the API. It's especially slow for large queries. But you can put a predicate on the quart, that allows no cloud music to go on it.

Ticon answered 5/3, 2018 at 9:27 Comment(0)
W
0

For anyone browsing this thread in the future, this was a known bug within all versions of iOS 11.2. It affected anyone using the systemMusicPlayer.

Apple sure does love to discourage us third party music app developers, eh? ;)

Regardless of my conspiracy theories (and I'm sure you have yours too), this bug was fixed in iOS 11.3.

We warn users on iOS 11.2 about the bug and recommend that they upgrade to iOS 11.3 for a (more or less) lag-free experience.

Wellturned answered 3/6, 2018 at 21:34 Comment(0)
M
0

I ran into this problem today - working code just stopped running correctly, but I found a (partial) workaround:

\\Do anything that updates (like changing the song title in the UI) in the selector called by this notification
NotificationCenter.default.addObserver(self, selector: #selector(remoteMusicChange), name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: nil)

The issue is that calls to say go to the next track for systemMusicPlayer are no longer (always) happening immediately. If you wait for the notification, at least you can be sure systemMusicPlayer has updated.

The problem with this is sometimes it can take a perceptibly long time for that notification to fire (and sometimes it's instant).

EDIT: https://forums.developer.apple.com/thread/96287 I am guessing this is related to these issues

EDIT2: Tested another related issue quickly in iOS12 and the problem no longer existed (changing playback speed) and the pauses when changing songs went away.

Maletta answered 4/8, 2018 at 15:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.