diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java index 7d8d05bbaa6..80d9817a463 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java @@ -458,32 +458,16 @@ public void seekTo(int windowIndex, long positionMs) { flushNotifications(); } - /** @deprecated Use {@link #setPlaybackSpeed(float)} instead. */ - @SuppressWarnings("deprecation") - @Deprecated @Override public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) { // Unsupported by the RemoteMediaClient API. Do nothing. } - /** @deprecated Use {@link #getPlaybackSpeed()} instead. */ - @SuppressWarnings("deprecation") - @Deprecated @Override public PlaybackParameters getPlaybackParameters() { return PlaybackParameters.DEFAULT; } - @Override - public void setPlaybackSpeed(float playbackSpeed) { - // Unsupported by the RemoteMediaClient API. Do nothing. - } - - @Override - public float getPlaybackSpeed() { - return Player.DEFAULT_PLAYBACK_SPEED; - } - @Override public void stop(boolean reset) { playbackState = STATE_IDLE; diff --git a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java index 888eccbe940..453a7b6d55f 100644 --- a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java +++ b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java @@ -26,6 +26,7 @@ import com.google.android.exoplayer2.ControlDispatcher; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.audio.AudioAttributes; @@ -383,11 +384,11 @@ public AudioAttributesCompat getAudioAttributes() { } public void setPlaybackSpeed(float playbackSpeed) { - player.setPlaybackSpeed(playbackSpeed); + player.setPlaybackParameters(new PlaybackParameters(playbackSpeed)); } public float getPlaybackSpeed() { - return player.getPlaybackSpeed(); + return player.getPlaybackParameters().speed; } public void reset() { @@ -483,8 +484,8 @@ private void handleShuffleMode(boolean shuffleModeEnabled) { listener.onShuffleModeChanged(Utils.getShuffleMode(shuffleModeEnabled)); } - private void handlePlaybackSpeedChanged(float playbackSpeed) { - listener.onPlaybackSpeedChanged(playbackSpeed); + private void handlePlaybackParametersChanged(PlaybackParameters playbackParameters) { + listener.onPlaybackSpeedChanged(playbackParameters.speed); } private void handleTimelineChanged(Timeline timeline) { @@ -627,8 +628,8 @@ public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) { } @Override - public void onPlaybackSpeedChanged(float playbackSpeed) { - handlePlaybackSpeedChanged(playbackSpeed); + public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { + handlePlaybackParametersChanged(playbackParameters); } @Override diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index f3edfa3545a..85d0155bd77 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -38,6 +38,7 @@ import com.google.android.exoplayer2.DefaultControlDispatcher; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.util.Assertions; @@ -127,8 +128,8 @@ public final class MediaSessionConnector { @PlaybackActions public static final long DEFAULT_PLAYBACK_ACTIONS = ALL_PLAYBACK_ACTIONS; /** - * The name of the {@link PlaybackStateCompat} float extra with the value of {@link - * Player#getPlaybackSpeed()}. + * The name of the {@link PlaybackStateCompat} float extra with the value of {@code + * Player.getPlaybackParameters().speed}. */ public static final String EXTRAS_SPEED = "EXO_SPEED"; @@ -765,7 +766,7 @@ public final void invalidateMediaSessionPlaybackState() { queueNavigator != null ? queueNavigator.getActiveQueueItemId(player) : MediaSessionCompat.QueueItem.UNKNOWN_ID; - float playbackSpeed = player.getPlaybackSpeed(); + float playbackSpeed = player.getPlaybackParameters().speed; extras.putFloat(EXTRAS_SPEED, playbackSpeed); float sessionPlaybackSpeed = player.isPlaying() ? playbackSpeed : 0f; builder @@ -1134,7 +1135,7 @@ public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) { } @Override - public void onPlaybackSpeedChanged(float playbackSpeed) { + public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { invalidateMediaSessionPlaybackState(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultMediaClock.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultMediaClock.java index 6276f3bca88..9ee1846fc12 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultMediaClock.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultMediaClock.java @@ -27,20 +27,20 @@ */ /* package */ final class DefaultMediaClock implements MediaClock { - /** Listener interface to be notified of changes to the active playback speed. */ - public interface PlaybackSpeedListener { + /** Listener interface to be notified of changes to the active playback parameters. */ + public interface PlaybackParametersListener { /** - * Called when the active playback speed changed. Will not be called for {@link - * #setPlaybackSpeed(float)}. + * Called when the active playback parameters changed. Will not be called for {@link + * #setPlaybackParameters(PlaybackParameters)}. * - * @param newPlaybackSpeed The newly active playback speed. + * @param newPlaybackParameters The newly active playback parameters. */ - void onPlaybackSpeedChanged(float newPlaybackSpeed); + void onPlaybackParametersChanged(PlaybackParameters newPlaybackParameters); } private final StandaloneMediaClock standaloneClock; - private final PlaybackSpeedListener listener; + private final PlaybackParametersListener listener; @Nullable private Renderer rendererClockSource; @Nullable private MediaClock rendererClock; @@ -48,13 +48,13 @@ public interface PlaybackSpeedListener { private boolean standaloneClockIsStarted; /** - * Creates a new instance with listener for playback speed changes and a {@link Clock} to use for - * the standalone clock implementation. + * Creates a new instance with a listener for playback parameters changes and a {@link Clock} to + * use for the standalone clock implementation. * - * @param listener A {@link PlaybackSpeedListener} to listen for playback speed changes. + * @param listener A {@link PlaybackParametersListener} to listen for playback parameters changes. * @param clock A {@link Clock}. */ - public DefaultMediaClock(PlaybackSpeedListener listener, Clock clock) { + public DefaultMediaClock(PlaybackParametersListener listener, Clock clock) { this.listener = listener; this.standaloneClock = new StandaloneMediaClock(clock); isUsingStandaloneClock = true; @@ -102,7 +102,7 @@ public void onRendererEnabled(Renderer renderer) throws ExoPlaybackException { } this.rendererClock = rendererMediaClock; this.rendererClockSource = renderer; - rendererClock.setPlaybackSpeed(standaloneClock.getPlaybackSpeed()); + rendererClock.setPlaybackParameters(standaloneClock.getPlaybackParameters()); } } @@ -140,19 +140,19 @@ public long getPositionUs() { } @Override - public void setPlaybackSpeed(float playbackSpeed) { + public void setPlaybackParameters(PlaybackParameters playbackParameters) { if (rendererClock != null) { - rendererClock.setPlaybackSpeed(playbackSpeed); - playbackSpeed = rendererClock.getPlaybackSpeed(); + rendererClock.setPlaybackParameters(playbackParameters); + playbackParameters = rendererClock.getPlaybackParameters(); } - standaloneClock.setPlaybackSpeed(playbackSpeed); + standaloneClock.setPlaybackParameters(playbackParameters); } @Override - public float getPlaybackSpeed() { + public PlaybackParameters getPlaybackParameters() { return rendererClock != null - ? rendererClock.getPlaybackSpeed() - : standaloneClock.getPlaybackSpeed(); + ? rendererClock.getPlaybackParameters() + : standaloneClock.getPlaybackParameters(); } private void syncClocks(boolean isReadingAhead) { @@ -180,10 +180,10 @@ private void syncClocks(boolean isReadingAhead) { } // Continuously sync stand-alone clock to renderer clock so that it can take over if needed. standaloneClock.resetPosition(rendererClockPositionUs); - float playbackSpeed = rendererClock.getPlaybackSpeed(); - if (playbackSpeed != standaloneClock.getPlaybackSpeed()) { - standaloneClock.setPlaybackSpeed(playbackSpeed); - listener.onPlaybackSpeedChanged(playbackSpeed); + PlaybackParameters playbackParameters = rendererClock.getPlaybackParameters(); + if (!playbackParameters.equals(standaloneClock.getPlaybackParameters())) { + standaloneClock.setPlaybackParameters(playbackParameters); + listener.onPlaybackParametersChanged(playbackParameters); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 76be46eb40a..b1f57364658 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -619,32 +619,17 @@ public void seekTo(int windowIndex, long positionMs) { /* seekProcessed= */ true); } - /** @deprecated Use {@link #setPlaybackSpeed(float)} instead. */ - @SuppressWarnings("deprecation") - @Deprecated @Override public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) { - setPlaybackSpeed( - playbackParameters != null ? playbackParameters.speed : Player.DEFAULT_PLAYBACK_SPEED); - } - - /** @deprecated Use {@link #getPlaybackSpeed()} instead. */ - @SuppressWarnings("deprecation") - @Deprecated - @Override - public PlaybackParameters getPlaybackParameters() { - return new PlaybackParameters(playbackInfo.playbackSpeed); - } - - @Override - public void setPlaybackSpeed(float playbackSpeed) { - checkState(playbackSpeed > 0); - if (playbackInfo.playbackSpeed == playbackSpeed) { + if (playbackParameters == null) { + playbackParameters = PlaybackParameters.DEFAULT; + } + if (playbackInfo.playbackParameters.equals(playbackParameters)) { return; } - PlaybackInfo newPlaybackInfo = playbackInfo.copyWithPlaybackSpeed(playbackSpeed); + PlaybackInfo newPlaybackInfo = playbackInfo.copyWithPlaybackParameters(playbackParameters); pendingOperationAcks++; - internalPlayer.setPlaybackSpeed(playbackSpeed); + internalPlayer.setPlaybackParameters(playbackParameters); updatePlaybackInfo( newPlaybackInfo, /* positionDiscontinuity= */ false, @@ -655,8 +640,8 @@ public void setPlaybackSpeed(float playbackSpeed) { } @Override - public float getPlaybackSpeed() { - return playbackInfo.playbackSpeed; + public PlaybackParameters getPlaybackParameters() { + return playbackInfo.playbackParameters; } @Override @@ -1366,7 +1351,7 @@ private static final class PlaybackInfoUpdate implements Runnable { private final boolean playWhenReadyChanged; private final boolean playbackSuppressionReasonChanged; private final boolean isPlayingChanged; - private final boolean playbackSpeedChanged; + private final boolean playbackParametersChanged; private final boolean offloadSchedulingEnabledChanged; public PlaybackInfoUpdate( @@ -1405,7 +1390,8 @@ public PlaybackInfoUpdate( playbackSuppressionReasonChanged = previousPlaybackInfo.playbackSuppressionReason != playbackInfo.playbackSuppressionReason; isPlayingChanged = isPlaying(previousPlaybackInfo) != isPlaying(playbackInfo); - playbackSpeedChanged = previousPlaybackInfo.playbackSpeed != playbackInfo.playbackSpeed; + playbackParametersChanged = + !previousPlaybackInfo.playbackParameters.equals(playbackInfo.playbackParameters); offloadSchedulingEnabledChanged = previousPlaybackInfo.offloadSchedulingEnabled != playbackInfo.offloadSchedulingEnabled; } @@ -1473,13 +1459,11 @@ public void run() { invokeAll( listenerSnapshot, listener -> listener.onIsPlayingChanged(isPlaying(playbackInfo))); } - if (playbackSpeedChanged) { - PlaybackParameters playbackParameters = new PlaybackParameters(playbackInfo.playbackSpeed); + if (playbackParametersChanged) { invokeAll( listenerSnapshot, listener -> { - listener.onPlaybackSpeedChanged(playbackInfo.playbackSpeed); - listener.onPlaybackParametersChanged(playbackParameters); + listener.onPlaybackParametersChanged(playbackInfo.playbackParameters); }); } if (seekProcessed) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index c1c6a629202..220b2633178 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -27,7 +27,7 @@ import android.util.Pair; import androidx.annotation.CheckResult; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.DefaultMediaClock.PlaybackSpeedListener; +import com.google.android.exoplayer2.DefaultMediaClock.PlaybackParametersListener; import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.PlayWhenReadyChangeReason; import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; @@ -61,7 +61,7 @@ MediaPeriod.Callback, TrackSelector.InvalidationListener, MediaSourceList.MediaSourceListInfoRefreshListener, - PlaybackSpeedListener, + PlaybackParametersListener, PlayerMessage.Sender { private static final String TAG = "ExoPlayerImplInternal"; @@ -121,7 +121,7 @@ public interface PlaybackInfoUpdateListener { private static final int MSG_SET_PLAY_WHEN_READY = 1; private static final int MSG_DO_SOME_WORK = 2; private static final int MSG_SEEK_TO = 3; - private static final int MSG_SET_PLAYBACK_SPEED = 4; + private static final int MSG_SET_PLAYBACK_PARAMETERS = 4; private static final int MSG_SET_SEEK_PARAMETERS = 5; private static final int MSG_STOP = 6; private static final int MSG_RELEASE = 7; @@ -133,7 +133,7 @@ public interface PlaybackInfoUpdateListener { private static final int MSG_SET_FOREGROUND_MODE = 13; private static final int MSG_SEND_MESSAGE = 14; private static final int MSG_SEND_MESSAGE_TO_TARGET_THREAD = 15; - private static final int MSG_PLAYBACK_SPEED_CHANGED_INTERNAL = 16; + private static final int MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL = 16; private static final int MSG_SET_MEDIA_SOURCES = 17; private static final int MSG_ADD_MEDIA_SOURCES = 18; private static final int MSG_MOVE_MEDIA_SOURCES = 19; @@ -301,8 +301,8 @@ public void seekTo(Timeline timeline, int windowIndex, long positionUs) { .sendToTarget(); } - public void setPlaybackSpeed(float playbackSpeed) { - handler.obtainMessage(MSG_SET_PLAYBACK_SPEED, playbackSpeed).sendToTarget(); + public void setPlaybackParameters(PlaybackParameters playbackParameters) { + handler.obtainMessage(MSG_SET_PLAYBACK_PARAMETERS, playbackParameters).sendToTarget(); } public void setSeekParameters(SeekParameters seekParameters) { @@ -432,11 +432,11 @@ public void onTrackSelectionsInvalidated() { handler.sendEmptyMessage(MSG_TRACK_SELECTION_INVALIDATED); } - // DefaultMediaClock.PlaybackSpeedListener implementation. + // DefaultMediaClock.PlaybackParametersListener implementation. @Override - public void onPlaybackSpeedChanged(float playbackSpeed) { - sendPlaybackSpeedChangedInternal(playbackSpeed, /* acknowledgeCommand= */ false); + public void onPlaybackParametersChanged(PlaybackParameters newPlaybackParameters) { + sendPlaybackParametersChangedInternal(newPlaybackParameters, /* acknowledgeCommand= */ false); } // Handler.Callback implementation. @@ -467,8 +467,8 @@ public boolean handleMessage(Message msg) { case MSG_SEEK_TO: seekToInternal((SeekPosition) msg.obj); break; - case MSG_SET_PLAYBACK_SPEED: - setPlaybackSpeedInternal((Float) msg.obj); + case MSG_SET_PLAYBACK_PARAMETERS: + setPlaybackParametersInternal((PlaybackParameters) msg.obj); break; case MSG_SET_SEEK_PARAMETERS: setSeekParametersInternal((SeekParameters) msg.obj); @@ -489,8 +489,9 @@ public boolean handleMessage(Message msg) { case MSG_TRACK_SELECTION_INVALIDATED: reselectTracksInternal(); break; - case MSG_PLAYBACK_SPEED_CHANGED_INTERNAL: - handlePlaybackSpeed((Float) msg.obj, /* acknowledgeCommand= */ msg.arg1 != 0); + case MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL: + handlePlaybackParameters( + (PlaybackParameters) msg.obj, /* acknowledgeCommand= */ msg.arg1 != 0); break; case MSG_SEND_MESSAGE: sendMessageInternal((PlayerMessage) msg.obj); @@ -1184,9 +1185,10 @@ private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackExce notifyTrackSelectionDiscontinuity(); } - private void setPlaybackSpeedInternal(float playbackSpeed) { - mediaClock.setPlaybackSpeed(playbackSpeed); - sendPlaybackSpeedChangedInternal(mediaClock.getPlaybackSpeed(), /* acknowledgeCommand= */ true); + private void setPlaybackParametersInternal(PlaybackParameters playbackParameters) { + mediaClock.setPlaybackParameters(playbackParameters); + sendPlaybackParametersChangedInternal( + mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true); } private void setSeekParametersInternal(SeekParameters seekParameters) { @@ -1303,7 +1305,7 @@ private void resetInternal( mediaPeriodId, playbackInfo.playWhenReady, playbackInfo.playbackSuppressionReason, - playbackInfo.playbackSpeed, + playbackInfo.playbackParameters, startPositionUs, /* totalBufferedDurationUs= */ 0, startPositionUs, @@ -1508,7 +1510,7 @@ private void disableRenderer(Renderer renderer) throws ExoPlaybackException { } private void reselectTracksInternal() throws ExoPlaybackException { - float playbackSpeed = mediaClock.getPlaybackSpeed(); + float playbackSpeed = mediaClock.getPlaybackParameters().speed; // Reselect tracks on each period in turn, until the selection changes. MediaPeriodHolder periodHolder = queue.getPlayingPeriod(); MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod(); @@ -1626,7 +1628,7 @@ private boolean shouldTransitionToReadyState(boolean renderersReadyOrEnded) { boolean bufferedToEnd = loadingHolder.isFullyBuffered() && loadingHolder.info.isFinal; return bufferedToEnd || loadControl.shouldStartPlayback( - getTotalBufferedDurationUs(), mediaClock.getPlaybackSpeed(), rebuffering); + getTotalBufferedDurationUs(), mediaClock.getPlaybackParameters().speed, rebuffering); } private boolean isTimelineReady() { @@ -1962,7 +1964,8 @@ private void handlePeriodPrepared(MediaPeriod mediaPeriod) throws ExoPlaybackExc return; } MediaPeriodHolder loadingPeriodHolder = queue.getLoadingPeriod(); - loadingPeriodHolder.handlePrepared(mediaClock.getPlaybackSpeed(), playbackInfo.timeline); + loadingPeriodHolder.handlePrepared( + mediaClock.getPlaybackParameters().speed, playbackInfo.timeline); updateLoadControlTrackSelection( loadingPeriodHolder.getTrackGroups(), loadingPeriodHolder.getTrackSelectorResult()); if (loadingPeriodHolder == queue.getPlayingPeriod()) { @@ -1987,14 +1990,15 @@ private void handleContinueLoadingRequested(MediaPeriod mediaPeriod) { maybeContinueLoading(); } - private void handlePlaybackSpeed(float playbackSpeed, boolean acknowledgeCommand) + private void handlePlaybackParameters( + PlaybackParameters playbackParameters, boolean acknowledgeCommand) throws ExoPlaybackException { playbackInfoUpdate.incrementPendingOperationAcks(acknowledgeCommand ? 1 : 0); - playbackInfo = playbackInfo.copyWithPlaybackSpeed(playbackSpeed); - updateTrackSelectionPlaybackSpeed(playbackSpeed); + playbackInfo = playbackInfo.copyWithPlaybackParameters(playbackParameters); + updateTrackSelectionPlaybackSpeed(playbackParameters.speed); for (Renderer renderer : renderers) { if (renderer != null) { - renderer.setOperatingRate(playbackSpeed); + renderer.setOperatingRate(playbackParameters.speed); } } } @@ -2020,7 +2024,7 @@ private boolean shouldContinueLoading() { : loadingPeriodHolder.toPeriodTime(rendererPositionUs) - loadingPeriodHolder.info.startPositionUs; return loadControl.shouldContinueLoading( - playbackPositionUs, bufferedDurationUs, mediaClock.getPlaybackSpeed()); + playbackPositionUs, bufferedDurationUs, mediaClock.getPlaybackParameters().speed); } private boolean isLoadingPossible() { @@ -2196,10 +2200,14 @@ private void updateLoadControlTrackSelection( loadControl.onTracksSelected(renderers, trackGroups, trackSelectorResult.selections); } - private void sendPlaybackSpeedChangedInternal(float playbackSpeed, boolean acknowledgeCommand) { + private void sendPlaybackParametersChangedInternal( + PlaybackParameters playbackParameters, boolean acknowledgeCommand) { handler .obtainMessage( - MSG_PLAYBACK_SPEED_CHANGED_INTERNAL, acknowledgeCommand ? 1 : 0, 0, playbackSpeed) + MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, + acknowledgeCommand ? 1 : 0, + 0, + playbackParameters) .sendToTarget(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java index 57295c54fc6..9fb65630058 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java @@ -63,8 +63,8 @@ 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; + /** The playback parameters. */ + public final PlaybackParameters playbackParameters; /** Whether offload scheduling is enabled for the main player loop. */ public final boolean offloadSchedulingEnabled; @@ -105,7 +105,7 @@ public static PlaybackInfo createDummy(TrackSelectorResult emptyTrackSelectorRes PLACEHOLDER_MEDIA_PERIOD_ID, /* playWhenReady= */ false, Player.PLAYBACK_SUPPRESSION_REASON_NONE, - Player.DEFAULT_PLAYBACK_SPEED, + PlaybackParameters.DEFAULT, /* bufferedPositionUs= */ 0, /* totalBufferedDurationUs= */ 0, /* positionUs= */ 0, @@ -119,10 +119,14 @@ public static PlaybackInfo createDummy(TrackSelectorResult emptyTrackSelectorRes * @param periodId See {@link #periodId}. * @param requestedContentPositionUs See {@link #requestedContentPositionUs}. * @param playbackState See {@link #playbackState}. + * @param playbackError See {@link #playbackError}. * @param isLoading See {@link #isLoading}. * @param trackGroups See {@link #trackGroups}. * @param trackSelectorResult See {@link #trackSelectorResult}. * @param loadingMediaPeriodId See {@link #loadingMediaPeriodId}. + * @param playWhenReady See {@link #playWhenReady}. + * @param playbackSuppressionReason See {@link #playbackSuppressionReason}. + * @param playbackParameters See {@link #playbackParameters}. * @param bufferedPositionUs See {@link #bufferedPositionUs}. * @param totalBufferedDurationUs See {@link #totalBufferedDurationUs}. * @param positionUs See {@link #positionUs}. @@ -140,7 +144,7 @@ public PlaybackInfo( MediaPeriodId loadingMediaPeriodId, boolean playWhenReady, @PlaybackSuppressionReason int playbackSuppressionReason, - float playbackSpeed, + PlaybackParameters playbackParameters, long bufferedPositionUs, long totalBufferedDurationUs, long positionUs, @@ -156,7 +160,7 @@ public PlaybackInfo( this.loadingMediaPeriodId = loadingMediaPeriodId; this.playWhenReady = playWhenReady; this.playbackSuppressionReason = playbackSuppressionReason; - this.playbackSpeed = playbackSpeed; + this.playbackParameters = playbackParameters; this.bufferedPositionUs = bufferedPositionUs; this.totalBufferedDurationUs = totalBufferedDurationUs; this.positionUs = positionUs; @@ -201,7 +205,7 @@ public PlaybackInfo copyWithNewPosition( loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -228,7 +232,7 @@ public PlaybackInfo copyWithTimeline(Timeline timeline) { loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -255,7 +259,7 @@ public PlaybackInfo copyWithPlaybackState(int playbackState) { loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -282,7 +286,7 @@ public PlaybackInfo copyWithPlaybackError(@Nullable ExoPlaybackException playbac loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -309,7 +313,7 @@ public PlaybackInfo copyWithIsLoading(boolean isLoading) { loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -336,7 +340,7 @@ public PlaybackInfo copyWithLoadingMediaPeriodId(MediaPeriodId loadingMediaPerio loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -367,7 +371,7 @@ public PlaybackInfo copyWithPlayWhenReady( loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -375,13 +379,13 @@ public PlaybackInfo copyWithPlayWhenReady( } /** - * Copies playback info with new playback speed. + * Copies playback info with new playback parameters. * - * @param playbackSpeed New playback speed. See {@link #playbackSpeed}. - * @return Copied playback info with new playback speed. + * @param playbackParameters New playback parameters. See {@link #playbackParameters}. + * @return Copied playback info with new playback parameters. */ @CheckResult - public PlaybackInfo copyWithPlaybackSpeed(float playbackSpeed) { + public PlaybackInfo copyWithPlaybackParameters(PlaybackParameters playbackParameters) { return new PlaybackInfo( timeline, periodId, @@ -394,7 +398,7 @@ public PlaybackInfo copyWithPlaybackSpeed(float playbackSpeed) { loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, @@ -422,7 +426,7 @@ public PlaybackInfo copyWithOffloadSchedulingEnabled(boolean offloadSchedulingEn loadingMediaPeriodId, playWhenReady, playbackSuppressionReason, - playbackSpeed, + playbackParameters, bufferedPositionUs, totalBufferedDurationUs, positionUs, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackParameters.java b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackParameters.java index afa0a7ebc40..7dcd6f80aa0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackParameters.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackParameters.java @@ -17,13 +17,9 @@ import androidx.annotation.Nullable; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; -/** - * @deprecated Use {@link Player#setPlaybackSpeed(float)} and {@link - * Player.AudioComponent#setSkipSilenceEnabled(boolean)} instead. - */ -@SuppressWarnings("deprecation") -@Deprecated +/** Parameters that apply to playback, including speed setting. */ public final class PlaybackParameters { /** The default playback parameters: real-time playback with no silence skipping. */ @@ -32,16 +28,34 @@ public final class PlaybackParameters { /** The factor by which playback will be sped up. */ public final float speed; + /** The factor by which pitch will be shifted. */ + public final float pitch; + private final int scaledUsPerMs; /** - * Creates new playback parameters that set the playback speed. + * Creates new playback parameters that set the playback speed. The pitch of audio will not be + * adjusted, so the effect is to time-stretch the audio. * * @param speed The factor by which playback will be sped up. Must be greater than zero. */ public PlaybackParameters(float speed) { + this(speed, /* pitch= */ 1f); + } + + /** + * Creates new playback parameters that set the playback speed/pitch. + * + * @param speed The factor by which playback will be sped up. Must be greater than zero. + * @param pitch The factor by which the pitch of audio will be adjusted. Must be greater than + * zero. Useful values are {@code 1} (to time-stretch audio) and the same value as passed in + * as the {@code speed} (to resample audio, which is useful for slow-motion videos). + */ + public PlaybackParameters(float speed, float pitch) { Assertions.checkArgument(speed > 0); + Assertions.checkArgument(pitch > 0); this.speed = speed; + this.pitch = pitch; scaledUsPerMs = Math.round(speed * 1000f); } @@ -65,11 +79,19 @@ public boolean equals(@Nullable Object obj) { return false; } PlaybackParameters other = (PlaybackParameters) obj; - return this.speed == other.speed; + return this.speed == other.speed && this.pitch == other.pitch; } @Override public int hashCode() { - return Float.floatToRawIntBits(speed); + int result = 17; + result = 31 * result + Float.floatToRawIntBits(speed); + result = 31 * result + Float.floatToRawIntBits(pitch); + return result; + } + + @Override + public String toString() { + return Util.formatInvariant("PlaybackParameters(speed=%.2f, pitch=%.2f)", speed, pitch); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Player.java b/library/core/src/main/java/com/google/android/exoplayer2/Player.java index 93443453753..490022de93c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Player.java @@ -583,21 +583,15 @@ default void onPlayerError(ExoPlaybackException error) {} default void onPositionDiscontinuity(@DiscontinuityReason int reason) {} /** - * @deprecated Use {@link #onPlaybackSpeedChanged(float)} and {@link - * AudioListener#onSkipSilenceEnabledChanged(boolean)} instead. + * Called when the current playback parameters change. The playback parameters may change due to + * a call to {@link #setPlaybackParameters(PlaybackParameters)}, or the player itself may change + * them (for example, if audio playback switches to passthrough or offload mode, where speed + * adjustment is no longer possible). + * + * @param playbackParameters The playback parameters. */ - @SuppressWarnings("deprecation") - @Deprecated default void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {} - /** - * Called when the current playback speed changes. The normal playback speed is 1. The speed may - * change due to a call to {@link #setPlaybackSpeed(float)}, or the player itself may change it - * (for example, if audio playback switches to passthrough mode, where speed adjustment is no - * longer possible). - */ - default void onPlaybackSpeedChanged(float playbackSpeed) {} - /** * @deprecated Seeks are processed without delay. Listen to {@link * #onPositionDiscontinuity(int)} with reason {@link #DISCONTINUITY_REASON_SEEK} instead. @@ -810,9 +804,6 @@ public void onTimelineChanged(Timeline timeline, @Nullable Object manifest) { */ int MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED = 3; - /** The default playback speed. */ - float DEFAULT_PLAYBACK_SPEED = 1.0f; - /** Returns the component of this player for audio output, or null if audio is not supported. */ @Nullable AudioComponent getAudioComponent(); @@ -1161,38 +1152,23 @@ public void onTimelineChanged(Timeline timeline, @Nullable Object manifest) { void next(); /** - * @deprecated Use {@link #setPlaybackSpeed(float)} or {@link - * AudioComponent#setSkipSilenceEnabled(boolean)} instead. - */ - @SuppressWarnings("deprecation") - @Deprecated - void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters); - - /** - * @deprecated Use {@link #getPlaybackSpeed()} or {@link AudioComponent#getSkipSilenceEnabled()} - * instead. - */ - @SuppressWarnings("deprecation") - @Deprecated - PlaybackParameters getPlaybackParameters(); - - /** - * Attempts to set the playback speed. + * Attempts to set the playback parameters. Passing {@code null} sets the parameters to the + * default, {@link PlaybackParameters#DEFAULT}, which means there is no speed or pitch adjustment. * - *
Playback speed changes may cause the player to buffer. {@link - * EventListener#onPlaybackSpeedChanged(float)} will be called whenever the currently active - * playback speed change. + *
Playback parameters changes may cause the player to buffer. {@link
+ * EventListener#onPlaybackParametersChanged(PlaybackParameters)} will be called whenever the
+ * currently active playback parameters change.
*
- * @param playbackSpeed The playback speed.
+ * @param playbackParameters The playback parameters, or {@code null} to use the defaults.
*/
- void setPlaybackSpeed(float playbackSpeed);
+ void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters);
/**
- * Returns the currently active playback speed.
+ * Returns the currently active playback parameters.
*
- * @see EventListener#onPlaybackSpeedChanged(float)
+ * @see EventListener#onPlaybackParametersChanged(PlaybackParameters)
*/
- float getPlaybackSpeed();
+ PlaybackParameters getPlaybackParameters();
/**
* Stops playback without resetting the player. Use {@link #pause()} rather than this method if
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
index d927161d168..a43973b31c9 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
@@ -1030,18 +1030,23 @@ public void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskMan
this.priorityTaskManager = priorityTaskManager;
}
- /** @deprecated Use {@link #setPlaybackSpeed(float)} instead. */
+ /**
+ * Sets the {@link PlaybackParams} governing audio playback.
+ *
+ * @param params The {@link PlaybackParams}, or null to clear any previously set parameters.
+ * @deprecated Use {@link #setPlaybackParameters(PlaybackParameters)}.
+ */
@Deprecated
@RequiresApi(23)
public void setPlaybackParams(@Nullable PlaybackParams params) {
- float playbackSpeed;
+ PlaybackParameters playbackParameters;
if (params != null) {
params.allowDefaults();
- playbackSpeed = params.getSpeed();
+ playbackParameters = new PlaybackParameters(params.getSpeed(), params.getPitch());
} else {
- playbackSpeed = 1.0f;
+ playbackParameters = null;
}
- setPlaybackSpeed(playbackSpeed);
+ setPlaybackParameters(playbackParameters);
}
/** Returns the video format currently being played, or null if no video is being played. */
@@ -1623,39 +1628,18 @@ public void seekTo(int windowIndex, long positionMs) {
player.seekTo(windowIndex, positionMs);
}
- /**
- * @deprecated Use {@link #setPlaybackSpeed(float)} and {@link #setSkipSilenceEnabled(boolean)}
- * instead.
- */
- @SuppressWarnings("deprecation")
- @Deprecated
@Override
public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) {
verifyApplicationThread();
player.setPlaybackParameters(playbackParameters);
}
- /** @deprecated Use {@link #getPlaybackSpeed()} and {@link #getSkipSilenceEnabled()} instead. */
- @SuppressWarnings("deprecation")
- @Deprecated
@Override
public PlaybackParameters getPlaybackParameters() {
verifyApplicationThread();
return player.getPlaybackParameters();
}
- @Override
- public void setPlaybackSpeed(float playbackSpeed) {
- verifyApplicationThread();
- player.setPlaybackSpeed(playbackSpeed);
- }
-
- @Override
- public float getPlaybackSpeed() {
- verifyApplicationThread();
- return player.getPlaybackSpeed();
- }
-
@Override
public void setSeekParameters(@Nullable SeekParameters seekParameters) {
verifyApplicationThread();
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
index 0193c94deb6..35f3099dc94 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
@@ -552,12 +552,6 @@ public final void onPositionDiscontinuity(@Player.DiscontinuityReason int reason
}
}
- /**
- * @deprecated Use {@link #onPlaybackSpeedChanged(float)} and {@link
- * #onSkipSilenceEnabledChanged(boolean)} instead.
- */
- @SuppressWarnings("deprecation")
- @Deprecated
@Override
public final void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
@@ -566,14 +560,6 @@ public final void onPlaybackParametersChanged(PlaybackParameters playbackParamet
}
}
- @Override
- public void onPlaybackSpeedChanged(float playbackSpeed) {
- EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
- for (AnalyticsListener listener : listeners) {
- listener.onPlaybackSpeedChanged(eventTime, playbackSpeed);
- }
- }
-
@SuppressWarnings("deprecation")
@Override
public final void onSeekProcessed() {
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
index d80ef5f70ab..2e26019541e 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
@@ -279,21 +279,13 @@ default void onSeekStarted(EventTime eventTime) {}
default void onSeekProcessed(EventTime eventTime) {}
/**
- * @deprecated Use {@link #onPlaybackSpeedChanged(EventTime, float)} and {@link
- * #onSkipSilenceEnabledChanged(EventTime, boolean)} instead.
- */
- @SuppressWarnings("deprecation")
- @Deprecated
- default void onPlaybackParametersChanged(
- EventTime eventTime, PlaybackParameters playbackParameters) {}
-
- /**
- * Called when the playback speed changes.
+ * Called when the playback parameters changed.
*
* @param eventTime The event time.
- * @param playbackSpeed The playback speed.
+ * @param playbackParameters The new playback parameters.
*/
- default void onPlaybackSpeedChanged(EventTime eventTime, float playbackSpeed) {}
+ default void onPlaybackParametersChanged(
+ EventTime eventTime, PlaybackParameters playbackParameters) {}
/**
* Called when the repeat mode changed.
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
index 1efb072ef0a..ab137f98e19 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
@@ -22,6 +22,7 @@
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
@@ -334,8 +335,9 @@ public void onPlayerError(EventTime eventTime, ExoPlaybackException error) {
}
@Override
- public void onPlaybackSpeedChanged(EventTime eventTime, float playbackSpeed) {
- this.playbackSpeed = playbackSpeed;
+ public void onPlaybackParametersChanged(
+ EventTime eventTime, PlaybackParameters playbackParameters) {
+ playbackSpeed = playbackParameters.speed;
maybeAddSession(eventTime);
for (PlaybackStatsTracker tracker : playbackStatsTrackers.values()) {
tracker.onPlaybackSpeedChanged(eventTime, playbackSpeed);
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
index 21683bda480..b7d375fd9dc 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
@@ -20,6 +20,7 @@
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.PlaybackParameters;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -306,16 +307,21 @@ boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs, int encodedAcce
*/
boolean hasPendingData();
- /** Sets the playback speed. */
- void setPlaybackSpeed(float playbackSpeed);
+ /**
+ * Attempts to set the playback parameters. The audio sink may override these parameters if they
+ * are not supported.
+ *
+ * @param playbackParameters The new playback parameters to attempt to set.
+ */
+ void setPlaybackParameters(PlaybackParameters playbackParameters);
- /** Gets the playback speed. */
- float getPlaybackSpeed();
+ /** Returns the active {@link PlaybackParameters}. */
+ PlaybackParameters getPlaybackParameters();
/** Sets whether silences should be skipped in the audio stream. */
void setSkipSilenceEnabled(boolean skipSilenceEnabled);
- /** Gets whether silences are skipped in the audio stream. */
+ /** Returns whether silences are skipped in the audio stream. */
boolean getSkipSilenceEnabled();
/**
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java
index 84a4e36d074..1c1e593e223 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java
@@ -29,6 +29,7 @@
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
+import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.PlayerMessage.Target;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
@@ -498,13 +499,13 @@ public long getPositionUs() {
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {
- audioSink.setPlaybackSpeed(playbackSpeed);
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {
+ audioSink.setPlaybackParameters(playbackParameters);
}
@Override
- public float getPlaybackSpeed() {
- return audioSink.getPlaybackSpeed();
+ public PlaybackParameters getPlaybackParameters() {
+ return audioSink.getPlaybackParameters();
}
@Override
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
index 7075fce5d08..1e04b1e8d7b 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
@@ -32,6 +32,7 @@
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log;
@@ -92,14 +93,14 @@ public interface AudioProcessorChain {
AudioProcessor[] getAudioProcessors();
/**
- * Configures audio processors to apply the specified playback speed immediately, returning the
- * new playback speed, which may differ from the speed passed in. Only called when processors
- * have no input pending.
+ * Configures audio processors to apply the specified playback parameters immediately, returning
+ * the new playback parameters, which may differ from those passed in. Only called when
+ * processors have no input pending.
*
- * @param playbackSpeed The playback speed to try to apply.
- * @return The playback speed that was actually applied.
+ * @param playbackParameters The playback parameters to try to apply.
+ * @return The playback parameters that were actually applied.
*/
- float applyPlaybackSpeed(float playbackSpeed);
+ PlaybackParameters applyPlaybackParameters(PlaybackParameters playbackParameters);
/**
* Configures audio processors to apply whether to skip silences immediately, returning the new
@@ -170,8 +171,10 @@ public AudioProcessor[] getAudioProcessors() {
}
@Override
- public float applyPlaybackSpeed(float playbackSpeed) {
- return sonicAudioProcessor.setSpeed(playbackSpeed);
+ public PlaybackParameters applyPlaybackParameters(PlaybackParameters playbackParameters) {
+ float speed = sonicAudioProcessor.setSpeed(playbackParameters.speed);
+ float pitch = sonicAudioProcessor.setPitch(playbackParameters.pitch);
+ return new PlaybackParameters(speed, pitch);
}
@Override
@@ -197,6 +200,10 @@ public long getSkippedOutputFrameCount() {
public static final float MIN_PLAYBACK_SPEED = 0.1f;
/** The maximum allowed playback speed. Higher values will be constrained to fall in range. */
public static final float MAX_PLAYBACK_SPEED = 8f;
+ /** The minimum allowed pitch factor. Lower values will be constrained to fall in range. */
+ public static final float MIN_PITCH = 0.1f;
+ /** The maximum allowed pitch factor. Higher values will be constrained to fall in range. */
+ public static final float MAX_PITCH = 8f;
/** The default skip silence flag. */
private static final boolean DEFAULT_SKIP_SILENCE = false;
@@ -296,7 +303,7 @@ public long getSkippedOutputFrameCount() {
private AudioAttributes audioAttributes;
@Nullable private MediaPositionParameters afterDrainParameters;
private MediaPositionParameters mediaPositionParameters;
- private float audioTrackPlaybackSpeed;
+ private PlaybackParameters audioTrackPlaybackParameters;
@Nullable private ByteBuffer avSyncHeader;
private int bytesUntilNextAvSync;
@@ -418,11 +425,11 @@ public DefaultAudioSink(
auxEffectInfo = new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, 0f);
mediaPositionParameters =
new MediaPositionParameters(
- DEFAULT_PLAYBACK_SPEED,
+ PlaybackParameters.DEFAULT,
DEFAULT_SKIP_SILENCE,
/* mediaTimeUs= */ 0,
/* audioTrackPositionUs= */ 0);
- audioTrackPlaybackSpeed = 1f;
+ audioTrackPlaybackParameters = PlaybackParameters.DEFAULT;
drainingAudioProcessorIndex = C.INDEX_UNSET;
activeAudioProcessors = new AudioProcessor[0];
outputBuffers = new ByteBuffer[0];
@@ -707,7 +714,7 @@ public boolean handleBuffer(
}
}
// Re-apply playback parameters.
- applyAudioProcessorPlaybackSpeedAndSkipSilence(presentationTimeUs);
+ applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs);
}
if (!isAudioTrackInitialized()) {
@@ -720,9 +727,9 @@ public boolean handleBuffer(
startMediaTimeUsNeedsInit = false;
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) {
- setAudioTrackPlaybackSpeedV23(audioTrackPlaybackSpeed);
+ setAudioTrackPlaybackParametersV23(audioTrackPlaybackParameters);
}
- applyAudioProcessorPlaybackSpeedAndSkipSilence(presentationTimeUs);
+ applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs);
if (playing) {
play();
@@ -758,7 +765,7 @@ public boolean handleBuffer(
// Don't process any more input until draining completes.
return false;
}
- applyAudioProcessorPlaybackSpeedAndSkipSilence(presentationTimeUs);
+ applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs);
afterDrainParameters = null;
}
@@ -789,7 +796,7 @@ public boolean handleBuffer(
startMediaTimeUs += adjustmentUs;
startMediaTimeUsNeedsSync = false;
// Re-apply playback parameters because the startMediaTimeUs changed.
- applyAudioProcessorPlaybackSpeedAndSkipSilence(presentationTimeUs);
+ applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs);
if (listener != null && adjustmentUs != 0) {
listener.onPositionDiscontinuity();
}
@@ -1011,26 +1018,30 @@ public boolean hasPendingData() {
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {
- playbackSpeed = Util.constrainValue(playbackSpeed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED);
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {
+ playbackParameters =
+ new PlaybackParameters(
+ Util.constrainValue(playbackParameters.speed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED),
+ Util.constrainValue(playbackParameters.pitch, MIN_PITCH, MAX_PITCH));
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) {
- setAudioTrackPlaybackSpeedV23(playbackSpeed);
+ setAudioTrackPlaybackParametersV23(playbackParameters);
} else {
- setAudioProcessorPlaybackSpeedAndSkipSilence(playbackSpeed, getSkipSilenceEnabled());
+ setAudioProcessorPlaybackParametersAndSkipSilence(
+ playbackParameters, getSkipSilenceEnabled());
}
}
@Override
- public float getPlaybackSpeed() {
- // We use either audio processor speed adjustment or AudioTrack playback parameters, so one of
- // the operands is always 1f.
- return getAudioProcessorPlaybackSpeed() * audioTrackPlaybackSpeed;
+ public PlaybackParameters getPlaybackParameters() {
+ return enableAudioTrackPlaybackParams
+ ? audioTrackPlaybackParameters
+ : getAudioProcessorPlaybackParameters();
}
@Override
public void setSkipSilenceEnabled(boolean skipSilenceEnabled) {
- setAudioProcessorPlaybackSpeedAndSkipSilence(
- getAudioProcessorPlaybackSpeed(), skipSilenceEnabled);
+ setAudioProcessorPlaybackParametersAndSkipSilence(
+ getAudioProcessorPlaybackParameters(), skipSilenceEnabled);
}
@Override
@@ -1212,7 +1223,7 @@ private void resetSinkStateForFlush() {
framesPerEncodedSample = 0;
mediaPositionParameters =
new MediaPositionParameters(
- getAudioProcessorPlaybackSpeed(),
+ getAudioProcessorPlaybackParameters(),
getSkipSilenceEnabled(),
/* mediaTimeUs= */ 0,
/* audioTrackPositionUs= */ 0);
@@ -1249,12 +1260,13 @@ public void run() {
}
@RequiresApi(23)
- private void setAudioTrackPlaybackSpeedV23(float audioTrackPlaybackSpeed) {
+ private void setAudioTrackPlaybackParametersV23(PlaybackParameters audioTrackPlaybackParameters) {
if (isAudioTrackInitialized()) {
PlaybackParams playbackParams =
new PlaybackParams()
.allowDefaults()
- .setSpeed(audioTrackPlaybackSpeed)
+ .setSpeed(audioTrackPlaybackParameters.speed)
+ .setPitch(audioTrackPlaybackParameters.pitch)
.setAudioFallbackMode(PlaybackParams.AUDIO_FALLBACK_MODE_FAIL);
try {
audioTrack.setPlaybackParams(playbackParams);
@@ -1262,20 +1274,22 @@ private void setAudioTrackPlaybackSpeedV23(float audioTrackPlaybackSpeed) {
Log.w(TAG, "Failed to set playback params", e);
}
// Update the speed using the actual effective speed from the audio track.
- audioTrackPlaybackSpeed = audioTrack.getPlaybackParams().getSpeed();
- audioTrackPositionTracker.setAudioTrackPlaybackSpeed(audioTrackPlaybackSpeed);
+ audioTrackPlaybackParameters =
+ new PlaybackParameters(
+ audioTrack.getPlaybackParams().getSpeed(), audioTrack.getPlaybackParams().getPitch());
+ audioTrackPositionTracker.setAudioTrackPlaybackSpeed(audioTrackPlaybackParameters.speed);
}
- this.audioTrackPlaybackSpeed = audioTrackPlaybackSpeed;
+ this.audioTrackPlaybackParameters = audioTrackPlaybackParameters;
}
- private void setAudioProcessorPlaybackSpeedAndSkipSilence(
- float playbackSpeed, boolean skipSilence) {
+ private void setAudioProcessorPlaybackParametersAndSkipSilence(
+ PlaybackParameters playbackParameters, boolean skipSilence) {
MediaPositionParameters currentMediaPositionParameters = getMediaPositionParameters();
- if (playbackSpeed != currentMediaPositionParameters.playbackSpeed
+ if (!playbackParameters.equals(currentMediaPositionParameters.playbackParameters)
|| skipSilence != currentMediaPositionParameters.skipSilence) {
MediaPositionParameters mediaPositionParameters =
new MediaPositionParameters(
- playbackSpeed,
+ playbackParameters,
skipSilence,
/* mediaTimeUs= */ C.TIME_UNSET,
/* audioTrackPositionUs= */ C.TIME_UNSET);
@@ -1291,8 +1305,8 @@ private void setAudioProcessorPlaybackSpeedAndSkipSilence(
}
}
- private float getAudioProcessorPlaybackSpeed() {
- return getMediaPositionParameters().playbackSpeed;
+ private PlaybackParameters getAudioProcessorPlaybackParameters() {
+ return getMediaPositionParameters().playbackParameters;
}
private MediaPositionParameters getMediaPositionParameters() {
@@ -1304,18 +1318,18 @@ private MediaPositionParameters getMediaPositionParameters() {
: mediaPositionParameters;
}
- private void applyAudioProcessorPlaybackSpeedAndSkipSilence(long presentationTimeUs) {
- float playbackSpeed =
+ private void applyAudioProcessorPlaybackParametersAndSkipSilence(long presentationTimeUs) {
+ PlaybackParameters playbackParameters =
configuration.canApplyPlaybackParameters
- ? audioProcessorChain.applyPlaybackSpeed(getAudioProcessorPlaybackSpeed())
- : DEFAULT_PLAYBACK_SPEED;
+ ? audioProcessorChain.applyPlaybackParameters(getAudioProcessorPlaybackParameters())
+ : PlaybackParameters.DEFAULT;
boolean skipSilenceEnabled =
configuration.canApplyPlaybackParameters
? audioProcessorChain.applySkipSilenceEnabled(getSkipSilenceEnabled())
: DEFAULT_SKIP_SILENCE;
mediaPositionParametersCheckpoints.add(
new MediaPositionParameters(
- playbackSpeed,
+ playbackParameters,
skipSilenceEnabled,
/* mediaTimeUs= */ max(0, presentationTimeUs),
/* audioTrackPositionUs= */ configuration.framesToDurationUs(getWrittenFrames())));
@@ -1340,7 +1354,7 @@ private long applyMediaPositionParameters(long positionUs) {
long playoutDurationSinceLastCheckpoint =
positionUs - mediaPositionParameters.audioTrackPositionUs;
- if (mediaPositionParameters.playbackSpeed != 1f) {
+ if (!mediaPositionParameters.playbackParameters.equals(PlaybackParameters.DEFAULT)) {
if (mediaPositionParametersCheckpoints.isEmpty()) {
playoutDurationSinceLastCheckpoint =
audioProcessorChain.getMediaDuration(playoutDurationSinceLastCheckpoint);
@@ -1348,7 +1362,8 @@ private long applyMediaPositionParameters(long positionUs) {
// Playing data at a previous playback speed, so fall back to multiplying by the speed.
playoutDurationSinceLastCheckpoint =
Util.getMediaDurationForPlayoutDuration(
- playoutDurationSinceLastCheckpoint, mediaPositionParameters.playbackSpeed);
+ playoutDurationSinceLastCheckpoint,
+ mediaPositionParameters.playbackParameters.speed);
}
}
return mediaPositionParameters.mediaTimeUs + playoutDurationSinceLastCheckpoint;
@@ -1692,8 +1707,8 @@ public void unregister(AudioTrack audioTrack) {
/** Stores parameters used to calculate the current media position. */
private static final class MediaPositionParameters {
- /** The playback speed. */
- public final float playbackSpeed;
+ /** The playback parameters. */
+ public final PlaybackParameters playbackParameters;
/** Whether to skip silences. */
public final boolean skipSilence;
/** The media time from which the playback parameters apply, in microseconds. */
@@ -1702,8 +1717,11 @@ private static final class MediaPositionParameters {
public final long audioTrackPositionUs;
private MediaPositionParameters(
- float playbackSpeed, boolean skipSilence, long mediaTimeUs, long audioTrackPositionUs) {
- this.playbackSpeed = playbackSpeed;
+ PlaybackParameters playbackParameters,
+ boolean skipSilence,
+ long mediaTimeUs,
+ long audioTrackPositionUs) {
+ this.playbackParameters = playbackParameters;
this.skipSilence = skipSilence;
this.mediaTimeUs = mediaTimeUs;
this.audioTrackPositionUs = audioTrackPositionUs;
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java
index 3f755a71300..7460d124576 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java
@@ -17,6 +17,7 @@
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.PlaybackParameters;
import java.nio.ByteBuffer;
/** An overridable {@link AudioSink} implementation forwarding all methods to another sink. */
@@ -88,13 +89,13 @@ public boolean hasPendingData() {
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {
- sink.setPlaybackSpeed(playbackSpeed);
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {
+ sink.setPlaybackParameters(playbackParameters);
}
@Override
- public float getPlaybackSpeed() {
- return sink.getPlaybackSpeed();
+ public PlaybackParameters getPlaybackParameters() {
+ return sink.getPlaybackParameters();
}
@Override
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
index dfcc41d670c..2d034335c8d 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
@@ -33,6 +33,7 @@
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
+import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.PlayerMessage.Target;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispatcher;
@@ -545,13 +546,13 @@ public long getPositionUs() {
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {
- audioSink.setPlaybackSpeed(playbackSpeed);
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {
+ audioSink.setPlaybackParameters(playbackParameters);
}
@Override
- public float getPlaybackSpeed() {
- return audioSink.getPlaybackSpeed();
+ public PlaybackParameters getPlaybackParameters() {
+ return audioSink.getPlaybackParameters();
}
@Override
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java
index a2cdaa8b742..ae65eacd130 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java
@@ -37,6 +37,7 @@
private final int inputSampleRateHz;
private final int channelCount;
private final float speed;
+ private final float pitch;
private final float rate;
private final int minPeriod;
private final int maxPeriod;
@@ -63,12 +64,15 @@
* @param inputSampleRateHz The sample rate of input audio, in hertz.
* @param channelCount The number of channels in the input audio.
* @param speed The speedup factor for output audio.
+ * @param pitch The pitch factor for output audio.
* @param outputSampleRateHz The sample rate for output audio, in hertz.
*/
- public Sonic(int inputSampleRateHz, int channelCount, float speed, int outputSampleRateHz) {
+ public Sonic(
+ int inputSampleRateHz, int channelCount, float speed, float pitch, int outputSampleRateHz) {
this.inputSampleRateHz = inputSampleRateHz;
this.channelCount = channelCount;
this.speed = speed;
+ this.pitch = pitch;
rate = (float) inputSampleRateHz / outputSampleRateHz;
minPeriod = inputSampleRateHz / MAXIMUM_PITCH;
maxPeriod = inputSampleRateHz / MINIMUM_PITCH;
@@ -118,8 +122,10 @@ public void getOutput(ShortBuffer buffer) {
*/
public void queueEndOfStream() {
int remainingFrameCount = inputFrameCount;
+ float s = speed / pitch;
+ float r = rate * pitch;
int expectedOutputFrames =
- outputFrameCount + (int) ((remainingFrameCount / speed + pitchFrameCount) / rate + 0.5f);
+ outputFrameCount + (int) ((remainingFrameCount / s + pitchFrameCount) / r + 0.5f);
// Add enough silence to flush both input and pitch buffers.
inputBuffer =
@@ -464,14 +470,16 @@ private void changeSpeed(float speed) {
private void processStreamInput() {
// Resample as many pitch periods as we have buffered on the input.
int originalOutputFrameCount = outputFrameCount;
- if (speed > 1.00001 || speed < 0.99999) {
- changeSpeed(speed);
+ float s = speed / pitch;
+ float r = rate * pitch;
+ if (s > 1.00001 || s < 0.99999) {
+ changeSpeed(s);
} else {
copyToOutput(inputBuffer, 0, inputFrameCount);
inputFrameCount = 0;
}
- if (rate != 1.0f) {
- adjustRate(rate, originalOutputFrameCount);
+ if (r != 1.0f) {
+ adjustRate(r, originalOutputFrameCount);
}
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java
index d582461c810..5c3c1db0c74 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java
@@ -43,6 +43,7 @@ public final class SonicAudioProcessor implements AudioProcessor {
private int pendingOutputSampleRate;
private float speed;
+ private float pitch;
private AudioFormat pendingInputAudioFormat;
private AudioFormat pendingOutputAudioFormat;
@@ -61,6 +62,7 @@ public final class SonicAudioProcessor implements AudioProcessor {
/** Creates a new Sonic audio processor. */
public SonicAudioProcessor() {
speed = 1f;
+ pitch = 1f;
pendingInputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputAudioFormat = AudioFormat.NOT_SET;
@@ -87,6 +89,22 @@ public float setSpeed(float speed) {
return speed;
}
+ /**
+ * Sets the playback pitch. This method may only be called after draining data through the
+ * processor. The value returned by {@link #isActive()} may change, and the processor must be
+ * {@link #flush() flushed} before queueing more data.
+ *
+ * @param pitch The requested new pitch.
+ * @return The actual new pitch.
+ */
+ public float setPitch(float pitch) {
+ if (this.pitch != pitch) {
+ this.pitch = pitch;
+ pendingSonicRecreation = true;
+ }
+ return pitch;
+ }
+
/**
* Sets the sample rate for output audio, in Hertz. Pass {@link #SAMPLE_RATE_NO_CHANGE} to output
* audio at the same sample rate as the input. After calling this method, call {@link
@@ -140,6 +158,7 @@ public AudioFormat configure(AudioFormat inputAudioFormat) throws UnhandledAudio
public boolean isActive() {
return pendingOutputAudioFormat.sampleRate != Format.NO_VALUE
&& (Math.abs(speed - 1f) >= CLOSE_THRESHOLD
+ || Math.abs(pitch - 1f) >= CLOSE_THRESHOLD
|| pendingOutputAudioFormat.sampleRate != pendingInputAudioFormat.sampleRate);
}
@@ -200,6 +219,7 @@ public void flush() {
inputAudioFormat.sampleRate,
inputAudioFormat.channelCount,
speed,
+ pitch,
outputAudioFormat.sampleRate);
} else if (sonic != null) {
sonic.flush();
@@ -214,6 +234,7 @@ public void flush() {
@Override
public void reset() {
speed = 1f;
+ pitch = 1f;
pendingInputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputAudioFormat = AudioFormat.NOT_SET;
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java
index 4d1ebe0111c..aa82d41414f 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java
@@ -25,6 +25,7 @@
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
import com.google.android.exoplayer2.RendererCapabilities;
@@ -147,8 +148,9 @@ public void onSeekStarted(EventTime eventTime) {
}
@Override
- public void onPlaybackSpeedChanged(EventTime eventTime, float playbackSpeed) {
- logd(eventTime, "playbackSpeed", Float.toString(playbackSpeed));
+ public void onPlaybackParametersChanged(
+ EventTime eventTime, PlaybackParameters playbackParameters) {
+ logd(eventTime, "playbackParameters", playbackParameters.toString());
}
@Override
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/MediaClock.java b/library/core/src/main/java/com/google/android/exoplayer2/util/MediaClock.java
index 44c3c5e7fae..df335908c09 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/util/MediaClock.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/util/MediaClock.java
@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.util;
+import com.google.android.exoplayer2.PlaybackParameters;
+
/**
* Tracks the progression of media time.
*/
@@ -26,13 +28,13 @@ public interface MediaClock {
long getPositionUs();
/**
- * Attempts to set the playback speed. The media clock may override the speed if changing the
- * speed is not supported.
+ * Attempts to set the playback parameters. The media clock may override the speed if changing the
+ * playback parameters is not supported.
*
- * @param playbackSpeed The playback speed to attempt to set.
+ * @param playbackParameters The playback parameters to attempt to set.
*/
- void setPlaybackSpeed(float playbackSpeed);
+ void setPlaybackParameters(PlaybackParameters playbackParameters);
- /** Returns the active playback speed. */
- float getPlaybackSpeed();
+ /** Returns the active playback parameters. */
+ PlaybackParameters getPlaybackParameters();
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/StandaloneMediaClock.java b/library/core/src/main/java/com/google/android/exoplayer2/util/StandaloneMediaClock.java
index e1df77a2002..87970d3c003 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/util/StandaloneMediaClock.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/util/StandaloneMediaClock.java
@@ -16,7 +16,7 @@
package com.google.android.exoplayer2.util;
import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.PlaybackParameters;
/**
* A {@link MediaClock} whose position advances with real time based on the playback parameters when
@@ -29,8 +29,7 @@ public final class StandaloneMediaClock implements MediaClock {
private boolean started;
private long baseUs;
private long baseElapsedMs;
- private float playbackSpeed;
- private int scaledUsPerMs;
+ private PlaybackParameters playbackParameters;
/**
* Creates a new standalone media clock using the given {@link Clock} implementation.
@@ -39,8 +38,7 @@ public final class StandaloneMediaClock implements MediaClock {
*/
public StandaloneMediaClock(Clock clock) {
this.clock = clock;
- playbackSpeed = Player.DEFAULT_PLAYBACK_SPEED;
- scaledUsPerMs = getScaledUsPerMs(playbackSpeed);
+ playbackParameters = PlaybackParameters.DEFAULT;
}
/**
@@ -80,33 +78,29 @@ public long getPositionUs() {
long positionUs = baseUs;
if (started) {
long elapsedSinceBaseMs = clock.elapsedRealtime() - baseElapsedMs;
- if (playbackSpeed == 1f) {
+ if (playbackParameters.speed == 1f) {
positionUs += C.msToUs(elapsedSinceBaseMs);
} else {
// Add the media time in microseconds that will elapse in elapsedSinceBaseMs milliseconds of
// wallclock time
- positionUs += elapsedSinceBaseMs * scaledUsPerMs;
+ positionUs += playbackParameters.getMediaTimeUsForPlayoutTimeMs(elapsedSinceBaseMs);
}
}
return positionUs;
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {
// Store the current position as the new base, in case the playback speed has changed.
if (started) {
resetPosition(getPositionUs());
}
- this.playbackSpeed = playbackSpeed;
- scaledUsPerMs = getScaledUsPerMs(playbackSpeed);
+ this.playbackParameters = playbackParameters;
}
@Override
- public float getPlaybackSpeed() {
- return playbackSpeed;
+ public PlaybackParameters getPlaybackParameters() {
+ return playbackParameters;
}
- private static int getScaledUsPerMs(float playbackSpeed) {
- return Math.round(playbackSpeed * 1000f);
- }
}
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/DefaultMediaClockTest.java b/library/core/src/test/java/com/google/android/exoplayer2/DefaultMediaClockTest.java
index 217df762f64..867857cbe5d 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/DefaultMediaClockTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/DefaultMediaClockTest.java
@@ -22,7 +22,7 @@
import static org.mockito.MockitoAnnotations.initMocks;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.google.android.exoplayer2.DefaultMediaClock.PlaybackSpeedListener;
+import com.google.android.exoplayer2.DefaultMediaClock.PlaybackParametersListener;
import com.google.android.exoplayer2.testutil.FakeClock;
import com.google.android.exoplayer2.testutil.FakeMediaClockRenderer;
import org.junit.Before;
@@ -36,9 +36,10 @@ public class DefaultMediaClockTest {
private static final long TEST_POSITION_US = 123456789012345678L;
private static final long SLEEP_TIME_MS = 1_000;
- private static final float TEST_PLAYBACK_SPEED = 2f;
+ private static final PlaybackParameters TEST_PLAYBACK_PARAMETERS =
+ new PlaybackParameters(/* speed= */ 2f);
- @Mock private PlaybackSpeedListener listener;
+ @Mock private PlaybackParametersListener listener;
private FakeClock fakeClock;
private DefaultMediaClock mediaClock;
@@ -109,44 +110,44 @@ public void standaloneStartAndStop_shouldNotTriggerCallback() throws Exception {
}
@Test
- public void standaloneGetPlaybackSpeed_initializedWithDefaultPlaybackSpeed() {
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(Player.DEFAULT_PLAYBACK_SPEED);
+ public void standaloneGetPlaybackParameters_initializedWithDefaultPlaybackParameters() {
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(PlaybackParameters.DEFAULT);
}
@Test
- public void standaloneSetPlaybackSpeed_getPlaybackSpeedShouldReturnSameValue() {
- mediaClock.setPlaybackSpeed(TEST_PLAYBACK_SPEED);
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(TEST_PLAYBACK_SPEED);
+ public void standaloneSetPlaybackParameters_getPlaybackParametersShouldReturnSameValue() {
+ mediaClock.setPlaybackParameters(TEST_PLAYBACK_PARAMETERS);
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(TEST_PLAYBACK_PARAMETERS);
}
@Test
- public void standaloneSetPlaybackSpeed_shouldNotTriggerCallback() {
- mediaClock.setPlaybackSpeed(TEST_PLAYBACK_SPEED);
+ public void standaloneSetPlaybackParameters_shouldNotTriggerCallback() {
+ mediaClock.setPlaybackParameters(TEST_PLAYBACK_PARAMETERS);
verifyNoMoreInteractions(listener);
}
@Test
- public void standaloneSetPlaybackSpeed_shouldApplyNewPlaybackSpeed() {
- mediaClock.setPlaybackSpeed(TEST_PLAYBACK_SPEED);
+ public void standaloneSetPlaybackParameters_shouldApplyNewPlaybackParameters() {
+ mediaClock.setPlaybackParameters(TEST_PLAYBACK_PARAMETERS);
mediaClock.start();
- // Asserts that clock is running with speed declared in getPlaybackSpeed().
+ // Asserts that clock is running with speed declared in getPlaybackParameters().
assertClockIsRunning(/* isReadingAhead= */ false);
}
@Test
- public void standaloneSetOtherPlaybackSpeed_getPlaybackSpeedShouldReturnSameValue() {
- mediaClock.setPlaybackSpeed(TEST_PLAYBACK_SPEED);
- mediaClock.setPlaybackSpeed(Player.DEFAULT_PLAYBACK_SPEED);
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(Player.DEFAULT_PLAYBACK_SPEED);
+ public void standaloneSetOtherPlaybackParameters_getPlaybackParametersShouldReturnSameValue() {
+ mediaClock.setPlaybackParameters(TEST_PLAYBACK_PARAMETERS);
+ mediaClock.setPlaybackParameters(PlaybackParameters.DEFAULT);
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(PlaybackParameters.DEFAULT);
}
@Test
- public void enableRendererMediaClock_shouldOverwriteRendererPlaybackSpeedIfPossible()
+ public void enableRendererMediaClock_shouldOverwriteRendererPlaybackParametersIfPossible()
throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(TEST_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ true);
+ new MediaClockRenderer(TEST_PLAYBACK_PARAMETERS, /* playbackParametersAreMutable= */ true);
mediaClock.onRendererEnabled(mediaClockRenderer);
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(Player.DEFAULT_PLAYBACK_SPEED);
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(PlaybackParameters.DEFAULT);
verifyNoMoreInteractions(listener);
}
@@ -154,26 +155,27 @@ public void enableRendererMediaClock_shouldOverwriteRendererPlaybackSpeedIfPossi
public void enableRendererMediaClockWithFixedPlaybackSpeed_usesRendererPlaybackSpeed()
throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(TEST_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ false);
+ new MediaClockRenderer(TEST_PLAYBACK_PARAMETERS, /* playbackParametersAreMutable= */ false);
mediaClock.onRendererEnabled(mediaClockRenderer);
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(TEST_PLAYBACK_SPEED);
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(TEST_PLAYBACK_PARAMETERS);
}
@Test
public void enableRendererMediaClockWithFixedPlaybackSpeed_shouldTriggerCallback()
throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(TEST_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ false);
+ new MediaClockRenderer(TEST_PLAYBACK_PARAMETERS, /* playbackParametersAreMutable= */ false);
mediaClock.onRendererEnabled(mediaClockRenderer);
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
- verify(listener).onPlaybackSpeedChanged(TEST_PLAYBACK_SPEED);
+ verify(listener).onPlaybackParametersChanged(TEST_PLAYBACK_PARAMETERS);
}
@Test
public void enableRendererMediaClockWithFixedButSamePlaybackSpeed_shouldNotTriggerCallback()
throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(Player.DEFAULT_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ false);
+ new MediaClockRenderer(
+ PlaybackParameters.DEFAULT, /* playbackParametersAreMutable= */ false);
mediaClock.onRendererEnabled(mediaClockRenderer);
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
verifyNoMoreInteractions(listener);
@@ -182,44 +184,47 @@ public void enableRendererMediaClockWithFixedButSamePlaybackSpeed_shouldNotTrigg
@Test
public void disableRendererMediaClock_shouldKeepPlaybackSpeed() throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(TEST_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ false);
+ new MediaClockRenderer(TEST_PLAYBACK_PARAMETERS, /* playbackParametersAreMutable= */ false);
mediaClock.onRendererEnabled(mediaClockRenderer);
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
mediaClock.onRendererDisabled(mediaClockRenderer);
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(TEST_PLAYBACK_SPEED);
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(TEST_PLAYBACK_PARAMETERS);
}
@Test
- public void rendererClockSetPlaybackSpeed_getPlaybackSpeedShouldReturnSameValue()
+ public void rendererClockSetPlaybackSpeed_getPlaybackParametersShouldReturnSameValue()
throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(Player.DEFAULT_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ true);
+ new MediaClockRenderer(
+ PlaybackParameters.DEFAULT, /* playbackParametersAreMutable= */ true);
mediaClock.onRendererEnabled(mediaClockRenderer);
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
- mediaClock.setPlaybackSpeed(TEST_PLAYBACK_SPEED);
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(TEST_PLAYBACK_SPEED);
+ mediaClock.setPlaybackParameters(TEST_PLAYBACK_PARAMETERS);
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(TEST_PLAYBACK_PARAMETERS);
}
@Test
public void rendererClockSetPlaybackSpeed_shouldNotTriggerCallback() throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(Player.DEFAULT_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ true);
+ new MediaClockRenderer(
+ PlaybackParameters.DEFAULT, /* playbackParametersAreMutable= */ true);
mediaClock.onRendererEnabled(mediaClockRenderer);
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
- mediaClock.setPlaybackSpeed(TEST_PLAYBACK_SPEED);
+ mediaClock.setPlaybackParameters(TEST_PLAYBACK_PARAMETERS);
verifyNoMoreInteractions(listener);
}
@Test
- public void rendererClockSetPlaybackSpeedOverwrite_getPlaybackSpeedShouldReturnSameValue()
+ public void rendererClockSetPlaybackSpeedOverwrite_getPlaybackParametersShouldReturnSameValue()
throws ExoPlaybackException {
FakeMediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(Player.DEFAULT_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ false);
+ new MediaClockRenderer(
+ PlaybackParameters.DEFAULT, /* playbackParametersAreMutable= */ false);
mediaClock.onRendererEnabled(mediaClockRenderer);
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
- mediaClock.setPlaybackSpeed(TEST_PLAYBACK_SPEED);
- assertThat(mediaClock.getPlaybackSpeed()).isEqualTo(Player.DEFAULT_PLAYBACK_SPEED);
+ mediaClock.setPlaybackParameters(TEST_PLAYBACK_PARAMETERS);
+ assertThat(mediaClock.getPlaybackParameters()).isEqualTo(PlaybackParameters.DEFAULT);
}
@Test
@@ -266,12 +271,13 @@ public void disableRendererMediaClock_standaloneShouldBeSynced() throws ExoPlayb
public void getPositionWithPlaybackSpeedChange_shouldTriggerCallback()
throws ExoPlaybackException {
MediaClockRenderer mediaClockRenderer =
- new MediaClockRenderer(Player.DEFAULT_PLAYBACK_SPEED, /* playbackSpeedIsMutable= */ true);
+ new MediaClockRenderer(
+ PlaybackParameters.DEFAULT, /* playbackParametersAreMutable= */ true);
mediaClock.onRendererEnabled(mediaClockRenderer);
// Silently change playback speed of renderer clock.
- mediaClockRenderer.playbackSpeed = TEST_PLAYBACK_SPEED;
+ mediaClockRenderer.playbackParameters = TEST_PLAYBACK_PARAMETERS;
mediaClock.syncAndGetPositionUs(/* isReadingAhead= */ false);
- verify(listener).onPlaybackSpeedChanged(TEST_PLAYBACK_SPEED);
+ verify(listener).onPlaybackParametersChanged(TEST_PLAYBACK_PARAMETERS);
}
@Test
@@ -356,7 +362,7 @@ public void enableOtherRendererClock_shouldThrow()
private void assertClockIsRunning(boolean isReadingAhead) {
long clockStartUs = mediaClock.syncAndGetPositionUs(isReadingAhead);
fakeClock.advanceTime(SLEEP_TIME_MS);
- int scaledUsPerMs = Math.round(mediaClock.getPlaybackSpeed() * 1000f);
+ int scaledUsPerMs = Math.round(mediaClock.getPlaybackParameters().speed * 1000f);
assertThat(mediaClock.syncAndGetPositionUs(isReadingAhead))
.isEqualTo(clockStartUs + (SLEEP_TIME_MS * scaledUsPerMs));
}
@@ -371,37 +377,53 @@ private void assertClockIsStopped() {
@SuppressWarnings("HidingField")
private static class MediaClockRenderer extends FakeMediaClockRenderer {
- private final boolean playbackSpeedIsMutable;
+ private final boolean playbackParametersAreMutable;
private final boolean isReady;
private final boolean isEnded;
- public float playbackSpeed;
+ public PlaybackParameters playbackParameters;
public long positionUs;
public MediaClockRenderer() throws ExoPlaybackException {
- this(Player.DEFAULT_PLAYBACK_SPEED, false, true, false, false);
+ this(
+ PlaybackParameters.DEFAULT,
+ /* playbackParametersAreMutable= */ false,
+ /* isReady= */ true,
+ /* isEnded= */ false,
+ /* hasReadStreamToEnd= */ false);
}
- public MediaClockRenderer(float playbackSpeed, boolean playbackSpeedIsMutable)
+ public MediaClockRenderer(
+ PlaybackParameters playbackParameters, boolean playbackParametersAreMutable)
throws ExoPlaybackException {
- this(playbackSpeed, playbackSpeedIsMutable, true, false, false);
+ this(
+ playbackParameters,
+ playbackParametersAreMutable,
+ /* isReady= */ true,
+ /* isEnded= */ false,
+ /* hasReadStreamToEnd= */ false);
}
public MediaClockRenderer(boolean isReady, boolean isEnded, boolean hasReadStreamToEnd)
throws ExoPlaybackException {
- this(Player.DEFAULT_PLAYBACK_SPEED, false, isReady, isEnded, hasReadStreamToEnd);
+ this(
+ PlaybackParameters.DEFAULT,
+ /* playbackParametersAreMutable= */ false,
+ isReady,
+ isEnded,
+ hasReadStreamToEnd);
}
private MediaClockRenderer(
- float playbackSpeed,
- boolean playbackSpeedIsMutable,
+ PlaybackParameters playbackParameters,
+ boolean playbackParametersAreMutable,
boolean isReady,
boolean isEnded,
boolean hasReadStreamToEnd)
throws ExoPlaybackException {
super(C.TRACK_TYPE_UNKNOWN);
- this.playbackSpeed = playbackSpeed;
- this.playbackSpeedIsMutable = playbackSpeedIsMutable;
+ this.playbackParameters = playbackParameters;
+ this.playbackParametersAreMutable = playbackParametersAreMutable;
this.isReady = isReady;
this.isEnded = isEnded;
this.positionUs = TEST_POSITION_US;
@@ -416,15 +438,15 @@ public long getPositionUs() {
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {
- if (playbackSpeedIsMutable) {
- this.playbackSpeed = playbackSpeed;
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {
+ if (playbackParametersAreMutable) {
+ this.playbackParameters = playbackParameters;
}
}
@Override
- public float getPlaybackSpeed() {
- return playbackSpeed;
+ public PlaybackParameters getPlaybackParameters() {
+ return playbackParameters;
}
@Override
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
index 3c43d3c22f5..0043cb9e748 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
@@ -328,11 +328,11 @@ public long getPositionUs() {
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {}
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {}
@Override
- public float getPlaybackSpeed() {
- return Player.DEFAULT_PLAYBACK_SPEED;
+ public PlaybackParameters getPlaybackParameters() {
+ return PlaybackParameters.DEFAULT;
}
@Override
@@ -1010,7 +1010,7 @@ protected FakeMediaPeriod createFakeMediaPeriod(
}
})
// Set playback speed (while the fake media period is not yet prepared).
- .setPlaybackSpeed(2f)
+ .setPlaybackParameters(new PlaybackParameters(/* speed= */ 2f))
// Complete preparation of the fake media period.
.executeRunnable(() -> fakeMediaPeriodHolder[0].setPreparationComplete())
.build();
@@ -3378,18 +3378,18 @@ protected void doActionImpl(
SimpleExoPlayer player,
DefaultTrackSelector trackSelector,
@Nullable Surface surface) {
- maskedPlaybackSpeeds.add(player.getPlaybackSpeed());
+ maskedPlaybackSpeeds.add(player.getPlaybackParameters().speed);
}
};
ActionSchedule actionSchedule =
new ActionSchedule.Builder(TAG)
.pause()
.waitForPlaybackState(Player.STATE_READY)
- .setPlaybackSpeed(1.1f)
+ .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.1f))
.apply(getPlaybackSpeedAction)
- .setPlaybackSpeed(1.2f)
+ .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.2f))
.apply(getPlaybackSpeedAction)
- .setPlaybackSpeed(1.3f)
+ .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.3f))
.apply(getPlaybackSpeedAction)
.play()
.build();
@@ -3397,8 +3397,8 @@ protected void doActionImpl(
EventListener listener =
new EventListener() {
@Override
- public void onPlaybackSpeedChanged(float playbackSpeed) {
- reportedPlaybackSpeeds.add(playbackSpeed);
+ public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
+ reportedPlaybackSpeeds.add(playbackParameters.speed);
}
};
new ExoPlayerTestRunner.Builder(context)
@@ -3424,28 +3424,28 @@ public long getPositionUs() {
}
@Override
- public void setPlaybackSpeed(float playbackSpeed) {}
+ public void setPlaybackParameters(PlaybackParameters playbackParameters) {}
@Override
- public float getPlaybackSpeed() {
- return Player.DEFAULT_PLAYBACK_SPEED;
+ public PlaybackParameters getPlaybackParameters() {
+ return PlaybackParameters.DEFAULT;
}
};
ActionSchedule actionSchedule =
new ActionSchedule.Builder(TAG)
.pause()
.waitForPlaybackState(Player.STATE_READY)
- .setPlaybackSpeed(1.1f)
- .setPlaybackSpeed(1.2f)
- .setPlaybackSpeed(1.3f)
+ .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.1f))
+ .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.2f))
+ .setPlaybackParameters(new PlaybackParameters(/* speed= */ 1.3f))
.play()
.build();
- List