diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java index 8f85a0ac17..62a40b0110 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.source; +import static com.google.android.exoplayer2.util.Util.castNonNull; + import android.content.Context; import android.net.Uri; import android.util.SparseArray; @@ -107,6 +109,9 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { @Nullable private DrmSessionManager drmSessionManager; @Nullable private List streamKeys; @Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy; + private long liveTargetOffsetMs; + private float liveMinSpeed; + private float liveMaxSpeed; /** * Creates a new instance. @@ -155,6 +160,9 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { for (int i = 0; i < mediaSourceFactories.size(); i++) { supportedTypes[i] = mediaSourceFactories.keyAt(i); } + liveTargetOffsetMs = C.TIME_UNSET; + liveMinSpeed = C.RATE_UNSET; + liveMaxSpeed = C.RATE_UNSET; } /** @@ -181,6 +189,42 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { return this; } + /** + * Sets the target live offset for live streams, in milliseconds. + * + * @param liveTargetOffsetMs The target live offset, in milliseconds, or {@link C#TIME_UNSET} to + * use the media-defined default. + * @return This factory, for convenience. + */ + public DefaultMediaSourceFactory setLiveTargetOffsetMs(long liveTargetOffsetMs) { + this.liveTargetOffsetMs = liveTargetOffsetMs; + return this; + } + + /** + * Sets the minimum playback speed for live streams. + * + * @param minSpeed The minimum playback speed for live streams, or {@link C#RATE_UNSET} to use the + * media-defined default. + * @return This factory, for convenience. + */ + public DefaultMediaSourceFactory setLiveMinSpeed(float minSpeed) { + this.liveMinSpeed = minSpeed; + return this; + } + + /** + * Sets the maximum playback speed for live streams. + * + * @param maxSpeed The maximum playback speed for live streams, or {@link C#RATE_UNSET} to use the + * media-defined default. + * @return This factory, for convenience. + */ + public DefaultMediaSourceFactory setLiveMaxSpeed(float maxSpeed) { + this.liveMaxSpeed = maxSpeed; + return this; + } + @Override public DefaultMediaSourceFactory setDrmHttpDataSourceFactory( @Nullable HttpDataSource.Factory drmHttpDataSourceFactory) { @@ -244,9 +288,33 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory { : streamKeys); mediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy); + // Make sure to retain the very same media item instance, if no value needs to be overridden. + if ((mediaItem.liveConfiguration.targetLiveOffsetMs == C.TIME_UNSET + && liveTargetOffsetMs != C.TIME_UNSET) + || (mediaItem.liveConfiguration.minPlaybackSpeed == C.RATE_UNSET + && liveMinSpeed != C.RATE_UNSET) + || (mediaItem.liveConfiguration.maxPlaybackSpeed == C.RATE_UNSET + && liveMaxSpeed != C.RATE_UNSET)) { + mediaItem = + mediaItem + .buildUpon() + .setLiveTargetOffsetMs( + mediaItem.liveConfiguration.targetLiveOffsetMs == C.TIME_UNSET + ? liveTargetOffsetMs + : mediaItem.liveConfiguration.targetLiveOffsetMs) + .setLiveMinPlaybackSpeed( + mediaItem.liveConfiguration.minPlaybackSpeed == C.RATE_UNSET + ? liveMinSpeed + : mediaItem.liveConfiguration.minPlaybackSpeed) + .setLiveMaxPlaybackSpeed( + mediaItem.liveConfiguration.maxPlaybackSpeed == C.RATE_UNSET + ? liveMaxSpeed + : mediaItem.liveConfiguration.maxPlaybackSpeed) + .build(); + } MediaSource mediaSource = mediaSourceFactory.createMediaSource(mediaItem); - List subtitles = mediaItem.playbackProperties.subtitles; + List subtitles = castNonNull(mediaItem.playbackProperties).subtitles; if (!subtitles.isEmpty()) { MediaSource[] mediaSources = new MediaSource[subtitles.size() + 1]; mediaSources[0] = mediaSource; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactoryTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactoryTest.java index d02f04d097..29fe5c690e 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactoryTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactoryTest.java @@ -235,4 +235,56 @@ public final class DefaultMediaSourceFactoryTest { assertThat(mediaSource).isNotInstanceOf(AdsMediaSource.class); } + + @Test + public void createMediaSource_undefinedLiveProperties_livePropertiesUnset() { + DefaultMediaSourceFactory defaultMediaSourceFactory = + new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext()); + MediaItem mediaItem = new MediaItem.Builder().setUri(URI_MEDIA + "/file.mp4").build(); + MediaSource mediaSource = defaultMediaSourceFactory.createMediaSource(mediaItem); + + MediaItem mediaItemFromSource = mediaSource.getMediaItem(); + + assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(C.TIME_UNSET); + assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(C.RATE_UNSET); + assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(C.RATE_UNSET); + } + + @Test + public void createMediaSource_withoutMediaItemProperties_usesFactoryLiveProperties() { + DefaultMediaSourceFactory defaultMediaSourceFactory = + new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext()) + .setLiveTargetOffsetMs(20) + .setLiveMinSpeed(.1f) + .setLiveMaxSpeed(2.0f); + MediaItem mediaItem = new MediaItem.Builder().setUri(URI_MEDIA + "/file.mp4").build(); + MediaSource mediaSource = defaultMediaSourceFactory.createMediaSource(mediaItem); + + MediaItem mediaItemFromSource = mediaSource.getMediaItem(); + + assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(20); + assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(.1f); + assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(2.0f); + } + + @Test + public void createMediaSource_withMediaItemLiveProperties_overridesFactoryLiveProperties() { + DefaultMediaSourceFactory defaultMediaSourceFactory = + new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext()) + .setLiveTargetOffsetMs(20) + .setLiveMinSpeed(.1f) + .setLiveMaxSpeed(2.0f); + MediaItem mediaItem = + new MediaItem.Builder() + .setUri(URI_MEDIA + "/file.mp4") + .setLiveTargetOffsetMs(10) + .setLiveMinPlaybackSpeed(20.0f) + .setLiveMaxPlaybackSpeed(20.0f) + .build(); + MediaSource mediaSource = defaultMediaSourceFactory.createMediaSource(mediaItem); + + MediaItem mediaItemFromSource = mediaSource.getMediaItem(); + + assertThat(mediaItemFromSource).isEqualTo(mediaItem); + } }