Book

Exploring MusicKit and Apple Music API

Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!

Working with a music app inevitably requires you to work the music player’s queue. MusicKit offers some robust methods to work with the queue. However, you may get into errors when inserting items in a queue, especially something related to a transient item. This post explores what a transient item is, the errors related to it, and how to work with it.

transientItem

An entry for the playback queue of the music player in MusicKit is represented by a structure Entry with many properties.

Two are particularly useful to understand, especially when inserting music items in the queue. These are transientItem and isTransient.

Directly copying the description from the documentation to avoid any confusion:

  • var transientItem: (PlayableMusicItem)? { get } A music item that corresponds to a recently inserted entry in the playback queue that has underlying items the music player still needs to resolve.
  • var isTransient: Bool { get } A Boolean value that indicates whether this entry of the playback queue has a transient music item.

If you directly try to insert items in a queue, you may see the following error:

[Playback] Inserting entries at the beginning of the queue because the previous entry (MusicPlayer.Queue.Entry(id: "1234-1234-1234", transientItem: Song(id: "12341234", title: "Transient", artistName: "MusicKit"))) is unexpectedly transient: [MusicPlayer.Queue.Entry(id: "45678-456789", transientItem: Song(id: "1234567890", title: "Oh No)", artistName: "Me"))]

While Apple’s docs, as usual, do not go deep into what this means, [Joel] from the MusicKit team covers the above error in detail here.

What is transient?

When the music player adds an item to the playback queue, it typically needs to load or resolve the underlying audio or media content associated with it before it can begin playback. This process can take some time, especially if the media is large or there are network or device issues.

Quoting directly from the comment:

ApplicationMusicPlayer’s Queue maintains a collection of Entries that can be mutated by the application and that get automatically updated under the hood when the state of the playback engine’s queue changes.

When you insert an item in the queue, the entry being inserted is transient, indicating that it hasn’t been fully inserted in the playback queue; hence, it has a temporary identifier; this entry remains transient until ApplicationMusicPlayer gets notified by the playback engine of the new state of the queue, with all inserted entries fully resolved.

This resolution process is especially important for collections such as albums or playlists; you could insert a MusicPlayer.Queue.Entrywith an Album; when you do, the playback engine will asynchronously resolve the tracks of the album, and the transient entry with an album will get replaced with regular entries for each track.

The music player may refer to this item as a “transientItem” to indicate that it is a temporary placeholder in the playback queue and that the underlying media content is still being processed. Once the media content has been fully resolved, the music player can replace the “transientItem” with the actual media item and continue playback without interruption.

Using “transientItem” allows for more efficient and seamless playback of media content, especially in situations where loading or resolving the media content may take some time.

So, what does that mean to you? You need to wait before adding a new item to the queue. Wait for it to go from the transient state to a regular entry state. How do you know about that?

Use the isTransient property on the current entry.

isTransient

The “isTransient” property indicates whether this entry in the playback queue has a “transientItem” associated with it or not.

If the value of “isTransient” is true, it means the corresponding entry in the playback queue has a “transientItem” currently being loaded or resolved in the background. This may be the case if the music player recently added a new item to the playback queue but has not fully loaded or resolved the underlying media content. So you need to wait before adding a new item to the queue.

Suppose the value of “isTransient” is false. In that case, the corresponding entry in the playback queue does not have a “transientItem” associated with it. The music player has fully loaded and resolved the underlying media content for this item. So you do not need to wait before adding a new item to the queue.

Observing Transient Changes

You can take advantage of the ApplicationMusicPlayer.Queue as it conforms to the ObservableObject protocol and be notified of the queue changes.

When there are changes in the queue, including when transient entries are replaced with regular ones, the objectWillChange publisher will emit a new value.

Example

You can observe the changes in the current entry and act accordingly:

@ObservedObject private var queue = ApplicationMusicPlayer.shared.queue

var body: some View {
  ScrollView {
  // view 
  }
  .onChange(of: queue.currentEntry, perform: { _ in
    if queue.currentEntry?.isTransient == false {
      // UPDATE THE QUEUE NOW!
      queue.insert(newSong, at: .tail)
    } else {
      // WAIT
  }
}
Book

Exploring MusicKit and Apple Music API

Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!

Written by

Rudrank Riyam

Hi, my name is Rudrank. I create apps for Apple Platforms while listening to music all day and night. Author of "Exploring MusicKit". Apple WWDC 2019 scholarship winner.