ExoPlayer icon indicating copy to clipboard operation
ExoPlayer copied to clipboard

MediaItemConverter does not convert MediaQueueItem to MediaItem

Open roubertedgar opened this issue 5 years ago • 8 comments

Hi, I am working with CastPlayer and I have some questions about the recovery of the current session. The scenario is:

  • I start the cast and the content is played on TV
  • Then I finish my application, killing the whole process.
  • After that, the content still playing on TV, and then, i start my app again
  • The CastPlayer is able to recover the session, with MeduaQueueItem on the RemoteMediaClient.

The problem here is; the MediaItem currentMediaItem present in the Player interface is not recovered correctly, coming with empty fields. I was looking at the codes, in the MediaItemConverter and realised that the method toMediaItem (MediaQueueItem mediaQueueItem) is called only on tests. Is it possible to make CastPlayer use this method and be able to set the currentMediaItem correctly? This would be helpful, as it would make it easier to check if a content that i'am opening was already being played on TV before the session was recovered by reopening the application.

Today, i need to access the CastContext to recover the session and then convert the MediaQueueItem to MediaItem:

        val mediaItem =
            castContext?.sessionManager?.currentCastSession?.remoteMediaClient?.currentItem?.let {
                mediaItemConverter.toMediaItem(it)
            }

        return isPlaying() && content.contentId() == mediaItem?.mediaId

Thanks.

roubertedgar avatar Nov 12 '20 17:11 roubertedgar

Same here, any updates? I can not find a way to alter the CastPlayer behavior in any way since it is not extendable, we can not override timeline implementation or something like this. So for now I also stuck with this kind of workaround, which I don't really like. Thanks!

makp9k avatar Mar 07 '21 13:03 makp9k

I marked this issue as enhancement. We should convert MediaQueueItems that are coming in from cast to MediaItems, and then update the CastTimteline appropriately. The conversion should be done by the MediaItemConverter that can be customized by apps by injecting it's own version into CastPlayer. DefaultMediaItemConverter should make this process work so that eg. the uri is shared with the case device and in the other direction. Metadata will likely be left not converted back and forth because mapping the meta data is not as straightforward as it looks like (see #8669 also).

Thanks for your comment @makp9k

Are you looking for altering the CastPlayer behaviour in any other way than what is provided with MediaItemConverter? I mean, assumend the converter is also converting MediaQueueItems from a cast device to show up in the CastTmeline which the CastPlayer is using (see this issue and my paragraph above in this comment). Besides this, is there anything else you are missing? (I also assume you are aware that you can inject your custom MediaItemConverter as mentioned in ##8669)

marcbaechinger avatar Mar 08 '21 12:03 marcbaechinger

If CastPlayer will properly call toMediaItem, then it would be totally sufficient for my needs. I was just looking for a way to hook into MediaItems conversion process until this issue is resolved and realised there is not much we can do about the CastPlayer in general. Thank you!

makp9k avatar Mar 09 '21 08:03 makp9k

Currently, CastTimeline doesn't care about MediaItem and it works only with itemIds and also with this ItemData(long durationUs, long defaultPositionUs, boolean isLive). It is really bad in terms of currentMediaItem behavior, especially this method

@Override
  public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {
    long durationUs = durationsUs[windowIndex];
    boolean isDynamic = durationUs == C.TIME_UNSET;
    MediaItem mediaItem =
        new MediaItem.Builder().setUri(Uri.EMPTY).setTag(ids[windowIndex]).build();
    return window.set(
        /* uid= */ ids[windowIndex],
        /* mediaItem= */ mediaItem,
        /* manifest= */ null,
        /* presentationStartTimeMs= */ C.TIME_UNSET,
        /* windowStartTimeMs= */ C.TIME_UNSET,
        /* elapsedRealtimeEpochOffsetMs= */ C.TIME_UNSET,
        /* isSeekable= */ !isDynamic,
        isDynamic,
        isLive[windowIndex] ? mediaItem.liveConfiguration : null,
        defaultPositionsUs[windowIndex],
        durationUs,
        /* firstPeriodIndex= */ windowIndex,
        /* lastPeriodIndex= */ windowIndex,
        /* positionInFirstPeriodUs= */ 0);
  }

Setting an empty mediaItem with only the index as a tag is such a hidden thing. Please, at least comment such stuff.

n0m0r3pa1n avatar May 26 '21 15:05 n0m0r3pa1n

@marcbaechinger this is kind of a bug? CurrentMediaItem is always empty one, it is not returned correctly.

n0m0r3pa1n avatar May 27 '21 06:05 n0m0r3pa1n

The reason for which we are not bringing in the Timeline from the receiver is that the Cast default receiver does not behave reliably, so that we can guarantee a consistent state across all senders and the receiver. I've recently revisited this, but I haven't been able to make progress. If you have some time to invest in this, I encourage you to send a pull request. It will be more than welcome.

AquilesCanta avatar May 27 '21 16:05 AquilesCanta

Fixed by the commits above.

tonihei avatar Jul 15 '22 08:07 tonihei

I think we need google/ExoPlayer#9078 also to have this properly working.

marcbaechinger avatar Jul 15 '22 10:07 marcbaechinger