Add convenience methods to query current window

- Support querying whether the current window is dynamic
  and seekable. The new methods are similar to getDuration,
  which is also a convenience method for the current window.
- Improve demo app to restore positions in VOD items within
  playlists where the last item is live. Also restore the
  position within the window for live items unless the player
  failed with BehindLiveWindowException.

Issue: #2320

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144443898
This commit is contained in:
olly 2017-01-13 08:11:08 -08:00 committed by Oliver Woodman
parent ca7febe442
commit 270f68a95e
4 changed files with 107 additions and 47 deletions

View File

@ -45,6 +45,7 @@ import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
@ -100,7 +101,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
}
private Handler mainHandler;
private Timeline.Window window;
private EventLogger eventLogger;
private SimpleExoPlayerView simpleExoPlayerView;
private LinearLayout debugRootView;
@ -115,9 +115,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
private boolean playerNeedsSource;
private boolean shouldAutoPlay;
private boolean isTimelineStatic;
private int playerWindow;
private long playerPosition;
private int resumeWindow;
private long resumePosition;
// Activity lifecycle
@ -125,9 +124,9 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
shouldAutoPlay = true;
clearResumePosition();
mediaDataSourceFactory = buildDataSourceFactory(true);
mainHandler = new Handler();
window = new Timeline.Window();
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER);
}
@ -148,7 +147,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
@Override
public void onNewIntent(Intent intent) {
releasePlayer();
isTimelineStatic = false;
shouldAutoPlay = true;
clearResumePosition();
setIntent(intent);
}
@ -281,13 +281,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
player.setMetadataOutput(eventLogger);
simpleExoPlayerView.setPlayer(player);
if (isTimelineStatic) {
if (playerPosition == C.TIME_UNSET) {
player.seekToDefaultPosition(playerWindow);
} else {
player.seekTo(playerWindow, playerPosition);
}
}
player.setPlayWhenReady(shouldAutoPlay);
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
debugViewHelper.start();
@ -324,7 +317,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
}
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
: new ConcatenatingMediaSource(mediaSources);
player.prepare(mediaSource, !isTimelineStatic, !isTimelineStatic);
player.seekTo(resumeWindow, resumePosition);
player.prepare(mediaSource, false, false);
playerNeedsSource = false;
updateButtonVisibilities();
}
@ -367,12 +361,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
debugViewHelper.stop();
debugViewHelper = null;
shouldAutoPlay = player.getPlayWhenReady();
playerWindow = player.getCurrentWindowIndex();
playerPosition = C.TIME_UNSET;
Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty() && timeline.getWindow(playerWindow, window).isSeekable) {
playerPosition = player.getCurrentPosition();
}
updateResumePosition();
player.release();
player = null;
trackSelector = null;
@ -381,6 +370,17 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
}
}
private void updateResumePosition() {
resumeWindow = player.getCurrentWindowIndex();
resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getCurrentPosition())
: C.TIME_UNSET;
}
private void clearResumePosition() {
resumeWindow = 0;
resumePosition = C.TIME_UNSET;
}
/**
* Returns a new DataSource factory.
*
@ -427,8 +427,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
isTimelineStatic = !timeline.isEmpty()
&& !timeline.getWindow(timeline.getWindowCount() - 1, window).isDynamic;
// Do nothing.
}
@Override
@ -460,6 +459,11 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
showToast(errorString);
}
playerNeedsSource = true;
if (isBehindLiveWindow(e)) {
clearResumePosition();
} else {
updateResumePosition();
}
updateButtonVisibilities();
showControls();
}
@ -535,4 +539,18 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
private static boolean isBehindLiveWindow(ExoPlaybackException e) {
if (e.type != ExoPlaybackException.TYPE_SOURCE) {
return false;
}
Throwable cause = e.getSourceException();
while (cause != null) {
if (cause instanceof BehindLiveWindowException) {
return true;
}
cause = cause.getCause();
}
return false;
}
}

View File

@ -447,4 +447,20 @@ public interface ExoPlayer {
*/
int getBufferedPercentage();
/**
* Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is
* empty.
*
* @see Timeline.Window#isDynamic
*/
boolean isCurrentWindowDynamic();
/**
* Returns whether the current window is seekable, or {@code false} if the {@link Timeline} is
* empty.
*
* @see Timeline.Window#isSeekable
*/
boolean isCurrentWindowSeekable();
}

View File

@ -271,6 +271,22 @@ import java.util.concurrent.CopyOnWriteArraySet;
: (int) (duration == 0 ? 100 : (bufferedPosition * 100) / duration);
}
@Override
public boolean isCurrentWindowDynamic() {
if (timeline.isEmpty()) {
return false;
}
return timeline.getWindow(getCurrentWindowIndex(), window).isDynamic;
}
@Override
public boolean isCurrentWindowSeekable() {
if (timeline.isEmpty()) {
return false;
}
return timeline.getWindow(getCurrentWindowIndex(), window).isSeekable;
}
@Override
public int getRendererCount() {
return renderers.length;

View File

@ -545,6 +545,36 @@ public class SimpleExoPlayer implements ExoPlayer {
player.blockingSendMessages(messages);
}
@Override
public int getRendererCount() {
return player.getRendererCount();
}
@Override
public int getRendererType(int index) {
return player.getRendererType(index);
}
@Override
public TrackGroupArray getCurrentTrackGroups() {
return player.getCurrentTrackGroups();
}
@Override
public TrackSelectionArray getCurrentTrackSelections() {
return player.getCurrentTrackSelections();
}
@Override
public Timeline getCurrentTimeline() {
return player.getCurrentTimeline();
}
@Override
public Object getCurrentManifest() {
return player.getCurrentManifest();
}
@Override
public int getCurrentPeriodIndex() {
return player.getCurrentPeriodIndex();
@ -576,33 +606,13 @@ public class SimpleExoPlayer implements ExoPlayer {
}
@Override
public int getRendererCount() {
return player.getRendererCount();
public boolean isCurrentWindowDynamic() {
return player.isCurrentWindowDynamic();
}
@Override
public int getRendererType(int index) {
return player.getRendererType(index);
}
@Override
public TrackGroupArray getCurrentTrackGroups() {
return player.getCurrentTrackGroups();
}
@Override
public TrackSelectionArray getCurrentTrackSelections() {
return player.getCurrentTrackSelections();
}
@Override
public Timeline getCurrentTimeline() {
return player.getCurrentTimeline();
}
@Override
public Object getCurrentManifest() {
return player.getCurrentManifest();
public boolean isCurrentWindowSeekable() {
return player.isCurrentWindowSeekable();
}
// Renderer building.