Expose source indices via ExoPlayer (playlists #5).

ExoPlayer.EventListener.onPositionDiscontinuity is notified during seeking and
transitioning from one source to the next.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=125578976
This commit is contained in:
andrewlewis 2016-06-22 10:21:07 -07:00 committed by Oliver Woodman
parent f9fa54cd5d
commit 2073f3fce3
11 changed files with 224 additions and 99 deletions

View File

@ -72,6 +72,11 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb
+ getStateString(state) + "]");
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
Log.d(TAG, "discontinuity [" + sourceIndex + ", " + positionMs + "]");
}
@Override
public void onPlayWhenReadyCommitted() {
// Do nothing.

View File

@ -391,6 +391,14 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
// Do nothing.
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
if (mediaController.isShowing()) {
// The MediaController is visible, so force it to show the updated position immediately.
mediaController.show();
}
}
@Override
public void onPlayerError(ExoPlaybackException e) {
String errorString = null;

View File

@ -92,6 +92,11 @@ public class FlacPlaybackTest extends InstrumentationTestCase {
// Do nothing.
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
// Do nothing.
}
@Override
public void onPlayerError(ExoPlaybackException error) {
playbackException = error;

View File

@ -92,6 +92,11 @@ public class OpusPlaybackTest extends InstrumentationTestCase {
// Do nothing.
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
// Do nothing.
}
@Override
public void onPlayerError(ExoPlaybackException error) {
playbackException = error;

View File

@ -111,6 +111,11 @@ public class VpxPlaybackTest extends InstrumentationTestCase {
// Do nothing.
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
// Do nothing.
}
@Override
public void onPlayerError(ExoPlaybackException error) {
playbackException = error;

View File

@ -118,6 +118,16 @@ public interface ExoPlayer {
*/
void onPlayWhenReadyCommitted();
// TODO[playlists]: Should source-initiated resets also cause this to be invoked?
/**
* Invoked when the player's position changes due to a discontinuity (seeking or playback
* transitioning to the next source).
*
* @param sourceIndex The index of the source being played.
* @param positionMs The playback position in that source, in milliseconds.
*/
void onPositionDiscontinuity(int sourceIndex, long positionMs);
/**
* Invoked when an error occurs. The playback state will transition to
* {@link ExoPlayer#STATE_IDLE} immediately after this method is invoked. The player instance
@ -227,8 +237,9 @@ public interface ExoPlayer {
void setSource(SampleSource sampleSource);
/**
* Sets the player's source provider. The player will transition to {@link #STATE_BUFFERING} until
* it is ready to play the first source.
* Sets the player's source provider. The player's position will be reset to the start of the
* first source and the player will transition to {@link #STATE_BUFFERING} until it is ready to
* play it.
*
* @param sourceProvider The provider of {@link SampleSource}s to play.
*/
@ -259,12 +270,20 @@ public interface ExoPlayer {
boolean isPlayWhenReadyCommitted();
/**
* Seeks to a position specified in milliseconds.
* Seeks to a position specified in milliseconds in the current source.
*
* @param positionMs The seek position.
*/
void seekTo(long positionMs);
/**
* Seeks to a position specified in milliseconds in the specified source.
*
* @param sourceIndex The index of the source to seek to.
* @param positionMs The seek position relative to the start of the specified source.
*/
void seekTo(int sourceIndex, long positionMs);
/**
* Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention
* is to pause playback.
@ -312,12 +331,19 @@ public interface ExoPlayer {
long getDuration();
/**
* Gets the current playback position in milliseconds.
* Gets the playback position in the current source, in milliseconds.
*
* @return The current playback position in milliseconds.
* @return The playback position in the current source, in milliseconds.
*/
long getCurrentPosition();
/**
* Gets the index of the current source.
*
* @return The index of the current source.
*/
int getCurrentSourceIndex();
/**
* Gets an estimate of the absolute position in milliseconds up to which data is buffered.
*

View File

@ -39,6 +39,15 @@ import java.util.concurrent.CopyOnWriteArraySet;
private boolean playWhenReady;
private int playbackState;
private int pendingPlayWhenReadyAcks;
private int pendingSetSourceProviderAndSeekAcks;
// Playback information when there is no pending seek/set source operation.
private ExoPlayerImplInternal.PlaybackInfo playbackInfo;
// Playback information when there is a pending seek/set source operation.
private int sourceIndex;
private long position;
private long duration;
/**
* Constructs an instance. Must be invoked from a thread that has an associated {@link Looper}.
@ -68,6 +77,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
};
internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, minBufferMs, minRebufferMs,
playWhenReady, eventHandler);
playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(0);
}
@Override
@ -87,12 +97,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public void setSource(final SampleSource sampleSource) {
internalPlayer.setSourceProvider(new SingleSampleSourceProvider(sampleSource));
setSourceProvider(new SingleSampleSourceProvider(sampleSource));
}
@Override
public void setSourceProvider(SampleSourceProvider sourceProvider) {
duration = ExoPlayer.UNKNOWN_TIME;
position = 0;
sourceIndex = 0;
pendingSetSourceProviderAndSeekAcks++;
internalPlayer.setSourceProvider(sourceProvider);
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity(sourceIndex, position);
}
}
@Override
@ -119,7 +137,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public void seekTo(long positionMs) {
internalPlayer.seekTo(positionMs);
seekTo(getCurrentSourceIndex(), positionMs);
}
@Override
public void seekTo(int sourceIndex, long positionMs) {
duration = sourceIndex == getCurrentSourceIndex() ? getDuration() : ExoPlayer.UNKNOWN_TIME;
position = positionMs;
this.sourceIndex = sourceIndex;
pendingSetSourceProviderAndSeekAcks++;
internalPlayer.seekTo(sourceIndex, position);
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity(sourceIndex, position);
}
}
@Override
@ -145,17 +176,33 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public long getDuration() {
return internalPlayer.getDuration();
if (pendingSetSourceProviderAndSeekAcks == 0) {
long durationUs = playbackInfo.durationUs;
return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : durationUs / 1000;
} else {
return duration;
}
}
@Override
public long getCurrentPosition() {
return internalPlayer.getCurrentPosition();
return pendingSetSourceProviderAndSeekAcks == 0 ? playbackInfo.positionUs / 1000 : position;
}
@Override
public int getCurrentSourceIndex() {
return pendingSetSourceProviderAndSeekAcks == 0 ? playbackInfo.sourceIndex : sourceIndex;
}
@Override
public long getBufferedPosition() {
return internalPlayer.getBufferedPosition();
if (pendingSetSourceProviderAndSeekAcks == 0) {
long bufferedPositionUs = playbackInfo.bufferedPositionUs;
return bufferedPositionUs == C.UNSET_TIME_US || bufferedPositionUs == C.END_OF_SOURCE_US
? ExoPlayer.UNKNOWN_TIME : bufferedPositionUs / 1000;
} else {
return position;
}
}
@Override
@ -185,6 +232,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
break;
}
case ExoPlayerImplInternal.MSG_SET_SOURCE_PROVIDER_ACK: // Fall through.
case ExoPlayerImplInternal.MSG_SEEK_ACK: {
pendingSetSourceProviderAndSeekAcks--;
break;
}
case ExoPlayerImplInternal.MSG_SOURCE_CHANGED: {
playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj;
if (pendingSetSourceProviderAndSeekAcks == 0) {
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity(playbackInfo.sourceIndex, 0);
}
}
break;
}
case ExoPlayerImplInternal.MSG_ERROR: {
ExoPlaybackException exception = (ExoPlaybackException) msg.obj;
for (EventListener listener : listeners) {

View File

@ -31,7 +31,6 @@ import android.util.Pair;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Implements the internal behavior of {@link ExoPlayerImpl}.
@ -40,12 +39,35 @@ import java.util.concurrent.atomic.AtomicInteger;
// always propagated properly.
/* package */ final class ExoPlayerImplInternal implements Handler.Callback, InvalidationListener {
/**
* Playback position information which is read on the application's thread by
* {@link ExoPlayerImpl} and read/written internally on the player's thread.
*/
public static final class PlaybackInfo {
public final int sourceIndex;
public volatile long positionUs;
public volatile long bufferedPositionUs;
public volatile long durationUs;
public PlaybackInfo(int sourceIndex) {
this.sourceIndex = sourceIndex;
bufferedPositionUs = C.UNSET_TIME_US;
durationUs = C.UNSET_TIME_US;
}
}
private static final String TAG = "ExoPlayerImplInternal";
// External messages
public static final int MSG_STATE_CHANGED = 1;
public static final int MSG_SET_PLAY_WHEN_READY_ACK = 2;
public static final int MSG_ERROR = 3;
public static final int MSG_SET_SOURCE_PROVIDER_ACK = 3;
public static final int MSG_SEEK_ACK = 4;
public static final int MSG_SOURCE_CHANGED = 5;
public static final int MSG_ERROR = 6;
// Internal messages
private static final int MSG_SET_SOURCE_PROVIDER = 0;
@ -69,12 +91,13 @@ import java.util.concurrent.atomic.AtomicInteger;
private final Handler handler;
private final HandlerThread internalPlaybackThread;
private final Handler eventHandler;
private final AtomicInteger pendingSeekCount;
private final Timeline timeline;
private PlaybackInfo playbackInfo;
private TrackRenderer rendererMediaClockSource;
private MediaClock rendererMediaClock;
private SampleSourceProvider sampleSourceProvider;
// TODO[playlists]: Use timeline.playingSource.sampleSource instead.
private SampleSource sampleSource;
private TrackRenderer[] enabledRenderers;
private boolean released;
@ -83,17 +106,10 @@ import java.util.concurrent.atomic.AtomicInteger;
private int state;
private int customMessagesSent;
private int customMessagesProcessed;
private long lastSeekPositionMs;
private int lastSeekSourceIndex;
private long elapsedRealtimeUs;
private long sourceOffsetUs;
private long internalPositionUs;
private int sourceIndex;
private volatile long durationUs;
private volatile long positionUs;
private volatile long bufferedPositionUs;
public ExoPlayerImplInternal(TrackRenderer[] renderers, TrackSelector trackSelector,
int minBufferMs, int minRebufferMs, boolean playWhenReady, Handler eventHandler) {
@ -104,17 +120,15 @@ import java.util.concurrent.atomic.AtomicInteger;
this.playWhenReady = playWhenReady;
this.eventHandler = eventHandler;
this.state = ExoPlayer.STATE_IDLE;
this.durationUs = C.UNSET_TIME_US;
this.bufferedPositionUs = C.UNSET_TIME_US;
for (int i = 0; i < renderers.length; i++) {
renderers[i].setIndex(i);
}
standaloneMediaClock = new StandaloneMediaClock();
pendingSeekCount = new AtomicInteger();
enabledRenderers = new TrackRenderer[0];
timeline = new Timeline();
playbackInfo = new PlaybackInfo(0);
trackSelector.init(this);
@ -126,21 +140,6 @@ import java.util.concurrent.atomic.AtomicInteger;
handler = new Handler(internalPlaybackThread.getLooper(), this);
}
public long getCurrentPosition() {
return pendingSeekCount.get() > 0 ? lastSeekPositionMs : (positionUs / 1000);
}
public long getBufferedPosition() {
long bufferedPositionUs = this.bufferedPositionUs;
return bufferedPositionUs == C.UNSET_TIME_US || bufferedPositionUs == C.END_OF_SOURCE_US
? ExoPlayer.UNKNOWN_TIME : bufferedPositionUs / 1000;
}
public long getDuration() {
long durationUs = this.durationUs;
return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : durationUs / 1000;
}
public void setSourceProvider(SampleSourceProvider sourceProvider) {
handler.obtainMessage(MSG_SET_SOURCE_PROVIDER, sourceProvider).sendToTarget();
}
@ -149,21 +148,8 @@ import java.util.concurrent.atomic.AtomicInteger;
handler.obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, 0).sendToTarget();
}
public void seekTo(long positionMs) {
// TODO[playlists]: Move to ExoPlayerImpl.
int sourceIndex;
synchronized (timeline) {
sourceIndex = this.sourceIndex;
}
seekTo(sourceIndex, positionMs);
}
public void seekTo(int sourceIndex, long positionMs) {
// TODO[playlists]: Expose the current source index and seeking to sources in ExoPlayer.
lastSeekSourceIndex = sourceIndex;
lastSeekPositionMs = positionMs;
pendingSeekCount.incrementAndGet();
handler.obtainMessage(MSG_SEEK_TO, lastSeekSourceIndex, -1, positionMs).sendToTarget();
handler.obtainMessage(MSG_SEEK_TO, sourceIndex, -1, positionMs).sendToTarget();
}
public void stop() {
@ -294,17 +280,22 @@ import java.util.concurrent.atomic.AtomicInteger;
// TODO[playlists]: Take into account the buffered position in the timeline.
long minBufferDurationUs = rebuffering ? minRebufferUs : minBufferUs;
return minBufferDurationUs <= 0
|| bufferedPositionUs == C.UNSET_TIME_US
|| bufferedPositionUs == C.END_OF_SOURCE_US
|| bufferedPositionUs >= positionUs + minBufferDurationUs
|| (durationUs != C.UNSET_TIME_US && bufferedPositionUs >= durationUs);
|| playbackInfo.bufferedPositionUs == C.UNSET_TIME_US
|| playbackInfo.bufferedPositionUs == C.END_OF_SOURCE_US
|| playbackInfo.bufferedPositionUs >= playbackInfo.positionUs + minBufferDurationUs
|| (playbackInfo.durationUs != C.UNSET_TIME_US
&& playbackInfo.bufferedPositionUs >= playbackInfo.durationUs);
}
private void setSourceProviderInternal(SampleSourceProvider sourceProvider) {
resetInternal();
sampleSourceProvider = sourceProvider;
setState(ExoPlayer.STATE_BUFFERING);
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
try {
resetInternal();
sampleSourceProvider = sourceProvider;
setState(ExoPlayer.STATE_BUFFERING);
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
} finally {
eventHandler.sendEmptyMessage(MSG_SET_SOURCE_PROVIDER_ACK);
}
}
private void setPlayWhenReadyInternal(boolean playWhenReady) throws ExoPlaybackException {
@ -323,7 +314,7 @@ import java.util.concurrent.atomic.AtomicInteger;
}
}
} finally {
eventHandler.obtainMessage(MSG_SET_PLAY_WHEN_READY_ACK).sendToTarget();
eventHandler.sendEmptyMessage(MSG_SET_PLAY_WHEN_READY_ACK);
}
}
@ -349,14 +340,15 @@ import java.util.concurrent.atomic.AtomicInteger;
} else {
internalPositionUs = standaloneMediaClock.getPositionUs();
}
positionUs = internalPositionUs - sourceOffsetUs;
playbackInfo.positionUs = internalPositionUs - sourceOffsetUs;
elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
}
private void updateBufferedPositionUs() {
long sourceBufferedPositionUs = enabledRenderers.length > 0
? sampleSource.getBufferedPositionUs() : C.END_OF_SOURCE_US;
bufferedPositionUs = sourceBufferedPositionUs == C.END_OF_SOURCE_US
? timeline.playingSource.sampleSource.getBufferedPositionUs() : C.END_OF_SOURCE_US;
long durationUs = playbackInfo.durationUs;
playbackInfo.bufferedPositionUs = sourceBufferedPositionUs == C.END_OF_SOURCE_US
&& durationUs != C.UNSET_TIME_US ? durationUs : sourceBufferedPositionUs;
}
@ -406,7 +398,8 @@ import java.util.concurrent.atomic.AtomicInteger;
}
boolean timelineIsReady = timeline.isReady();
if (allRenderersEnded && (durationUs == C.UNSET_TIME_US || durationUs <= positionUs)) {
if (allRenderersEnded && (playbackInfo.durationUs == C.UNSET_TIME_US
|| playbackInfo.durationUs <= playbackInfo.positionUs)) {
setState(ExoPlayer.STATE_ENDED);
stopRenderers();
} else if (state == ExoPlayer.STATE_BUFFERING && allRenderersReadyOrEnded
@ -444,11 +437,17 @@ import java.util.concurrent.atomic.AtomicInteger;
private void seekToInternal(int sourceIndex, long seekPositionMs) throws ExoPlaybackException {
try {
if (seekPositionMs == (positionUs / 1000)) {
if (sourceIndex == playbackInfo.sourceIndex
&& seekPositionMs == (playbackInfo.positionUs / 1000)) {
// Seek is to the current position. Do nothing.
return;
}
if (sourceIndex != playbackInfo.sourceIndex) {
playbackInfo = new PlaybackInfo(sourceIndex);
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
}
long seekPositionUs = seekPositionMs * 1000;
rebuffering = false;
standaloneMediaClock.stop();
@ -470,7 +469,7 @@ import java.util.concurrent.atomic.AtomicInteger;
setNewSourcePositionInternal(seekPositionUs);
resumeInternal();
} finally {
pendingSeekCount.decrementAndGet();
eventHandler.sendEmptyMessage(MSG_SEEK_ACK);
}
}
@ -483,7 +482,8 @@ import java.util.concurrent.atomic.AtomicInteger;
}
updateBufferedPositionUs();
if (allRenderersEnded && (durationUs == C.UNSET_TIME_US || durationUs <= positionUs)) {
if (allRenderersEnded && (playbackInfo.durationUs == C.UNSET_TIME_US
|| playbackInfo.durationUs <= playbackInfo.positionUs)) {
setState(ExoPlayer.STATE_ENDED);
} else {
setState(allRenderersReadyOrEnded && haveSufficientBuffer() && timeline.isReady()
@ -507,7 +507,7 @@ import java.util.concurrent.atomic.AtomicInteger;
}
private void setNewSourcePositionInternal(long sourcePositionUs) throws ExoPlaybackException {
positionUs = sourcePositionUs;
playbackInfo.positionUs = sourcePositionUs;
internalPositionUs = sourceOffsetUs + sourcePositionUs;
standaloneMediaClock.setPositionUs(internalPositionUs);
for (TrackRenderer renderer : enabledRenderers) {
@ -636,7 +636,7 @@ import java.util.concurrent.atomic.AtomicInteger;
if (!bufferingSource.prepared) {
// Continue preparation.
// TODO[playlists]: Add support for setting the start position to play in a source.
long startPositionUs = playingSource == null ? positionUs : 0;
long startPositionUs = playingSource == null ? playbackInfo.positionUs : 0;
if (bufferingSource.prepare(startPositionUs)) {
Pair<TrackSelectionArray, Object> result = trackSelector.selectTracks(renderers,
bufferingSource.sampleSource.getTrackGroups());
@ -710,7 +710,9 @@ import java.util.concurrent.atomic.AtomicInteger;
if (readingSource != playingSource && playingSourceEndPositionUs != C.UNSET_TIME_US
&& internalPositionUs >= playingSourceEndPositionUs) {
playingSource.release();
playbackInfo = new PlaybackInfo(readingSource.index);
setPlayingSource(readingSource, playingSourceEndPositionUs);
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
}
return playingSource.sampleSource;
}
@ -727,23 +729,24 @@ import java.util.concurrent.atomic.AtomicInteger;
}
source = source.nextSource;
}
if (newPlayingSource != null) {
nextSourceIndex = sourceIndex + 1;
newPlayingSource.nextSource = null;
setPlayingSource(newPlayingSource, sourceOffsetUs);
bufferingSource = playingSource;
bufferingSourceOffsetUs = sourceOffsetUs;
nextSourceIndex = sourceIndex + 1;
} else {
// TODO[REFACTOR]: Presumably we need to disable the renderers somewhere in here?
playingSource = null;
readingSource = null;
bufferingSource = null;
bufferingSourceOffsetUs = 0;
durationUs = C.UNSET_TIME_US;
sampleSource = null;
// Set the next source index so that the required source is created in updateSources.
nextSourceIndex = sourceIndex;
}
return sampleSource;
}
@ -794,7 +797,7 @@ import java.util.concurrent.atomic.AtomicInteger;
int enabledRendererCount = disableRenderers(false, newTrackSelections);
TrackStream[] newStreams = playingSource.updateTrackStreams(oldStreams, newTrackSelections,
newSelections, positionUs);
newSelections, playbackInfo.positionUs);
trackSelector.onSelectionActivated(trackSelectionData);
// Update the stored TrackStreams.
@ -819,32 +822,16 @@ import java.util.concurrent.atomic.AtomicInteger;
playingSource = null;
readingSource = null;
bufferingSource = null;
durationUs = C.UNSET_TIME_US;
playingSourceEndPositionUs = C.UNSET_TIME_US;
nextSourceIndex = 0;
sourceOffsetUs = 0;
bufferingSourceOffsetUs = 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Timeline[");
Source source = playingSource != null ? playingSource : bufferingSource;
while (source != null) {
sb.append(source);
source = source.nextSource;
if (source != null) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
playbackInfo = new PlaybackInfo(0);
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
}
private void setPlayingSource(Source source, long offsetUs) throws ExoPlaybackException {
sourceOffsetUs = offsetUs;
durationUs = source.sampleSource.getDurationUs();
// Disable/enable renderers for the new source.
int enabledRendererCount = disableRenderers(true, source.trackSelections);
@ -856,11 +843,10 @@ import java.util.concurrent.atomic.AtomicInteger;
playingSourceEndPositionUs = C.UNSET_TIME_US;
enableRenderers(source.trackSelections, enabledRendererCount);
// Update the timeline position for the new source index.
synchronized (timeline) {
sourceIndex = source.index;
updatePositionUs();
}
// Update playback information.
playbackInfo.durationUs = source.sampleSource.getDurationUs();
updateBufferedPositionUs();
updatePositionUs();
}
private int disableRenderers(boolean sourceTransition, TrackSelectionArray newTrackSelections)

View File

@ -343,6 +343,11 @@ public final class SimpleExoPlayer implements ExoPlayer {
player.seekTo(positionMs);
}
@Override
public void seekTo(int sourceIndex, long positionMs) {
player.seekTo(sourceIndex, positionMs);
}
@Override
public void stop() {
player.stop();
@ -373,6 +378,11 @@ public final class SimpleExoPlayer implements ExoPlayer {
return player.getCurrentPosition();
}
@Override
public int getCurrentSourceIndex() {
return player.getCurrentSourceIndex();
}
@Override
public long getBufferedPosition() {
return player.getBufferedPosition();

View File

@ -81,11 +81,11 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
}
private void updateTextView() {
textView.setText(getPlayerStateString() + getBandwidthString() + getVideoString()
+ getAudioString());
textView.setText(getPlayerStateString() + getPlayerSourceIndexString() + getBandwidthString()
+ getVideoString() + getAudioString());
}
public String getPlayerStateString() {
private String getPlayerStateString() {
String text = "playWhenReady:" + player.getPlayWhenReady() + " playbackState:";
switch(player.getPlaybackState()) {
case ExoPlayer.STATE_BUFFERING:
@ -107,6 +107,10 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
return text;
}
private String getPlayerSourceIndexString() {
return " source:" + player.getCurrentSourceIndex();
}
private String getBandwidthString() {
BandwidthMeter bandwidthMeter = player.getBandwidthMeter();
if (bandwidthMeter == null
@ -159,6 +163,11 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
// Do nothing.
}
@Override
public void onPositionDiscontinuity(int sourceIndex, long positionMs) {
updateTextView();
}
@Override
public void onPlayerError(ExoPlaybackException error) {
// Do nothing.

View File

@ -204,6 +204,11 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
// Do nothing.
}
@Override
public final void onPositionDiscontinuity(int sourceIndex, long positionMs) {
// Do nothing.
}
// SimpleExoPlayer.DebugListener
@Override