google / google/ExoPlayer

All CastPlayer bugs I found and possiblie solutions

Open
#4,168 4 comments 0 reactions 1 assignee Claimed by @AquilesCanta View on GitHub
Dominant language
Java
Stars
21.9k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

I work for some chromecast-ready apps and CastPlayer make it a lot of easier but I found a lot of troubles with it too:

**1. Wrong getCurrentWindowIndex after setting media sources when CastPlayer is connected to Chromecast device.**

There is use case where you connect to your chromecast device and after that you select media source.

How to recreate:
- connect to Chromecast device by tapping MediaRouteButton button
- create CastPlayer and set sources (castPlayer.loadItems(mediaItems, window, time, Player.REPEAT_MODE_OFF)) after some time (you can do it with some button)
- get currentWindowIndex (it's always 0)

Cause:
StatusListener don't invoke onSessionStarted which don't invoke setRemoteMediaClient when we set new sources so statusListener is no added to remoteMediaClient.

Solution:
Add statusListener to remoteMediaClient in contructor:
```java
if (remoteMediaClient != null) {
try {
remoteMediaClient.addListener(statusListener);
remoteMediaClient.addProgressListener(statusListener, PROGRESS_REPORT_PERIOD_MS);
updateInternalState();
} catch (NullPointerException ignored) {
}
}
```

**2. I get 0 from getCurrentWindowIndex() which is not true.**

How to recreate:
- invoke getCurrentWindowIndex() in onPositionDiscontinuity

Cause:
We get the value from fetchCurrentWindowIndex() when there is no media session. So current window is not actually 0.

Solution:
Change 0 to other value in fetchCurrentWindowIndex() when there is no media session. You will be able to recognize the real current window index from "no media session":
```java
/**
* Retrieves the current item index from {@code mediaStatus} and maps it into a window index. If
* there is no media session, returns -1.
*/
private static int fetchCurrentWindowIndex(@Nullable MediaStatus mediaStatus) {
Integer currentItemId = mediaStatus != null
? mediaStatus.getIndexById(mediaStatus.getCurrentItemId()) : null;
return currentItemId != null ? currentItemId : -1;
}
```

You should change getDuration and some other methods (isCurrentWindowDynamic(), isCurrentWindowSeekable()) in this case too to avoid some exceptions:
```java
@Override
public long getDuration() {
return currentTimeline.isEmpty() ? C.TIME_UNSET
: currentTimeline.getWindow(getCurrentWindowIndex() < 0 ? 0 : getCurrentWindowIndex(),
window).getDurationMs();
}
```

**3. ArrayIndexOutOfBoundsException: length=2; index=2 when setting new media sources and some other problems with wrong current position.**

How to recreate:
- create a pleyer with 3 sources
- seekTo 3'rd sources
- loadItems() with 2 sources

Cause:
The getCurrentWindowIndex() returns old value for some time.

Solution:
Update currentWindowIndex and pendingSeekWindowIndex values in loadItem and loadItems:
```java
/**
* Loads a single item media queue. If no session is available, does nothing.
*
* @param item The item to load.
* @param positionMs The position at which the playback should start in milliseconds relative to
* the start of the item at {@code startIndex}. If {@link C#TIME_UNSET} is passed, playback
* starts at position 0.
* @return The Cast {@code PendingResult}, or null if no session is available.
*/
public PendingResult loadItem(MediaQueueItem item, long positionMs) {
pendingSeekWindowIndex = 0;
currentWindowIndex = 0;
return loadItems(new MediaQueueItem[]{item}, 0, positionMs, REPEAT_MODE_OFF);
}

/**
* Loads a media queue. If no session is available, does nothing.
*
* @param items The items to load.
* @param startIndex The index of the item at which playback should start.
* @param positionMs The position at which the playback should start in milliseconds relative to
* the start of the item at {@code startIndex}. If {@link C#TIME_UNSET} is passed, playback
* starts at position 0.
* @param repeatMode The repeat mode for the created media queue.
* @return The Cast {@code PendingResult}, or null if no session is available.
*/
public PendingResult loadItems(MediaQueueItem[] items, int startIndex,
long positionMs, @RepeatMode int repeatMode) {
if (remoteMediaClient != null) {
positionMs = positionMs != C.TIME_UNSET ? positionMs : 0;
waitingForInitialTimeline = true;
pendingSeekWindowIndex = startIndex;
currentWindowIndex = startIndex;
return remoteMediaClient.queueLoad(items, startIndex, getCastRepeatMode(repeatMode),
positionMs, null);
}
return null;
}
```

**4. There is no indicator to get to know that the media sources are finished.**

[https://github.com/google/ExoPlayer/issues/4130](https://github.com/google/ExoPlayer/issues/4130)
I have no solution for now.

Hope it is helpful :) If you need some more info (videos with examples or something like that) let me know.
I will do pull request soon.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.