Use listener notification batching in CastPlayer
PiperOrigin-RevId: 251399230
This commit is contained in:
parent
9ca6f60c3a
commit
44aa731476
@ -45,8 +45,11 @@ import com.google.android.gms.cast.framework.media.RemoteMediaClient;
|
||||
import com.google.android.gms.cast.framework.media.RemoteMediaClient.MediaChannelResult;
|
||||
import com.google.android.gms.common.api.PendingResult;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* {@link Player} implementation that communicates with a Cast receiver app.
|
||||
@ -86,8 +89,10 @@ public final class CastPlayer extends BasePlayer {
|
||||
private final StatusListener statusListener;
|
||||
private final SeekResultCallback seekResultCallback;
|
||||
|
||||
// Listeners.
|
||||
private final CopyOnWriteArraySet<EventListener> listeners;
|
||||
// Listeners and notification.
|
||||
private final CopyOnWriteArrayList<ListenerHolder> listeners;
|
||||
private final ArrayList<ListenerNotificationTask> notificationsBatch;
|
||||
private final ArrayDeque<ListenerNotificationTask> ongoingNotificationsTasks;
|
||||
private SessionAvailabilityListener sessionAvailabilityListener;
|
||||
|
||||
// Internal state.
|
||||
@ -113,7 +118,9 @@ public final class CastPlayer extends BasePlayer {
|
||||
period = new Timeline.Period();
|
||||
statusListener = new StatusListener();
|
||||
seekResultCallback = new SeekResultCallback();
|
||||
listeners = new CopyOnWriteArraySet<>();
|
||||
listeners = new CopyOnWriteArrayList<>();
|
||||
notificationsBatch = new ArrayList<>();
|
||||
ongoingNotificationsTasks = new ArrayDeque<>();
|
||||
|
||||
SessionManager sessionManager = castContext.getSessionManager();
|
||||
sessionManager.addSessionManagerListener(statusListener, CastSession.class);
|
||||
@ -296,12 +303,17 @@ public final class CastPlayer extends BasePlayer {
|
||||
|
||||
@Override
|
||||
public void addListener(EventListener listener) {
|
||||
listeners.add(listener);
|
||||
listeners.addIfAbsent(new ListenerHolder(listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(EventListener listener) {
|
||||
listeners.remove(listener);
|
||||
for (ListenerHolder listenerHolder : listeners) {
|
||||
if (listenerHolder.listener.equals(listener)) {
|
||||
listenerHolder.release();
|
||||
listeners.remove(listenerHolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -348,14 +360,13 @@ public final class CastPlayer extends BasePlayer {
|
||||
pendingSeekCount++;
|
||||
pendingSeekWindowIndex = windowIndex;
|
||||
pendingSeekPositionMs = positionMs;
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onPositionDiscontinuity(Player.DISCONTINUITY_REASON_SEEK);
|
||||
}
|
||||
notificationsBatch.add(
|
||||
new ListenerNotificationTask(
|
||||
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_SEEK)));
|
||||
} else if (pendingSeekCount == 0) {
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onSeekProcessed();
|
||||
}
|
||||
notificationsBatch.add(new ListenerNotificationTask(EventListener::onSeekProcessed));
|
||||
}
|
||||
flushNotifications();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -531,30 +542,31 @@ public final class CastPlayer extends BasePlayer {
|
||||
|| this.playWhenReady != playWhenReady) {
|
||||
this.playbackState = playbackState;
|
||||
this.playWhenReady = playWhenReady;
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onPlayerStateChanged(this.playWhenReady, this.playbackState);
|
||||
}
|
||||
notificationsBatch.add(
|
||||
new ListenerNotificationTask(
|
||||
listener -> listener.onPlayerStateChanged(this.playWhenReady, this.playbackState)));
|
||||
}
|
||||
@RepeatMode int repeatMode = fetchRepeatMode(remoteMediaClient);
|
||||
if (this.repeatMode != repeatMode) {
|
||||
this.repeatMode = repeatMode;
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onRepeatModeChanged(repeatMode);
|
||||
}
|
||||
notificationsBatch.add(
|
||||
new ListenerNotificationTask(listener -> listener.onRepeatModeChanged(this.repeatMode)));
|
||||
}
|
||||
int currentWindowIndex = fetchCurrentWindowIndex(getMediaStatus());
|
||||
if (this.currentWindowIndex != currentWindowIndex && pendingSeekCount == 0) {
|
||||
this.currentWindowIndex = currentWindowIndex;
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_PERIOD_TRANSITION);
|
||||
}
|
||||
notificationsBatch.add(
|
||||
new ListenerNotificationTask(
|
||||
listener ->
|
||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_PERIOD_TRANSITION)));
|
||||
}
|
||||
if (updateTracksAndSelections()) {
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onTracksChanged(currentTrackGroups, currentTrackSelection);
|
||||
}
|
||||
notificationsBatch.add(
|
||||
new ListenerNotificationTask(
|
||||
listener -> listener.onTracksChanged(currentTrackGroups, currentTrackSelection)));
|
||||
}
|
||||
maybeUpdateTimelineAndNotify();
|
||||
flushNotifications();
|
||||
}
|
||||
|
||||
private void maybeUpdateTimelineAndNotify() {
|
||||
@ -562,9 +574,10 @@ public final class CastPlayer extends BasePlayer {
|
||||
@Player.TimelineChangeReason int reason = waitingForInitialTimeline
|
||||
? Player.TIMELINE_CHANGE_REASON_PREPARED : Player.TIMELINE_CHANGE_REASON_DYNAMIC;
|
||||
waitingForInitialTimeline = false;
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onTimelineChanged(currentTimeline, null, reason);
|
||||
}
|
||||
notificationsBatch.add(
|
||||
new ListenerNotificationTask(
|
||||
listener ->
|
||||
listener.onTimelineChanged(currentTimeline, /* manifest= */ null, reason)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,7 +840,23 @@ public final class CastPlayer extends BasePlayer {
|
||||
|
||||
}
|
||||
|
||||
// Result callbacks hooks.
|
||||
// Internal methods.
|
||||
|
||||
private void flushNotifications() {
|
||||
boolean recursiveNotification = !ongoingNotificationsTasks.isEmpty();
|
||||
ongoingNotificationsTasks.addAll(notificationsBatch);
|
||||
notificationsBatch.clear();
|
||||
if (recursiveNotification) {
|
||||
// This will be handled once the current notification task is finished.
|
||||
return;
|
||||
}
|
||||
while (!ongoingNotificationsTasks.isEmpty()) {
|
||||
ongoingNotificationsTasks.peekFirst().execute();
|
||||
ongoingNotificationsTasks.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
// Internal classes.
|
||||
|
||||
private final class SeekResultCallback implements ResultCallback<MediaChannelResult> {
|
||||
|
||||
@ -841,9 +870,25 @@ public final class CastPlayer extends BasePlayer {
|
||||
if (--pendingSeekCount == 0) {
|
||||
pendingSeekWindowIndex = C.INDEX_UNSET;
|
||||
pendingSeekPositionMs = C.TIME_UNSET;
|
||||
for (EventListener listener : listeners) {
|
||||
listener.onSeekProcessed();
|
||||
}
|
||||
notificationsBatch.add(new ListenerNotificationTask(EventListener::onSeekProcessed));
|
||||
flushNotifications();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class ListenerNotificationTask {
|
||||
|
||||
private final Iterator<ListenerHolder> listenersSnapshot;
|
||||
private final ListenerInvocation listenerInvocation;
|
||||
|
||||
private ListenerNotificationTask(ListenerInvocation listenerInvocation) {
|
||||
this.listenersSnapshot = listeners.iterator();
|
||||
this.listenerInvocation = listenerInvocation;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
while (listenersSnapshot.hasNext()) {
|
||||
listenersSnapshot.next().invoke(listenerInvocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user