You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
currentMediaItem is empty when a CastPlayer is being used #25
I'm using a MediaLibraryService that switches the player from ExoPlayer to CastPlayer when a CastSession is available. When the ExoPlayer is active, calling getCurrentMediaItem() from a MediaController returns the correct MediaItem, but if the same call is done when the CastPlayer is the active one, I receive an empty MediaItem.
The method getWindow(...) inside CastTimeline is the one creating and using an empty MediaItem instead of the expected currentMediaItem.
This is a known issue which becomes more sever with AndroidX Media3 MediaSession. Implementing the Player interface properly is more important when we aim to be able to build a MediaSession with a MediaSession.Builder.
For right now I'm afraid I can't really give a better advice than that you need to maintain your own list of MediaItems that represents the playlist and from where you can lookup the media item by index with the given window index.
Somewhat aside: I think an approach to have a MediaSession with a Player that can change (local vs. remote playback with Cast) would be to have a custom Player implementation that delegates to an actual Player implementation and that allows to swap the actual implementation. It may for instance have a setPlayer(Player) method for swapping the current player with another. This way you can build a MediaSession with a MediaSession.Builder and delegate commands sent by a MediaController to either of the implementations under the hood. If you do that, that custom Player implementation would be the best place to maintain the list of MediaItems that is the playlist. It can also help you to work around #26 that is related to the CastPlayer not properly implementing the Player interface in the current state.
--
Some comments for context when someone is going to fix this (I stick with the bug label because I agree this is now a bug in context of AndroidX Media3):
There is an unwritten contract that a Player should provide an equal MediaItem with Player.getMediaItemAt(int index) that have been passed to the set/addMediaItem(MediaItem) methods. The same should be the case for Timeline.getWindow(...) as well.
CastPlayer currently fails to do that which we need to improve. At the very least CastPlayer should propagate the mediaId correctly which would be a first step although if we fix this that way we probably should comply with the whole MediaItem because the mediaId is not necessarily unique. There is a commit in the ExoPlayer repo for the dev2 branch which includes the mediaId when un/marshalling which is a first step towards this. CastTimeline is another step as mentioned above in the user's post.
Thank you very much @marcbaechinger for the idea of the custom Player. I was able to fix the empty MediaItem problem with a modified CastTimeline, CastTimelineTracker and a custom MediaItemConverter (like you already said, the default is a bit limited), but your idea is way better than calling MediaSession#setPlayer(...) each time the player changes. By the way, something like that inside the media3-cast would be awesome.
@spun Could you elaborate how you managed to solve the empty MediaItem? I am currently relying on onMediaItemTransition and onMediaMetadataChanged callbacks inside my MediaController and I need the mediaId and mediaMetadata in said callbacks. Obviously this doesn't work when I switch to the CastPlayer in the MediaSessionService.
Hi @NielsMasdorp. Unfortunately, I decided to wait until the issue is fixed. I'm currently running a modified version of the library with some changes made to CastTimeline (I could link you a Gist with the changes if you want) to fix the empty MediaItem problem until something is implemented in media3.
You could try the custom Player that switches between local and cast and also maintains the list of MediaItems. It's still a promising solution but, when I tried to do it, I was a bit overwhelmed with the RemoteMediaClient also being able to change the list of MediaItems and I don't have a working implementation yet.
If you can wait, when this issue is fixed, we should be able to at least retrieve the mediaId from the "empty" MediaItem. I think there was already a first step, but CastTimeline still returns the empty one, so we'll have to wait a bit longer.
@spun Thanks for the update. In the meantime i've decided to tackle the problem as well. I am currently working on my own implementation of a custom Player which indeed switches from local to cast internally. It works, but it is tailored to my use case. I don't have a list of items but only playback a single MediaItem at a time, so the solution is just to keep a reference to the current MediaItem and that's that. But I am sure i've missed some edge cases. After that I will wait for updates in the media3 implementation (or at least a CastPlayer which implements the Player correctly).
@marcbaechinger Sorry to open this again, but during active play of CastPlayergetCurrentMediaItem() returns the correct MediaItem however when listening to onCastSessionUnavailable() callback and subsequently checking getCurrentMediaItem() it is empty again. Is this intentional? Looking at the source it seems that the Timeline is cleared by the CastPlayer before the onCastSessionUnavailable() callback is invoked.
This means we still have to resort to locally caching the MediaItems, no? Or am I missing something?
When the remote media client is set to null the timeline is updated and set to an empty timeline. I agree that's surprising and unfortunate for a Player implementation, specifically that this happens before the callback is called.
we still have to resort to locally caching the MediaItem
I think this is a known behaviour though. CastPlayer is missing abilities to nicely connect/reconnect. To resume playback, the playlist media items need to be set again. Apps probably mostly maintain the playlist, position, window index and the like to be able to either setup a local ExoPlayer or CastPlayer like PlayerManager in the demo app. UAMP uses a ForwardingPlayer.
However, now that we support the media items in the timeline with CastPlayer, we could and probably should do better. Re-opened to track decoupling cast session and CastPlayer state and keeping timeline, currentMediaIndex and currentPosition when the cast session ends (probably similar to when ExoPlayer.stop() is called). Then we probably also need to think about the behaviour when the session/remote media client returns again.
I don't know when we come around to look into this I'm afraid .
Thank you for this comment @marcbaechinger. I stumbled upon it accidentally, I wish I could have read it before e.g. in README, it would have saved me a lot of time and debugging.
Just wondering if there were and updates on The empty media item issue?
It presents quite a significant problem, when resuming of a session is required. Caching a copy of the playlist, for the purpose of recovering from a Cast connection loss, if fairly ugly and highly prone to issues.
I am working around it by retaining a playlist of current items, which I reference rather than metadata on castplayer. I do this to avoid re-pushing a play queue if a resume is required. It's not ideal, due to potential to become out of sync, if queue items change for example. Have to be very careful to keep that list in sync on queue edits and so forth
I have noticed that the notification published by media 3 seems to have awareness of metadata post resume. I Was wondering how the notification is obtaining this information?
Cheers
Reacted by Didier116, Blaz Magdic and Christian Albinus
Activity
marcbaechinger commentedon Jan 10, 2022
This is a known issue which becomes more sever with AndroidX Media3
MediaSession. Implementing thePlayerinterface properly is more important when we aim to be able to build aMediaSessionwith aMediaSession.Builder.For right now I'm afraid I can't really give a better advice than that you need to maintain your own list of
MediaItems that represents the playlist and from where you can lookup the media item by index with the given window index.Somewhat aside: I think an approach to have a
MediaSessionwith aPlayerthat can change (local vs. remote playback with Cast) would be to have a customPlayerimplementation that delegates to an actualPlayerimplementation and that allows to swap the actual implementation. It may for instance have asetPlayer(Player)method for swapping the current player with another. This way you can build aMediaSessionwith aMediaSession.Builderand delegate commands sent by aMediaControllerto either of the implementations under the hood. If you do that, that customPlayerimplementation would be the best place to maintain the list ofMediaItems that is the playlist. It can also help you to work around #26 that is related to theCastPlayernot properly implementing thePlayerinterface in the current state.--
Some comments for context when someone is going to fix this (I stick with the
buglabel because I agree this is now a bug in context of AndroidX Media3):There is an unwritten contract that a
Playershould provide an equalMediaItemwithPlayer.getMediaItemAt(int index)that have been passed to theset/addMediaItem(MediaItem)methods. The same should be the case forTimeline.getWindow(...)as well.CastPlayercurrently fails to do that which we need to improve. At the very leastCastPlayershould propagate themediaIdcorrectly which would be a first step although if we fix this that way we probably should comply with the wholeMediaItembecause themediaIdis not necessarily unique. There is a commit in the ExoPlayer repo for the dev2 branch which includes themediaIdwhen un/marshalling which is a first step towards this.CastTimelineis another step as mentioned above in the user's post.spun commentedon Jan 10, 2022
Thank you very much @marcbaechinger for the idea of the custom
Player. I was able to fix the emptyMediaItemproblem with a modifiedCastTimeline,CastTimelineTrackerand a customMediaItemConverter(like you already said, the default is a bit limited), but your idea is way better than callingMediaSession#setPlayer(...)each time the player changes. By the way, something like that inside themedia3-castwould be awesome.Thanks again!
NielsMasdorp commentedon Feb 13, 2022
@spun Could you elaborate how you managed to solve the empty
MediaItem? I am currently relying ononMediaItemTransitionandonMediaMetadataChangedcallbacks inside myMediaControllerand I need themediaIdandmediaMetadatain said callbacks. Obviously this doesn't work when I switch to theCastPlayerin theMediaSessionService.spun commentedon Feb 14, 2022
Hi @NielsMasdorp. Unfortunately, I decided to wait until the issue is fixed. I'm currently running a modified version of the library with some changes made to
CastTimeline(I could link you a Gist with the changes if you want) to fix the emptyMediaItemproblem until something is implemented inmedia3.You could try the custom
Playerthat switches between local and cast and also maintains the list of MediaItems. It's still a promising solution but, when I tried to do it, I was a bit overwhelmed with theRemoteMediaClientalso being able to change the list ofMediaItemsand I don't have a working implementation yet.If you can wait, when this issue is fixed, we should be able to at least retrieve the
mediaIdfrom the "empty"MediaItem. I think there was already a first step, butCastTimelinestill returns the empty one, so we'll have to wait a bit longer.NielsMasdorp commentedon Feb 14, 2022
@spun Thanks for the update. In the meantime i've decided to tackle the problem as well. I am currently working on my own implementation of a custom
Playerwhich indeed switches from local to cast internally. It works, but it is tailored to my use case. I don't have a list of items but only playback a singleMediaItemat a time, so the solution is just to keep a reference to the currentMediaItemand that's that. But I am sure i've missed some edge cases. After that I will wait for updates in the media3 implementation (or at least aCastPlayerwhich implements thePlayercorrectly).Use the public MediaItem in the timeline of CastPlayer
Use the public MediaItem in the timeline of CastPlayer
Enable onMediaMetadataChanged in CastPlayer
Enable onMediaMetadataChanged in CastPlayer
tonihei commentedon Jul 15, 2022
Fixed by the commits above.
1 remaining item
Enable onMediaMetadataChanged in CastPlayer
Use the public MediaItem in the timeline of CastPlayer
Enable onMediaMetadataChanged in CastPlayer
Djsolutions1 commentedon Oct 19, 2022
Nice work
NielsMasdorp commentedon Mar 1, 2023
@marcbaechinger Sorry to open this again, but during active play of
CastPlayergetCurrentMediaItem()returns the correctMediaItemhowever when listening toonCastSessionUnavailable()callback and subsequently checkinggetCurrentMediaItem()it is empty again. Is this intentional? Looking at the source it seems that theTimelineis cleared by theCastPlayerbefore theonCastSessionUnavailable()callback is invoked.This means we still have to resort to locally caching the
MediaItems, no? Or am I missing something?marcbaechinger commentedon Mar 1, 2023
When the remote media client is set to null the timeline is updated and set to an empty timeline. I agree that's surprising and unfortunate for a
Playerimplementation, specifically that this happens before the callback is called.I think this is a known behaviour though.
CastPlayeris missing abilities to nicely connect/reconnect. To resume playback, the playlist media items need to be set again. Apps probably mostly maintain the playlist, position, window index and the like to be able to either setup a localExoPlayerorCastPlayerlikePlayerManagerin the demo app. UAMP uses aForwardingPlayer.However, now that we support the media items in the timeline with
CastPlayer, we could and probably should do better. Re-opened to track decoupling cast session andCastPlayerstate and keepingtimeline,currentMediaIndexandcurrentPositionwhen the cast session ends (probably similar to whenExoPlayer.stop()is called). Then we probably also need to think about the behaviour when the session/remote media client returns again.I don't know when we come around to look into this I'm afraid .
NielsMasdorp commentedon Mar 2, 2023
Thank you, seems logical. I was just verifying to be sure I didn't miss anything. I'll keep an eye on improvements in the future.
TomasValenta commentedon Nov 6, 2023
Thank you for this comment @marcbaechinger. I stumbled upon it accidentally, I wish I could have read it before e.g. in README, it would have saved me a lot of time and debugging.
fdfmobileapps commentedon Nov 17, 2023
Hi @marcbaechinger
Just wondering if there were and updates on The empty media item issue?
It presents quite a significant problem, when resuming of a session is required. Caching a copy of the playlist, for the purpose of recovering from a Cast connection loss, if fairly ugly and highly prone to issues.
I am working around it by retaining a playlist of current items, which I reference rather than metadata on castplayer. I do this to avoid re-pushing a play queue if a resume is required. It's not ideal, due to potential to become out of sync, if queue items change for example. Have to be very careful to keep that list in sync on queue edits and so forth
I have noticed that the notification published by media 3 seems to have awareness of metadata post resume. I Was wondering how the notification is obtaining this information?
Cheers
fdfmobileapps commentedon Mar 17, 2024
Hi @marcbaechinger
Was wondering if you had any updates or further advice on this issue, as yet?
Cheers
Merge pull request androidx#25 from Guovin/dev
fix(android): cast start position race + resume-point zeroing (androi…
Make cast playback actually work: authenticated URLs and per-track qu…