mirror of
https://github.com/samsonjs/media.git
synced 2026-03-29 10:05:48 +00:00
Add fast forward and rewind methods to Player
PiperOrigin-RevId: 378104210
This commit is contained in:
parent
d0dc72fb6a
commit
e4263c4a67
10 changed files with 422 additions and 6 deletions
|
|
@ -9,6 +9,7 @@
|
|||
* Add `needsReconfiguration` API to the `MediaCodecAdapter` interface.
|
||||
* Update `MediaItem.Builder` javadoc to discourage calling setters that
|
||||
will be (currently) ignored if another setter is not also called.
|
||||
* Add `fastForward` and `rewind` methods to `Player`.
|
||||
* Extractors:
|
||||
* Add support for MPEG-H 3D Audio in MP4 extractors
|
||||
([#8860](https://github.com/google/ExoPlayer/pull/8860)).
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.ext.cast;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
|
|
@ -141,6 +142,8 @@ public final class CastPlayer extends BasePlayer {
|
|||
private int pendingSeekWindowIndex;
|
||||
private long pendingSeekPositionMs;
|
||||
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
|
||||
private long fastForwardIncrementMs;
|
||||
private long rewindIncrementMs;
|
||||
|
||||
/**
|
||||
* Creates a new cast player that uses a {@link DefaultMediaItemConverter}.
|
||||
|
|
@ -178,6 +181,8 @@ public final class CastPlayer extends BasePlayer {
|
|||
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
|
||||
pendingSeekWindowIndex = C.INDEX_UNSET;
|
||||
pendingSeekPositionMs = C.TIME_UNSET;
|
||||
fastForwardIncrementMs = DEFAULT_FAST_FORWARD_INCREMENT_MS;
|
||||
rewindIncrementMs = DEFAULT_REWIND_INCREMENT_MS;
|
||||
|
||||
SessionManager sessionManager = castContext.getSessionManager();
|
||||
sessionManager.addSessionManagerListener(statusListener, CastSession.class);
|
||||
|
|
@ -411,6 +416,28 @@ public final class CastPlayer extends BasePlayer {
|
|||
listeners.flushEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFastForwardIncrement(long fastForwardIncrementMs) {
|
||||
checkArgument(fastForwardIncrementMs > 0);
|
||||
this.fastForwardIncrementMs = fastForwardIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFastForwardIncrement() {
|
||||
return fastForwardIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRewindIncrement(long rewindIncrementMs) {
|
||||
checkArgument(rewindIncrementMs > 0);
|
||||
this.rewindIncrementMs = rewindIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRewindIncrement() {
|
||||
return rewindIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
|
||||
// Unsupported by the RemoteMediaClient API. Do nothing.
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ import static com.google.android.exoplayer2.Player.COMMAND_SET_SHUFFLE_MODE;
|
|||
import static com.google.android.exoplayer2.Player.COMMAND_SET_SPEED_AND_PITCH;
|
||||
import static com.google.android.exoplayer2.Player.COMMAND_SET_VIDEO_SURFACE;
|
||||
import static com.google.android.exoplayer2.Player.COMMAND_SET_VOLUME;
|
||||
import static com.google.android.exoplayer2.Player.DEFAULT_FAST_FORWARD_INCREMENT_MS;
|
||||
import static com.google.android.exoplayer2.Player.DEFAULT_REWIND_INCREMENT_MS;
|
||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_REMOVE;
|
||||
import static com.google.android.exoplayer2.Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
|
@ -1102,6 +1104,98 @@ public class CastPlayerTest {
|
|||
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
|
||||
public void fastForward_notifiesPositionDiscontinuity() {
|
||||
when(mockRemoteMediaClient.seek(anyLong())).thenReturn(mockPendingResult);
|
||||
int[] mediaQueueItemIds = new int[] {1};
|
||||
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
|
||||
int currentItemId = 1;
|
||||
int[] streamTypes = new int[] {MediaInfo.STREAM_TYPE_BUFFERED};
|
||||
long[] durationsMs = new long[] {2 * DEFAULT_FAST_FORWARD_INCREMENT_MS};
|
||||
long positionMs = 0;
|
||||
|
||||
castPlayer.addMediaItems(mediaItems);
|
||||
updateTimeLine(
|
||||
mediaItems, mediaQueueItemIds, currentItemId, streamTypes, durationsMs, positionMs);
|
||||
castPlayer.fastForward();
|
||||
|
||||
Player.PositionInfo oldPosition =
|
||||
new Player.PositionInfo(
|
||||
/* windowUid= */ 1,
|
||||
/* windowIndex= */ 0,
|
||||
/* periodUid= */ 1,
|
||||
/* periodIndex= */ 0,
|
||||
/* positionMs= */ 0,
|
||||
/* contentPositionMs= */ 0,
|
||||
/* adGroupIndex= */ C.INDEX_UNSET,
|
||||
/* adIndexInAdGroup= */ C.INDEX_UNSET);
|
||||
Player.PositionInfo newPosition =
|
||||
new Player.PositionInfo(
|
||||
/* windowUid= */ 1,
|
||||
/* windowIndex= */ 0,
|
||||
/* periodUid= */ 1,
|
||||
/* periodIndex= */ 0,
|
||||
/* positionMs= */ DEFAULT_FAST_FORWARD_INCREMENT_MS,
|
||||
/* contentPositionMs= */ DEFAULT_FAST_FORWARD_INCREMENT_MS,
|
||||
/* adGroupIndex= */ C.INDEX_UNSET,
|
||||
/* adIndexInAdGroup= */ C.INDEX_UNSET);
|
||||
InOrder inOrder = Mockito.inOrder(mockListener);
|
||||
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_SEEK));
|
||||
inOrder
|
||||
.verify(mockListener)
|
||||
.onPositionDiscontinuity(
|
||||
eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_SEEK));
|
||||
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
|
||||
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
|
||||
public void rewind_notifiesPositionDiscontinuity() {
|
||||
when(mockRemoteMediaClient.seek(anyLong())).thenReturn(mockPendingResult);
|
||||
int[] mediaQueueItemIds = new int[] {1};
|
||||
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
|
||||
int currentItemId = 1;
|
||||
int[] streamTypes = new int[] {MediaInfo.STREAM_TYPE_BUFFERED};
|
||||
long[] durationsMs = new long[] {3 * DEFAULT_REWIND_INCREMENT_MS};
|
||||
long positionMs = 2 * DEFAULT_REWIND_INCREMENT_MS;
|
||||
|
||||
castPlayer.addMediaItems(mediaItems);
|
||||
updateTimeLine(
|
||||
mediaItems, mediaQueueItemIds, currentItemId, streamTypes, durationsMs, positionMs);
|
||||
castPlayer.rewind();
|
||||
|
||||
Player.PositionInfo oldPosition =
|
||||
new Player.PositionInfo(
|
||||
/* windowUid= */ 1,
|
||||
/* windowIndex= */ 0,
|
||||
/* periodUid= */ 1,
|
||||
/* periodIndex= */ 0,
|
||||
/* positionMs= */ 2 * DEFAULT_REWIND_INCREMENT_MS,
|
||||
/* contentPositionMs= */ 2 * DEFAULT_REWIND_INCREMENT_MS,
|
||||
/* adGroupIndex= */ C.INDEX_UNSET,
|
||||
/* adIndexInAdGroup= */ C.INDEX_UNSET);
|
||||
Player.PositionInfo newPosition =
|
||||
new Player.PositionInfo(
|
||||
/* windowUid= */ 1,
|
||||
/* windowIndex= */ 0,
|
||||
/* periodUid= */ 1,
|
||||
/* periodIndex= */ 0,
|
||||
/* positionMs= */ DEFAULT_REWIND_INCREMENT_MS,
|
||||
/* contentPositionMs= */ DEFAULT_REWIND_INCREMENT_MS,
|
||||
/* adGroupIndex= */ C.INDEX_UNSET,
|
||||
/* adIndexInAdGroup= */ C.INDEX_UNSET);
|
||||
InOrder inOrder = Mockito.inOrder(mockListener);
|
||||
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_SEEK));
|
||||
inOrder
|
||||
.verify(mockListener)
|
||||
.onPositionDiscontinuity(
|
||||
eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_SEEK));
|
||||
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
|
||||
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCommandAvailable_isTrueForAvailableCommands() {
|
||||
int[] mediaQueueItemIds = new int[] {1, 2};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.Collections;
|
||||
|
|
@ -118,6 +121,16 @@ public abstract class BasePlayer implements Player {
|
|||
seekTo(getCurrentWindowIndex(), positionMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void fastForward() {
|
||||
seekToOffset(getFastForwardIncrement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void rewind() {
|
||||
seekToOffset(-getRewindIncrement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasPrevious() {
|
||||
return getPreviousWindowIndex() != C.INDEX_UNSET;
|
||||
|
|
@ -246,12 +259,6 @@ public abstract class BasePlayer implements Player {
|
|||
: timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs();
|
||||
}
|
||||
|
||||
@RepeatMode
|
||||
private int getRepeatModeForNavigation() {
|
||||
@RepeatMode int repeatMode = getRepeatMode();
|
||||
return repeatMode == REPEAT_MODE_ONE ? REPEAT_MODE_OFF : repeatMode;
|
||||
}
|
||||
|
||||
protected Commands getAvailableCommands(Commands permanentAvailableCommands) {
|
||||
return new Commands.Builder()
|
||||
.addAll(permanentAvailableCommands)
|
||||
|
|
@ -262,4 +269,20 @@ public abstract class BasePlayer implements Player {
|
|||
.addIf(COMMAND_SEEK_TO_MEDIA_ITEM, !isPlayingAd())
|
||||
.build();
|
||||
}
|
||||
|
||||
@RepeatMode
|
||||
private int getRepeatModeForNavigation() {
|
||||
@RepeatMode int repeatMode = getRepeatMode();
|
||||
return repeatMode == REPEAT_MODE_ONE ? REPEAT_MODE_OFF : repeatMode;
|
||||
}
|
||||
|
||||
private void seekToOffset(long offsetMs) {
|
||||
long positionMs = getCurrentPosition() + offsetMs;
|
||||
long durationMs = getDuration();
|
||||
if (durationMs != C.TIME_UNSET) {
|
||||
positionMs = min(positionMs, durationMs);
|
||||
}
|
||||
positionMs = max(positionMs, 0);
|
||||
seekTo(positionMs);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,6 +247,36 @@ public class ForwardingPlayer implements Player {
|
|||
player.seekTo(windowIndex, positionMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFastForwardIncrement(long fastForwardIncrementMs) {
|
||||
player.setFastForwardIncrement(fastForwardIncrementMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFastForwardIncrement() {
|
||||
return player.getFastForwardIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fastForward() {
|
||||
player.fastForward();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRewindIncrement(long rewindIncrementMs) {
|
||||
player.setRewindIncrement(rewindIncrementMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRewindIncrement() {
|
||||
return player.getRewindIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind() {
|
||||
player.rewind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return player.hasPrevious();
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import android.view.SurfaceHolder;
|
|||
import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.audio.AudioListener;
|
||||
|
|
@ -842,6 +843,11 @@ public interface Player {
|
|||
default void onMetadata(Metadata metadata) {}
|
||||
}
|
||||
|
||||
/** The default {@link #fastForward()} increment, in milliseconds. */
|
||||
long DEFAULT_FAST_FORWARD_INCREMENT_MS = 15_000;
|
||||
/** The default {@link #rewind()} increment, in milliseconds. */
|
||||
long DEFAULT_REWIND_INCREMENT_MS = 5000;
|
||||
|
||||
/**
|
||||
* Playback state. One of {@link #STATE_IDLE}, {@link #STATE_BUFFERING}, {@link #STATE_READY} or
|
||||
* {@link #STATE_ENDED}.
|
||||
|
|
@ -1536,6 +1542,46 @@ public interface Player {
|
|||
*/
|
||||
void seekTo(int windowIndex, long positionMs);
|
||||
|
||||
/**
|
||||
* Sets the {@link #fastForward()} increment.
|
||||
*
|
||||
* @param fastForwardIncrementMs The fast forward increment, in milliseconds.
|
||||
* @throws IllegalArgumentException If {@code fastForwardIncrementMs} is non-positive.
|
||||
*/
|
||||
void setFastForwardIncrement(@IntRange(from = 1) long fastForwardIncrementMs);
|
||||
|
||||
/**
|
||||
* Returns the {@link #fastForward()} increment.
|
||||
*
|
||||
* <p>The default value is {@link #DEFAULT_FAST_FORWARD_INCREMENT_MS}.
|
||||
*
|
||||
* @return The fast forward increment, in milliseconds.
|
||||
*/
|
||||
long getFastForwardIncrement();
|
||||
|
||||
/** Seeks forward in the current window by {@link #getFastForwardIncrement()} milliseconds. */
|
||||
void fastForward();
|
||||
|
||||
/**
|
||||
* Sets the {@link #rewind()} increment.
|
||||
*
|
||||
* @param rewindIncrementMs The rewind increment, in milliseconds.
|
||||
* @throws IllegalArgumentException If {@code rewindIncrementMs} is non-positive.
|
||||
*/
|
||||
void setRewindIncrement(@IntRange(from = 1) long rewindIncrementMs);
|
||||
|
||||
/**
|
||||
* Returns the {@link #rewind()} increment.
|
||||
*
|
||||
* <p>The default value is {@link #DEFAULT_REWIND_INCREMENT_MS}.
|
||||
*
|
||||
* @return The rewind increment, in milliseconds.
|
||||
*/
|
||||
long getRewindIncrement();
|
||||
|
||||
/** Seeks back in the current window by {@link #getRewindIncrement()} milliseconds. */
|
||||
void rewind();
|
||||
|
||||
/**
|
||||
* Returns whether a previous window exists, which may depend on the current repeat mode and
|
||||
* whether shuffle mode is enabled.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
|
|
@ -102,6 +103,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
private boolean pauseAtEndOfMediaItems;
|
||||
private Commands availableCommands;
|
||||
private MediaMetadata mediaMetadata;
|
||||
private long fastForwardIncrementMs;
|
||||
private long rewindIncrementMs;
|
||||
|
||||
// Playback information when there is no pending seek/set source operation.
|
||||
private PlaybackInfo playbackInfo;
|
||||
|
|
@ -210,6 +213,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
.add(COMMAND_SEEK_TO_MEDIA_ITEM)
|
||||
.build();
|
||||
mediaMetadata = MediaMetadata.EMPTY;
|
||||
fastForwardIncrementMs = DEFAULT_FAST_FORWARD_INCREMENT_MS;
|
||||
rewindIncrementMs = DEFAULT_REWIND_INCREMENT_MS;
|
||||
maskingWindowIndex = C.INDEX_UNSET;
|
||||
playbackInfoUpdateHandler = clock.createHandler(applicationLooper, /* callback= */ null);
|
||||
playbackInfoUpdateListener =
|
||||
|
|
@ -710,6 +715,28 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
oldMaskingWindowIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFastForwardIncrement(long fastForwardIncrementMs) {
|
||||
checkArgument(fastForwardIncrementMs > 0);
|
||||
this.fastForwardIncrementMs = fastForwardIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFastForwardIncrement() {
|
||||
return fastForwardIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRewindIncrement(long rewindIncrementMs) {
|
||||
checkArgument(rewindIncrementMs > 0);
|
||||
this.rewindIncrementMs = rewindIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRewindIncrement() {
|
||||
return rewindIncrementMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
|
||||
if (playbackParameters == null) {
|
||||
|
|
|
|||
|
|
@ -1552,6 +1552,30 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
player.seekTo(windowIndex, positionMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFastForwardIncrement(long fastForwardIncrementMs) {
|
||||
verifyApplicationThread();
|
||||
player.setFastForwardIncrement(fastForwardIncrementMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFastForwardIncrement() {
|
||||
verifyApplicationThread();
|
||||
return player.getFastForwardIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRewindIncrement(long rewindIncrementMs) {
|
||||
verifyApplicationThread();
|
||||
player.setRewindIncrement(rewindIncrementMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRewindIncrement() {
|
||||
verifyApplicationThread();
|
||||
return player.getRewindIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
|
||||
verifyApplicationThread();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ import static com.google.android.exoplayer2.Player.COMMAND_SET_SHUFFLE_MODE;
|
|||
import static com.google.android.exoplayer2.Player.COMMAND_SET_SPEED_AND_PITCH;
|
||||
import static com.google.android.exoplayer2.Player.COMMAND_SET_VIDEO_SURFACE;
|
||||
import static com.google.android.exoplayer2.Player.COMMAND_SET_VOLUME;
|
||||
import static com.google.android.exoplayer2.Player.DEFAULT_FAST_FORWARD_INCREMENT_MS;
|
||||
import static com.google.android.exoplayer2.Player.DEFAULT_REWIND_INCREMENT_MS;
|
||||
import static com.google.android.exoplayer2.robolectric.RobolectricUtil.runMainLooperUntil;
|
||||
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.playUntilPosition;
|
||||
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.playUntilStartOfWindow;
|
||||
|
|
@ -10334,6 +10336,128 @@ public final class ExoPlayerTest {
|
|||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fastForward_callsOnPositionDiscontinuity() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
Player.Listener listener = mock(Player.Listener.class);
|
||||
player.addListener(listener);
|
||||
Timeline fakeTimeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* durationUs= */ C.msToUs(2 * DEFAULT_FAST_FORWARD_INCREMENT_MS)));
|
||||
player.setMediaSource(new FakeMediaSource(fakeTimeline));
|
||||
|
||||
player.prepare();
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY);
|
||||
player.fastForward();
|
||||
|
||||
ArgumentCaptor<Player.PositionInfo> oldPosition =
|
||||
ArgumentCaptor.forClass(Player.PositionInfo.class);
|
||||
ArgumentCaptor<Player.PositionInfo> newPosition =
|
||||
ArgumentCaptor.forClass(Player.PositionInfo.class);
|
||||
verify(listener, never())
|
||||
.onPositionDiscontinuity(any(), any(), not(eq(Player.DISCONTINUITY_REASON_SEEK)));
|
||||
verify(listener)
|
||||
.onPositionDiscontinuity(
|
||||
oldPosition.capture(), newPosition.capture(), eq(Player.DISCONTINUITY_REASON_SEEK));
|
||||
List<Player.PositionInfo> oldPositions = oldPosition.getAllValues();
|
||||
List<Player.PositionInfo> newPositions = newPosition.getAllValues();
|
||||
assertThat(oldPositions.get(0).windowIndex).isEqualTo(0);
|
||||
assertThat(oldPositions.get(0).positionMs).isEqualTo(0);
|
||||
assertThat(oldPositions.get(0).contentPositionMs).isEqualTo(0);
|
||||
assertThat(newPositions.get(0).windowIndex).isEqualTo(0);
|
||||
assertThat(newPositions.get(0).positionMs).isEqualTo(DEFAULT_FAST_FORWARD_INCREMENT_MS);
|
||||
assertThat(newPositions.get(0).contentPositionMs).isEqualTo(DEFAULT_FAST_FORWARD_INCREMENT_MS);
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fastForward_pastDuration_seeksToDuration() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
Timeline fakeTimeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* durationUs= */ C.msToUs(DEFAULT_FAST_FORWARD_INCREMENT_MS / 2)));
|
||||
player.setMediaSource(new FakeMediaSource(fakeTimeline));
|
||||
|
||||
player.prepare();
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY);
|
||||
player.fastForward();
|
||||
|
||||
assertThat(player.getCurrentPosition()).isEqualTo(DEFAULT_FAST_FORWARD_INCREMENT_MS / 2);
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rewind_callsOnPositionDiscontinuity() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
Player.Listener listener = mock(Player.Listener.class);
|
||||
player.addListener(listener);
|
||||
Timeline fakeTimeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* durationUs= */ C.msToUs(3 * DEFAULT_REWIND_INCREMENT_MS)));
|
||||
player.setMediaSource(new FakeMediaSource(fakeTimeline));
|
||||
|
||||
player.prepare();
|
||||
TestPlayerRunHelper.playUntilPosition(
|
||||
player, /* windowIndex= */ 0, /* positionMs= */ 2 * DEFAULT_REWIND_INCREMENT_MS);
|
||||
player.rewind();
|
||||
|
||||
ArgumentCaptor<Player.PositionInfo> oldPosition =
|
||||
ArgumentCaptor.forClass(Player.PositionInfo.class);
|
||||
ArgumentCaptor<Player.PositionInfo> newPosition =
|
||||
ArgumentCaptor.forClass(Player.PositionInfo.class);
|
||||
verify(listener, never())
|
||||
.onPositionDiscontinuity(any(), any(), not(eq(Player.DISCONTINUITY_REASON_SEEK)));
|
||||
verify(listener)
|
||||
.onPositionDiscontinuity(
|
||||
oldPosition.capture(), newPosition.capture(), eq(Player.DISCONTINUITY_REASON_SEEK));
|
||||
List<Player.PositionInfo> oldPositions = oldPosition.getAllValues();
|
||||
List<Player.PositionInfo> newPositions = newPosition.getAllValues();
|
||||
assertThat(oldPositions.get(0).windowIndex).isEqualTo(0);
|
||||
assertThat(oldPositions.get(0).positionMs)
|
||||
.isIn(Range.closed(2 * DEFAULT_REWIND_INCREMENT_MS - 20, 2 * DEFAULT_REWIND_INCREMENT_MS));
|
||||
assertThat(oldPositions.get(0).contentPositionMs)
|
||||
.isIn(Range.closed(2 * DEFAULT_REWIND_INCREMENT_MS - 20, 2 * DEFAULT_REWIND_INCREMENT_MS));
|
||||
assertThat(newPositions.get(0).windowIndex).isEqualTo(0);
|
||||
assertThat(newPositions.get(0).positionMs)
|
||||
.isIn(Range.closed(DEFAULT_REWIND_INCREMENT_MS - 20, DEFAULT_REWIND_INCREMENT_MS));
|
||||
assertThat(newPositions.get(0).contentPositionMs)
|
||||
.isIn(Range.closed(DEFAULT_REWIND_INCREMENT_MS - 20, DEFAULT_REWIND_INCREMENT_MS));
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rewind_pastZero_seeksToZero() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
Timeline fakeTimeline =
|
||||
new FakeTimeline(
|
||||
new TimelineWindowDefinition(
|
||||
/* isSeekable= */ true,
|
||||
/* isDynamic= */ true,
|
||||
/* durationUs= */ C.msToUs(DEFAULT_REWIND_INCREMENT_MS)));
|
||||
player.setMediaSource(new FakeMediaSource(fakeTimeline));
|
||||
|
||||
player.prepare();
|
||||
TestPlayerRunHelper.playUntilPosition(
|
||||
player, /* windowIndex= */ 0, /* positionMs= */ DEFAULT_REWIND_INCREMENT_MS / 2);
|
||||
player.rewind();
|
||||
|
||||
assertThat(player.getCurrentPosition()).isEqualTo(0);
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stop_doesNotCallOnPositionDiscontinuity() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
|
|
|
|||
|
|
@ -299,6 +299,26 @@ public class StubExoPlayer extends BasePlayer implements ExoPlayer {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFastForwardIncrement(long fastForwardIncrementMs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFastForwardIncrement() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRewindIncrement(long rewindIncrementMs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRewindIncrement() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
|||
Loading…
Reference in a new issue