Search code examples
mpmediaplayercontroller

Can't set MPMusicPlayerController queue with MPMusicPlayerMediaItemQueueDescriptor


This code results in silence:

let query = MPMediaQuery.songs()
let result = query.items
guard let items = result, items.count > 0 else {return}
let song = items[0]

let player = MPMusicPlayerController.applicationQueuePlayer

let coll = MPMediaItemCollection(items: [song])
let q = MPMusicPlayerMediaItemQueueDescriptor(itemCollection: coll)
player.setQueue(with: q)
player.play()

I've stepped through the code, and we reach player.play(). I have an MPMediaItem and I've correctly formed an MPMediaItemCollection from that, and an MPMusicPlayerMediaItemQueueDescriptor from that. So why isn't my player playing?


Solution

  • You've found a bug. It appears that the initializer MPMusicPlayerMediaItemQueueDescriptor(itemCollection:) is completely broken: it results in an unusable queue descriptor.

    The workaround, where possible, is to use the other initializer instead, namely MPMusicPlayerMediaItemQueueDescriptor(query:).

    For example, in this case, you could write (picking up in the last four lines of the original code):

    let coll = MPMediaItemCollection(items: [song])
    let predicate = MPMediaPropertyPredicate(
                    value: song.persistentID,
                    forProperty: MPMediaItemPropertyPersistentID)
    let query = MPMediaQuery(filterPredicates: [predicate])
    let q = MPMusicPlayerMediaItemQueueDescriptor(query: query)
    player.setQueue(with: q)
    player.play()
    

    Unfortunately, there are many circumstances where you can't form a single query that gets the MPMediaItemCollection you really wanted.

    In this particular example you could work around that, too, by setting the player's queue directly with an MPMediaItemCollection instead of a MPMusicPlayerMediaItemQueueDescriptor made from an MPMediaItemCollection.

    But alas, there are some commands (such as append(_:)) that require an MPMusicPlayerMediaItemQueueDescriptor, and for things like that, this entire API is basically hosed. It has been hosed since iOS 10.1 and it remains hosed in iOS 11.1.