Merge playback speed into PlaybackInfo and update EPI and EPII

PiperOrigin-RevId: 322539001
This commit is contained in:
ibaker 2020-07-22 11:05:19 +01:00 committed by Oliver Woodman
parent 78260e2021
commit 1c6aaac958
5 changed files with 98 additions and 91 deletions

View File

@ -22,7 +22,6 @@ import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Pair;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.PlayerMessage.Target;
@ -67,7 +66,8 @@ import java.util.concurrent.TimeoutException;
private final Renderer[] renderers;
private final TrackSelector trackSelector;
private final PlaybackUpdateListenerImpl playbackUpdateListener;
private final Handler playbackInfoUpdateHandler;
private final ExoPlayerImplInternal.PlaybackInfoUpdateListener playbackInfoUpdateListener;
private final ExoPlayerImplInternal internalPlayer;
private final Handler internalPlayerHandler;
private final CopyOnWriteArrayList<ListenerHolder> listeners;
@ -87,8 +87,6 @@ import java.util.concurrent.TimeoutException;
@DiscontinuityReason private int pendingDiscontinuityReason;
@PlayWhenReadyChangeReason private int pendingPlayWhenReadyChangeReason;
private boolean foregroundMode;
private int pendingSetPlaybackSpeedAcks;
private float playbackSpeed;
private SeekParameters seekParameters;
private ShuffleOrder shuffleOrder;
private boolean pauseAtEndOfMediaItems;
@ -155,9 +153,11 @@ import java.util.concurrent.TimeoutException;
new TrackSelection[renderers.length],
null);
period = new Timeline.Period();
playbackSpeed = Player.DEFAULT_PLAYBACK_SPEED;
maskingWindowIndex = C.INDEX_UNSET;
playbackUpdateListener = new PlaybackUpdateListenerImpl(applicationLooper);
playbackInfoUpdateHandler = new Handler(applicationLooper);
playbackInfoUpdateListener =
playbackInfoUpdate ->
playbackInfoUpdateHandler.post(() -> handlePlaybackInfo(playbackInfoUpdate));
playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult);
pendingListenerNotifications = new ArrayDeque<>();
if (analyticsCollector != null) {
@ -179,7 +179,7 @@ import java.util.concurrent.TimeoutException;
pauseAtEndOfMediaItems,
applicationLooper,
clock,
playbackUpdateListener);
playbackInfoUpdateListener);
internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
}
@ -595,7 +595,7 @@ import java.util.concurrent.TimeoutException;
// general because the midroll ad preceding the seek destination must be played before the
// content position can be played, if a different ad is playing at the moment.
Log.w(TAG, "seekTo ignored because an ad is playing");
playbackUpdateListener.onPlaybackInfoUpdate(
playbackInfoUpdateListener.onPlaybackInfoUpdate(
new ExoPlayerImplInternal.PlaybackInfoUpdate(playbackInfo));
return;
}
@ -632,30 +632,30 @@ import java.util.concurrent.TimeoutException;
@Deprecated
@Override
public PlaybackParameters getPlaybackParameters() {
return new PlaybackParameters(playbackSpeed);
return new PlaybackParameters(playbackInfo.playbackSpeed);
}
@SuppressWarnings("deprecation")
@Override
public void setPlaybackSpeed(float playbackSpeed) {
checkState(playbackSpeed > 0);
if (this.playbackSpeed == playbackSpeed) {
if (playbackInfo.playbackSpeed == playbackSpeed) {
return;
}
pendingSetPlaybackSpeedAcks++;
this.playbackSpeed = playbackSpeed;
PlaybackParameters playbackParameters = new PlaybackParameters(playbackSpeed);
PlaybackInfo newPlaybackInfo = playbackInfo.copyWithPlaybackSpeed(playbackSpeed);
pendingOperationAcks++;
internalPlayer.setPlaybackSpeed(playbackSpeed);
notifyListeners(
listener -> {
listener.onPlaybackParametersChanged(playbackParameters);
listener.onPlaybackSpeedChanged(playbackSpeed);
});
updatePlaybackInfo(
newPlaybackInfo,
/* positionDiscontinuity= */ false,
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
/* ignored */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
/* seekProcessed= */ false);
}
@Override
public float getPlaybackSpeed() {
return playbackSpeed;
return playbackInfo.playbackSpeed;
}
@Override
@ -726,7 +726,7 @@ import java.util.concurrent.TimeoutException;
ExoPlaybackException.createForUnexpected(
new RuntimeException(new TimeoutException("Player release timed out.")))));
}
playbackUpdateListener.handler.removeCallbacksAndMessages(null);
playbackInfoUpdateHandler.removeCallbacksAndMessages(null);
if (analyticsCollector != null) {
bandwidthMeter.removeEventListener(analyticsCollector);
}
@ -896,23 +896,6 @@ import java.util.concurrent.TimeoutException;
return mediaSources;
}
@SuppressWarnings("deprecation")
private void handlePlaybackSpeed(float playbackSpeed, boolean operationAck) {
if (operationAck) {
pendingSetPlaybackSpeedAcks--;
}
if (pendingSetPlaybackSpeedAcks == 0) {
if (this.playbackSpeed != playbackSpeed) {
this.playbackSpeed = playbackSpeed;
notifyListeners(
listener -> {
listener.onPlaybackParametersChanged(new PlaybackParameters(playbackSpeed));
listener.onPlaybackSpeedChanged(playbackSpeed);
});
}
}
}
private void handlePlaybackInfo(ExoPlayerImplInternal.PlaybackInfoUpdate playbackInfoUpdate) {
pendingOperationAcks -= playbackInfoUpdate.operationAcks;
if (playbackInfoUpdate.positionDiscontinuity) {
@ -996,7 +979,7 @@ import java.util.concurrent.TimeoutException;
PlaybackInfo playbackInfo,
PlaybackInfo oldPlaybackInfo,
boolean positionDiscontinuity,
int positionDiscontinuityReason,
@DiscontinuityReason int positionDiscontinuityReason,
boolean timelineChanged) {
Timeline oldTimeline = oldPlaybackInfo.timeline;
@ -1360,49 +1343,6 @@ import java.util.concurrent.TimeoutException;
return positionMs;
}
private final class PlaybackUpdateListenerImpl
implements ExoPlayerImplInternal.PlaybackUpdateListener, Handler.Callback {
private static final int MSG_PLAYBACK_INFO_CHANGED = 0;
private static final int MSG_PLAYBACK_SPEED_CHANGED = 1;
private final Handler handler;
private PlaybackUpdateListenerImpl(Looper applicationLooper) {
handler = Util.createHandler(applicationLooper, /* callback= */ this);
}
@Override
public void onPlaybackInfoUpdate(ExoPlayerImplInternal.PlaybackInfoUpdate playbackInfo) {
handler.obtainMessage(MSG_PLAYBACK_INFO_CHANGED, playbackInfo).sendToTarget();
}
@Override
public void onPlaybackSpeedChange(float playbackSpeed, boolean acknowledgeCommand) {
handler
.obtainMessage(
MSG_PLAYBACK_SPEED_CHANGED,
/* arg1= */ acknowledgeCommand ? 1 : 0,
/* arg2= */ 0,
/* obj= */ playbackSpeed)
.sendToTarget();
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_PLAYBACK_INFO_CHANGED:
handlePlaybackInfo((ExoPlayerImplInternal.PlaybackInfoUpdate) msg.obj);
break;
case MSG_PLAYBACK_SPEED_CHANGED:
handlePlaybackSpeed((Float) msg.obj, /* operationAck= */ msg.arg1 != 0);
break;
default:
throw new IllegalStateException();
}
return true;
}
}
private static final class PlaybackInfoUpdate implements Runnable {
private final PlaybackInfo playbackInfo;
@ -1424,6 +1364,7 @@ import java.util.concurrent.TimeoutException;
private final boolean playWhenReadyChanged;
private final boolean playbackSuppressionReasonChanged;
private final boolean isPlayingChanged;
private final boolean playbackSpeedChanged;
public PlaybackInfoUpdate(
PlaybackInfo playbackInfo,
@ -1461,6 +1402,7 @@ import java.util.concurrent.TimeoutException;
playbackSuppressionReasonChanged =
previousPlaybackInfo.playbackSuppressionReason != playbackInfo.playbackSuppressionReason;
isPlayingChanged = isPlaying(previousPlaybackInfo) != isPlaying(playbackInfo);
playbackSpeedChanged = previousPlaybackInfo.playbackSpeed != playbackInfo.playbackSpeed;
}
@SuppressWarnings("deprecation")
@ -1526,6 +1468,15 @@ import java.util.concurrent.TimeoutException;
invokeAll(
listenerSnapshot, listener -> listener.onIsPlayingChanged(isPlaying(playbackInfo)));
}
if (playbackSpeedChanged) {
PlaybackParameters playbackParameters = new PlaybackParameters(playbackInfo.playbackSpeed);
invokeAll(
listenerSnapshot,
listener -> {
listener.onPlaybackSpeedChanged(playbackInfo.playbackSpeed);
listener.onPlaybackParametersChanged(playbackParameters);
});
}
if (seekProcessed) {
invokeAll(listenerSnapshot, EventListener::onSeekProcessed);
}

View File

@ -109,10 +109,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
public interface PlaybackUpdateListener {
public interface PlaybackInfoUpdateListener {
void onPlaybackInfoUpdate(ExoPlayerImplInternal.PlaybackInfoUpdate playbackInfo);
void onPlaybackSpeedChange(float playbackSpeed, boolean acknowledgeCommand);
}
// Internal messages
@ -168,7 +166,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private final DefaultMediaClock mediaClock;
private final ArrayList<PendingMessageInfo> pendingMessages;
private final Clock clock;
private final PlaybackUpdateListener playbackUpdateListener;
private final PlaybackInfoUpdateListener playbackInfoUpdateListener;
private final MediaPeriodQueue queue;
private final MediaSourceList mediaSourceList;
@ -210,8 +208,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
boolean pauseAtEndOfWindow,
Looper applicationLooper,
Clock clock,
PlaybackUpdateListener playbackUpdateListener) {
this.playbackUpdateListener = playbackUpdateListener;
PlaybackInfoUpdateListener playbackInfoUpdateListener) {
this.playbackInfoUpdateListener = playbackInfoUpdateListener;
this.renderers = renderers;
this.trackSelector = trackSelector;
this.emptyTrackSelectorResult = emptyTrackSelectorResult;
@ -624,7 +622,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void maybeNotifyPlaybackInfoChanged() {
playbackInfoUpdate.setPlaybackInfo(playbackInfo);
if (playbackInfoUpdate.hasPendingChange) {
playbackUpdateListener.onPlaybackInfoUpdate(playbackInfoUpdate);
playbackInfoUpdateListener.onPlaybackInfoUpdate(playbackInfoUpdate);
playbackInfoUpdate = new PlaybackInfoUpdate(playbackInfo);
}
}
@ -1279,6 +1277,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
mediaPeriodId,
playbackInfo.playWhenReady,
playbackInfo.playbackSuppressionReason,
playbackInfo.playbackSpeed,
startPositionUs,
/* totalBufferedDurationUs= */ 0,
startPositionUs);
@ -1964,7 +1963,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void handlePlaybackSpeed(float playbackSpeed, boolean acknowledgeCommand)
throws ExoPlaybackException {
playbackUpdateListener.onPlaybackSpeedChange(playbackSpeed, acknowledgeCommand);
playbackInfoUpdate.incrementPendingOperationAcks(acknowledgeCommand ? 1 : 0);
playbackInfo = playbackInfo.copyWithPlaybackSpeed(playbackSpeed);
updateTrackSelectionPlaybackSpeed(playbackSpeed);
for (Renderer renderer : renderers) {
if (renderer != null) {

View File

@ -63,6 +63,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
public final boolean playWhenReady;
/** Reason why playback is suppressed even though {@link #playWhenReady} is {@code true}. */
@PlaybackSuppressionReason public final int playbackSuppressionReason;
/** The playback speed. */
public final float playbackSpeed;
/**
* Position up to which media is buffered in {@link #loadingMediaPeriodId) relative to the start
@ -101,6 +103,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
PLACEHOLDER_MEDIA_PERIOD_ID,
/* playWhenReady= */ false,
Player.PLAYBACK_SUPPRESSION_REASON_NONE,
Player.DEFAULT_PLAYBACK_SPEED,
/* bufferedPositionUs= */ 0,
/* totalBufferedDurationUs= */ 0,
/* positionUs= */ 0);
@ -133,6 +136,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
MediaPeriodId loadingMediaPeriodId,
boolean playWhenReady,
@PlaybackSuppressionReason int playbackSuppressionReason,
float playbackSpeed,
long bufferedPositionUs,
long totalBufferedDurationUs,
long positionUs) {
@ -147,6 +151,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
this.loadingMediaPeriodId = loadingMediaPeriodId;
this.playWhenReady = playWhenReady;
this.playbackSuppressionReason = playbackSuppressionReason;
this.playbackSpeed = playbackSpeed;
this.bufferedPositionUs = bufferedPositionUs;
this.totalBufferedDurationUs = totalBufferedDurationUs;
this.positionUs = positionUs;
@ -190,6 +195,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);
@ -215,6 +221,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);
@ -240,6 +247,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);
@ -265,6 +273,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);
@ -290,6 +299,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);
@ -315,6 +325,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);
@ -344,6 +355,33 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);
}
/**
* Copies playback info with new playback speed.
*
* @param playbackSpeed New playback speed. See {@link #playbackSpeed}.
* @return Copied playback info with new playback speed.
*/
@CheckResult
public PlaybackInfo copyWithPlaybackSpeed(float playbackSpeed) {
return new PlaybackInfo(
timeline,
periodId,
requestedContentPositionUs,
playbackState,
playbackError,
isLoading,
trackGroups,
trackSelectorResult,
loadingMediaPeriodId,
playWhenReady,
playbackSuppressionReason,
playbackSpeed,
bufferedPositionUs,
totalBufferedDurationUs,
positionUs);

View File

@ -62,6 +62,7 @@ import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.source.ads.AdsLoader;
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
import com.google.android.exoplayer2.testutil.Action;
import com.google.android.exoplayer2.testutil.ActionSchedule;
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable;
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerTarget;
@ -82,6 +83,7 @@ import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinit
import com.google.android.exoplayer2.testutil.FakeTrackSelection;
import com.google.android.exoplayer2.testutil.FakeTrackSelector;
import com.google.android.exoplayer2.testutil.TestExoPlayer;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.Allocation;
@ -3333,15 +3335,29 @@ public final class ExoPlayerTest {
}
@Test
public void setPlaybackParametersConsecutivelyNotifiesListenerForEveryChangeOnce()
public void setPlaybackParametersConsecutivelyNotifiesListenerForEveryChangeOnceAndIsMasked()
throws Exception {
List<Float> maskedPlaybackSpeeds = new ArrayList<>();
Action getPlaybackSpeedAction =
new Action("getPlaybackSpeed", /* description= */ null) {
@Override
protected void doActionImpl(
SimpleExoPlayer player,
DefaultTrackSelector trackSelector,
@Nullable Surface surface) {
maskedPlaybackSpeeds.add(player.getPlaybackSpeed());
}
};
ActionSchedule actionSchedule =
new ActionSchedule.Builder(TAG)
.pause()
.waitForPlaybackState(Player.STATE_READY)
.setPlaybackSpeed(1.1f)
.apply(getPlaybackSpeedAction)
.setPlaybackSpeed(1.2f)
.apply(getPlaybackSpeedAction)
.setPlaybackSpeed(1.3f)
.apply(getPlaybackSpeedAction)
.play()
.build();
List<Float> reportedPlaybackSpeeds = new ArrayList<>();
@ -3360,6 +3376,7 @@ public final class ExoPlayerTest {
.blockUntilEnded(TIMEOUT_MS);
assertThat(reportedPlaybackSpeeds).containsExactly(1.1f, 1.2f, 1.3f).inOrder();
assertThat(maskedPlaybackSpeeds).isEqualTo(reportedPlaybackSpeeds);
}
@Test

View File

@ -437,6 +437,7 @@ public final class MediaPeriodQueueTest {
/* loadingMediaPeriodId= */ null,
/* playWhenReady= */ false,
Player.PLAYBACK_SUPPRESSION_REASON_NONE,
/* playbackSpeed= */ Player.DEFAULT_PLAYBACK_SPEED,
/* bufferedPositionUs= */ 0,
/* totalBufferedDurationUs= */ 0,
/* positionUs= */ 0);