Proper way to convert MediaItem to MediaQueueItem
@marcbaechinger is already working on this.
Since Mar 8, 2023.
- Dominant language
- Java
- Stars
- 3k
- Forks
- 955
- Avg merge
- 12d 14h
- Merged PRs (30d)
- 2
Description
Hi,
Apologies in advance if this is too vague of a question, but I am having some issues in properly converting from MediaItem to MediaQueueItem. My use case is quite simple (I think) I have a simple MediaItem which streams a live radio station. I create the MediaItem like so:
fun Stream.toMediaItem(): MediaItem {
return MediaItem.Builder()
.setMediaId(id)
.setRequestMetadata(
MediaItem.RequestMetadata.Builder()
.setMediaUri(url.toUri())
.build()
)
.setMediaMetadata(
MediaMetadata.Builder()
.setSubtitle(station)
.setArtist(station)
.setArtworkUri(imageUrl.toUri())
.build()
)
.build()
}
So the artist is set to the radio station name. Now when using an local ExoPlayer the MediaMetadata.title is getting dynamically set internally with the current song playing in the stream. This song is then shown in the app through Player.Listener.onMediaMetadataChanged(mediaMetadata: MediaMetadata), The song name is also correctly shown in the media notifications on my device. This all works fine.
Now I also have the option of switching to CastPlayer via pretty much the same implementation of the ReplacableForwardingPlayer in uamp. But I am not sure what the simplest implementation of a MediaItemConverter to properly convert to the MediaQueueItem. I was hoping I could just use the DefaultMediaItemConverter but alas. I see uamp uses the default one from converting to MediaQueueItem to MediaItem, yet uses a custom implementation the other way around. I tried using the default one too, but it requires mediaInfo.getCustomData() to be set, which i don't use. But the uamp/media3 branch hasn't been updated for a long time, so I don't know if the new media3 beta release changes anything for that app.
This is my current implementation. Since CastPlayer does not internally handles dynamic track information from the stream I use a static title instead of the song name.
class StreamMediaItemConverter(private val staticTitle: String) : MediaItemConverter {
override fun toMediaItem(mediaQueueItem: MediaQueueItem): MediaItem {
val mediaInfo = mediaQueueItem.media!!
val metadata = mediaInfo.metadata!!
val contentUrl = mediaInfo.contentUrl!!
val imageUrl = metadata.images.first().url
val title = metadata.getString(CastMetadata.KEY_TITLE)!!
val mediaId = metadata.getString(KEY_MEDIA_ID)!!
return MediaItem.Builder()
.setMediaId(mediaId)
.setRequestMetadata(
MediaItem.RequestMetadata.Builder()
.setMediaUri(contentUrl.toUri())
.build()
)
.setMediaMetadata(
MediaMetadata.Builder()
.setArtist(title)
.setSubtitle(title)
.setMediaType(MediaMetadata.MEDIA_TYPE_RADIO_STATION)
.setArtworkUri(imageUrl)
.build()
)
.build()
}
override fun toMediaQueueItem(mediaItem: MediaItem): MediaQueueItem {
// CastMetadata is a typealias for com.google.android.gms.cast.MediaMetadata
val metadata = CastMetadata(MEDIA_TYPE_GENERIC).apply {
putString(KEY_MEDIA_ID, mediaItem.mediaId)
putString(CastMetadata.KEY_ARTIST, mediaItem.mediaMetadata.artist.toString())
putString(CastMetadata.KEY_TITLE, staticTitle)
addImage(WebImage(mediaItem.mediaMetadata.artworkUri!!))
}
val mediaInfo = MediaInfo.Builder(mediaItem.mediaId)
.setContentUrl(mediaItem.localConfiguration?.uri.toString())
.setMetadata(metadata)
.build()
return MediaQueueItem.Builder(mediaInfo).build()
}
companion object {
private const val KEY_MEDIA_ID = "mediaId"
}
There are a couple of issues though, the first one being MediaQueueItem.Builder shows a warning that it should only be used in tests, which is concerning and secondly: I cant seem to show both the radio station name (which is set in mediaItem.mediaMetadata.artist and the static title in my media notification which is shown when switching from ExoPlayer to CastPlayer. I only see the CastMetadata.KEY_ARTIST. Both strings are shown when casting to my TV and in the Google Home app as well, so I am confused why it doesn't show in my notification. I have tried a lot of combinations of values but they do not seem to work. Keep in mind I am using CastMediaOptions.Builder()..setMediaSessionEnabled(false).setNotificationOptions(null) like uamp does in order to not have 2 separate notifications when casting. So I guess this issue is kind of related to this old issue made by yours truly. However I am not changing the player instance in the mediaSession anymore, but instead using a ReplacableForwardingPlayer like uamp. Honestly the process of having a uniform notification experience for local and cast playback is just confusing to me as an developer.
A small aside: it took me a while to figure out that the MediaInfo.Builder(String contentId) is needed when using CastPlayer.setMediaItems() with more then 1 item in the playlist. I was using the empty MediaInfo.Builder() constructor, but since the CastTimelineTracker uses the contentId as keys that led to some weird behaviour. But you can probably don't touch the public API anymore after RC status..
What am I missing here? I want the simplest conversion possible when and I only need to show artist, title and artwork.
Thank you for reading.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.