Commit 8f952162 by tonihei Committed by Oliver Woodman

Allow multiple media source event listeners.

This is achieved by moving the listener registration and the creation of the
event dispatcher into BaseMediaSource.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=188461932
parent ebfd9d05
......@@ -31,6 +31,8 @@
date time is still available via the informational
`Timeline.Window.windowStartTimeMs` field
([#3865](https://github.com/google/ExoPlayer/issues/3865)).
* Allow adding and removing `MediaSourceEventListener`s to MediaSources after
they have been created.
* Enable seeking in MP4 streams where duration is set incorrectly in the track
header ([#3926](https://github.com/google/ExoPlayer/issues/3926)).
* Video: force rendering a frame periodically in `MediaCodecVideoRenderer` and
......
......@@ -17,8 +17,6 @@ package com.google.android.exoplayer2.imademo;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.C.ContentType;
import com.google.android.exoplayer2.ExoPlayer;
......@@ -27,7 +25,6 @@ import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener;
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
......@@ -83,8 +80,7 @@ import com.google.android.exoplayer2.util.Util;
// This is the MediaSource representing the content media (i.e. not the ad).
String contentUrl = context.getString(R.string.content_url);
MediaSource contentMediaSource =
buildMediaSource(Uri.parse(contentUrl), /* handler= */ null, /* listener= */ null);
MediaSource contentMediaSource = buildMediaSource(Uri.parse(contentUrl));
// Compose the content media source into a new AdsMediaSource with both ads and content.
MediaSource mediaSourceWithAds =
......@@ -121,9 +117,8 @@ import com.google.android.exoplayer2.util.Util;
// AdsMediaSource.MediaSourceFactory implementation.
@Override
public MediaSource createMediaSource(
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
return buildMediaSource(uri, handler, listener);
public MediaSource createMediaSource(Uri uri) {
return buildMediaSource(uri);
}
@Override
......@@ -134,25 +129,22 @@ import com.google.android.exoplayer2.util.Util;
// Internal methods.
private MediaSource buildMediaSource(
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
private MediaSource buildMediaSource(Uri uri) {
@ContentType int type = Util.inferContentType(uri);
switch (type) {
case C.TYPE_DASH:
return new DashMediaSource.Factory(
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
manifestDataSourceFactory)
.createMediaSource(uri, handler, listener);
.createMediaSource(uri);
case C.TYPE_SS:
return new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(mediaDataSourceFactory), manifestDataSourceFactory)
.createMediaSource(uri, handler, listener);
.createMediaSource(uri);
case C.TYPE_HLS:
return new HlsMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(uri, handler, listener);
return new HlsMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
case C.TYPE_OTHER:
return new ExtractorMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(uri, handler, listener);
return new ExtractorMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
default:
throw new IllegalStateException("Unsupported type: " + type);
}
......
......@@ -53,7 +53,6 @@ import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.ads.AdsLoader;
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
......@@ -342,7 +341,8 @@ public class PlayerActivity extends Activity
}
MediaSource[] mediaSources = new MediaSource[uris.length];
for (int i = 0; i < uris.length; i++) {
mediaSources[i] = buildMediaSource(uris[i], extensions[i], mainHandler, eventLogger);
mediaSources[i] = buildMediaSource(uris[i], extensions[i]);
mediaSources[i].addEventListener(mainHandler, eventLogger);
}
mediaSource =
mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources);
......@@ -372,11 +372,7 @@ public class PlayerActivity extends Activity
updateButtonVisibilities();
}
private MediaSource buildMediaSource(
Uri uri,
String overrideExtension,
@Nullable Handler handler,
@Nullable MediaSourceEventListener listener) {
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
@ContentType int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri)
: Util.inferContentType("." + overrideExtension);
switch (type) {
......@@ -384,18 +380,16 @@ public class PlayerActivity extends Activity
return new DashMediaSource.Factory(
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false))
.createMediaSource(uri, handler, listener);
.createMediaSource(uri);
case C.TYPE_SS:
return new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false))
.createMediaSource(uri, handler, listener);
.createMediaSource(uri);
case C.TYPE_HLS:
return new HlsMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(uri, handler, listener);
return new HlsMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
case C.TYPE_OTHER:
return new ExtractorMediaSource.Factory(mediaDataSourceFactory)
.createMediaSource(uri, handler, listener);
return new ExtractorMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
default: {
throw new IllegalStateException("Unsupported type: " + type);
}
......@@ -488,10 +482,8 @@ public class PlayerActivity extends Activity
AdsMediaSource.MediaSourceFactory adMediaSourceFactory =
new AdsMediaSource.MediaSourceFactory() {
@Override
public MediaSource createMediaSource(
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
return PlayerActivity.this.buildMediaSource(
uri, /* overrideExtension= */ null, handler, listener);
public MediaSource createMediaSource(Uri uri) {
return PlayerActivity.this.buildMediaSource(uri, /* overrideExtension= */ null);
}
@Override
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
......@@ -22,7 +23,8 @@ import com.google.android.exoplayer2.util.Assertions;
import java.util.ArrayList;
/**
* Base {@link MediaSource} implementation to handle parallel reuse.
* Base {@link MediaSource} implementation to handle parallel reuse and to keep a list of {@link
* MediaSourceEventListener}s.
*
* <p>Whenever an implementing subclass needs to provide a new timeline and/or manifest, it must
* call {@link #refreshSourceInfo(Timeline, Object)} to notify all listeners.
......@@ -30,6 +32,7 @@ import java.util.ArrayList;
public abstract class BaseMediaSource implements MediaSource {
private final ArrayList<SourceInfoRefreshListener> sourceInfoListeners;
private final MediaSourceEventListener.EventDispatcher eventDispatcher;
private ExoPlayer player;
private Timeline timeline;
......@@ -37,6 +40,7 @@ public abstract class BaseMediaSource implements MediaSource {
public BaseMediaSource() {
sourceInfoListeners = new ArrayList<>(/* initialCapacity= */ 1);
eventDispatcher = new MediaSourceEventListener.EventDispatcher();
}
/**
......@@ -70,6 +74,24 @@ public abstract class BaseMediaSource implements MediaSource {
}
}
/**
* Returns a {@link MediaSourceEventListener.EventDispatcher} which dispatches all events to the
* registered listeners.
*/
protected final MediaSourceEventListener.EventDispatcher getEventDispatcher() {
return eventDispatcher;
}
@Override
public final void addEventListener(Handler handler, MediaSourceEventListener eventListener) {
eventDispatcher.addEventListener(handler, eventListener);
}
@Override
public final void removeEventListener(MediaSourceEventListener eventListener) {
eventDispatcher.removeEventListener(eventListener);
}
@Override
public final void prepareSource(
ExoPlayer player, boolean isTopLevelSource, SourceInfoRefreshListener listener) {
......
......@@ -187,34 +187,38 @@ public final class ExtractorMediaSource extends BaseMediaSource
}
/**
* Returns a new {@link ExtractorMediaSource} using the current parameters. Media source events
* will not be delivered.
* Returns a new {@link ExtractorMediaSource} using the current parameters.
*
* @param uri The {@link Uri}.
* @return The new {@link ExtractorMediaSource}.
*/
@Override
public ExtractorMediaSource createMediaSource(Uri uri) {
return createMediaSource(uri, null, null);
isCreateCalled = true;
if (extractorsFactory == null) {
extractorsFactory = new DefaultExtractorsFactory();
}
return new ExtractorMediaSource(
uri,
dataSourceFactory,
extractorsFactory,
minLoadableRetryCount,
customCacheKey,
continueLoadingCheckIntervalBytes);
}
/**
* Returns a new {@link ExtractorMediaSource} using the current parameters.
*
* @param uri The {@link Uri}.
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return The new {@link ExtractorMediaSource}.
* @deprecated Use {@link #createMediaSource(Uri)} and {@link #addEventListener(Handler,
* MediaSourceEventListener)} instead.
*/
@Override
@Deprecated
public ExtractorMediaSource createMediaSource(
Uri uri, @Nullable Handler eventHandler, @Nullable MediaSourceEventListener eventListener) {
isCreateCalled = true;
if (extractorsFactory == null) {
extractorsFactory = new DefaultExtractorsFactory();
ExtractorMediaSource mediaSource = createMediaSource(uri);
if (eventHandler != null && eventListener != null) {
mediaSource.addEventListener(eventHandler, eventListener);
}
return new ExtractorMediaSource(uri, dataSourceFactory, extractorsFactory,
minLoadableRetryCount, eventHandler, eventListener, customCacheKey,
continueLoadingCheckIntervalBytes);
return mediaSource;
}
@Override
......@@ -297,10 +301,11 @@ public final class ExtractorMediaSource extends BaseMediaSource
dataSourceFactory,
extractorsFactory,
minLoadableRetryCount,
eventHandler,
eventListener == null ? null : new EventListenerWrapper(eventListener),
customCacheKey,
continueLoadingCheckIntervalBytes);
if (eventListener != null && eventHandler != null) {
addEventListener(eventHandler, new EventListenerWrapper(eventListener));
}
}
private ExtractorMediaSource(
......@@ -308,15 +313,13 @@ public final class ExtractorMediaSource extends BaseMediaSource
DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
int minLoadableRetryCount,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener,
@Nullable String customCacheKey,
int continueLoadingCheckIntervalBytes) {
this.uri = uri;
this.dataSourceFactory = dataSourceFactory;
this.extractorsFactory = extractorsFactory;
this.minLoadableRetryCount = minLoadableRetryCount;
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
this.eventDispatcher = getEventDispatcher();
this.customCacheKey = customCacheKey;
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
this.timelineDurationUs = C.TIME_UNSET;
......
......@@ -15,6 +15,7 @@
*/
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;
......@@ -172,6 +173,23 @@ public interface MediaSource {
}
/**
* Adds a {@link MediaSourceEventListener} to the list of listeners which are notified of media
* source events.
*
* @param handler A handler on the which listener events will be posted.
* @param eventListener The listener to be added.
*/
void addEventListener(Handler handler, MediaSourceEventListener eventListener);
/**
* Removes a {@link MediaSourceEventListener} from the list of listeners which are notified of
* media source events.
*
* @param eventListener The listener to be removed.
*/
void removeEventListener(MediaSourceEventListener eventListener);
/**
* Starts source preparation if not yet started, and adds a listener for timeline and/or manifest
* updates.
*
......
......@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.CheckResult;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
......@@ -24,6 +25,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
/** Interface for callbacks to be notified of {@link MediaSource} events. */
public interface MediaSourceEventListener {
......@@ -190,30 +192,61 @@ public interface MediaSourceEventListener {
*/
void onDownstreamFormatChanged(MediaLoadData mediaLoadData);
/** Dispatches events to a {@link MediaSourceEventListener}. */
/** Dispatches events to {@link MediaSourceEventListener}s. */
final class EventDispatcher {
@Nullable private final Handler handler;
@Nullable private final MediaSourceEventListener listener;
private final CopyOnWriteArrayList<ListenerAndHandler> listenerAndHandlers;
private final long mediaTimeOffsetMs;
public EventDispatcher(@Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
this(handler, listener, 0);
/** Create event dispatcher. */
/* package */ EventDispatcher() {
this(
/* listenerAndHandlers= */ new CopyOnWriteArrayList<ListenerAndHandler>(),
/* mediaTimeOffsetMs= */ 0);
}
public EventDispatcher(
@Nullable Handler handler,
@Nullable MediaSourceEventListener listener,
long mediaTimeOffsetMs) {
this.handler = listener != null ? Assertions.checkNotNull(handler) : null;
this.listener = listener;
private EventDispatcher(
CopyOnWriteArrayList<ListenerAndHandler> listenerAndHandlers, long mediaTimeOffsetMs) {
this.listenerAndHandlers = listenerAndHandlers;
this.mediaTimeOffsetMs = mediaTimeOffsetMs;
}
public EventDispatcher copyWithMediaTimeOffsetMs(long mediaTimeOffsetMs) {
return new EventDispatcher(handler, listener, mediaTimeOffsetMs);
/**
* Creates a view of the event dispatcher with a media time offset.
*
* @param mediaTimeOffsetMs The offset to be added to all media times, in milliseconds.
* @return A view of the event dispatcher with the added media time offset.
*/
@CheckResult
public EventDispatcher withMediaTimeOffsetMs(long mediaTimeOffsetMs) {
return new EventDispatcher(listenerAndHandlers, mediaTimeOffsetMs);
}
/**
* Adds a listener to the event dispatcher.
*
* @param handler A handler on the which listener events will be posted.
* @param eventListener The listener to be added.
*/
public void addEventListener(Handler handler, MediaSourceEventListener eventListener) {
Assertions.checkArgument(handler != null && eventListener != null);
listenerAndHandlers.add(new ListenerAndHandler(handler, eventListener));
}
/**
* Removes a listener from the event dispatcher.
*
* @param eventListener The listener to be removed.
*/
public void removeEventListener(MediaSourceEventListener eventListener) {
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
if (listenerAndHandler.listener == eventListener) {
listenerAndHandlers.remove(listenerAndHandler);
}
}
}
/** Dispatches {@link #onLoadStarted(LoadEventInfo, MediaLoadData)}. */
public void loadStarted(DataSpec dataSpec, int dataType, long elapsedRealtimeMs) {
loadStarted(
dataSpec,
......@@ -238,12 +271,12 @@ public interface MediaSourceEventListener {
final long mediaStartTimeUs,
final long mediaEndTimeUs,
final long elapsedRealtimeMs) {
if (listener != null && handler != null) {
handler.post(
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
listenerAndHandler.handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadStarted(
listenerAndHandler.listener.onLoadStarted(
new LoadEventInfo(
dataSpec, elapsedRealtimeMs, /* loadDurationMs= */ 0, /* bytesLoaded= */ 0),
new MediaLoadData(
......@@ -293,12 +326,12 @@ public interface MediaSourceEventListener {
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded) {
if (listener != null && handler != null) {
handler.post(
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
listenerAndHandler.handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadCompleted(
listenerAndHandler.listener.onLoadCompleted(
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
new MediaLoadData(
dataType,
......@@ -347,12 +380,12 @@ public interface MediaSourceEventListener {
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded) {
if (listener != null && handler != null) {
handler.post(
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
listenerAndHandler.handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadCanceled(
listenerAndHandler.listener.onLoadCanceled(
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
new MediaLoadData(
dataType,
......@@ -407,12 +440,12 @@ public interface MediaSourceEventListener {
final long bytesLoaded,
final IOException error,
final boolean wasCanceled) {
if (listener != null && handler != null) {
handler.post(
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
listenerAndHandler.handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadError(
listenerAndHandler.listener.onLoadError(
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
new MediaLoadData(
dataType,
......@@ -432,12 +465,12 @@ public interface MediaSourceEventListener {
/** Dispatches {@link #onUpstreamDiscarded(MediaLoadData)}. */
public void upstreamDiscarded(
final int trackType, final long mediaStartTimeUs, final long mediaEndTimeUs) {
if (listener != null && handler != null) {
handler.post(
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
listenerAndHandler.handler.post(
new Runnable() {
@Override
public void run() {
listener.onUpstreamDiscarded(
listenerAndHandler.listener.onUpstreamDiscarded(
new MediaLoadData(
C.DATA_TYPE_MEDIA,
trackType,
......@@ -458,12 +491,12 @@ public interface MediaSourceEventListener {
final int trackSelectionReason,
final @Nullable Object trackSelectionData,
final long mediaTimeUs) {
if (listener != null && handler != null) {
handler.post(
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
listenerAndHandler.handler.post(
new Runnable() {
@Override
public void run() {
listener.onDownstreamFormatChanged(
listenerAndHandler.listener.onDownstreamFormatChanged(
new MediaLoadData(
C.DATA_TYPE_MEDIA,
trackType,
......@@ -481,5 +514,16 @@ public interface MediaSourceEventListener {
long mediaTimeMs = C.usToMs(mediaTimeUs);
return mediaTimeMs == C.TIME_UNSET ? C.TIME_UNSET : mediaTimeOffsetMs + mediaTimeMs;
}
private static final class ListenerAndHandler {
public final Handler handler;
public final MediaSourceEventListener listener;
public ListenerAndHandler(Handler handler, MediaSourceEventListener listener) {
this.handler = handler;
this.listener = listener;
}
}
}
}
......@@ -21,7 +21,6 @@ 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.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
......@@ -102,8 +101,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
}
/**
* Returns a new {@link ExtractorMediaSource} using the current parameters. Media source events
* will not be delivered.
* Returns a new {@link ExtractorMediaSource} using the current parameters.
*
* @param uri The {@link Uri}.
* @param format The {@link Format} of the media stream.
......@@ -111,35 +109,32 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
* @return The new {@link ExtractorMediaSource}.
*/
public SingleSampleMediaSource createMediaSource(Uri uri, Format format, long durationUs) {
return createMediaSource(uri, format, durationUs, null, null);
isCreateCalled = true;
return new SingleSampleMediaSource(
uri,
dataSourceFactory,
format,
durationUs,
minLoadableRetryCount,
treatLoadErrorsAsEndOfStream);
}
/**
* Returns a new {@link SingleSampleMediaSource} using the current parameters.
*
* @param uri The {@link Uri}.
* @param format The {@link Format} of the media stream.
* @param durationUs The duration of the media stream in microseconds.
* @param eventHandler A handler for events.
* @param eventListener A listener of events., Format format, long durationUs
* @return The newly built {@link SingleSampleMediaSource}.
* @deprecated Use {@link #createMediaSource(Uri, Format, long)} and {@link
* #addEventListener(Handler, MediaSourceEventListener)} instead.
*/
@Deprecated
public SingleSampleMediaSource createMediaSource(
Uri uri,
Format format,
long durationUs,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
isCreateCalled = true;
return new SingleSampleMediaSource(
uri,
dataSourceFactory,
format,
durationUs,
minLoadableRetryCount,
eventHandler,
eventListener,
treatLoadErrorsAsEndOfStream);
SingleSampleMediaSource mediaSource = createMediaSource(uri, format, durationUs);
if (eventHandler != null && eventListener != null) {
mediaSource.addEventListener(eventHandler, eventListener);
}
return mediaSource;
}
}
......@@ -188,7 +183,13 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
Format format,
long durationUs,
int minLoadableRetryCount) {
this(uri, dataSourceFactory, format, durationUs, minLoadableRetryCount, null, null, false);
this(
uri,
dataSourceFactory,
format,
durationUs,
minLoadableRetryCount,
/* treatLoadErrorsAsEndOfStream= */ false);
}
/**
......@@ -223,9 +224,10 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
format,
durationUs,
minLoadableRetryCount,
eventHandler,
eventListener == null ? null : new EventListenerWrapper(eventListener, eventSourceId),
treatLoadErrorsAsEndOfStream);
if (eventHandler != null && eventListener != null) {
addEventListener(eventHandler, new EventListenerWrapper(eventListener, eventSourceId));
}
}
private SingleSampleMediaSource(
......@@ -234,15 +236,13 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
Format format,
long durationUs,
int minLoadableRetryCount,
Handler eventHandler,
MediaSourceEventListener eventListener,
boolean treatLoadErrorsAsEndOfStream) {
this.dataSourceFactory = dataSourceFactory;
this.format = format;
this.durationUs = durationUs;
this.minLoadableRetryCount = minLoadableRetryCount;
this.treatLoadErrorsAsEndOfStream = treatLoadErrorsAsEndOfStream;
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
this.eventDispatcher = getEventDispatcher();
dataSpec = new DataSpec(uri);
timeline = new SinglePeriodTimeline(durationUs, true, false);
}
......
......@@ -51,13 +51,9 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
* Creates a new {@link MediaSource} for loading the ad media with the specified {@code uri}.
*
* @param uri The URI of the media or manifest to play.
* @param handler A handler for listener events. May be null if delivery of events is not
* required.
* @param listener A listener for events. May be null if delivery of events is not required.
* @return The new media source.
*/
MediaSource createMediaSource(
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener);
MediaSource createMediaSource(Uri uri);
/**
* Returns the content types supported by media sources created by this factory. Each element
......@@ -224,8 +220,8 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
int adIndexInAdGroup = id.adIndexInAdGroup;
if (adGroupMediaSources[adGroupIndex].length <= adIndexInAdGroup) {
Uri adUri = adPlaybackState.adGroups[id.adGroupIndex].uris[id.adIndexInAdGroup];
MediaSource adMediaSource =
adMediaSourceFactory.createMediaSource(adUri, eventHandler, eventListener);
MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adUri);
adMediaSource.addEventListener(eventHandler, eventListener);
int oldAdCount = adGroupMediaSources[id.adGroupIndex].length;
if (adIndexInAdGroup >= oldAdCount) {
int adCount = adIndexInAdGroup + 1;
......
......@@ -167,15 +167,10 @@ public final class DashMediaSource extends BaseMediaSource {
* sideloaded manifest.
*
* @param manifest The manifest. {@link DashManifest#dynamic} must be false.
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return The new {@link DashMediaSource}.
* @throws IllegalArgumentException If {@link DashManifest#dynamic} is true.
*/
public DashMediaSource createMediaSource(
DashManifest manifest,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
public DashMediaSource createMediaSource(DashManifest manifest) {
Assertions.checkArgument(!manifest.dynamic);
isCreateCalled = true;
return new DashMediaSource(
......@@ -186,35 +181,33 @@ public final class DashMediaSource extends BaseMediaSource {
chunkSourceFactory,
compositeSequenceableLoaderFactory,
minLoadableRetryCount,
livePresentationDelayMs,
eventHandler,
eventListener);
livePresentationDelayMs);
}
/**
* Returns a new {@link DashMediaSource} using the current parameters. Media source events will
* not be delivered.
*
* @param manifestUri The manifest {@link Uri}.
* @return The new {@link DashMediaSource}.
* @deprecated Use {@link #createMediaSource(DashManifest)} and {@link
* #addEventListener(Handler, MediaSourceEventListener)} instead.
*/
public DashMediaSource createMediaSource(Uri manifestUri) {
return createMediaSource(manifestUri, null, null);
@Deprecated
public DashMediaSource createMediaSource(
DashManifest manifest,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
DashMediaSource mediaSource = createMediaSource(manifest);
if (eventHandler != null && eventListener != null) {
mediaSource.addEventListener(eventHandler, eventListener);
}
return mediaSource;
}
/**
* Returns a new {@link DashMediaSource} using the current parameters.
*
* @param manifestUri The manifest {@link Uri}.
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return The new {@link DashMediaSource}.
*/
@Override
public DashMediaSource createMediaSource(
Uri manifestUri,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
public DashMediaSource createMediaSource(Uri manifestUri) {
isCreateCalled = true;
if (manifestParser == null) {
manifestParser = new DashManifestParser();
......@@ -227,9 +220,23 @@ public final class DashMediaSource extends BaseMediaSource {
chunkSourceFactory,
compositeSequenceableLoaderFactory,
minLoadableRetryCount,
livePresentationDelayMs,
eventHandler,
eventListener);
livePresentationDelayMs);
}
/**
* @deprecated Use {@link #createMediaSource(Uri)} and {@link #addEventListener(Handler,
* MediaSourceEventListener)} instead.
*/
@Deprecated
public DashMediaSource createMediaSource(
Uri manifestUri,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
DashMediaSource mediaSource = createMediaSource(manifestUri);
if (eventHandler != null && eventListener != null) {
mediaSource.addEventListener(eventHandler, eventListener);
}
return mediaSource;
}
@Override
......@@ -340,9 +347,18 @@ public final class DashMediaSource extends BaseMediaSource {
int minLoadableRetryCount,
Handler eventHandler,
MediaSourceEventListener eventListener) {
this(manifest, null, null, null, chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS, eventHandler, eventListener);
this(
manifest,
null,
null,
null,
chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(),
minLoadableRetryCount,
DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS);
if (eventHandler != null && eventListener != null) {
addEventListener(eventHandler, eventListener);
}
}
/**
......@@ -427,9 +443,18 @@ public final class DashMediaSource extends BaseMediaSource {
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
livePresentationDelayMs, eventHandler, eventListener);
this(
null,
manifestUri,
manifestDataSourceFactory,
manifestParser,
chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(),
minLoadableRetryCount,
livePresentationDelayMs);
if (eventHandler != null && eventListener != null) {
addEventListener(eventHandler, eventListener);
}
}
private DashMediaSource(
......@@ -440,9 +465,7 @@ public final class DashMediaSource extends BaseMediaSource {
DashChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
int minLoadableRetryCount,
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
long livePresentationDelayMs) {
this.initialManifestUri = manifestUri;
this.manifest = manifest;
this.manifestUri = manifestUri;
......@@ -453,7 +476,7 @@ public final class DashMediaSource extends BaseMediaSource {
this.livePresentationDelayMs = livePresentationDelayMs;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
sideloadedManifest = manifest != null;
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
eventDispatcher = getEventDispatcher();
manifestUriLock = new Object();
periodsById = new SparseArray<>();
playerEmsgCallback = new DefaultPlayerEmsgCallback();
......@@ -516,8 +539,8 @@ public final class DashMediaSource extends BaseMediaSource {
@Override
public MediaPeriod createPeriod(MediaPeriodId periodId, Allocator allocator) {
int periodIndex = periodId.periodIndex;
EventDispatcher periodEventDispatcher = eventDispatcher.copyWithMediaTimeOffsetMs(
manifest.getPeriod(periodIndex).startMs);
EventDispatcher periodEventDispatcher =
eventDispatcher.withMediaTimeOffsetMs(manifest.getPeriod(periodIndex).startMs);
DashMediaPeriod mediaPeriod =
new DashMediaPeriod(
firstPeriodId + periodIndex,
......
......@@ -164,28 +164,12 @@ public final class HlsMediaSource extends BaseMediaSource
}
/**
* Returns a new {@link HlsMediaSource} using the current parameters. Media source events will
* not be delivered.
*
* @return The new {@link HlsMediaSource}.
*/
public HlsMediaSource createMediaSource(Uri playlistUri) {
return createMediaSource(playlistUri, null, null);
}
/**
* Returns a new {@link HlsMediaSource} using the current parameters.
*
* @param playlistUri The playlist {@link Uri}.
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return The new {@link HlsMediaSource}.
*/
@Override
public HlsMediaSource createMediaSource(
Uri playlistUri,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
public HlsMediaSource createMediaSource(Uri playlistUri) {
isCreateCalled = true;
if (playlistParser == null) {
playlistParser = new HlsPlaylistParser();
......@@ -196,12 +180,26 @@ public final class HlsMediaSource extends BaseMediaSource
extractorFactory,
compositeSequenceableLoaderFactory,
minLoadableRetryCount,
eventHandler,
eventListener,
playlistParser,
allowChunklessPreparation);
}
/**
* @deprecated Use {@link #createMediaSource(Uri)} and {@link #addEventListener(Handler,
* MediaSourceEventListener)} instead.
*/
@Deprecated
public HlsMediaSource createMediaSource(
Uri playlistUri,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
HlsMediaSource mediaSource = createMediaSource(playlistUri);
if (eventHandler != null && eventListener != null) {
mediaSource.addEventListener(eventHandler, eventListener);
}
return mediaSource;
}
@Override
public int[] getSupportedTypes() {
return new int[] {C.TYPE_HLS};
......@@ -294,10 +292,11 @@ public final class HlsMediaSource extends BaseMediaSource
extractorFactory,
new DefaultCompositeSequenceableLoaderFactory(),
minLoadableRetryCount,
eventHandler,
eventListener,
playlistParser,
false);
if (eventHandler != null && eventListener != null) {
addEventListener(eventHandler, eventListener);
}
}
private HlsMediaSource(
......@@ -306,8 +305,6 @@ public final class HlsMediaSource extends BaseMediaSource
HlsExtractorFactory extractorFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
int minLoadableRetryCount,
Handler eventHandler,
MediaSourceEventListener eventListener,
ParsingLoadable.Parser<HlsPlaylist> playlistParser,
boolean allowChunklessPreparation) {
this.manifestUri = manifestUri;
......@@ -317,7 +314,7 @@ public final class HlsMediaSource extends BaseMediaSource
this.minLoadableRetryCount = minLoadableRetryCount;
this.playlistParser = playlistParser;
this.allowChunklessPreparation = allowChunklessPreparation;
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
eventDispatcher = getEventDispatcher();
}
@Override
......
......@@ -153,15 +153,10 @@ public final class SsMediaSource extends BaseMediaSource
* manifest.
*
* @param manifest The manifest. {@link SsManifest#isLive} must be false.
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return The new {@link SsMediaSource}.
* @throws IllegalArgumentException If {@link SsManifest#isLive} is true.
*/
public SsMediaSource createMediaSource(
SsManifest manifest,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
public SsMediaSource createMediaSource(SsManifest manifest) {
Assertions.checkArgument(!manifest.isLive);
isCreateCalled = true;
return new SsMediaSource(
......@@ -172,35 +167,33 @@ public final class SsMediaSource extends BaseMediaSource
chunkSourceFactory,
compositeSequenceableLoaderFactory,
minLoadableRetryCount,
livePresentationDelayMs,
eventHandler,
eventListener);
livePresentationDelayMs);
}
/**
* Returns a new {@link SsMediaSource} using the current parameters. Media source events will
* not be delivered.
*
* @param manifestUri The manifest {@link Uri}.
* @return The new {@link SsMediaSource}.
* @deprecated Use {@link #createMediaSource(SsManifest)} and {@link #addEventListener(Handler,
* MediaSourceEventListener)} instead.
*/
public SsMediaSource createMediaSource(Uri manifestUri) {
return createMediaSource(manifestUri, null, null);
@Deprecated
public SsMediaSource createMediaSource(
SsManifest manifest,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
SsMediaSource mediaSource = createMediaSource(manifest);
if (eventHandler != null && eventListener != null) {
mediaSource.addEventListener(eventHandler, eventListener);
}
return mediaSource;
}
/**
* Returns a new {@link SsMediaSource} using the current parameters.
*
* @param manifestUri The manifest {@link Uri}.
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return The new {@link SsMediaSource}.
*/
@Override
public SsMediaSource createMediaSource(
Uri manifestUri,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
public SsMediaSource createMediaSource(Uri manifestUri) {
isCreateCalled = true;
if (manifestParser == null) {
manifestParser = new SsManifestParser();
......@@ -213,9 +206,23 @@ public final class SsMediaSource extends BaseMediaSource
chunkSourceFactory,
compositeSequenceableLoaderFactory,
minLoadableRetryCount,
livePresentationDelayMs,
eventHandler,
eventListener);
livePresentationDelayMs);
}
/**
* @deprecated Use {@link #createMediaSource(Uri)} and {@link #addEventListener(Handler,
* MediaSourceEventListener)} instead.
*/
@Deprecated
public SsMediaSource createMediaSource(
Uri manifestUri,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener) {
SsMediaSource mediaSource = createMediaSource(manifestUri);
if (eventHandler != null && eventListener != null) {
mediaSource.addEventListener(eventHandler, eventListener);
}
return mediaSource;
}
@Override
......@@ -300,9 +307,18 @@ public final class SsMediaSource extends BaseMediaSource
int minLoadableRetryCount,
Handler eventHandler,
MediaSourceEventListener eventListener) {
this(manifest, null, null, null, chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
DEFAULT_LIVE_PRESENTATION_DELAY_MS, eventHandler, eventListener);
this(
manifest,
null,
null,
null,
chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(),
minLoadableRetryCount,
DEFAULT_LIVE_PRESENTATION_DELAY_MS);
if (eventHandler != null && eventListener != null) {
addEventListener(eventHandler, eventListener);
}
}
/**
......@@ -383,9 +399,18 @@ public final class SsMediaSource extends BaseMediaSource
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
livePresentationDelayMs, eventHandler, eventListener);
this(
null,
manifestUri,
manifestDataSourceFactory,
manifestParser,
chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(),
minLoadableRetryCount,
livePresentationDelayMs);
if (eventHandler != null && eventListener != null) {
addEventListener(eventHandler, eventListener);
}
}
private SsMediaSource(
......@@ -396,9 +421,7 @@ public final class SsMediaSource extends BaseMediaSource
SsChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
int minLoadableRetryCount,
long livePresentationDelayMs,
Handler eventHandler,
MediaSourceEventListener eventListener) {
long livePresentationDelayMs) {
Assertions.checkState(manifest == null || !manifest.isLive);
this.manifest = manifest;
this.manifestUri = manifestUri == null ? null : SsUtil.fixManifestUri(manifestUri);
......@@ -408,7 +431,7 @@ public final class SsMediaSource extends BaseMediaSource
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
this.minLoadableRetryCount = minLoadableRetryCount;
this.livePresentationDelayMs = livePresentationDelayMs;
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
this.eventDispatcher = getEventDispatcher();
sideloadedManifest = manifest != null;
mediaPeriods = new ArrayList<>();
}
......
......@@ -20,7 +20,6 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.upstream.Allocator;
......@@ -30,7 +29,6 @@ import com.google.android.exoplayer2.upstream.Allocator;
*/
public class FakeAdaptiveMediaSource extends FakeMediaSource {
private final EventDispatcher eventDispatcher;
private final FakeChunkSource.Factory chunkSourceFactory;
public FakeAdaptiveMediaSource(
......@@ -41,16 +39,16 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource {
MediaSourceEventListener eventListener,
FakeChunkSource.Factory chunkSourceFactory) {
super(timeline, manifest, trackGroupArray);
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
this.chunkSourceFactory = chunkSourceFactory;
addEventListener(eventHandler, eventListener);
}
@Override
protected FakeMediaPeriod createFakeMediaPeriod(MediaPeriodId id, TrackGroupArray trackGroupArray,
Allocator allocator) {
Period period = timeline.getPeriod(id.periodIndex, new Period());
return new FakeAdaptiveMediaPeriod(trackGroupArray, eventDispatcher, allocator,
chunkSourceFactory, period.durationUs);
return new FakeAdaptiveMediaPeriod(
trackGroupArray, getEventDispatcher(), allocator, chunkSourceFactory, period.durationUs);
}
}
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