Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always-on Display Is Not Updated Dynamically #246

Open
1 task done
y20k opened this issue Jan 23, 2023 · 13 comments
Open
1 task done

Always-on Display Is Not Updated Dynamically #246

y20k opened this issue Jan 23, 2023 · 13 comments
Assignees
Labels

Comments

@y20k
Copy link

y20k commented Jan 23, 2023

Media3 Version

1.0.0-beta03

Devices that reproduce the issue

  • Pixel 4a running Android 13

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

I maintain an Android radio app. The app displays the currently playing song in the notification. Media3 automatically updates the notification when no Title has been set in MediaMetadata of a MediaItem - which is pretty neat (see also #153).

The Always-on Display on the other hand is not automatically updated.

To reproduce:

  1. turn on the Always-on Display in Settings > Display > Lock screen > Always show time and info on the testing device
  2. modify the demo-session app to not set a title in MediaItemTree.kt
  3. play back a radio station via the demo-session app
  4. the Notification is updated dynamically ✅
  5. turn off the display to see if the title is updated dynamically in the Always-on Display

Expected result

In the Always-on Display the same Title should be displayed as in the Notification.

Actual result

The Always-on Display displays "No title", when a title has not been set.

The photos above are from a fork of the demo-session app (see y20k@2e722ac).

Media

I added a radio station to demos/session/src/main/assets/catalog.json in a fork of the demo app to test the issue.

Bug Report

@tinsae-ghilay
Copy link

same here with Media3 on Pixel 6a. but I am not using the demo app. local file with title set shows on both notification and always on display. Online radio with title not set, shows only on Notification but No Title on always on display

@marcbaechinger
Copy link
Contributor

marcbaechinger commented Jan 30, 2023

Thanks for the excellent bug report!

However, I can not repro this as far as I do the steps correctly and understand the issue.

Media3 implementation

From Media3 side I see that metadata of the session and the notifcation is updated accordingly, when the player's metadata has been reported to change:

2023-01-30 13:57:53.167 11811-11811 alwayson                androidx.media3.demo.session         D  onMediaMetadataChanged SUPER BOWL 57 IS SET-Tom Goldman
2023-01-30 13:57:53.168 11811-11811 alwayson                androidx.media3.demo.session         D  set legacy metadata with SUPER BOWL 57 IS SET-Tom Goldman
2023-01-30 13:57:53.183 11811-11811 alwayson                androidx.media3.demo.session         D  set notification title SUPER BOWL 57 IS SET-Tom Goldman
2023-01-30 14:00:45.188 11811-11811 alwayson                androidx.media3.demo.session         D  onMediaMetadataChanged BBC News-BBC World Service
2023-01-30 14:00:45.190 11811-11811 alwayson                androidx.media3.demo.session         D  set legacy metadata with BBC News-BBC World Service
2023-01-30 14:00:45.213 11811-11811 alwayson                androidx.media3.demo.session         D  set notification title BBC News-BBC World Service
2023-01-30 14:06:45.162 11811-11811 alwayson                androidx.media3.demo.session         D  onMediaMetadataChanged Newshour-BBC World Service
2023-01-30 14:06:45.164 11811-11811 alwayson                androidx.media3.demo.session         D  set legacy metadata with Newshour-BBC World Service
2023-01-30 14:06:45.192 11811-11811 alwayson                androidx.media3.demo.session         D  set notification title Newshour-BBC World Service

That pretty much meets the expectation, even if the the metadata is not really precisely updated. In the example above SUPER BOWL 57 IS SET-Tom Goldman was displayed much too long after the talking already went on to another topic, but once the next title was set, the always-on display was swiftly updated as well.

manual UI testing

I followed the steps above and after starting playback I go to the lock screen and I see "No title" of the current program above the station WNYC. After a while it changes to the title of the current news report. When I leave the phone in lock screen for a while I see that the title changes according to the onMediaMetdata calls reported to the session from the player.

I have tested with Pixel 6 Android 13, a Pixel 5 on U and a Pixel 4 on Android 12 (settings in Android 12 are under Idle screen).

I have seen these cases on the always on screen without interaction:

  • Start with No title and change to the actual program title once changed
  • Start with the actual title and change to the next program title once changed

From this I can't see something is not working as expected. Can you confirm I tested the right thing?

@y20k
Copy link
Author

y20k commented Jan 31, 2023

Hi @marcbaechinger

for me the Always-on Display never displays anything other than "No title" - even if I wait 30+ minutes. Steps to reproduce are the five steps mentioned in the bug report. The difference is probably device-specific, since you experienced a different behavior following the same steps.

An additional information that might be helpful:

My bug report was the result of a ticket opened for my radio app. The reporter noted that the Always-on Display used to work in the version of my app that still used support.v4.media.

My app used to update the metadata like this:

in/via onMetadata:

mediaSessionConnector.invalidateMediaSessionQueue()
mediaSessionConnector.invalidateMediaSessionMetadata()
...
notificationManager.invalidate()

... and this seemed to prompt the Always-on Display to update

@NielsMasdorp
Copy link

NielsMasdorp commented Jan 17, 2024

@marcbaechinger I have this issue, not when using local ExoPlayer but when I switch to CastPlayer in forwarding player implementation "No title" is shown in AOD as well. Even when the title is correctly set on the device I am casting to (e.g. a TV). AOD does show the artist (in my case a radio station) correctly, but not the title I set via putString(MediaMetadata.KEY_TITLE, castTitle()).

Implementation of converter:

class Converter(private val castTitle: 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 artist = metadata.getString(CastMetadata.KEY_ARTIST)!!
        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(artist)
                    .setTitle(title)
                    .setMediaType(MediaMetadata.MEDIA_TYPE_MUSIC)
                    .setArtworkUri(imageUrl)
                    .build()
            )
            .build()
    }

    override fun toMediaQueueItem(mediaItem: MediaItem): MediaQueueItem {
        val metadata = CastMetadata(MEDIA_TYPE_MUSIC_TRACK).apply {
            putString("mediaId", mediaItem.mediaId)
            putString(CastMetadata.KEY_ARTIST, mediaItem.mediaMetadata.artist.toString())
            putString(CastMetadata.KEY_TITLE, castTitle)
            addImage(WebImage(mediaItem.mediaMetadata.artworkUri!!))
        }
        val mediaInfo = MediaInfo.Builder(mediaItem.mediaId)
            .setContentUrl(mediaItem.localConfiguration?.uri.toString())
            .setMetadata(metadata)
            .build()
        return MediaQueueItem.Builder(mediaInfo).build()
    }
}

@marcbaechinger
Copy link
Contributor

I'm not sure where always on display is getting this information from to be honest.

Are saying that it works with ExoPlayer but not when you are casting?
If so, can you please go in this AOD state once with ExoPlayer and once while casting and then do a

adb shell dumpsys media_session

then paste this here?

I also wonder if this is API level related. Can you repro this on different API levels/devices? The interesting buckets that come to mind is up to API 30 and from API 31 and above.

@NielsMasdorp
Copy link

NielsMasdorp commented Jan 18, 2024

Hi @marcbaechinger sure. I am doing this on Android 14:

dump when playing locally:

MEDIA SESSION SERVICE (dumpsys media_session)

7 sessions listeners.
Global priority session is com.android.server.telecom/HeadsetMediaButton (userId=0)
  HeadsetMediaButton com.android.server.telecom/HeadsetMediaButton (userId=0)
    ownerPid=1451, ownerUid=1000, userId=0
    package=com.android.server.telecom
    launchIntent=null
    mediaButtonReceiver=null
    active=false
    flags=65537
    rating type=0
    controllers: 0
    state=null
    audioAttrs=AudioAttributes: usage=USAGE_VOICE_COMMUNICATION content=CONTENT_TYPE_SPEECH flags=0x800 tags= bundle=null
    volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
    metadata: null
    queueTitle=null, size=0
User Records:
Record for full_user=0
  Volume key long-press listener: null
  Volume key long-press listener package: 
  Media key listener: null
  Media key listener package: 
  OnMediaKeyEventDispatchedListener: added 0 listener(s)
  OnMediaKeyEventSessionChangedListener: added 2 listener(s)
    from com.android.bluetooth
    from com.android.bluetooth
  Last MediaButtonReceiver: MBR {pi=null, componentName=ComponentInfo{com.nielsmasdorp.nederadio/androidx.media3.session.MediaButtonReceiver}, type=1, pkg=com.nielsmasdorp.nederadio}
  Media button session is com.nielsmasdorp.nederadio/androidx.media3.session.id. (userId=0)
  Sessions Stack - have 4 sessions:
    androidx.media3.session.id. com.nielsmasdorp.nederadio/androidx.media3.session.id. (userId=0)
      ownerPid=27083, ownerUid=10452, userId=0
      package=com.nielsmasdorp.nederadio
      launchIntent=PendingIntent{aac4779: PendingIntentRecord{5b3c594 com.nielsmasdorp.nederadio startActivity (allowlist: 541545d:+30s0ms/0/NOTIFICATION_SERVICE/NotificationManagerService)}}
      mediaButtonReceiver=MBR {pi=null, componentName=ComponentInfo{com.nielsmasdorp.nederadio/androidx.media3.session.MediaButtonReceiver}, type=1, pkg=com.nielsmasdorp.nederadio}
      active=true
      flags=7
      rating type=0
      controllers: 8
      state=PlaybackState {state=PLAYING(3), position=14843, buffered position=36936, speed=1.0, updated=1537372664, actions=7339703, custom actions=[], active item id=2, error=null}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_MUSIC flags=0x800 tags= bundle=null
      volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: size=11, description=ERIC PRYDZ - PJANOO, NPO 3FM, null
      queueTitle=null, size=85
    YouTube playerlib com.google.android.youtube/YouTube playerlib (userId=0)
      ownerPid=11260, ownerUid=10189, userId=0
      package=com.google.android.youtube
      launchIntent=PendingIntent{9b77cbe: PendingIntentRecord{416311f com.google.android.youtube startActivity}}
      mediaButtonReceiver=MBR {pi=PendingIntent{d648c6c: PendingIntentRecord{e20e235 com.google.android.youtube broadcastIntent}}, componentName=ComponentInfo{com.google.android.youtube/com.google.android.libraries.youtube.player.ui.mediasession.MediaButtonIntentReceiverProvider$DefaultMediaButtonIntentReceiver}, type=1, pkg=com.google.android.youtube}
      active=true
      flags=3
      rating type=2
      controllers: 4
      state=PlaybackState {state=STOPPED(1), position=330622, buffered position=0, speed=1.0, updated=1536794993, actions=8615, custom actions=[], active item id=-1, error=null}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_UNKNOWN flags=0x800 tags= bundle=null
      volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: size=7, description=Drie Kwartjes #3 - Wij haten Duitsland, Drie Kwartjes, Drie Kwartjes
      queueTitle=null, size=0
    BluetoothMediaBrowserService com.google.android.bluetooth/BluetoothMediaBrowserService (userId=0)
      ownerPid=31303, ownerUid=1002, userId=0
      package=com.google.android.bluetooth
      launchIntent=null
      mediaButtonReceiver=null
      active=false
      flags=3
      rating type=0
      controllers: 0
      state=PlaybackState {state=ERROR(7), position=0, buffered position=0, speed=0.0, updated=1514368326, actions=0, custom actions=[], active item id=-1, error=Bluetooth audio disconnected}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_UNKNOWN flags=0x800 tags= bundle=null
      volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: null
      queueTitle=Now Playing, size=0
    BluetoothMediaBrowserService com.google.android.bluetooth/BluetoothMediaBrowserService (userId=0)
      ownerPid=31303, ownerUid=1002, userId=0
      package=com.google.android.bluetooth
      launchIntent=null
      mediaButtonReceiver=null
      active=false
      flags=3
      rating type=0
      controllers: 0
      state=PlaybackState {state=ERROR(7), position=0, buffered position=0, speed=0.0, updated=1514369421, actions=0, custom actions=[], active item id=-1, error=Bluetooth audio disconnected}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_UNKNOWN flags=0x800 tags= bundle=null
      volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: null
      queueTitle=Now Playing, size=0
Audio playback (lastly played comes first)
  uid=10452 packages=com.nielsmasdorp.nederadio 
Media session config:
  media_button_receiver_fgs_allowlist_duration_ms: [cur: 10000, def: 10000]
  media_session_calback_fgs_allowlist_duration_ms: [cur: 10000, def: 10000]
  media_session_callback_fgs_while_in_use_temp_allow_duration_ms: [cur: 10000, def: 10000]

Dump when casting:

MEDIA SESSION SERVICE (dumpsys media_session)

7 sessions listeners.
Global priority session is com.android.server.telecom/HeadsetMediaButton (userId=0)
  HeadsetMediaButton com.android.server.telecom/HeadsetMediaButton (userId=0)
    ownerPid=1451, ownerUid=1000, userId=0
    package=com.android.server.telecom
    launchIntent=null
    mediaButtonReceiver=null
    active=false
    flags=65537
    rating type=0
    controllers: 0
    state=null
    audioAttrs=AudioAttributes: usage=USAGE_VOICE_COMMUNICATION content=CONTENT_TYPE_SPEECH flags=0x800 tags= bundle=null
    volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
    metadata: null
    queueTitle=null, size=0
User Records:
Record for full_user=0
  Volume key long-press listener: null
  Volume key long-press listener package: 
  Media key listener: null
  Media key listener package: 
  OnMediaKeyEventDispatchedListener: added 0 listener(s)
  OnMediaKeyEventSessionChangedListener: added 2 listener(s)
    from com.android.bluetooth
    from com.android.bluetooth
  Last MediaButtonReceiver: MBR {pi=null, componentName=ComponentInfo{com.nielsmasdorp.nederadio/androidx.media3.session.MediaButtonReceiver}, type=1, pkg=com.nielsmasdorp.nederadio}
  Media button session is com.nielsmasdorp.nederadio/androidx.media3.session.id. (userId=0)
  Sessions Stack - have 5 sessions:
    androidx.media3.session.id. com.nielsmasdorp.nederadio/androidx.media3.session.id. (userId=0)
      ownerPid=27083, ownerUid=10452, userId=0
      package=com.nielsmasdorp.nederadio
      launchIntent=PendingIntent{aac4779: PendingIntentRecord{5b3c594 com.nielsmasdorp.nederadio startActivity (allowlist: 541545d:+30s0ms/0/NOTIFICATION_SERVICE/NotificationManagerService)}}
      mediaButtonReceiver=MBR {pi=null, componentName=ComponentInfo{com.nielsmasdorp.nederadio/androidx.media3.session.MediaButtonReceiver}, type=1, pkg=com.nielsmasdorp.nederadio}
      active=true
      flags=7
      rating type=0
      controllers: 8
      state=PlaybackState {state=PLAYING(3), position=9143, buffered position=9143, speed=1.0, updated=1537430924, actions=4718263, custom actions=[], active item id=2, error=null}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_MUSIC flags=0x800 tags= bundle=null
      volumeType=REMOTE, controlType=FIXED, max=0, current=0, volumeControlId=null
      metadata: size=9, description=NPO 3FM, null, null
      queueTitle=null, size=85
    YouTube playerlib com.google.android.youtube/YouTube playerlib (userId=0)
      ownerPid=11260, ownerUid=10189, userId=0
      package=com.google.android.youtube
      launchIntent=PendingIntent{9b77cbe: PendingIntentRecord{416311f com.google.android.youtube startActivity}}
      mediaButtonReceiver=MBR {pi=PendingIntent{d648c6c: PendingIntentRecord{e20e235 com.google.android.youtube broadcastIntent}}, componentName=ComponentInfo{com.google.android.youtube/com.google.android.libraries.youtube.player.ui.mediasession.MediaButtonIntentReceiverProvider$DefaultMediaButtonIntentReceiver}, type=1, pkg=com.google.android.youtube}
      active=true
      flags=3
      rating type=2
      controllers: 4
      state=PlaybackState {state=STOPPED(1), position=330622, buffered position=0, speed=1.0, updated=1536794993, actions=8615, custom actions=[], active item id=-1, error=null}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_UNKNOWN flags=0x800 tags= bundle=null
      volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: size=7, description=Drie Kwartjes #3 - Wij haten Duitsland, Drie Kwartjes, Drie Kwartjes
      queueTitle=null, size=0
    BluetoothMediaBrowserService com.google.android.bluetooth/BluetoothMediaBrowserService (userId=0)
      ownerPid=31303, ownerUid=1002, userId=0
      package=com.google.android.bluetooth
      launchIntent=null
      mediaButtonReceiver=null
      active=false
      flags=3
      rating type=0
      controllers: 0
      state=PlaybackState {state=ERROR(7), position=0, buffered position=0, speed=0.0, updated=1514368326, actions=0, custom actions=[], active item id=-1, error=Bluetooth audio disconnected}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_UNKNOWN flags=0x800 tags= bundle=null
      volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: null
      queueTitle=Now Playing, size=0
    BluetoothMediaBrowserService com.google.android.bluetooth/BluetoothMediaBrowserService (userId=0)
      ownerPid=31303, ownerUid=1002, userId=0
      package=com.google.android.bluetooth
      launchIntent=null
      mediaButtonReceiver=null
      active=false
      flags=3
      rating type=0
      controllers: 0
      state=PlaybackState {state=ERROR(7), position=0, buffered position=0, speed=0.0, updated=1514369421, actions=0, custom actions=[], active item id=-1, error=Bluetooth audio disconnected}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_UNKNOWN flags=0x800 tags= bundle=null
      volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: null
      queueTitle=Now Playing, size=0
    cast_rcn_media_session com.google.android.gms/cast_rcn_media_session (userId=0)
      ownerPid=23875, ownerUid=10161, userId=0
      package=com.google.android.gms
      launchIntent=null
      mediaButtonReceiver=MBR {pi=PendingIntent{bd32a4f: PendingIntentRecord{a7bdee2 com.google.android.gms/com.google.android.gms.cast broadcastIntent}}, componentName=null, type=0, pkg=com.google.android.gms}
      active=false
      flags=3
      rating type=0
      controllers: 0
      state=PlaybackState {state=NONE(0), position=0, buffered position=0, speed=1.0, updated=1537429718, actions=0, custom actions=[], active item id=-1, error=null}
      audioAttrs=AudioAttributes: usage=USAGE_MEDIA content=CONTENT_TYPE_UNKNOWN flags=0x800 tags= bundle=null
      volumeType=REMOTE, controlType=RELATIVE, max=0, current=0, volumeControlId=null
      metadata: size=0, description=null, null, null
      queueTitle=null, size=0
Audio playback (lastly played comes first)
  uid=10452 packages=com.nielsmasdorp.nederadio 
Media session config:
  media_button_receiver_fgs_allowlist_duration_ms: [cur: 10000, def: 10000]
  media_session_calback_fgs_allowlist_duration_ms: [cur: 10000, def: 10000]
  media_session_callback_fgs_while_in_use_temp_allow_duration_ms: [cur: 10000, def: 10000]

Looks kind of weird, the media3 session when casting has the following data:

volumeType=REMOTE, controlType=FIXED, max=0, current=0, volumeControlId=null
      metadata: size=9, description=NPO 3FM, null, null

And when playing locally:

volumeType=LOCAL, controlType=ABSOLUTE, max=0, current=0, volumeControlId=null
      metadata: size=11, description=ERIC PRYDZ - PJANOO, NPO 3FM, null

So the artist should be "NPO 3FM" and is shown like that on AOD in both cases, but the title is missing.

When playing locally the "ERIC PRYDZ - PJANOO" song is loaded dynamically by ExoPlayer, but when casting the title should be "Casting to $device" as per the above mentioned Converter, since CastPlayer does not support dynamic song loading.

But I suspect the Converter only changes the metadata in de CastPlayer hence why the title is correctly shown on the TV, but it does not update the session.

@marcbaechinger
Copy link
Contributor

Thanks for sharing the dump.

It's a bit unclear to me what the issue is I'm afraid. I think the interesting thing is that the number of metadata keys is smaller when playing with cast metadata: size=9. I'm a bit unsure why this is. I believe that we are probably distracted by the converter but the problem is somewhere else.

I'm trying to repro this, but it looks quite difficult as for me the AOD doesn't seem to work consistently. It appears to me that it works with UAMP intermittedly and I haven't figured out yet why this is.

Do you have a ForwardingPlayer wrapped around your local and cast player? If this is the case it would be interested to log the metadata when onMediaMetadataChanged is called by a listener of the wrapping player.

The library updates the platform session here and the player that is used is the player passed to the session.

I need to dig some further here when I find some time.

@NielsMasdorp
Copy link

NielsMasdorp commented Jan 22, 2024

Hi @marcbaechinger thanks for the response. I am indeed using a wrapping Player. The listener for onMediaMetadataChanged for the wrapping Player receives the following:

Playing locally when song is loaded:

[{0=SERA - HEAD HELD HIGH, 1=NPO 3FM, 5=NPO 3FM, b=https://luisteren.nl/app/uploads/2018/11/NPO_3fm.jpg, e=-1, f=true, r=Pop, u=NPO 3FM, v=4, w=false}]

Switch to casting:

[{1=NPO 3FM, 5=NPO 3FM, b=https://luisteren.nl/app/uploads/2018/11/NPO_3fm.jpg, e=-1, f=true, v=4, w=false}]

Switch back to local playback

[{1=NPO 3FM, 5=NPO 3FM, b=https://luisteren.nl/app/uploads/2018/11/NPO_3fm.jpg, e=-1, f=true, v=4, w=false}]
[{0=SERA - HEAD HELD HIGH, 1=NPO 3FM, 5=NPO 3FM, b=https://luisteren.nl/app/uploads/2018/11/NPO_3fm.jpg, e=-1, f=true, r=Pop, u=NPO 3FM, v=4, w=false}]

So it appears that the 0 key (title I presume) in the metadata for a stream is only set when ExoPlayer dynamically loads a song from the stream. The question is: how does one populate that key in the Metadata when casting and maybe also how does one provide a fallback when ExoPlayer does not load a song or the stream does not support it. Because when creating the MediaItem and hardcoding the title does stop ExoPlayer from dynamically updating the title in the metadata when playing that MediaItem.

For reference the MediaItem is created as follows:

fun Stream.toMediaItem(): MediaItem {
    return MediaItem.Builder()
        .setMediaId(id)
        .setUri(url.toUri())
        .setMediaMetadata(
            MediaMetadata.Builder()
                .setMediaType(MediaMetadata.MEDIA_TYPE_RADIO_STATION)
                .setSubtitle(title)
                .setArtist(title)
                .setArtworkUri(imageUrl.toUri())
                .setIsPlayable(true)
                .setIsBrowsable(false)
                .build()
        )
        .build()
}

@marcbaechinger
Copy link
Contributor

Your ForwardingPlayer knows whether the player currently playing is player.getDeviceInfo().playbackType == PLAYBACK_TYPE_LOCAL. If it's local it can assume that the title is going to be read from in-band media metadata, so it may augment the metadata delivered by the PLAYBACK_TYPE_REMOTE with whatever is the appropriate title for the given item.

@NielsMasdorp
Copy link

@marcbaechinger I guess I could augment the metadata in the ForwardingPlayer and call the listener with the updated metadata, but how would that update the actual data in the session?

@marcbaechinger
Copy link
Contributor

Calling the listeners as you say should be sufficient I think. The session registers a listener to the player that is set on the session. So it would trigger MediaSessionLegacyStub here I think.

@NielsMasdorp
Copy link

NielsMasdorp commented Jan 24, 2024

Hi @marcbaechinger conceptually that doesn't make much sense in my head but I've tried having a list of external listeners in the ForwardingPlayer and an internal listener on the current Player and I augment the media metadata in the internal listener before calling the external listeners but that does not update the data in the session dump unfortunately.

override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
    val updatedMetadata = if (isCasting()) {
        mediaMetadata
            .buildUpon()
            .setTitle(castTitle)
            .build()
        } else {
            mediaMetadata
        }
     // TODO how to propagate this title change when casting 
     // to the session so that it shows inside the media notification and AOD??
    for (listener in externalListeners) {
       listener.onMediaMetadataChanged(updatedMetadata)
    }
}

I am guessing we need some kind of player.updateMediaMetadata(updatedMetadata) API or another way of setting the new media metadata in the current media session.

This kind of works, but looks hacky and sometimes crashes when player somehow doesn't have a currentMediaItem, probably when switching players. Need to investigate further. But when it works it does update the title in the Always on Display and the media notification with the correct "Casting to $deviceName" string so I guess that's something.

override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
    val updatedMetadata = if (isCasting()) {
        mediaMetadata
            .buildUpon()
            .setTitle(castTitle)
            .build()
     } else {
        mediaMetadata
     }
     if (player.mediaMetadata != updatedMetadata) {
         val updatedMediaItem = player.currentMediaItem!!
             .buildUpon()
             .setMediaMetadata(updatedMetadata)
             .build()
         player.replaceMediaItem(player.currentMediaItemIndex, updatedMediaItem)
     }
    for (listener in externalListeners) {
       listener.onMediaMetadataChanged(updatedMetadata)
    }
}

@NielsMasdorp
Copy link

I've solved this issue by updating all MediaItems in the playlist in the ForwardingPlayer when the Player switches to a CastPlayer and resetting the title to null when the playback switches back to local playback. This way the session has a correct title and this title shows in AOD as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants