Commit aab6aef4 by tonihei Committed by Oliver Woodman

Set min/max supported live offset in DashMediaSource.

In order to ensure we can update the values for new manifests but still use
the user provided override, we need to save the original and the updated MediaItem
seperately.

And in order to incorporate the existing logic for the min/max supported live
offset, which we already use to correct the target offset, also move both places
together so that all the adjustment happens in one place.

Logical adjustments to the previous min/max supported live offset:
 - Use the user-provided MediaItem values if set
 - Use the newly parsed ServiceDescription values if available.
 - Limit the minimum to 0 if the current time is in the window and we can
   assume to have low-latency stream.
 - Add minBufferTime from the manifest to ensure we don't reduce the live
   offset below this value.

Issue: #4904
PiperOrigin-RevId: 339452816
parent 32a72fa2
...@@ -427,6 +427,7 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -427,6 +427,7 @@ public final class DashMediaSource extends BaseMediaSource {
private static final String TAG = "DashMediaSource"; private static final String TAG = "DashMediaSource";
private final MediaItem originalMediaItem;
private final boolean sideloadedManifest; private final boolean sideloadedManifest;
private final DataSource.Factory manifestDataSourceFactory; private final DataSource.Factory manifestDataSourceFactory;
private final DashChunkSource.Factory chunkSourceFactory; private final DashChunkSource.Factory chunkSourceFactory;
...@@ -451,8 +452,7 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -451,8 +452,7 @@ public final class DashMediaSource extends BaseMediaSource {
private IOException manifestFatalError; private IOException manifestFatalError;
private Handler handler; private Handler handler;
private MediaItem mediaItem; private MediaItem updatedMediaItem;
private MediaItem.PlaybackProperties playbackProperties;
private Uri manifestUri; private Uri manifestUri;
private Uri initialManifestUri; private Uri initialManifestUri;
private DashManifest manifest; private DashManifest manifest;
...@@ -476,10 +476,10 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -476,10 +476,10 @@ public final class DashMediaSource extends BaseMediaSource {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
LoadErrorHandlingPolicy loadErrorHandlingPolicy, LoadErrorHandlingPolicy loadErrorHandlingPolicy,
long fallbackTargetLiveOffsetMs) { long fallbackTargetLiveOffsetMs) {
this.mediaItem = mediaItem; this.originalMediaItem = mediaItem;
this.playbackProperties = checkNotNull(mediaItem.playbackProperties); this.updatedMediaItem = mediaItem;
this.manifestUri = playbackProperties.uri; this.manifestUri = checkNotNull(mediaItem.playbackProperties).uri;
this.initialManifestUri = playbackProperties.uri; this.initialManifestUri = mediaItem.playbackProperties.uri;
this.manifest = manifest; this.manifest = manifest;
this.manifestDataSourceFactory = manifestDataSourceFactory; this.manifestDataSourceFactory = manifestDataSourceFactory;
this.manifestParser = manifestParser; this.manifestParser = manifestParser;
...@@ -531,12 +531,12 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -531,12 +531,12 @@ public final class DashMediaSource extends BaseMediaSource {
@Override @Override
@Nullable @Nullable
public Object getTag() { public Object getTag() {
return playbackProperties.tag; return castNonNull(updatedMediaItem.playbackProperties).tag;
} }
@Override @Override
public MediaItem getMediaItem() { public MediaItem getMediaItem() {
return mediaItem; return updatedMediaItem;
} }
@Override @Override
...@@ -692,9 +692,6 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -692,9 +692,6 @@ public final class DashMediaSource extends BaseMediaSource {
staleManifestReloadAttempt = 0; staleManifestReloadAttempt = 0;
} }
mediaItem = mergeLiveConfiguration(mediaItem, fallbackTargetLiveOffsetMs, newManifest);
playbackProperties = castNonNull(mediaItem.playbackProperties);
manifest = newManifest; manifest = newManifest;
manifestLoadPending &= manifest.dynamic; manifestLoadPending &= manifest.dynamic;
manifestLoadStartTimestampMs = elapsedRealtimeMs - loadDurationMs; manifestLoadStartTimestampMs = elapsedRealtimeMs - loadDurationMs;
...@@ -939,13 +936,13 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -939,13 +936,13 @@ public final class DashMediaSource extends BaseMediaSource {
long windowDefaultStartPositionUs = 0; long windowDefaultStartPositionUs = 0;
if (manifest.dynamic) { if (manifest.dynamic) {
ensureTargetLiveOffsetIsInLiveWindow( updateMediaItemLiveConfiguration(
/* nowPeriodTimeUs= */ currentStartTimeUs + nowUnixTimeUs - C.msToUs(windowStartTimeMs), /* nowPeriodTimeUs= */ currentStartTimeUs + nowUnixTimeUs - C.msToUs(windowStartTimeMs),
/* windowStartPeriodTimeUs= */ currentStartTimeUs, /* windowStartPeriodTimeUs= */ currentStartTimeUs,
/* windowEndPeriodTimeUs= */ currentEndTimeUs); /* windowEndPeriodTimeUs= */ currentEndTimeUs);
windowDefaultStartPositionUs = windowDefaultStartPositionUs =
nowUnixTimeUs nowUnixTimeUs
- C.msToUs(windowStartTimeMs + mediaItem.liveConfiguration.targetLiveOffsetMs); - C.msToUs(windowStartTimeMs + updatedMediaItem.liveConfiguration.targetLiveOffsetMs);
long minimumDefaultStartPositionUs = long minimumDefaultStartPositionUs =
min(MIN_LIVE_DEFAULT_START_POSITION_US, windowDurationUs / 2); min(MIN_LIVE_DEFAULT_START_POSITION_US, windowDurationUs / 2);
if (windowDefaultStartPositionUs < minimumDefaultStartPositionUs) { if (windowDefaultStartPositionUs < minimumDefaultStartPositionUs) {
...@@ -965,7 +962,7 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -965,7 +962,7 @@ public final class DashMediaSource extends BaseMediaSource {
windowDurationUs, windowDurationUs,
windowDefaultStartPositionUs, windowDefaultStartPositionUs,
manifest, manifest,
mediaItem); updatedMediaItem);
refreshSourceInfo(timeline); refreshSourceInfo(timeline);
if (!sideloadedManifest) { if (!sideloadedManifest) {
...@@ -999,24 +996,81 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -999,24 +996,81 @@ public final class DashMediaSource extends BaseMediaSource {
} }
} }
private void ensureTargetLiveOffsetIsInLiveWindow( private void updateMediaItemLiveConfiguration(
long nowPeriodTimeUs, long windowStartPeriodTimeUs, long windowEndPeriodTimeUs) { long nowPeriodTimeUs, long windowStartPeriodTimeUs, long windowEndPeriodTimeUs) {
long targetLiveOffsetUs = C.msToUs(mediaItem.liveConfiguration.targetLiveOffsetMs); long maxLiveOffsetMs;
long minOffsetUs = nowPeriodTimeUs - windowEndPeriodTimeUs; if (originalMediaItem.liveConfiguration.maxLiveOffsetMs != C.TIME_UNSET) {
if (targetLiveOffsetUs < minOffsetUs) { maxLiveOffsetMs = originalMediaItem.liveConfiguration.maxLiveOffsetMs;
targetLiveOffsetUs = minOffsetUs; } else if (manifest.serviceDescription != null
&& manifest.serviceDescription.maxOffsetMs != C.TIME_UNSET) {
maxLiveOffsetMs = manifest.serviceDescription.maxOffsetMs;
} else {
maxLiveOffsetMs = C.usToMs(nowPeriodTimeUs - windowStartPeriodTimeUs);
}
long minLiveOffsetMs;
if (originalMediaItem.liveConfiguration.minLiveOffsetMs != C.TIME_UNSET) {
minLiveOffsetMs = originalMediaItem.liveConfiguration.minLiveOffsetMs;
} else if (manifest.serviceDescription != null
&& manifest.serviceDescription.minOffsetMs != C.TIME_UNSET) {
minLiveOffsetMs = manifest.serviceDescription.minOffsetMs;
} else {
minLiveOffsetMs = C.usToMs(nowPeriodTimeUs - windowEndPeriodTimeUs);
if (minLiveOffsetMs < 0 && maxLiveOffsetMs > 0) {
// The current time is in the window, so assume all clocks are synchronized and set the
// minimum to a live offset of zero.
minLiveOffsetMs = 0;
}
if (manifest.minBufferTimeMs != C.TIME_UNSET) {
minLiveOffsetMs = min(minLiveOffsetMs + manifest.minBufferTimeMs, maxLiveOffsetMs);
}
} }
long maxOffsetUs = nowPeriodTimeUs - windowStartPeriodTimeUs; long targetOffsetMs;
if (targetLiveOffsetUs > maxOffsetUs) { if (updatedMediaItem.liveConfiguration.targetLiveOffsetMs != C.TIME_UNSET) {
// Keep existing target offset even if the media configuration changes.
targetOffsetMs = updatedMediaItem.liveConfiguration.targetLiveOffsetMs;
} else if (manifest.serviceDescription != null
&& manifest.serviceDescription.targetOffsetMs != C.TIME_UNSET) {
targetOffsetMs = manifest.serviceDescription.targetOffsetMs;
} else if (manifest.suggestedPresentationDelayMs != C.TIME_UNSET) {
targetOffsetMs = manifest.suggestedPresentationDelayMs;
} else {
targetOffsetMs = fallbackTargetLiveOffsetMs;
}
if (targetOffsetMs < minLiveOffsetMs) {
targetOffsetMs = minLiveOffsetMs;
}
if (targetOffsetMs > maxLiveOffsetMs) {
long windowDurationUs = windowEndPeriodTimeUs - windowStartPeriodTimeUs; long windowDurationUs = windowEndPeriodTimeUs - windowStartPeriodTimeUs;
targetLiveOffsetUs = long liveOffsetAtWindowStartUs = nowPeriodTimeUs - windowStartPeriodTimeUs;
maxOffsetUs - min(MIN_LIVE_DEFAULT_START_POSITION_US, windowDurationUs / 2); long safeDistanceFromWindowStartUs =
min(MIN_LIVE_DEFAULT_START_POSITION_US, windowDurationUs / 2);
long maxTargetOffsetForSafeDistanceToWindowStartMs =
C.usToMs(liveOffsetAtWindowStartUs - safeDistanceFromWindowStartUs);
targetOffsetMs =
Util.constrainValue(
maxTargetOffsetForSafeDistanceToWindowStartMs, minLiveOffsetMs, maxLiveOffsetMs);
}
float minPlaybackSpeed = C.RATE_UNSET;
if (originalMediaItem.liveConfiguration.minPlaybackSpeed != C.RATE_UNSET) {
minPlaybackSpeed = originalMediaItem.liveConfiguration.minPlaybackSpeed;
} else if (manifest.serviceDescription != null) {
minPlaybackSpeed = manifest.serviceDescription.minPlaybackSpeed;
} }
long targetLiveOffsetMs = C.usToMs(targetLiveOffsetUs); float maxPlaybackSpeed = C.RATE_UNSET;
if (mediaItem.liveConfiguration.targetLiveOffsetMs != targetLiveOffsetMs) { if (originalMediaItem.liveConfiguration.maxPlaybackSpeed != C.RATE_UNSET) {
mediaItem = mediaItem.buildUpon().setLiveTargetOffsetMs(targetLiveOffsetMs).build(); maxPlaybackSpeed = originalMediaItem.liveConfiguration.maxPlaybackSpeed;
playbackProperties = castNonNull(mediaItem.playbackProperties); } else if (manifest.serviceDescription != null) {
maxPlaybackSpeed = manifest.serviceDescription.maxPlaybackSpeed;
} }
updatedMediaItem =
originalMediaItem
.buildUpon()
.setLiveTargetOffsetMs(targetOffsetMs)
.setLiveMinOffsetMs(minLiveOffsetMs)
.setLiveMaxOffsetMs(maxLiveOffsetMs)
.setLiveMinPlaybackSpeed(minPlaybackSpeed)
.setLiveMaxPlaybackSpeed(maxPlaybackSpeed)
.build();
} }
private void scheduleManifestRefresh(long delayUntilNextLoadMs) { private void scheduleManifestRefresh(long delayUntilNextLoadMs) {
...@@ -1087,41 +1141,6 @@ public final class DashMediaSource extends BaseMediaSource { ...@@ -1087,41 +1141,6 @@ public final class DashMediaSource extends BaseMediaSource {
return LongMath.divide(intervalUs, 1000, RoundingMode.CEILING); return LongMath.divide(intervalUs, 1000, RoundingMode.CEILING);
} }
private static MediaItem mergeLiveConfiguration(
MediaItem mediaItem, long fallbackTargetLiveOffsetMs, DashManifest manifest) {
// Evaluate live config properties from media item and manifest according to precedence.
long liveTargetOffsetMs;
if (mediaItem.liveConfiguration.targetLiveOffsetMs != C.TIME_UNSET) {
liveTargetOffsetMs = mediaItem.liveConfiguration.targetLiveOffsetMs;
} else if (manifest.serviceDescription != null
&& manifest.serviceDescription.targetOffsetMs != C.TIME_UNSET) {
liveTargetOffsetMs = manifest.serviceDescription.targetOffsetMs;
} else if (manifest.suggestedPresentationDelayMs != C.TIME_UNSET) {
liveTargetOffsetMs = manifest.suggestedPresentationDelayMs;
} else {
liveTargetOffsetMs = fallbackTargetLiveOffsetMs;
}
float liveMinPlaybackSpeed = C.RATE_UNSET;
if (mediaItem.liveConfiguration.minPlaybackSpeed != C.RATE_UNSET) {
liveMinPlaybackSpeed = mediaItem.liveConfiguration.minPlaybackSpeed;
} else if (manifest.serviceDescription != null) {
liveMinPlaybackSpeed = manifest.serviceDescription.minPlaybackSpeed;
}
float liveMaxPlaybackSpeed = C.RATE_UNSET;
if (mediaItem.liveConfiguration.maxPlaybackSpeed != C.RATE_UNSET) {
liveMaxPlaybackSpeed = mediaItem.liveConfiguration.maxPlaybackSpeed;
} else if (manifest.serviceDescription != null) {
liveMaxPlaybackSpeed = manifest.serviceDescription.maxPlaybackSpeed;
}
// Update live configuration in the media item.
return mediaItem
.buildUpon()
.setLiveTargetOffsetMs(liveTargetOffsetMs)
.setLiveMinPlaybackSpeed(liveMinPlaybackSpeed)
.setLiveMaxPlaybackSpeed(liveMaxPlaybackSpeed)
.build();
}
private static final class PeriodSeekInfo { private static final class PeriodSeekInfo {
public static PeriodSeekInfo createPeriodSeekInfo( public static PeriodSeekInfo createPeriodSeekInfo(
......
...@@ -55,8 +55,9 @@ public final class DashMediaSourceTest { ...@@ -55,8 +55,9 @@ public final class DashMediaSourceTest {
private static final String SAMPLE_MPD_LIVE_WITHOUT_LIVE_CONFIGURATION = private static final String SAMPLE_MPD_LIVE_WITHOUT_LIVE_CONFIGURATION =
"media/mpd/sample_mpd_live_without_live_configuration"; "media/mpd/sample_mpd_live_without_live_configuration";
private static final String SAMPLE_MPD_LIVE_WITH_SUGGESTED_PRESENTATION_DELAY_2S = private static final String
"media/mpd/sample_mpd_live_with_suggested_presentation_delay_2s"; SAMPLE_MPD_LIVE_WITH_SUGGESTED_PRESENTATION_DELAY_2S_MIN_BUFFER_TIME_500MS =
"media/mpd/sample_mpd_live_with_suggested_presentation_delay_2s_min_buffer_time_500ms";
private static final String SAMPLE_MPD_LIVE_WITH_COMPLETE_SERVICE_DESCRIPTION = private static final String SAMPLE_MPD_LIVE_WITH_COMPLETE_SERVICE_DESCRIPTION =
"media/mpd/sample_mpd_live_with_complete_service_description"; "media/mpd/sample_mpd_live_with_complete_service_description";
private static final String SAMPLE_MPD_LIVE_WITH_OFFSET_INSIDE_WINDOW = private static final String SAMPLE_MPD_LIVE_WITH_OFFSET_INSIDE_WINDOW =
...@@ -290,6 +291,8 @@ public final class DashMediaSourceTest { ...@@ -290,6 +291,8 @@ public final class DashMediaSourceTest {
assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs) assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs)
.isEqualTo(DashMediaSource.DEFAULT_FALLBACK_TARGET_LIVE_OFFSET_MS); .isEqualTo(DashMediaSource.DEFAULT_FALLBACK_TARGET_LIVE_OFFSET_MS);
assertThat(mediaItemFromSource.liveConfiguration.minLiveOffsetMs).isEqualTo(0L);
assertThat(mediaItemFromSource.liveConfiguration.maxLiveOffsetMs).isEqualTo(58_000L);
assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(C.RATE_UNSET); assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(C.RATE_UNSET);
assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(C.RATE_UNSET); assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(C.RATE_UNSET);
} }
...@@ -306,6 +309,8 @@ public final class DashMediaSourceTest { ...@@ -306,6 +309,8 @@ public final class DashMediaSourceTest {
MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem; MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem;
assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(1234L); assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(1234L);
assertThat(mediaItemFromSource.liveConfiguration.minLiveOffsetMs).isEqualTo(0L);
assertThat(mediaItemFromSource.liveConfiguration.maxLiveOffsetMs).isEqualTo(58_000L);
assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(C.RATE_UNSET); assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(C.RATE_UNSET);
assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(C.RATE_UNSET); assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(C.RATE_UNSET);
} }
...@@ -319,6 +324,8 @@ public final class DashMediaSourceTest { ...@@ -319,6 +324,8 @@ public final class DashMediaSourceTest {
.setLiveTargetOffsetMs(876L) .setLiveTargetOffsetMs(876L)
.setLiveMinPlaybackSpeed(23f) .setLiveMinPlaybackSpeed(23f)
.setLiveMaxPlaybackSpeed(42f) .setLiveMaxPlaybackSpeed(42f)
.setLiveMinOffsetMs(500L)
.setLiveMaxOffsetMs(20_000L)
.build(); .build();
DashMediaSource mediaSource = DashMediaSource mediaSource =
new DashMediaSource.Factory( new DashMediaSource.Factory(
...@@ -329,29 +336,35 @@ public final class DashMediaSourceTest { ...@@ -329,29 +336,35 @@ public final class DashMediaSourceTest {
MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem; MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem;
assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(876L); assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(876L);
assertThat(mediaItemFromSource.liveConfiguration.minLiveOffsetMs).isEqualTo(500L);
assertThat(mediaItemFromSource.liveConfiguration.maxLiveOffsetMs).isEqualTo(20_000L);
assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(23f); assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(23f);
assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(42f); assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(42f);
} }
@Test @Test
public void prepare_withSuggestedPresentationDelay_usesManifestValue() public void prepare_withSuggestedPresentationDelayAndMinBufferTime_usesManifestValue()
throws InterruptedException { throws InterruptedException {
DashMediaSource mediaSource = DashMediaSource mediaSource =
new DashMediaSource.Factory( new DashMediaSource.Factory(
() -> () ->
createSampleMpdDataSource(SAMPLE_MPD_LIVE_WITH_SUGGESTED_PRESENTATION_DELAY_2S)) createSampleMpdDataSource(
SAMPLE_MPD_LIVE_WITH_SUGGESTED_PRESENTATION_DELAY_2S_MIN_BUFFER_TIME_500MS))
.setFallbackTargetLiveOffsetMs(1234L) .setFallbackTargetLiveOffsetMs(1234L)
.createMediaSource(MediaItem.fromUri(Uri.EMPTY)); .createMediaSource(MediaItem.fromUri(Uri.EMPTY));
MediaItem mediaItem = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem; MediaItem mediaItem = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem;
assertThat(mediaItem.liveConfiguration.targetLiveOffsetMs).isEqualTo(2_000L); assertThat(mediaItem.liveConfiguration.targetLiveOffsetMs).isEqualTo(2_000L);
assertThat(mediaItem.liveConfiguration.minLiveOffsetMs).isEqualTo(500L);
assertThat(mediaItem.liveConfiguration.maxLiveOffsetMs).isEqualTo(58_000L);
assertThat(mediaItem.liveConfiguration.minPlaybackSpeed).isEqualTo(C.RATE_UNSET); assertThat(mediaItem.liveConfiguration.minPlaybackSpeed).isEqualTo(C.RATE_UNSET);
assertThat(mediaItem.liveConfiguration.maxPlaybackSpeed).isEqualTo(C.RATE_UNSET); assertThat(mediaItem.liveConfiguration.maxPlaybackSpeed).isEqualTo(C.RATE_UNSET);
} }
@Test @Test
public void prepare_withSuggestedPresentationDelay_withMediaItemLiveProperties_usesMediaItem() public void
prepare_withSuggestedPresentationDelayAndMinBufferTime_withMediaItemLiveProperties_usesMediaItem()
throws InterruptedException { throws InterruptedException {
MediaItem mediaItem = MediaItem mediaItem =
new MediaItem.Builder() new MediaItem.Builder()
...@@ -359,17 +372,22 @@ public final class DashMediaSourceTest { ...@@ -359,17 +372,22 @@ public final class DashMediaSourceTest {
.setLiveTargetOffsetMs(876L) .setLiveTargetOffsetMs(876L)
.setLiveMinPlaybackSpeed(23f) .setLiveMinPlaybackSpeed(23f)
.setLiveMaxPlaybackSpeed(42f) .setLiveMaxPlaybackSpeed(42f)
.setLiveMinOffsetMs(200L)
.setLiveMaxOffsetMs(999L)
.build(); .build();
DashMediaSource mediaSource = DashMediaSource mediaSource =
new DashMediaSource.Factory( new DashMediaSource.Factory(
() -> () ->
createSampleMpdDataSource(SAMPLE_MPD_LIVE_WITH_SUGGESTED_PRESENTATION_DELAY_2S)) createSampleMpdDataSource(
SAMPLE_MPD_LIVE_WITH_SUGGESTED_PRESENTATION_DELAY_2S_MIN_BUFFER_TIME_500MS))
.setFallbackTargetLiveOffsetMs(1234L) .setFallbackTargetLiveOffsetMs(1234L)
.createMediaSource(mediaItem); .createMediaSource(mediaItem);
MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem; MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem;
assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(876L); assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(876L);
assertThat(mediaItem.liveConfiguration.minLiveOffsetMs).isEqualTo(200L);
assertThat(mediaItem.liveConfiguration.maxLiveOffsetMs).isEqualTo(999L);
assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(23f); assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(23f);
assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(42f); assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(42f);
} }
...@@ -386,6 +404,8 @@ public final class DashMediaSourceTest { ...@@ -386,6 +404,8 @@ public final class DashMediaSourceTest {
MediaItem mediaItem = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem; MediaItem mediaItem = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem;
assertThat(mediaItem.liveConfiguration.targetLiveOffsetMs).isEqualTo(4_000L); assertThat(mediaItem.liveConfiguration.targetLiveOffsetMs).isEqualTo(4_000L);
assertThat(mediaItem.liveConfiguration.minLiveOffsetMs).isEqualTo(2_000L);
assertThat(mediaItem.liveConfiguration.maxLiveOffsetMs).isEqualTo(6_000L);
assertThat(mediaItem.liveConfiguration.minPlaybackSpeed).isEqualTo(0.96f); assertThat(mediaItem.liveConfiguration.minPlaybackSpeed).isEqualTo(0.96f);
assertThat(mediaItem.liveConfiguration.maxPlaybackSpeed).isEqualTo(1.04f); assertThat(mediaItem.liveConfiguration.maxPlaybackSpeed).isEqualTo(1.04f);
} }
...@@ -399,6 +419,8 @@ public final class DashMediaSourceTest { ...@@ -399,6 +419,8 @@ public final class DashMediaSourceTest {
.setLiveTargetOffsetMs(876L) .setLiveTargetOffsetMs(876L)
.setLiveMinPlaybackSpeed(23f) .setLiveMinPlaybackSpeed(23f)
.setLiveMaxPlaybackSpeed(42f) .setLiveMaxPlaybackSpeed(42f)
.setLiveMinOffsetMs(100L)
.setLiveMaxOffsetMs(999L)
.build(); .build();
DashMediaSource mediaSource = DashMediaSource mediaSource =
new DashMediaSource.Factory( new DashMediaSource.Factory(
...@@ -409,6 +431,8 @@ public final class DashMediaSourceTest { ...@@ -409,6 +431,8 @@ public final class DashMediaSourceTest {
MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem; MediaItem mediaItemFromSource = prepareAndWaitForTimelineRefresh(mediaSource).mediaItem;
assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(876L); assertThat(mediaItemFromSource.liveConfiguration.targetLiveOffsetMs).isEqualTo(876L);
assertThat(mediaItemFromSource.liveConfiguration.minLiveOffsetMs).isEqualTo(100L);
assertThat(mediaItemFromSource.liveConfiguration.maxLiveOffsetMs).isEqualTo(999L);
assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(23f); assertThat(mediaItemFromSource.liveConfiguration.minPlaybackSpeed).isEqualTo(23f);
assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(42f); assertThat(mediaItemFromSource.liveConfiguration.maxPlaybackSpeed).isEqualTo(42f);
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
schemeIdUri="urn:mpeg:dash:utc:direct:2014" schemeIdUri="urn:mpeg:dash:utc:direct:2014"
value="2020-01-01T01:00:00Z" /> value="2020-01-01T01:00:00Z" />
<ServiceDescription id="0"> <ServiceDescription id="0">
<Latency target="4000" /> <Latency min="2000" target="4000" max="6000"/>
<PlaybackRate max="1.04" min="0.96" /> <PlaybackRate max="1.04" min="0.96" />
</ServiceDescription> </ServiceDescription>
<Period start="PT0.0S"> <Period start="PT0.0S">
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
<MPD <MPD
type="dynamic" type="dynamic"
suggestedPresentationDelay="PT2S" suggestedPresentationDelay="PT2S"
minBufferTime="PT0.5S"
minimumUpdatePeriod="PT4M" minimumUpdatePeriod="PT4M"
availabilityStartTime="2020-01-01T00:00:00Z" availabilityStartTime="2020-01-01T00:00:00Z"
timeShiftBufferDepth="PT6.0S"> timeShiftBufferDepth="PT1M">
<UTCTiming <UTCTiming
schemeIdUri="urn:mpeg:dash:utc:direct:2014" schemeIdUri="urn:mpeg:dash:utc:direct:2014"
value="2020-01-01T01:00:00Z" /> value="2020-01-01T01:00:00Z" />
......
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