diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java index ae0fdadfc9..a10692bca7 100644 --- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java +++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java @@ -157,8 +157,10 @@ import com.google.android.gms.cast.framework.CastContext; Uri uri = Uri.parse(sample.uri); switch (sample.mimeType) { case DemoUtil.MIME_TYPE_SS: - return new SsMediaSource(uri, DATA_SOURCE_FACTORY, - new DefaultSsChunkSource.Factory(DATA_SOURCE_FACTORY), null, null); + return SsMediaSource.Builder + .forManifestUri(uri, DATA_SOURCE_FACTORY, + new DefaultSsChunkSource.Factory(DATA_SOURCE_FACTORY)) + .build(); case DemoUtil.MIME_TYPE_DASH: return DashMediaSource.Builder .forManifestUri(uri, DATA_SOURCE_FACTORY, diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 614626077a..65e1c0e083 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -362,8 +362,11 @@ public class PlayerActivity extends Activity implements OnClickListener, : Util.inferContentType("." + overrideExtension); switch (type) { case C.TYPE_SS: - return new SsMediaSource(uri, buildDataSourceFactory(false), - new DefaultSsChunkSource.Factory(mediaDataSourceFactory), mainHandler, eventLogger); + return SsMediaSource.Builder + .forManifestUri(uri, buildDataSourceFactory(false), + new DefaultSsChunkSource.Factory(mediaDataSourceFactory)) + .setEventListener(mainHandler, eventLogger) + .build(); case C.TYPE_DASH: return DashMediaSource.Builder .forManifestUri(uri, buildDataSourceFactory(false), diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 3d5a9c393d..54a5086d3b 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -58,63 +58,6 @@ public final class DashMediaSource implements MediaSource { ExoPlayerLibraryInfo.registerModule("goog.exo.dash"); } - /** - * The default minimum number of times to retry loading data prior to failing. - */ - public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; - /** - * A constant indicating that the presentation delay for live streams should be set to - * {@link DashManifest#suggestedPresentationDelay} if specified by the manifest, or - * {@link #DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS} otherwise. The presentation delay is the - * duration by which the default start position precedes the end of the live window. - */ - public static final long DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS = -1; - /** - * A fixed default presentation delay for live streams. The presentation delay is the duration - * by which the default start position precedes the end of the live window. - */ - public static final long DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS = 30000; - - /** - * The interval in milliseconds between invocations of - * {@link MediaSource.Listener#onSourceInfoRefreshed(MediaSource, Timeline, Object)} when the - * source's {@link Timeline} is changing dynamically (for example, for incomplete live streams). - */ - private static final int NOTIFY_MANIFEST_INTERVAL_MS = 5000; - /** - * The minimum default start position for live streams, relative to the start of the live window. - */ - private static final long MIN_LIVE_DEFAULT_START_POSITION_US = 5000000; - - private static final String TAG = "DashMediaSource"; - - private final boolean sideloadedManifest; - private final DataSource.Factory manifestDataSourceFactory; - private final DashChunkSource.Factory chunkSourceFactory; - private final int minLoadableRetryCount; - private final long livePresentationDelayMs; - private final EventDispatcher eventDispatcher; - private final ParsingLoadable.Parser manifestParser; - private final ManifestCallback manifestCallback; - private final Object manifestUriLock; - private final SparseArray periodsById; - private final Runnable refreshManifestRunnable; - private final Runnable simulateManifestRefreshRunnable; - - private Listener sourceListener; - private DataSource dataSource; - private Loader loader; - private LoaderErrorThrower loaderErrorThrower; - - private Uri manifestUri; - private long manifestLoadStartTimestamp; - private long manifestLoadEndTimestamp; - private DashManifest manifest; - private Handler handler; - private long elapsedRealtimeOffsetMs; - - private int firstPeriodId; - /** * Builder for {@link DashMediaSource}. Each builder instance can only be used once. */ @@ -142,6 +85,7 @@ public final class DashMediaSource implements MediaSource { */ public static Builder forSideLoadedManifest(DashManifest manifest, DashChunkSource.Factory chunkSourceFactory) { + Assertions.checkArgument(!manifest.dynamic); return new Builder(manifest, null, null, chunkSourceFactory); } @@ -227,7 +171,6 @@ public final class DashMediaSource implements MediaSource { return this; } - /** * Builds a new {@link DashMediaSource} using the current parameters. *

@@ -236,7 +179,6 @@ public final class DashMediaSource implements MediaSource { * @return The newly built {@link DashMediaSource}. */ public DashMediaSource build() { - Assertions.checkArgument(manifest == null || !manifest.dynamic); Assertions.checkArgument((eventListener == null) == (eventHandler == null)); Assertions.checkState(!isBuildCalled); isBuildCalled = true; @@ -251,6 +193,63 @@ public final class DashMediaSource implements MediaSource { } + /** + * The default minimum number of times to retry loading data prior to failing. + */ + public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; + /** + * A constant indicating that the presentation delay for live streams should be set to + * {@link DashManifest#suggestedPresentationDelay} if specified by the manifest, or + * {@link #DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS} otherwise. The presentation delay is the + * duration by which the default start position precedes the end of the live window. + */ + public static final long DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS = -1; + /** + * A fixed default presentation delay for live streams. The presentation delay is the duration + * by which the default start position precedes the end of the live window. + */ + public static final long DEFAULT_LIVE_PRESENTATION_DELAY_FIXED_MS = 30000; + + /** + * The interval in milliseconds between invocations of + * {@link MediaSource.Listener#onSourceInfoRefreshed(MediaSource, Timeline, Object)} when the + * source's {@link Timeline} is changing dynamically (for example, for incomplete live streams). + */ + private static final int NOTIFY_MANIFEST_INTERVAL_MS = 5000; + /** + * The minimum default start position for live streams, relative to the start of the live window. + */ + private static final long MIN_LIVE_DEFAULT_START_POSITION_US = 5000000; + + private static final String TAG = "DashMediaSource"; + + private final boolean sideloadedManifest; + private final DataSource.Factory manifestDataSourceFactory; + private final DashChunkSource.Factory chunkSourceFactory; + private final int minLoadableRetryCount; + private final long livePresentationDelayMs; + private final EventDispatcher eventDispatcher; + private final ParsingLoadable.Parser manifestParser; + private final ManifestCallback manifestCallback; + private final Object manifestUriLock; + private final SparseArray periodsById; + private final Runnable refreshManifestRunnable; + private final Runnable simulateManifestRefreshRunnable; + + private Listener sourceListener; + private DataSource dataSource; + private Loader loader; + private LoaderErrorThrower loaderErrorThrower; + + private Uri manifestUri; + private long manifestLoadStartTimestamp; + private long manifestLoadEndTimestamp; + private DashManifest manifest; + private Handler handler; + private long elapsedRealtimeOffsetMs; + + private int firstPeriodId; + /** * Constructs an instance to play a given {@link DashManifest}, which must be static. * diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 548f787741..5a93847428 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.smoothstreaming; import android.net.Uri; 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; @@ -51,6 +52,138 @@ public final class SsMediaSource implements MediaSource, ExoPlayerLibraryInfo.registerModule("goog.exo.smoothstreaming"); } + /** + * Builder for {@link SsMediaSource}. Each builder instance can only be used once. + */ + public static final class Builder { + + private final SsManifest manifest; + private final Uri manifestUri; + private final DataSource.Factory manifestDataSourceFactory; + private final SsChunkSource.Factory chunkSourceFactory; + + private ParsingLoadable.Parser manifestParser; + private AdaptiveMediaSourceEventListener eventListener; + private Handler eventHandler; + + private int minLoadableRetryCount; + private long livePresentationDelayMs; + private boolean isBuildCalled; + + /** + * Creates a {@link Builder} for a {@link SsMediaSource} with a side-loaded manifest. + * + * @param manifest The manifest. {@link SsManifest#isLive} must be false. + * @param chunkSourceFactory A factory for {@link SsChunkSource} instances. + * @return A new builder. + */ + public static Builder forSideLoadedManifest(SsManifest manifest, + SsChunkSource.Factory chunkSourceFactory) { + Assertions.checkArgument(!manifest.isLive); + return new Builder(manifest, null, null, chunkSourceFactory); + } + + /** + * Creates a {@link Builder} for a {@link SsMediaSource} with a loadable manifest Uri. + * + * @param manifestUri The manifest {@link Uri}. + * @param manifestDataSourceFactory A factory for {@link DataSource} instances that will be used + * to load (and refresh) the manifest. + * @param chunkSourceFactory A factory for {@link SsChunkSource} instances. + * @return A new builder. + */ + public static Builder forManifestUri(Uri manifestUri, + DataSource.Factory manifestDataSourceFactory, SsChunkSource.Factory chunkSourceFactory) { + return new Builder(null, manifestUri, manifestDataSourceFactory, chunkSourceFactory); + } + + private Builder(@Nullable SsManifest manifest, @Nullable Uri manifestUri, + @Nullable DataSource.Factory manifestDataSourceFactory, + SsChunkSource.Factory chunkSourceFactory) { + this.manifest = manifest; + this.manifestUri = manifestUri; + this.manifestDataSourceFactory = manifestDataSourceFactory; + this.chunkSourceFactory = chunkSourceFactory; + + minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT; + livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS; + } + + /** + * Sets the minimum number of times to retry if a loading error occurs. The default value is + * {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}. + * + * @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs. + * @return This builder. + */ + public Builder setMinLoadableRetryCount(int minLoadableRetryCount) { + this.minLoadableRetryCount = minLoadableRetryCount; + return this; + } + + /** + * Sets the duration in milliseconds by which the default start position should precede the end + * of the live window for live playbacks. The default value is + * {@link #DEFAULT_LIVE_PRESENTATION_DELAY_MS}. + * + * @param livePresentationDelayMs For live playbacks, the duration in milliseconds by which the + * default start position should precede the end of the live window. + * @return This builder. + */ + public Builder setLivePresentationDelayMs(long livePresentationDelayMs) { + this.livePresentationDelayMs = livePresentationDelayMs; + return this; + } + + /** + * Sets the listener to respond to adaptive {@link MediaSource} events and the handler to + * deliver these events. + * + * @param eventHandler A handler for events. + * @param eventListener A listener of events. + * @return This builder. + */ + public Builder setEventListener(Handler eventHandler, + AdaptiveMediaSourceEventListener eventListener) { + this.eventHandler = eventHandler; + this.eventListener = eventListener; + return this; + } + + /** + * Sets the manifest parser to parse loaded manifest data. The default is an instance of + * {@link SsManifestParser}, or {@code null} if the manifest is sideloaded. + * + * @param manifestParser A parser for loaded manifest data. + * @return This builder. + */ + public Builder setManifestParser(ParsingLoadable.Parser manifestParser) { + this.manifestParser = manifestParser; + return this; + } + + /** + * Builds a new {@link SsMediaSource} using the current parameters. + *

+ * After this call, the builder should not be re-used. + * + * @return The newly built {@link SsMediaSource}. + */ + public SsMediaSource build() { + Assertions.checkArgument((eventListener == null) == (eventHandler == null)); + Assertions.checkState(!isBuildCalled); + isBuildCalled = true; + boolean loadableManifestUri = manifestUri != null; + if (loadableManifestUri && manifestParser == null) { + manifestParser = new SsManifestParser(); + } + return new SsMediaSource(manifest, manifestUri, manifestDataSourceFactory, manifestParser, + chunkSourceFactory, minLoadableRetryCount, livePresentationDelayMs, eventHandler, + eventListener); + } + + } + /** * The default minimum number of times to retry loading data prior to failing. */ @@ -96,7 +229,9 @@ public final class SsMediaSource implements MediaSource, * @param chunkSourceFactory A factory for {@link SsChunkSource} instances. * @param eventHandler A handler for events. 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. + * @deprecated Use {@link Builder} instead. */ + @Deprecated public SsMediaSource(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory, Handler eventHandler, AdaptiveMediaSourceEventListener eventListener) { this(manifest, chunkSourceFactory, DEFAULT_MIN_LOADABLE_RETRY_COUNT, @@ -111,7 +246,9 @@ public final class SsMediaSource implements MediaSource, * @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs. * @param eventHandler A handler for events. 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. + * @deprecated Use {@link Builder} instead. */ + @Deprecated public SsMediaSource(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, Handler eventHandler, AdaptiveMediaSourceEventListener eventListener) { @@ -129,7 +266,9 @@ public final class SsMediaSource implements MediaSource, * @param chunkSourceFactory A factory for {@link SsChunkSource} instances. * @param eventHandler A handler for events. 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. + * @deprecated Use {@link Builder} instead. */ + @Deprecated public SsMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory, SsChunkSource.Factory chunkSourceFactory, Handler eventHandler, AdaptiveMediaSourceEventListener eventListener) { @@ -151,7 +290,9 @@ public final class SsMediaSource implements MediaSource, * default start position should precede the end of the live window. * @param eventHandler A handler for events. 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. + * @deprecated Use {@link Builder} instead. */ + @Deprecated public SsMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory, SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, long livePresentationDelayMs, Handler eventHandler, @@ -174,7 +315,9 @@ public final class SsMediaSource implements MediaSource, * default start position should precede the end of the live window. * @param eventHandler A handler for events. 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. + * @deprecated Use {@link Builder} instead. */ + @Deprecated public SsMediaSource(Uri manifestUri, DataSource.Factory manifestDataSourceFactory, ParsingLoadable.Parser manifestParser, SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,