Commit 19d65a7a by olly Committed by Oliver Woodman

Report loading on/off changes via ExoPlayer.

Also attempt to clear up naming a little, using "buffering" to
mean the user visible buffering state, and "loading" to mean a
source being loaded.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=126693592
parent f4239eb5
...@@ -67,6 +67,11 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb ...@@ -67,6 +67,11 @@ public class EventLogger implements ExoPlayer.EventListener, SimpleExoPlayer.Deb
// ExoPlayer.EventListener // ExoPlayer.EventListener
@Override @Override
public void onLoadingChanged(boolean isLoading) {
Log.d(TAG, "loading [" + isLoading + "]");
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int state) { public void onPlayerStateChanged(boolean playWhenReady, int state) {
Log.d(TAG, "state [" + getSessionTimeString() + ", " + playWhenReady + ", " Log.d(TAG, "state [" + getSessionTimeString() + ", " + playWhenReady + ", "
+ getStateString(state) + "]"); + getStateString(state) + "]");
......
...@@ -18,7 +18,7 @@ package com.google.android.exoplayer.demo; ...@@ -18,7 +18,7 @@ package com.google.android.exoplayer.demo;
import com.google.android.exoplayer.AspectRatioFrameLayout; import com.google.android.exoplayer.AspectRatioFrameLayout;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ConcatenatingSampleSourceProvider; import com.google.android.exoplayer.ConcatenatingSampleSourceProvider;
import com.google.android.exoplayer.DefaultBufferingControl; import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.DefaultTrackSelectionPolicy; import com.google.android.exoplayer.DefaultTrackSelectionPolicy;
import com.google.android.exoplayer.DefaultTrackSelector; import com.google.android.exoplayer.DefaultTrackSelector;
import com.google.android.exoplayer.DefaultTrackSelector.TrackInfo; import com.google.android.exoplayer.DefaultTrackSelector.TrackInfo;
...@@ -268,8 +268,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -268,8 +268,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
trackSelector.addListener(this); trackSelector.addListener(this);
trackSelector.addListener(eventLogger); trackSelector.addListener(eventLogger);
trackSelectionHelper = new TrackSelectionHelper(trackSelector); trackSelectionHelper = new TrackSelectionHelper(trackSelector);
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, new DefaultLoadControl(),
new DefaultBufferingControl(), drmSessionManager, preferExtensionDecoders); drmSessionManager, preferExtensionDecoders);
player.addListener(this); player.addListener(this);
player.addListener(eventLogger); player.addListener(eventLogger);
player.setDebugListener(eventLogger); player.setDebugListener(eventLogger);
...@@ -389,6 +389,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -389,6 +389,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
// ExoPlayer.EventListener implementation // ExoPlayer.EventListener implementation
@Override @Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == ExoPlayer.STATE_ENDED) { if (playbackState == ExoPlayer.STATE_ENDED) {
showControls(); showControls();
......
...@@ -89,6 +89,11 @@ public class FlacPlaybackTest extends InstrumentationTestCase { ...@@ -89,6 +89,11 @@ public class FlacPlaybackTest extends InstrumentationTestCase {
} }
@Override @Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override
public void onPlayWhenReadyCommitted () { public void onPlayWhenReadyCommitted () {
// Do nothing. // Do nothing.
} }
......
...@@ -89,6 +89,11 @@ public class OpusPlaybackTest extends InstrumentationTestCase { ...@@ -89,6 +89,11 @@ public class OpusPlaybackTest extends InstrumentationTestCase {
} }
@Override @Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override
public void onPlayWhenReadyCommitted () { public void onPlayWhenReadyCommitted () {
// Do nothing. // Do nothing.
} }
......
...@@ -108,6 +108,11 @@ public class VpxPlaybackTest extends InstrumentationTestCase { ...@@ -108,6 +108,11 @@ public class VpxPlaybackTest extends InstrumentationTestCase {
} }
@Override @Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override
public void onPlayWhenReadyCommitted () { public void onPlayWhenReadyCommitted () {
// Do nothing. // Do nothing.
} }
......
...@@ -19,26 +19,10 @@ import com.google.android.exoplayer.upstream.Allocator; ...@@ -19,26 +19,10 @@ import com.google.android.exoplayer.upstream.Allocator;
import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.os.Handler;
/** /**
* The default {@link BufferingControl} implementation. * The default {@link LoadControl} implementation.
*/
public final class DefaultBufferingControl implements BufferingControl {
/**
* Interface definition for a callback to be notified of {@link DefaultBufferingControl} events.
*/ */
public interface EventListener { public final class DefaultLoadControl implements LoadControl {
/**
* Invoked when the control transitions from a buffering to a draining state or vice versa.
*
* @param buffering Whether the control is now in the buffering state.
*/
void onBufferingChanged(boolean buffering);
}
/** /**
* The default minimum duration of media that the player will attempt to ensure is buffered at all * The default minimum duration of media that the player will attempt to ensure is buffered at all
...@@ -69,8 +53,6 @@ public final class DefaultBufferingControl implements BufferingControl { ...@@ -69,8 +53,6 @@ public final class DefaultBufferingControl implements BufferingControl {
private static final int BELOW_LOW_WATERMARK = 2; private static final int BELOW_LOW_WATERMARK = 2;
private final DefaultAllocator allocator; private final DefaultAllocator allocator;
private final Handler eventHandler;
private final EventListener eventListener;
private final long minBufferUs; private final long minBufferUs;
private final long maxBufferUs; private final long maxBufferUs;
...@@ -83,7 +65,7 @@ public final class DefaultBufferingControl implements BufferingControl { ...@@ -83,7 +65,7 @@ public final class DefaultBufferingControl implements BufferingControl {
/** /**
* Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class. * Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class.
*/ */
public DefaultBufferingControl() { public DefaultLoadControl() {
this(new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE)); this(new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE));
} }
...@@ -92,22 +74,9 @@ public final class DefaultBufferingControl implements BufferingControl { ...@@ -92,22 +74,9 @@ public final class DefaultBufferingControl implements BufferingControl {
* *
* @param allocator The {@link DefaultAllocator} used by the loader. * @param allocator The {@link DefaultAllocator} used by the loader.
*/ */
public DefaultBufferingControl(DefaultAllocator allocator) { public DefaultLoadControl(DefaultAllocator allocator) {
this(allocator, null, null);
}
/**
* Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class.
*
* @param allocator The {@link DefaultAllocator} used by the loader.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public DefaultBufferingControl(DefaultAllocator allocator, Handler eventHandler,
EventListener eventListener) {
this(allocator, DEFAULT_MIN_BUFFER_MS, DEFAULT_MAX_BUFFER_MS, DEFAULT_BUFFER_FOR_PLAYBACK_MS, this(allocator, DEFAULT_MIN_BUFFER_MS, DEFAULT_MAX_BUFFER_MS, DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS, eventHandler, eventListener); DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
} }
/** /**
...@@ -123,16 +92,10 @@ public final class DefaultBufferingControl implements BufferingControl { ...@@ -123,16 +92,10 @@ public final class DefaultBufferingControl implements BufferingControl {
* @param bufferForPlaybackAfterRebufferMs The default duration of media that must be buffered for * @param bufferForPlaybackAfterRebufferMs The default duration of media that must be buffered for
* playback to resume after a player-invoked rebuffer (i.e. a rebuffer that occurs due to * playback to resume after a player-invoked rebuffer (i.e. a rebuffer that occurs due to
* buffer depletion rather than a user action), in milliseconds. * buffer depletion rather than a user action), in milliseconds.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/ */
public DefaultBufferingControl(DefaultAllocator allocator, int minBufferMs, int maxBufferMs, public DefaultLoadControl(DefaultAllocator allocator, int minBufferMs, int maxBufferMs,
long bufferForPlaybackMs, long bufferForPlaybackAfterRebufferMs, Handler eventHandler, long bufferForPlaybackMs, long bufferForPlaybackAfterRebufferMs) {
EventListener eventListener) {
this.allocator = allocator; this.allocator = allocator;
this.eventHandler = eventHandler;
this.eventListener = eventListener;
minBufferUs = minBufferMs * 1000L; minBufferUs = minBufferMs * 1000L;
maxBufferUs = maxBufferMs * 1000L; maxBufferUs = maxBufferMs * 1000L;
bufferForPlaybackUs = bufferForPlaybackMs * 1000L; bufferForPlaybackUs = bufferForPlaybackMs * 1000L;
...@@ -154,7 +117,7 @@ public final class DefaultBufferingControl implements BufferingControl { ...@@ -154,7 +117,7 @@ public final class DefaultBufferingControl implements BufferingControl {
@Override @Override
public void reset() { public void reset() {
targetBufferSize = 0; targetBufferSize = 0;
setBuffering(false); isBuffering = false;
} }
@Override @Override
...@@ -169,20 +132,12 @@ public final class DefaultBufferingControl implements BufferingControl { ...@@ -169,20 +132,12 @@ public final class DefaultBufferingControl implements BufferingControl {
} }
@Override @Override
public boolean shouldContinueBuffering(long bufferedDurationUs) { public boolean shouldContinueLoading(long bufferedDurationUs) {
int bufferTimeState = getBufferTimeState(bufferedDurationUs); int bufferTimeState = getBufferTimeState(bufferedDurationUs);
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize; boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
boolean shouldBuffer = bufferTimeState == BELOW_LOW_WATERMARK isBuffering = bufferTimeState == BELOW_LOW_WATERMARK
|| (bufferTimeState == BETWEEN_WATERMARKS && isBuffering && !targetBufferSizeReached); || (bufferTimeState == BETWEEN_WATERMARKS && isBuffering && !targetBufferSizeReached);
setBuffering(shouldBuffer); return isBuffering;
return shouldBuffer;
}
private void setBuffering(boolean isBuffering) {
if (this.isBuffering != isBuffering) {
this.isBuffering = isBuffering;
notifyBufferingChanged(isBuffering);
}
} }
private int getBufferTimeState(long bufferedDurationUs) { private int getBufferTimeState(long bufferedDurationUs) {
...@@ -190,15 +145,4 @@ public final class DefaultBufferingControl implements BufferingControl { ...@@ -190,15 +145,4 @@ public final class DefaultBufferingControl implements BufferingControl {
: (bufferedDurationUs < minBufferUs ? BELOW_LOW_WATERMARK : BETWEEN_WATERMARKS); : (bufferedDurationUs < minBufferUs ? BELOW_LOW_WATERMARK : BETWEEN_WATERMARKS);
} }
private void notifyBufferingChanged(final boolean buffering) {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onBufferingChanged(buffering);
}
});
}
}
} }
...@@ -98,6 +98,13 @@ public interface ExoPlayer { ...@@ -98,6 +98,13 @@ public interface ExoPlayer {
interface EventListener { interface EventListener {
/** /**
* Invoked when the player starts or stops loading the source.
*
* @param isLoading Whether the source is currently being loaded.
*/
void onLoadingChanged(boolean isLoading);
/**
* Invoked when the value returned from either {@link ExoPlayer#getPlayWhenReady()} or * Invoked when the value returned from either {@link ExoPlayer#getPlayWhenReady()} or
* {@link ExoPlayer#getPlaybackState()} changes. * {@link ExoPlayer#getPlaybackState()} changes.
* *
...@@ -270,6 +277,13 @@ public interface ExoPlayer { ...@@ -270,6 +277,13 @@ public interface ExoPlayer {
boolean isPlayWhenReadyCommitted(); boolean isPlayWhenReadyCommitted();
/** /**
* Whether the player is currently loading the source.
*
* @return True if the player is currently loading the source. False otherwise.
*/
boolean isLoading();
/**
* Seeks to a position specified in milliseconds in the current source. * Seeks to a position specified in milliseconds in the current source.
* *
* @param positionMs The seek position. * @param positionMs The seek position.
......
...@@ -42,7 +42,7 @@ public final class ExoPlayerFactory { ...@@ -42,7 +42,7 @@ public final class ExoPlayerFactory {
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
*/ */
public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector) { public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector) {
return newSimpleInstance(context, trackSelector, new DefaultBufferingControl(), null); return newSimpleInstance(context, trackSelector, new DefaultLoadControl(), null);
} }
/** /**
...@@ -52,13 +52,13 @@ public final class ExoPlayerFactory { ...@@ -52,13 +52,13 @@ public final class ExoPlayerFactory {
* *
* @param context A {@link Context}. * @param context A {@link Context}.
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
* @param bufferingControl The {@link BufferingControl} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance.
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * will not be used for DRM protected playbacks.
*/ */
public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector, public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector,
BufferingControl bufferingControl, DrmSessionManager drmSessionManager) { LoadControl loadControl, DrmSessionManager drmSessionManager) {
return newSimpleInstance(context, trackSelector, bufferingControl, drmSessionManager, false); return newSimpleInstance(context, trackSelector, loadControl, drmSessionManager, false);
} }
/** /**
...@@ -68,7 +68,7 @@ public final class ExoPlayerFactory { ...@@ -68,7 +68,7 @@ public final class ExoPlayerFactory {
* *
* @param context A {@link Context}. * @param context A {@link Context}.
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
* @param bufferingControl The {@link BufferingControl} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance.
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * will not be used for DRM protected playbacks.
* @param preferExtensionDecoders True to prefer {@link TrackRenderer} instances defined in * @param preferExtensionDecoders True to prefer {@link TrackRenderer} instances defined in
...@@ -76,9 +76,9 @@ public final class ExoPlayerFactory { ...@@ -76,9 +76,9 @@ public final class ExoPlayerFactory {
* included in the application build for setting this flag to have any effect. * included in the application build for setting this flag to have any effect.
*/ */
public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector, public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector,
BufferingControl bufferingControl, DrmSessionManager drmSessionManager, LoadControl loadControl, DrmSessionManager drmSessionManager,
boolean preferExtensionDecoders) { boolean preferExtensionDecoders) {
return newSimpleInstance(context, trackSelector, bufferingControl, drmSessionManager, return newSimpleInstance(context, trackSelector, loadControl, drmSessionManager,
preferExtensionDecoders, DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS); preferExtensionDecoders, DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS);
} }
...@@ -89,7 +89,7 @@ public final class ExoPlayerFactory { ...@@ -89,7 +89,7 @@ public final class ExoPlayerFactory {
* *
* @param context A {@link Context}. * @param context A {@link Context}.
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
* @param bufferingControl The {@link BufferingControl} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance.
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * will not be used for DRM protected playbacks.
* @param preferExtensionDecoders True to prefer {@link TrackRenderer} instances defined in * @param preferExtensionDecoders True to prefer {@link TrackRenderer} instances defined in
...@@ -99,9 +99,9 @@ public final class ExoPlayerFactory { ...@@ -99,9 +99,9 @@ public final class ExoPlayerFactory {
* seamlessly join an ongoing playback. * seamlessly join an ongoing playback.
*/ */
public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector, public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector,
BufferingControl bufferingControl, DrmSessionManager drmSessionManager, LoadControl loadControl, DrmSessionManager drmSessionManager,
boolean preferExtensionDecoders, long allowedVideoJoiningTimeMs) { boolean preferExtensionDecoders, long allowedVideoJoiningTimeMs) {
return new SimpleExoPlayer(context, trackSelector, bufferingControl, drmSessionManager, return new SimpleExoPlayer(context, trackSelector, loadControl, drmSessionManager,
preferExtensionDecoders, allowedVideoJoiningTimeMs); preferExtensionDecoders, allowedVideoJoiningTimeMs);
} }
...@@ -114,7 +114,7 @@ public final class ExoPlayerFactory { ...@@ -114,7 +114,7 @@ public final class ExoPlayerFactory {
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
*/ */
public static ExoPlayer newInstance(TrackRenderer[] renderers, TrackSelector trackSelector) { public static ExoPlayer newInstance(TrackRenderer[] renderers, TrackSelector trackSelector) {
return newInstance(renderers, trackSelector, new DefaultBufferingControl()); return newInstance(renderers, trackSelector, new DefaultLoadControl());
} }
/** /**
...@@ -124,11 +124,11 @@ public final class ExoPlayerFactory { ...@@ -124,11 +124,11 @@ public final class ExoPlayerFactory {
* *
* @param renderers The {@link TrackRenderer}s that will be used by the instance. * @param renderers The {@link TrackRenderer}s that will be used by the instance.
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
* @param bufferingControl The {@link BufferingControl} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance.
*/ */
public static ExoPlayer newInstance(TrackRenderer[] renderers, TrackSelector trackSelector, public static ExoPlayer newInstance(TrackRenderer[] renderers, TrackSelector trackSelector,
BufferingControl bufferingControl) { LoadControl loadControl) {
return new ExoPlayerImpl(renderers, trackSelector, bufferingControl); return new ExoPlayerImpl(renderers, trackSelector, loadControl);
} }
} }
...@@ -41,6 +41,7 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -41,6 +41,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private int playbackState; private int playbackState;
private int pendingPlayWhenReadyAcks; private int pendingPlayWhenReadyAcks;
private int pendingSetSourceProviderAndSeekAcks; private int pendingSetSourceProviderAndSeekAcks;
private boolean isLoading;
// Playback information when there is no pending seek/set source operation. // Playback information when there is no pending seek/set source operation.
private PlaybackInfo playbackInfo; private PlaybackInfo playbackInfo;
...@@ -55,11 +56,11 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -55,11 +56,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
* *
* @param renderers The {@link TrackRenderer}s that will be used by the instance. * @param renderers The {@link TrackRenderer}s that will be used by the instance.
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
* @param bufferingControl The {@link BufferingControl} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance.
*/ */
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
public ExoPlayerImpl(TrackRenderer[] renderers, TrackSelector trackSelector, public ExoPlayerImpl(TrackRenderer[] renderers, TrackSelector trackSelector,
BufferingControl bufferingControl) { LoadControl loadControl) {
Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION); Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION);
Assertions.checkNotNull(renderers); Assertions.checkNotNull(renderers);
Assertions.checkState(renderers.length > 0); Assertions.checkState(renderers.length > 0);
...@@ -72,8 +73,8 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -72,8 +73,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
ExoPlayerImpl.this.handleEvent(msg); ExoPlayerImpl.this.handleEvent(msg);
} }
}; };
internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, bufferingControl, internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, loadControl, playWhenReady,
playWhenReady, eventHandler); eventHandler);
playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(0); playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(0);
} }
...@@ -133,6 +134,11 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -133,6 +134,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
@Override @Override
public boolean isLoading() {
return isLoading;
}
@Override
public void seekTo(long positionMs) { public void seekTo(long positionMs) {
seekTo(getCurrentSourceIndex(), positionMs); seekTo(getCurrentSourceIndex(), positionMs);
} }
...@@ -221,6 +227,13 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -221,6 +227,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
break; break;
} }
case ExoPlayerImplInternal.MSG_LOADING_CHANGED: {
isLoading = msg.arg1 != 0;
for (EventListener listener : listeners) {
listener.onLoadingChanged(isLoading);
}
break;
}
case ExoPlayerImplInternal.MSG_SET_PLAY_WHEN_READY_ACK: { case ExoPlayerImplInternal.MSG_SET_PLAY_WHEN_READY_ACK: {
pendingPlayWhenReadyAcks--; pendingPlayWhenReadyAcks--;
if (pendingPlayWhenReadyAcks == 0) { if (pendingPlayWhenReadyAcks == 0) {
......
...@@ -35,8 +35,6 @@ import java.util.ArrayList; ...@@ -35,8 +35,6 @@ import java.util.ArrayList;
/** /**
* Implements the internal behavior of {@link ExoPlayerImpl}. * Implements the internal behavior of {@link ExoPlayerImpl}.
*/ */
// TODO[REFACTOR]: Make sure renderer errors that will prevent prepare from being called again are
// always propagated properly.
/* package */ final class ExoPlayerImplInternal implements Handler.Callback, SampleSource.Callback, /* package */ final class ExoPlayerImplInternal implements Handler.Callback, SampleSource.Callback,
InvalidationListener { InvalidationListener {
...@@ -63,11 +61,12 @@ import java.util.ArrayList; ...@@ -63,11 +61,12 @@ import java.util.ArrayList;
// External messages // External messages
public static final int MSG_STATE_CHANGED = 1; public static final int MSG_STATE_CHANGED = 1;
public static final int MSG_SET_PLAY_WHEN_READY_ACK = 2; public static final int MSG_LOADING_CHANGED = 2;
public static final int MSG_SET_SOURCE_PROVIDER_ACK = 3; public static final int MSG_SET_PLAY_WHEN_READY_ACK = 3;
public static final int MSG_SEEK_ACK = 4; public static final int MSG_SET_SOURCE_PROVIDER_ACK = 4;
public static final int MSG_SOURCE_CHANGED = 5; public static final int MSG_SEEK_ACK = 5;
public static final int MSG_ERROR = 6; public static final int MSG_SOURCE_CHANGED = 6;
public static final int MSG_ERROR = 7;
// Internal messages // Internal messages
private static final int MSG_SET_SOURCE_PROVIDER = 0; private static final int MSG_SET_SOURCE_PROVIDER = 0;
...@@ -93,7 +92,7 @@ import java.util.ArrayList; ...@@ -93,7 +92,7 @@ import java.util.ArrayList;
private static final int MAXIMUM_BUFFER_AHEAD_SOURCES = 100; private static final int MAXIMUM_BUFFER_AHEAD_SOURCES = 100;
private final TrackSelector trackSelector; private final TrackSelector trackSelector;
private final BufferingControl bufferingControl; private final LoadControl loadControl;
private final StandaloneMediaClock standaloneMediaClock; private final StandaloneMediaClock standaloneMediaClock;
private final Handler handler; private final Handler handler;
private final HandlerThread internalPlaybackThread; private final HandlerThread internalPlaybackThread;
...@@ -108,6 +107,7 @@ import java.util.ArrayList; ...@@ -108,6 +107,7 @@ import java.util.ArrayList;
private boolean released; private boolean released;
private boolean playWhenReady; private boolean playWhenReady;
private boolean rebuffering; private boolean rebuffering;
private boolean isLoading;
private int state; private int state;
private int customMessagesSent; private int customMessagesSent;
private int customMessagesProcessed; private int customMessagesProcessed;
...@@ -116,9 +116,9 @@ import java.util.ArrayList; ...@@ -116,9 +116,9 @@ import java.util.ArrayList;
private long internalPositionUs; private long internalPositionUs;
public ExoPlayerImplInternal(TrackRenderer[] renderers, TrackSelector trackSelector, public ExoPlayerImplInternal(TrackRenderer[] renderers, TrackSelector trackSelector,
BufferingControl bufferingControl, boolean playWhenReady, Handler eventHandler) { LoadControl loadControl, boolean playWhenReady, Handler eventHandler) {
this.trackSelector = trackSelector; this.trackSelector = trackSelector;
this.bufferingControl = bufferingControl; this.loadControl = loadControl;
this.playWhenReady = playWhenReady; this.playWhenReady = playWhenReady;
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
this.state = ExoPlayer.STATE_IDLE; this.state = ExoPlayer.STATE_IDLE;
...@@ -294,6 +294,13 @@ import java.util.ArrayList; ...@@ -294,6 +294,13 @@ import java.util.ArrayList;
} }
} }
private void setIsLoading(boolean isLoading) {
if (this.isLoading != isLoading) {
this.isLoading = isLoading;
eventHandler.obtainMessage(MSG_LOADING_CHANGED, isLoading ? 1 : 0, 0).sendToTarget();
}
}
private void setSourceProviderInternal(SampleSourceProvider sourceProvider) { private void setSourceProviderInternal(SampleSourceProvider sourceProvider) {
try { try {
resetInternal(); resetInternal();
...@@ -524,7 +531,8 @@ import java.util.ArrayList; ...@@ -524,7 +531,8 @@ import java.util.ArrayList;
enabledRenderers = new TrackRenderer[0]; enabledRenderers = new TrackRenderer[0];
sampleSourceProvider = null; sampleSourceProvider = null;
timeline.reset(); timeline.reset();
bufferingControl.reset(); loadControl.reset();
setIsLoading(false);
} }
private void sendMessagesInternal(ExoPlayerMessage[] messages) throws ExoPlaybackException { private void sendMessagesInternal(ExoPlayerMessage[] messages) throws ExoPlaybackException {
...@@ -572,7 +580,7 @@ import java.util.ArrayList; ...@@ -572,7 +580,7 @@ import java.util.ArrayList;
private Source playingSource; private Source playingSource;
private Source readingSource; private Source readingSource;
private Source bufferingSource; private Source loadingSource;
private int pendingSourceIndex; private int pendingSourceIndex;
private long playingSourceEndPositionUs; private long playingSourceEndPositionUs;
...@@ -587,62 +595,65 @@ import java.util.ArrayList; ...@@ -587,62 +595,65 @@ import java.util.ArrayList;
} }
public boolean haveSufficientBuffer(boolean rebuffering) { public boolean haveSufficientBuffer(boolean rebuffering) {
if (bufferingSource == null) { if (loadingSource == null) {
return false; return false;
} }
long positionUs = internalPositionUs - bufferingSource.offsetUs; long positionUs = internalPositionUs - loadingSource.offsetUs;
long bufferedPositionUs = !bufferingSource.prepared ? 0 long bufferedPositionUs = !loadingSource.prepared ? 0
: bufferingSource.sampleSource.getBufferedPositionUs(); : loadingSource.sampleSource.getBufferedPositionUs();
if (bufferedPositionUs == C.END_OF_SOURCE_US) { if (bufferedPositionUs == C.END_OF_SOURCE_US) {
int sourceCount = sampleSourceProvider.getSourceCount(); int sourceCount = sampleSourceProvider.getSourceCount();
if (sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT if (sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT
&& bufferingSource.index == sourceCount - 1) { && loadingSource.index == sourceCount - 1) {
return true; return true;
} }
bufferedPositionUs = bufferingSource.sampleSource.getDurationUs(); bufferedPositionUs = loadingSource.sampleSource.getDurationUs();
} }
return bufferingControl.shouldStartPlayback(bufferedPositionUs - positionUs, rebuffering); return loadControl.shouldStartPlayback(bufferedPositionUs - positionUs, rebuffering);
} }
public void maybeThrowSourcePrepareError() throws IOException { public void maybeThrowSourcePrepareError() throws IOException {
if (bufferingSource != null && !bufferingSource.prepared if (loadingSource != null && !loadingSource.prepared
&& (readingSource == null || readingSource.nextSource == bufferingSource)) { && (readingSource == null || readingSource.nextSource == loadingSource)) {
for (TrackRenderer renderer : enabledRenderers) { for (TrackRenderer renderer : enabledRenderers) {
if (!renderer.hasReadStreamToEnd()) { if (!renderer.hasReadStreamToEnd()) {
return; return;
} }
} }
bufferingSource.sampleSource.maybeThrowPrepareError(); loadingSource.sampleSource.maybeThrowPrepareError();
} }
} }
public void updateSources() throws ExoPlaybackException, IOException { public void updateSources() throws ExoPlaybackException, IOException {
// TODO[playlists]: Let sample source providers invalidate sources that are already buffering. // TODO[playlists]: Let sample source providers invalidate sources that are already loaded.
// Update the buffering source. // Update the loading source.
int sourceCount = sampleSourceProvider.getSourceCount(); int sourceCount = sampleSourceProvider.getSourceCount();
if (bufferingSource == null if (loadingSource == null
|| (bufferingSource.isFullyBuffered() && bufferingSource.index || (loadingSource.isFullyBuffered() && loadingSource.index
- (playingSource != null ? playingSource.index : 0) < MAXIMUM_BUFFER_AHEAD_SOURCES)) { - (playingSource != null ? playingSource.index : 0) < MAXIMUM_BUFFER_AHEAD_SOURCES)) {
// Try and obtain the next source to start buffering. // Try and obtain the next source to start loading.
int sourceIndex = bufferingSource == null ? pendingSourceIndex : bufferingSource.index + 1; int sourceIndex = loadingSource == null ? pendingSourceIndex : loadingSource.index + 1;
if (sourceCount == SampleSourceProvider.UNKNOWN_SOURCE_COUNT || sourceIndex < sourceCount) { if (sourceCount == SampleSourceProvider.UNKNOWN_SOURCE_COUNT || sourceIndex < sourceCount) {
// Attempt to create the next source. // Attempt to create the next source.
SampleSource sampleSource = sampleSourceProvider.createSource(sourceIndex); SampleSource sampleSource = sampleSourceProvider.createSource(sourceIndex);
if (sampleSource != null) { if (sampleSource != null) {
Source newSource = new Source(renderers, trackSelector, sampleSource, sourceIndex); Source newSource = new Source(renderers, trackSelector, sampleSource, sourceIndex);
if (bufferingSource != null) { if (loadingSource != null) {
bufferingSource.setNextSource(newSource); loadingSource.setNextSource(newSource);
} }
bufferingSource = newSource; loadingSource = newSource;
long startPositionUs = playingSource == null ? playbackInfo.positionUs : 0; long startPositionUs = playingSource == null ? playbackInfo.positionUs : 0;
bufferingSource.sampleSource.prepare(ExoPlayerImplInternal.this, setIsLoading(true);
bufferingControl.getAllocator(), startPositionUs); loadingSource.sampleSource.prepare(ExoPlayerImplInternal.this,
loadControl.getAllocator(), startPositionUs);
} }
} }
} }
if (bufferingSource != null && bufferingSource.needsContinueLoading) { if (loadingSource == null || loadingSource.isFullyBuffered()) {
setIsLoading(false);
} else if (loadingSource != null && loadingSource.needsContinueLoading) {
maybeContinueLoading(); maybeContinueLoading();
} }
...@@ -713,15 +724,15 @@ import java.util.ArrayList; ...@@ -713,15 +724,15 @@ import java.util.ArrayList;
} }
public void handleSourcePrepared(SampleSource source) throws ExoPlaybackException { public void handleSourcePrepared(SampleSource source) throws ExoPlaybackException {
if (bufferingSource == null || bufferingSource.sampleSource != source) { if (loadingSource == null || loadingSource.sampleSource != source) {
// Stale event. // Stale event.
return; return;
} }
long startPositionUs = playingSource == null ? playbackInfo.positionUs : 0; long startPositionUs = playingSource == null ? playbackInfo.positionUs : 0;
bufferingSource.handlePrepared(startPositionUs, bufferingControl); loadingSource.handlePrepared(startPositionUs, loadControl);
if (playingSource == null) { if (playingSource == null) {
// This is the first prepared source, so start playing it. // This is the first prepared source, so start playing it.
readingSource = bufferingSource; readingSource = loadingSource;
setPlayingSource(readingSource); setPlayingSource(readingSource);
updateTimelineState(); updateTimelineState();
} }
...@@ -729,24 +740,27 @@ import java.util.ArrayList; ...@@ -729,24 +740,27 @@ import java.util.ArrayList;
} }
public void handleContinueLoadingRequested(SampleSource source) { public void handleContinueLoadingRequested(SampleSource source) {
if (bufferingSource == null || bufferingSource.sampleSource != source) { if (loadingSource == null || loadingSource.sampleSource != source) {
return; return;
} }
maybeContinueLoading(); maybeContinueLoading();
} }
private void maybeContinueLoading() { private void maybeContinueLoading() {
long nextLoadPositionUs = bufferingSource.sampleSource.getNextLoadPositionUs(); long nextLoadPositionUs = loadingSource.sampleSource.getNextLoadPositionUs();
if (nextLoadPositionUs != C.END_OF_SOURCE_US) { if (nextLoadPositionUs != C.END_OF_SOURCE_US) {
long positionUs = internalPositionUs - bufferingSource.offsetUs; long positionUs = internalPositionUs - loadingSource.offsetUs;
long bufferedDurationUs = nextLoadPositionUs - positionUs; long bufferedDurationUs = nextLoadPositionUs - positionUs;
boolean continueBuffering = bufferingControl.shouldContinueBuffering(bufferedDurationUs); boolean continueLoading = loadControl.shouldContinueLoading(bufferedDurationUs);
if (continueBuffering) { setIsLoading(continueLoading);
bufferingSource.needsContinueLoading = false; if (continueLoading) {
bufferingSource.sampleSource.continueLoading(positionUs); loadingSource.needsContinueLoading = false;
loadingSource.sampleSource.continueLoading(positionUs);
} else { } else {
bufferingSource.needsContinueLoading = true; loadingSource.needsContinueLoading = true;
} }
} else {
setIsLoading(false);
} }
} }
...@@ -768,7 +782,7 @@ import java.util.ArrayList; ...@@ -768,7 +782,7 @@ import java.util.ArrayList;
setPlayingSource(newPlayingSource); setPlayingSource(newPlayingSource);
updateTimelineState(); updateTimelineState();
readingSource = playingSource; readingSource = playingSource;
bufferingSource = playingSource; loadingSource = playingSource;
if (playingSource.hasEnabledTracks) { if (playingSource.hasEnabledTracks) {
seekPositionUs = playingSource.sampleSource.seekToUs(seekPositionUs); seekPositionUs = playingSource.sampleSource.seekToUs(seekPositionUs);
} }
...@@ -782,7 +796,7 @@ import java.util.ArrayList; ...@@ -782,7 +796,7 @@ import java.util.ArrayList;
enabledRenderers = new TrackRenderer[0]; enabledRenderers = new TrackRenderer[0];
playingSource = null; playingSource = null;
readingSource = null; readingSource = null;
bufferingSource = null; loadingSource = null;
pendingSourceIndex = sourceIndex; pendingSourceIndex = sourceIndex;
resetInternalPosition(seekPositionUs); resetInternalPosition(seekPositionUs);
} }
...@@ -818,13 +832,13 @@ import java.util.ArrayList; ...@@ -818,13 +832,13 @@ import java.util.ArrayList;
} }
playingSource.nextSource = null; playingSource.nextSource = null;
readingSource = playingSource; readingSource = playingSource;
bufferingSource = playingSource; loadingSource = playingSource;
playingSourceEndPositionUs = C.UNSET_TIME_US; playingSourceEndPositionUs = C.UNSET_TIME_US;
// Update streams for the new selection, recreating all streams if reading ahead. // Update streams for the new selection, recreating all streams if reading ahead.
boolean recreateStreams = readingSource != playingSource; boolean recreateStreams = readingSource != playingSource;
TrackSelectionArray playingSourceOldTrackSelections = playingSource.sourceTrackSelections; TrackSelectionArray playingSourceOldTrackSelections = playingSource.sourceTrackSelections;
playingSource.updateSourceTrackSelection(playbackInfo.positionUs, bufferingControl, playingSource.updateSourceTrackSelection(playbackInfo.positionUs, loadControl,
recreateStreams); recreateStreams);
int enabledRendererCount = 0; int enabledRendererCount = 0;
...@@ -858,21 +872,21 @@ import java.util.ArrayList; ...@@ -858,21 +872,21 @@ import java.util.ArrayList;
enableRenderers(rendererWasEnabledFlags, enabledRendererCount); enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
} else { } else {
// Release and re-prepare/buffer sources after the one whose selection changed. // Release and re-prepare/buffer sources after the one whose selection changed.
bufferingSource = source; loadingSource = source;
source = bufferingSource.nextSource; source = loadingSource.nextSource;
while (source != null) { while (source != null) {
source.release(); source.release();
source = source.nextSource; source = source.nextSource;
} }
bufferingSource.nextSource = null; loadingSource.nextSource = null;
long positionUs = Math.max(0, internalPositionUs - bufferingSource.offsetUs); long positionUs = Math.max(0, internalPositionUs - loadingSource.offsetUs);
bufferingSource.updateSourceTrackSelection(positionUs, bufferingControl, false); loadingSource.updateSourceTrackSelection(positionUs, loadControl, false);
} }
maybeContinueLoading(); maybeContinueLoading();
} }
public void reset() { public void reset() {
Source source = playingSource != null ? playingSource : bufferingSource; Source source = playingSource != null ? playingSource : loadingSource;
while (source != null) { while (source != null) {
source.release(); source.release();
source = source.nextSource; source = source.nextSource;
...@@ -881,7 +895,7 @@ import java.util.ArrayList; ...@@ -881,7 +895,7 @@ import java.util.ArrayList;
isEnded = false; isEnded = false;
playingSource = null; playingSource = null;
readingSource = null; readingSource = null;
bufferingSource = null; loadingSource = null;
playingSourceEndPositionUs = C.UNSET_TIME_US; playingSourceEndPositionUs = C.UNSET_TIME_US;
pendingSourceIndex = 0; pendingSourceIndex = 0;
playbackInfo = new PlaybackInfo(0); playbackInfo = new PlaybackInfo(0);
...@@ -995,7 +1009,6 @@ import java.util.ArrayList; ...@@ -995,7 +1009,6 @@ import java.util.ArrayList;
int index) { int index) {
this.renderers = renderers; this.renderers = renderers;
this.trackSelector = trackSelector; this.trackSelector = trackSelector;
this.sampleSource = sampleSource; this.sampleSource = sampleSource;
this.index = index; this.index = index;
trackStreams = new TrackStream[renderers.length]; trackStreams = new TrackStream[renderers.length];
...@@ -1011,11 +1024,11 @@ import java.util.ArrayList; ...@@ -1011,11 +1024,11 @@ import java.util.ArrayList;
|| sampleSource.getBufferedPositionUs() == C.END_OF_SOURCE_US); || sampleSource.getBufferedPositionUs() == C.END_OF_SOURCE_US);
} }
public void handlePrepared(long positionUs, BufferingControl bufferingControl) public void handlePrepared(long positionUs, LoadControl loadControl)
throws ExoPlaybackException { throws ExoPlaybackException {
prepared = true; prepared = true;
selectTracks(); selectTracks();
updateSourceTrackSelection(positionUs, bufferingControl, false); updateSourceTrackSelection(positionUs, loadControl, false);
} }
public boolean selectTracks() throws ExoPlaybackException { public boolean selectTracks() throws ExoPlaybackException {
...@@ -1030,7 +1043,7 @@ import java.util.ArrayList; ...@@ -1030,7 +1043,7 @@ import java.util.ArrayList;
return true; return true;
} }
public void updateSourceTrackSelection(long positionUs, BufferingControl bufferingControl, public void updateSourceTrackSelection(long positionUs, LoadControl loadControl,
boolean forceRecreateStreams) throws ExoPlaybackException { boolean forceRecreateStreams) throws ExoPlaybackException {
// Populate lists of streams that are being disabled/newly enabled. // Populate lists of streams that are being disabled/newly enabled.
ArrayList<TrackStream> oldStreams = new ArrayList<>(); ArrayList<TrackStream> oldStreams = new ArrayList<>();
...@@ -1069,7 +1082,7 @@ import java.util.ArrayList; ...@@ -1069,7 +1082,7 @@ import java.util.ArrayList;
} }
// The track selection has changed. // The track selection has changed.
bufferingControl.onTrackSelections(renderers, sampleSource.getTrackGroups(), trackSelections); loadControl.onTrackSelections(renderers, sampleSource.getTrackGroups(), trackSelections);
} }
public void release() { public void release() {
......
...@@ -20,7 +20,7 @@ import com.google.android.exoplayer.upstream.Allocator; ...@@ -20,7 +20,7 @@ import com.google.android.exoplayer.upstream.Allocator;
/** /**
* Controls buffering of media. * Controls buffering of media.
*/ */
public interface BufferingControl { public interface LoadControl {
/** /**
* Invoked by the player when a track selection occurs. * Invoked by the player when a track selection occurs.
...@@ -55,11 +55,11 @@ public interface BufferingControl { ...@@ -55,11 +55,11 @@ public interface BufferingControl {
boolean shouldStartPlayback(long bufferedDurationUs, boolean rebuffering); boolean shouldStartPlayback(long bufferedDurationUs, boolean rebuffering);
/** /**
* Invoked by the player to determine whether buffering should continue. * Invoked by the player to determine whether it should continue to load the source.
* *
* @param bufferedDurationUs The duration of media that's currently buffered. * @param bufferedDurationUs The duration of media that's currently buffered.
* @return True if the buffering should continue. False otherwise. * @return True if the loading should continue. False otherwise.
*/ */
boolean shouldContinueBuffering(long bufferedDurationUs); boolean shouldContinueLoading(long bufferedDurationUs);
} }
...@@ -111,7 +111,7 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -111,7 +111,7 @@ public final class SimpleExoPlayer implements ExoPlayer {
private CodecCounters audioCodecCounters; private CodecCounters audioCodecCounters;
/* package */ SimpleExoPlayer(Context context, TrackSelector trackSelector, /* package */ SimpleExoPlayer(Context context, TrackSelector trackSelector,
BufferingControl bufferingControl, DrmSessionManager drmSessionManager, LoadControl loadControl, DrmSessionManager drmSessionManager,
boolean preferExtensionDecoders, long allowedVideoJoiningTimeMs) { boolean preferExtensionDecoders, long allowedVideoJoiningTimeMs) {
mainHandler = new Handler(); mainHandler = new Handler();
bandwidthMeter = new DefaultBandwidthMeter(); bandwidthMeter = new DefaultBandwidthMeter();
...@@ -145,7 +145,7 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -145,7 +145,7 @@ public final class SimpleExoPlayer implements ExoPlayer {
this.audioRendererCount = audioRendererCount; this.audioRendererCount = audioRendererCount;
// Build the player and associated objects. // Build the player and associated objects.
player = new ExoPlayerImpl(renderers, trackSelector, bufferingControl); player = new ExoPlayerImpl(renderers, trackSelector, loadControl);
} }
/** /**
...@@ -339,6 +339,11 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -339,6 +339,11 @@ public final class SimpleExoPlayer implements ExoPlayer {
} }
@Override @Override
public boolean isLoading() {
return player.isLoading();
}
@Override
public void seekTo(long positionMs) { public void seekTo(long positionMs) {
player.seekTo(positionMs); player.seekTo(positionMs);
} }
......
...@@ -154,6 +154,11 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe ...@@ -154,6 +154,11 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
// ExoPlayer.EventListener implementation // ExoPlayer.EventListener implementation
@Override @Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
updateTextView(); updateTextView();
} }
......
...@@ -174,7 +174,12 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen ...@@ -174,7 +174,12 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
assertPassed(audioCodecCounters, videoCodecCounters); assertPassed(audioCodecCounters, videoCodecCounters);
} }
// ExoPlayer.Listener // ExoPlayer.EventListener
@Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override @Override
public final void onPlayerStateChanged(boolean playWhenReady, int playbackState) { public final void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment