Remove player and isTopLevelSource parameters from MediaSource.prepare.

They are not longer needed anywhere, are error-prone (because of threading
requirements), and complicate testing and using MediaSources without a player.

PiperOrigin-RevId: 227871157
This commit is contained in:
tonihei 2019-01-04 17:56:10 +00:00 committed by Andrew Lewis
parent 5fc975b728
commit a973b6f34f
19 changed files with 45 additions and 183 deletions

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.ext.ima;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.view.ViewGroup;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.BaseMediaSource;
import com.google.android.exoplayer2.source.MediaPeriod;
@ -33,7 +32,8 @@ import java.io.IOException;
/**
* A {@link MediaSource} that inserts ads linearly with a provided content media source.
*
* @deprecated Use com.google.android.exoplayer2.source.ads.AdsMediaSource with ImaAdsLoader.
* @deprecated Use {@link com.google.android.exoplayer2.source.ads.AdsMediaSource} with
* ImaAdsLoader.
*/
@Deprecated
public final class ImaAdsMediaSource extends BaseMediaSource implements SourceInfoRefreshListener {
@ -83,12 +83,8 @@ public final class ImaAdsMediaSource extends BaseMediaSource implements SourceIn
}
@Override
public void prepareSourceInternal(
final ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
adsMediaSource.prepareSource(
player, isTopLevelSource, /* listener= */ this, mediaTransferListener);
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
adsMediaSource.prepareSource(/* listener= */ this, mediaTransferListener);
}
@Override

View File

@ -138,7 +138,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
repeatMode,
shuffleModeEnabled,
eventHandler,
this,
clock);
internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper());
}

View File

@ -93,7 +93,6 @@ import java.util.Collections;
private final HandlerWrapper handler;
private final HandlerThread internalPlaybackThread;
private final Handler eventHandler;
private final ExoPlayer player;
private final Timeline.Window window;
private final Timeline.Period period;
private final long backBufferDurationUs;
@ -131,7 +130,6 @@ import java.util.Collections;
@Player.RepeatMode int repeatMode,
boolean shuffleModeEnabled,
Handler eventHandler,
ExoPlayer player,
Clock clock) {
this.renderers = renderers;
this.trackSelector = trackSelector;
@ -142,7 +140,6 @@ import java.util.Collections;
this.repeatMode = repeatMode;
this.shuffleModeEnabled = shuffleModeEnabled;
this.eventHandler = eventHandler;
this.player = player;
this.clock = clock;
this.queue = new MediaPeriodQueue();
@ -398,11 +395,7 @@ import java.util.Collections;
loadControl.onPrepared();
this.mediaSource = mediaSource;
setState(Player.STATE_BUFFERING);
mediaSource.prepareSource(
player,
/* isTopLevelSource= */ true,
/* listener= */ this,
bandwidthMeter.getTransferListener());
mediaSource.prepareSource(/* listener= */ this, bandwidthMeter.getTransferListener());
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}

View File

@ -16,8 +16,8 @@
package com.google.android.exoplayer2.source;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
@ -35,9 +35,9 @@ public abstract class BaseMediaSource implements MediaSource {
private final ArrayList<SourceInfoRefreshListener> sourceInfoListeners;
private final MediaSourceEventListener.EventDispatcher eventDispatcher;
private @Nullable ExoPlayer player;
private @Nullable Timeline timeline;
private @Nullable Object manifest;
@Nullable private Looper looper;
@Nullable private Timeline timeline;
@Nullable private Object manifest;
public BaseMediaSource() {
sourceInfoListeners = new ArrayList<>(/* initialCapacity= */ 1);
@ -48,21 +48,16 @@ public abstract class BaseMediaSource implements MediaSource {
* Starts source preparation. This method is called at most once until the next call to {@link
* #releaseSourceInternal()}.
*
* @param player The player for which this source is being prepared.
* @param isTopLevelSource Whether this source has been passed directly to {@link
* ExoPlayer#prepare(MediaSource)} or {@link ExoPlayer#prepare(MediaSource, boolean,
* boolean)}.
* @param mediaTransferListener The transfer listener which should be informed of any media data
* transfers. May be null if no listener is available. Note that this listener should usually
* be only informed of transfers related to the media loads and not of auxiliary loads for
* manifests and other data.
*/
protected abstract void prepareSourceInternal(
ExoPlayer player, boolean isTopLevelSource, @Nullable TransferListener mediaTransferListener);
protected abstract void prepareSourceInternal(@Nullable TransferListener mediaTransferListener);
/**
* Releases the source. This method is called exactly once after each call to {@link
* #prepareSourceInternal(ExoPlayer, boolean, TransferListener)}.
* #prepareSourceInternal(TransferListener)}.
*/
protected abstract void releaseSourceInternal();
@ -135,21 +130,14 @@ public abstract class BaseMediaSource implements MediaSource {
@Override
public final void prepareSource(
ExoPlayer player, boolean isTopLevelSource, SourceInfoRefreshListener listener) {
prepareSource(player, isTopLevelSource, listener, /* mediaTransferListener= */ null);
}
@Override
public final void prepareSource(
ExoPlayer player,
boolean isTopLevelSource,
SourceInfoRefreshListener listener,
@Nullable TransferListener mediaTransferListener) {
Assertions.checkArgument(this.player == null || this.player == player);
Looper looper = Looper.myLooper();
Assertions.checkArgument(this.looper == null || this.looper == looper);
sourceInfoListeners.add(listener);
if (this.player == null) {
this.player = player;
prepareSourceInternal(player, isTopLevelSource, mediaTransferListener);
if (this.looper == null) {
this.looper = looper;
prepareSourceInternal(mediaTransferListener);
} else if (timeline != null) {
listener.onSourceInfoRefreshed(/* source= */ this, timeline, manifest);
}
@ -159,7 +147,7 @@ public abstract class BaseMediaSource implements MediaSource {
public final void releaseSource(SourceInfoRefreshListener listener) {
sourceInfoListeners.remove(listener);
if (sourceInfoListeners.isEmpty()) {
player = null;
looper = null;
timeline = null;
manifest = null;
releaseSourceInternal();

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.source;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
@ -223,11 +222,8 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener);
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
prepareChildSource(/* id= */ null, mediaSource);
}

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.source;
import android.os.Handler;
import android.support.annotation.CallSuper;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
@ -35,7 +34,6 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
private final HashMap<T, MediaSourceAndListener> childSources;
private @Nullable ExoPlayer player;
private @Nullable Handler eventHandler;
private @Nullable TransferListener mediaTransferListener;
@ -46,11 +44,7 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
@Override
@CallSuper
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
this.player = player;
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
this.mediaTransferListener = mediaTransferListener;
eventHandler = new Handler();
}
@ -71,7 +65,6 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
childSource.mediaSource.removeEventListener(childSource.eventListener);
}
childSources.clear();
player = null;
}
/**
@ -105,11 +98,7 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
MediaSourceEventListener eventListener = new ForwardingEventListener(id);
childSources.put(id, new MediaSourceAndListener(mediaSource, sourceListener, eventListener));
mediaSource.addEventListener(Assertions.checkNotNull(eventHandler), eventListener);
mediaSource.prepareSource(
Assertions.checkNotNull(player),
/* isTopLevelSource= */ false,
sourceListener,
mediaTransferListener);
mediaSource.prepareSource(sourceListener, mediaTransferListener);
}
/**

View File

@ -22,7 +22,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Pair;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource.MediaSourceHolder;
import com.google.android.exoplayer2.source.ShuffleOrder.DefaultShuffleOrder;
@ -428,10 +427,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
@Override
public final synchronized void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener);
super.prepareSourceInternal(mediaTransferListener);
playbackThreadHandler = new Handler(/* callback= */ this::handleMessage);
if (mediaSourcesPublic.isEmpty()) {
updateTimelineAndScheduleOnCompletionActions();
@ -1163,10 +1160,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
private static final class DummyMediaSource extends BaseMediaSource {
@Override
protected void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
// Do nothing.
}

View File

@ -19,7 +19,6 @@ import android.net.Uri;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.Extractor;
@ -365,10 +364,7 @@ public final class ExtractorMediaSource extends BaseMediaSource
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
transferListener = mediaTransferListener;
notifySourceInfoRefreshed(timelineDurationUs, timelineIsSeekable);
}

View File

@ -71,11 +71,8 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener);
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
prepareChildSource(/* id= */ null, childSource);
}

View File

@ -18,30 +18,30 @@ package com.google.android.exoplayer2.source;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
import java.io.IOException;
/**
* Defines and provides media to be played by an {@link ExoPlayer}. A MediaSource has two main
* responsibilities:
* Defines and provides media to be played by an {@link com.google.android.exoplayer2.ExoPlayer}. A
* MediaSource has two main responsibilities:
*
* <ul>
* <li>To provide the player with a {@link Timeline} defining the structure of its media, and to
* provide a new timeline whenever the structure of the media changes. The MediaSource
* provides these timelines by calling {@link SourceInfoRefreshListener#onSourceInfoRefreshed}
* on the {@link SourceInfoRefreshListener}s passed to {@link #prepareSource(ExoPlayer,
* boolean, SourceInfoRefreshListener, TransferListener)}.
* on the {@link SourceInfoRefreshListener}s passed to {@link
* #prepareSource(SourceInfoRefreshListener, TransferListener)}.
* <li>To provide {@link MediaPeriod} instances for the periods in its timeline. MediaPeriods are
* obtained by calling {@link #createPeriod(MediaPeriodId, Allocator, long)}, and provide a
* way for the player to load and read the media.
* </ul>
*
* All methods are called on the player's internal playback thread, as described in the {@link
* ExoPlayer} Javadoc. They should not be called directly from application code. Instances can be
* re-used, but only for one {@link ExoPlayer} instance simultaneously.
* com.google.android.exoplayer2.ExoPlayer} Javadoc. They should not be called directly from
* application code. Instances can be re-used, but only for one {@link
* com.google.android.exoplayer2.ExoPlayer} instance simultaneously.
*/
public interface MediaSource {
@ -242,11 +242,6 @@ public interface MediaSource {
* <p>For each call to this method, a call to {@link #releaseSource(SourceInfoRefreshListener)} is
* needed to remove the listener and to release the source if no longer required.
*
* @param player The player for which this source is being prepared.
* @param isTopLevelSource Whether this source has been passed directly to {@link
* ExoPlayer#prepare(MediaSource)} or {@link ExoPlayer#prepare(MediaSource, boolean,
* boolean)}. If {@code false}, this source is being prepared by another source (e.g. {@link
* ConcatenatingMediaSource}) for composition.
* @param listener The listener to be added.
* @param mediaTransferListener The transfer listener which should be informed of any media data
* transfers. May be null if no listener is available. Note that this listener should be only
@ -254,8 +249,6 @@ public interface MediaSource {
* and other data.
*/
void prepareSource(
ExoPlayer player,
boolean isTopLevelSource,
SourceInfoRefreshListener listener,
@Nullable TransferListener mediaTransferListener);

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer2.source;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
@ -105,11 +104,8 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener);
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
for (int i = 0; i < mediaSources.length; i++) {
prepareChildSource(i, mediaSources[i]);
}

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.source;
import android.net.Uri;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.Allocator;
@ -304,10 +303,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
transferListener = mediaTransferListener;
refreshSourceInfo(timeline, /* manifest= */ null);
}

View File

@ -22,7 +22,6 @@ import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.view.ViewGroup;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.CompositeMediaSource;
import com.google.android.exoplayer2.source.DeferredMediaPeriod;
@ -326,12 +325,9 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
}
@Override
public void prepareSourceInternal(
final ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener);
final ComponentListener componentListener = new ComponentListener();
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
ComponentListener componentListener = new ComponentListener();
this.componentListener = componentListener;
prepareChildSource(DUMMY_CONTENT_MEDIA_PERIOD_ID, contentMediaSource);
mainHandler.post(() -> adsLoader.start(componentListener, adUiViewGroup));

View File

@ -267,10 +267,8 @@ public final class ExoPlayerTest {
new FakeMediaSource(timeline, new Object(), Builder.VIDEO_FORMAT) {
@Override
public synchronized void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(player, isTopLevelSource, mediaTransferListener);
super.prepareSourceInternal(mediaTransferListener);
// We've queued a source info refresh on the playback thread's event queue. Allow the
// test thread to prepare the player with the third source, and block this thread (the
// playback thread) until the test thread's call to prepare() has returned.

View File

@ -22,7 +22,6 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.SparseArray;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline;
@ -614,10 +613,7 @@ public final class DashMediaSource extends BaseMediaSource {
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
this.mediaTransferListener = mediaTransferListener;
if (sideloadedManifest) {
processManifest(false);

View File

@ -19,7 +19,6 @@ import android.net.Uri;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.source.BaseMediaSource;
@ -397,10 +396,7 @@ public final class HlsMediaSource extends BaseMediaSource
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
this.mediaTransferListener = mediaTransferListener;
EventDispatcher eventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
playlistTracker.start(manifestUri, eventDispatcher, /* listener= */ this);

View File

@ -20,7 +20,6 @@ import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline;
@ -510,10 +509,7 @@ public final class SsMediaSource extends BaseMediaSource
}
@Override
public void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
this.mediaTransferListener = mediaTransferListener;
if (sideloadedManifest) {
manifestLoaderErrorThrower = new LoaderErrorThrower.Dummy();

View File

@ -22,7 +22,6 @@ import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
@ -96,10 +95,7 @@ public class FakeMediaSource extends BaseMediaSource {
}
@Override
public synchronized void prepareSourceInternal(
ExoPlayer player,
boolean isTopLevelSource,
@Nullable TransferListener mediaTransferListener) {
public synchronized void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
assertThat(preparedSource).isFalse();
transferListener = mediaTransferListener;
preparedSource = true;

View File

@ -17,17 +17,13 @@ package com.google.android.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Pair;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlayerMessage;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource;
@ -54,7 +50,6 @@ public class MediaSourceTestRunner {
public static final int TIMEOUT_MS = 10000;
private final StubExoPlayer player;
private final MediaSource mediaSource;
private final MediaSourceListener mediaSourceListener;
private final HandlerThread playbackThread;
@ -79,7 +74,6 @@ public class MediaSourceTestRunner {
playbackThread.start();
Looper playbackLooper = playbackThread.getLooper();
playbackHandler = new Handler(playbackLooper);
player = new EventHandlingExoPlayer(playbackLooper);
mediaSourceListener = new MediaSourceListener();
timelines = new LinkedBlockingDeque<>();
completedLoads = new CopyOnWriteArrayList<>();
@ -121,11 +115,7 @@ public class MediaSourceTestRunner {
final IOException[] prepareError = new IOException[1];
runOnPlaybackThread(
() -> {
mediaSource.prepareSource(
player,
/* isTopLevelSource= */ true,
mediaSourceListener,
/* mediaTransferListener= */ null);
mediaSource.prepareSource(mediaSourceListener, /* mediaTransferListener= */ null);
try {
// TODO: This only catches errors that are set synchronously in prepareSource. To
// capture async errors we'll need to poll maybeThrowSourceInfoRefreshError until the
@ -430,43 +420,4 @@ public class MediaSourceTestRunner {
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
}
}
private static class EventHandlingExoPlayer extends StubExoPlayer
implements Handler.Callback, PlayerMessage.Sender {
private final Handler handler;
public EventHandlingExoPlayer(Looper looper) {
this.handler = new Handler(looper, this);
}
@Override
public Looper getApplicationLooper() {
return handler.getLooper();
}
@Override
public PlayerMessage createMessage(PlayerMessage.Target target) {
return new PlayerMessage(
/* sender= */ this, target, Timeline.EMPTY, /* defaultWindowIndex= */ 0, handler);
}
@Override
public void sendMessage(PlayerMessage message) {
handler.obtainMessage(0, message).sendToTarget();
}
@Override
@SuppressWarnings("unchecked")
public boolean handleMessage(Message msg) {
PlayerMessage message = (PlayerMessage) msg.obj;
try {
message.getTarget().handleMessage(message.getType(), message.getPayload());
message.markAsProcessed(/* isDelivered= */ true);
} catch (ExoPlaybackException e) {
fail("Unexpected ExoPlaybackException.");
}
return true;
}
}
}