How can I play Apple Music Live Radio Station?

Hello,

I'm using systemMusicPlayer to play Apple Music Live Radio Station got from Apple Music API. But it doesn't work. How can I do that?

  • Error:
Test[46751:13235249] [SDKPlayback] Failed to prepareToPlay error: Error Domain=MPMusicPlayerControllerErrorDomain Code=6 "Failed to prepare to play" UserInfo={NSDebugDescription=Failed to prepare to play}

  • My implementation:
   let musicPlayerController = MPMusicPlayerController.systemMusicPlayer
musicPlayerController.beginGeneratingPlaybackNotifications()
     musicPlayerController.setQueue(with: "ra.978194965")
    musicPlayerController.play()
  • API response:
 {
            “id”: “ra.978194965”,
            “type”: “stations”,
            “href”: “/v1/catalog/us/stations/ra.978194965”,
            “attributes”: {
                “artwork”: {
                    “width”: 4320,
                    “url”: “https://is2-ssl.mzstatic.com/image/thumb/Features114/v4/e5/10/76/e5107683-9e51-ebc5-3901-d8fbd65f2c2a/source/{w}x{h}sr.jpeg”,
                    “height”: 1080,
                    “textColor3”: “332628”,
                    “textColor2”: “120509”,
                    “textColor4”: “33272a”,
                    “textColor1”: “000000”,
                    “bgColor”: “f4f4f4”,
                    “hasP3”: false
                },
                “url”: “https://music.apple.com/us/station/apple-music-1/ra.978194965”,
                “mediaKind”: “audio”,
                “supportedDrms”: [
                    “fairplay”,
                    “playready”,
                    “widevine”
                ],
                “requiresSubscription”: false,
                “name”: “Apple Music 1”,
                “kind”: “streaming”,
                “radioUrl”: “itsradio://music.apple.com/us/station/ra.978194965”,
                “playParams”: {
                    “id”: “ra.978194965”,
                    “kind”: “radioStation”,
                    “format”: “stream”,
                    “stationHash”: “CgkIBRoFlaS40gMQBA”,
                    “mediaType”: 0
                },
                “editorialNotes”: {
                    “name”: “Apple Music 1”,
                    “short”: “The new music that matters.”,
                    “tagline”: “The new music that matters.”
                },
                “isLive”: true
            }
        },```

Thank you!

Best regards,

MichaelNg

Replies

Hello @MichaelCS,

I tried to reproduce your issue, and the first thing that came up is that this line produces a compiler error:

musicPlayerController.setQueue(with: "ra.978194965")

It should be replaced with:

musicPlayerController.setQueue(with: ["ra.978194965"])

That said, once I applied this fix, I encountered the same issue as you did.

However, there is another way to set the queue on MPMusicPlayerController that is much better supported when dealing with resources loaded from Apple Music API.

As much as possible, you should use the variant of setQueue(with:) that requires a queue descriptor, and specifically use MPMusicPlayerPlayParametersQueueDescriptor.

To do that, you will need to decode the playParams attribute of the Apple Music API resource as an instance of MPMusicPlayerPlayParameters.

One way to do that is to decode that API response using a structure like this one:

struct MyStation: Decodable {
    struct Attributes: Decodable {
        let name: String?
        let playParams: MPMusicPlayerPlayParameters?
    }
    
    let id: String
    let attributes: Attributes
}

Please check this specific response in another recent thread for more information on this.

Once you get an instance of MyStation, you can begin playing this station with the following code:

let myStation = ...

if let myStationPlayParameters = myStation?.attributes.playParams {
    let queueDescriptor = MPMusicPlayerPlayParametersQueueDescriptor(playParametersQueue: [myStationPlayParameters])
    let musicPlayerController = MPMusicPlayerController.systemMusicPlayer
    musicPlayerController.beginGeneratingPlaybackNotifications()
    musicPlayerController.setQueue(with: queueDescriptor)
    musicPlayerController.play()
}

I hope this helps.

Best regards,

Hi again @MichaelCS,

By the way, I would be remiss if I didn't tell you that you can begin playing radio stations from Apple Music much more simply, using our new MusicKit framework.

The entire process of fetching the Station and playing it fits in just a few lines of code.

@MainActor
private func beginPlayingStation(id: MusicItemID) async throws {
    let stationRequest = MusicCatalogResourceRequest<Station>(matching: \.id, equalTo: id)
    let stationResponse = try await stationRequest.response()
    if let station = stationResponse.items.first {
        let musicPlayer = SystemMusicPlayer.shared
        musicPlayer.queue = [station]
        try await musicPlayer.play()
    }
}

You can then trigger this very simply by calling:

try await beginPlayingStation(id: "ra.978194965")

I would highly encourage you to learn more about MusicKit by watching our WWDC21 talk: Meet MusicKit for Swift.

I hope this helps.

Best regards,

  • @JoeKun Thank you for the above code! It worked great for me even using ApplicationMusicPlayer. I am running into a strange issue though. I have built in a way for the user to clear the queue, which works fine unless you play a radio station. Once you have selected a radio station to play, clearing the queue will get rid of the current two songs selected but will add two more. I'm not sure what to do to clear the queue. Any suggestions would be much appreciated. This is on iOS 16.5.

Add a Comment