mirror of
https://github.com/androidx/media.git
synced 2025-04-29 22:36:54 +08:00
Support X-SNAP with HLS interstitials
PiperOrigin-RevId: 745614349
This commit is contained in:
parent
c5b6489d5d
commit
6cae8ab8a0
@ -32,7 +32,11 @@ import static androidx.media3.common.util.Util.msToUs;
|
||||
import static androidx.media3.common.util.Util.usToMs;
|
||||
import static androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Interstitial.CUE_TRIGGER_POST;
|
||||
import static androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Interstitial.CUE_TRIGGER_PRE;
|
||||
import static androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Interstitial.SNAP_TYPE_IN;
|
||||
import static androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Interstitial.SNAP_TYPE_OUT;
|
||||
import static java.lang.Math.abs;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
@ -633,7 +637,7 @@ public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
window.positionInFirstPeriodUs,
|
||||
checkNotNull(insertedInterstitialIds.get(adsId)))
|
||||
: mapInterstitialsForVod(
|
||||
window.mediaItem,
|
||||
window,
|
||||
mediaPlaylist,
|
||||
adPlaybackState,
|
||||
checkNotNull(insertedInterstitialIds.get(adsId)));
|
||||
@ -913,13 +917,15 @@ public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
ArrayList<Interstitial> interstitials = new ArrayList<>(mediaPlaylist.interstitials);
|
||||
for (int i = 0; i < interstitials.size(); i++) {
|
||||
Interstitial interstitial = interstitials.get(i);
|
||||
long positionInPlaylistWindowUs =
|
||||
interstitial.cue.contains(CUE_TRIGGER_PRE)
|
||||
? 0L
|
||||
: (interstitial.startDateUnixUs - mediaPlaylist.startTimeUs);
|
||||
if (insertedInterstitialIds.contains(interstitial.id)
|
||||
|| interstitial.cue.contains(CUE_TRIGGER_POST)
|
||||
|| positionInPlaylistWindowUs < 0) {
|
||||
|| interstitial.cue.contains(CUE_TRIGGER_POST)) {
|
||||
continue;
|
||||
}
|
||||
long positionInPlaylistWindowUs =
|
||||
resolveInterstitialStartTimeUs(interstitial, mediaPlaylist) - mediaPlaylist.startTimeUs;
|
||||
if (positionInPlaylistWindowUs < 0 || mediaPlaylist.durationUs < positionInPlaylistWindowUs) {
|
||||
// Ignore when behind the window including C.TIME_UNSET and C.TIME_END_OF_SOURCE.
|
||||
// When not yet in the window we wait until the window advances.
|
||||
continue;
|
||||
}
|
||||
long timeUs = windowPositionInPeriodUs + positionInPlaylistWindowUs;
|
||||
@ -935,18 +941,18 @@ public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
isNewAdGroup = false;
|
||||
break;
|
||||
} else if (adGroup.timeUs < timeUs) {
|
||||
// Insert at index after group before interstitial.
|
||||
// Insert at index after group behind interstitial.
|
||||
insertionIndex = adGroupIndex + 1;
|
||||
break;
|
||||
}
|
||||
// Interstitial is before the ad group. Possible insertion index.
|
||||
// Interstitial is behind the ad group. Possible insertion index.
|
||||
insertionIndex = adGroupIndex;
|
||||
}
|
||||
if (isNewAdGroup) {
|
||||
if (insertionIndex < getLowestValidAdGroupInsertionIndex(adPlaybackState)) {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Skipping insertion of interstitial attempted to be inserted before an already"
|
||||
"Skipping insertion of interstitial attempted to be inserted behind an already"
|
||||
+ " initialized ad group.");
|
||||
continue;
|
||||
}
|
||||
@ -965,36 +971,49 @@ public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
}
|
||||
|
||||
private AdPlaybackState mapInterstitialsForVod(
|
||||
MediaItem mediaItem,
|
||||
Window window,
|
||||
HlsMediaPlaylist mediaPlaylist,
|
||||
AdPlaybackState adPlaybackState,
|
||||
Set<String> insertedInterstitialIds) {
|
||||
checkArgument(adPlaybackState.adGroupCount == 0);
|
||||
checkArgument(adPlaybackState.adGroupCount == adPlaybackState.removedAdGroupCount);
|
||||
ImmutableList<Interstitial> interstitials = mediaPlaylist.interstitials;
|
||||
long clippedWindowStartTimeUs = mediaPlaylist.startTimeUs + window.positionInFirstPeriodUs;
|
||||
long clippedWindowEndTimeUs = clippedWindowStartTimeUs + window.durationUs;
|
||||
for (int i = 0; i < interstitials.size(); i++) {
|
||||
Interstitial interstitial = interstitials.get(i);
|
||||
long timeUs;
|
||||
if (interstitial.cue.contains(CUE_TRIGGER_PRE)) {
|
||||
timeUs = 0L;
|
||||
} else if (interstitial.cue.contains(CUE_TRIGGER_POST)) {
|
||||
timeUs = C.TIME_END_OF_SOURCE;
|
||||
} else {
|
||||
timeUs = interstitial.startDateUnixUs - mediaPlaylist.startTimeUs;
|
||||
long interstitialStartTimeUs = resolveInterstitialStartTimeUs(interstitial, mediaPlaylist);
|
||||
if (interstitialStartTimeUs < clippedWindowStartTimeUs
|
||||
&& interstitial.cue.contains(CUE_TRIGGER_PRE)) {
|
||||
// Declared pre roll: move to the start of the clipped window.
|
||||
interstitialStartTimeUs = clippedWindowStartTimeUs;
|
||||
} else if (interstitialStartTimeUs > clippedWindowEndTimeUs
|
||||
&& interstitial.cue.contains(CUE_TRIGGER_POST)) {
|
||||
// Declared post roll: move to the end of the clipped window.
|
||||
interstitialStartTimeUs = clippedWindowEndTimeUs;
|
||||
} else if (interstitialStartTimeUs < clippedWindowStartTimeUs
|
||||
|| clippedWindowEndTimeUs < interstitialStartTimeUs) {
|
||||
// Ignore interstitials before or after the window that are not explicit pre or post rolls.
|
||||
continue;
|
||||
}
|
||||
long timeUs =
|
||||
clippedWindowEndTimeUs == interstitialStartTimeUs
|
||||
? C.TIME_END_OF_SOURCE
|
||||
: interstitialStartTimeUs - mediaPlaylist.startTimeUs;
|
||||
int adGroupIndex =
|
||||
adPlaybackState.getAdGroupIndexForPositionUs(timeUs, mediaPlaylist.durationUs);
|
||||
if (adGroupIndex == C.INDEX_UNSET) {
|
||||
// There is no ad group before or at the interstitials position.
|
||||
adGroupIndex = 0;
|
||||
adPlaybackState = adPlaybackState.withNewAdGroup(/* adGroupIndex= */ 0, timeUs);
|
||||
adGroupIndex = adPlaybackState.removedAdGroupCount;
|
||||
adPlaybackState =
|
||||
adPlaybackState.withNewAdGroup(adPlaybackState.removedAdGroupCount, timeUs);
|
||||
} else if (adPlaybackState.getAdGroup(adGroupIndex).timeUs != timeUs) {
|
||||
// There is an ad group before the interstitials. Insert after that index.
|
||||
// There is an ad group before the interstitial. Insert after that index.
|
||||
adGroupIndex++;
|
||||
adPlaybackState = adPlaybackState.withNewAdGroup(adGroupIndex, timeUs);
|
||||
}
|
||||
adPlaybackState =
|
||||
insertOrUpdateInterstitialInAdGroup(
|
||||
mediaItem,
|
||||
window.mediaItem,
|
||||
interstitial,
|
||||
adPlaybackState,
|
||||
adGroupIndex,
|
||||
@ -1021,7 +1040,7 @@ public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
adIndexInAdGroup = max(adGroup.count, 0);
|
||||
// Append duration of new interstitial into existing ad durations.
|
||||
long interstitialDurationUs =
|
||||
getInterstitialDurationUs(interstitial, /* defaultDurationUs= */ C.TIME_UNSET);
|
||||
resolveInterstitialDurationUs(interstitial, /* defaultDurationUs= */ C.TIME_UNSET);
|
||||
long[] adDurations;
|
||||
if (adIndexInAdGroup == 0) {
|
||||
adDurations = new long[1];
|
||||
@ -1081,7 +1100,8 @@ public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
return adPlaybackState.removedAdGroupCount;
|
||||
}
|
||||
|
||||
private static long getInterstitialDurationUs(Interstitial interstitial, long defaultDurationUs) {
|
||||
private static long resolveInterstitialDurationUs(
|
||||
Interstitial interstitial, long defaultDurationUs) {
|
||||
if (interstitial.playoutLimitUs != C.TIME_UNSET) {
|
||||
return interstitial.playoutLimitUs;
|
||||
} else if (interstitial.durationUs != C.TIME_UNSET) {
|
||||
@ -1094,6 +1114,45 @@ public final class HlsInterstitialsAdsLoader implements AdsLoader {
|
||||
return defaultDurationUs;
|
||||
}
|
||||
|
||||
private static long resolveInterstitialStartTimeUs(
|
||||
Interstitial interstitial, HlsMediaPlaylist mediaPlaylist) {
|
||||
if (interstitial.cue.contains(CUE_TRIGGER_PRE)) {
|
||||
return mediaPlaylist.startTimeUs;
|
||||
} else if (interstitial.cue.contains(CUE_TRIGGER_POST)) {
|
||||
return mediaPlaylist.startTimeUs + mediaPlaylist.durationUs;
|
||||
} else if (interstitial.snapTypes.contains(SNAP_TYPE_OUT)) {
|
||||
return getClosestSegmentBoundaryUs(interstitial.startDateUnixUs, mediaPlaylist);
|
||||
} else if (interstitial.snapTypes.contains(SNAP_TYPE_IN)) {
|
||||
long resumeOffsetUs =
|
||||
interstitial.resumeOffsetUs != C.TIME_UNSET
|
||||
? interstitial.resumeOffsetUs
|
||||
: resolveInterstitialDurationUs(interstitial, /* defaultDurationUs= */ 0L);
|
||||
return getClosestSegmentBoundaryUs(
|
||||
interstitial.startDateUnixUs + resumeOffsetUs, mediaPlaylist)
|
||||
- resumeOffsetUs;
|
||||
} else {
|
||||
return interstitial.startDateUnixUs;
|
||||
}
|
||||
}
|
||||
|
||||
private static long getClosestSegmentBoundaryUs(long unixTimeUs, HlsMediaPlaylist mediaPlaylist) {
|
||||
long positionInPlaylistUs = unixTimeUs - mediaPlaylist.startTimeUs;
|
||||
if (positionInPlaylistUs <= 0 || mediaPlaylist.segments.isEmpty()) {
|
||||
return mediaPlaylist.startTimeUs;
|
||||
} else if (positionInPlaylistUs >= mediaPlaylist.durationUs) {
|
||||
return mediaPlaylist.startTimeUs + mediaPlaylist.durationUs;
|
||||
}
|
||||
long segmentIndex =
|
||||
min(
|
||||
positionInPlaylistUs / mediaPlaylist.targetDurationUs,
|
||||
mediaPlaylist.segments.size() - 1);
|
||||
HlsMediaPlaylist.Segment segment = mediaPlaylist.segments.get((int) segmentIndex);
|
||||
return positionInPlaylistUs - segment.relativeStartTimeUs
|
||||
< abs(positionInPlaylistUs - (segment.relativeStartTimeUs + segment.durationUs))
|
||||
? mediaPlaylist.startTimeUs + segment.relativeStartTimeUs
|
||||
: mediaPlaylist.startTimeUs + segment.relativeStartTimeUs + segment.durationUs;
|
||||
}
|
||||
|
||||
private class PlayerListener implements Player.Listener {
|
||||
|
||||
private final Period period = new Period();
|
||||
|
@ -265,6 +265,10 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6,\n"
|
||||
+ "main1.0.ts\n"
|
||||
+ "#EXTINF:6,\n"
|
||||
+ "main2.0.ts\n"
|
||||
+ "#EXTINF:6,\n"
|
||||
+ "main3.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -332,6 +336,108 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleContentTimelineChanged_clippedWindow_translatedToClippedWindow()
|
||||
throws IOException {
|
||||
AdPlaybackState actual =
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6,\nmain1.0.ts\n"
|
||||
+ "#EXTINF:6,\nmain2.0.ts\n"
|
||||
+ "#EXTINF:6,\nmain3.0.ts\n"
|
||||
+ "#EXTINF:6,\nmain4.0.ts\n" // ends at 24_000_000 -> 21:56:04.000Z
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\"," // pre roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:44.000Z\","
|
||||
+ "CUE=\"PRE\"," // Explicit pre roll. Aligned to clip start.
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\"," // ignored
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:42.999Z\"," // non-pre roll behind clipped window
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad2-0\"," // ignored
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:39.999Z\"," // snaps to the playlist window start
|
||||
+ "X-SNAP=\"OUT\""
|
||||
+ "X-ASSET-URI=\"http://example.com/media-2-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad3-0\"," // mid roll at 15_000_000
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:55.000Z\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-3-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad4-0\"," // post roll 0
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:56:00.321Z\"," // exact match at end of clip
|
||||
+ "X-ASSET-URI=\"http://example.com/media-4-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad4-1\"," // ignored
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:56:00.322Z\"," // after end of clip
|
||||
+ "X-ASSET-URI=\"http://example.com/media-4-1.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad4-2\"," // post roll 1
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2050-01-02T21:55:08.000Z\","
|
||||
+ "CUE=\"POST\"," // explicit post roll
|
||||
+ "X-ASSET-URI=\"http://example.com/media-4-2.m3u8\"\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 1,
|
||||
6_000_123L, // clipped to 6s after start of period
|
||||
20_321_000L); // clipped to 4s before end of period
|
||||
assertThat(actual)
|
||||
.isEqualTo(
|
||||
new AdPlaybackState("adsId", 6_000_123L, 15_000_000L, C.TIME_END_OF_SOURCE)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 2, 2)
|
||||
.withAdId(0, 0, "ad0-0")
|
||||
.withAdId(1, 0, "ad3-0")
|
||||
.withAdId(2, 0, "ad4-0")
|
||||
.withAdId(2, 1, "ad4-2")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-3-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 2,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-4-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 2,
|
||||
/* adIndexInAdGroup= */ 1,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-4-2.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleContentTimelineChanged_3preRolls_mergedIntoSinglePreRollAdGroup()
|
||||
throws IOException {
|
||||
@ -416,18 +522,21 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:44.000Z\","
|
||||
+ "END-DATE=\"2020-01-02T21:55:46.000Z\"," // adds to resume offset
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-1\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:44.000Z\","
|
||||
+ "DURATION=1.1," // adds to resume offset
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-1.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-2\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:44.000Z\","
|
||||
+ "PLANNED-DURATION=1.2," // adds to resume offset
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-2.m3u8\""
|
||||
+ "\n";
|
||||
|
||||
@ -440,9 +549,9 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE))
|
||||
.isEqualTo(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 4_000_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 2_000_000L, 1_100_000L, 1_200_000L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 3)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 0L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 4_300_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1, "ad0-1")
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 2, "ad0-2")
|
||||
@ -472,51 +581,49 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
@Test
|
||||
public void handleContentTimelineChanged_3postRolls_mergedIntoSinglePostRollAdGroup()
|
||||
throws IOException {
|
||||
String playlistString =
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6,\n"
|
||||
+ "main1.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:30.000Z\","
|
||||
+ "END-DATE=\"2020-01-02T21:55:31.000Z\","
|
||||
+ "CUE=\"POST\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-1\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "CUE=\"POST\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:40.000Z\","
|
||||
+ "DURATION=1.1,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-1.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-2\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:51.000Z\","
|
||||
+ "CUE=\"POST\","
|
||||
+ "PLANNED-DURATION=1.2,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-2.m3u8\""
|
||||
+ "\n";
|
||||
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
playlistString,
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6,\n"
|
||||
+ "main1.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:30.000Z\","
|
||||
+ "CUE=\"POST\"," // cued as post roll
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-1\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:46.000Z\"," // exact match
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-1.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-2\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:46.001Z\"," // late but snaps to post roll.
|
||||
+ "X-SNAP=\"OUT\""
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-2.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-3\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:46.001Z\"," // late and hence ignored.
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-3.m3u8\""
|
||||
+ "\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE))
|
||||
.isEqualTo(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000_000L, 1_100_000L, 1_200_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, C.TIME_UNSET, C.TIME_UNSET, C.TIME_UNSET)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 3)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 3_300_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1, "ad0-1")
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 2, "ad0-2")
|
||||
@ -909,25 +1016,608 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleContentTimelineChanged_noDurationSet_durationTimeUnset() throws IOException {
|
||||
String playlistString =
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6,\n"
|
||||
+ "main1.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:41.123Z\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n";
|
||||
|
||||
public void handleContentTimelineChanged_snapOut_snapToClosestSegmentBoundaryOfStartPosition()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
playlistString,
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain1.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain2.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain3.ts\n" // end of window: 18_333_000 -> 21:55:58.333
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\"," // post roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:58.000Z\"," // snap to 21:55:58.333
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\"," // mid roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:46.000Z\"," // snap to 21:55:46.111
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad3-0\"," // pre roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:40.123Z\"," // snap to 21:55:40.000
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-3-0.m3u8\""
|
||||
+ "\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE))
|
||||
.isEqualTo(
|
||||
new AdPlaybackState(
|
||||
"adsId", /* adGroupTimesUs...= */ 0L, 6_111_000L, C.TIME_END_OF_SOURCE)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 2, 1)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad3-0")
|
||||
.withAdId(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, "ad1-0")
|
||||
.withAdId(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-3-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-1-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 2,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleContentTimelineChanged_snapOutLive_snapToClosestSegmentBoundaryOfStartPosition()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedForLiveAndCaptureAdPlaybackStates(
|
||||
adsLoader,
|
||||
/* startAdsLoader= */ true,
|
||||
/* windowOffsetInFirstPeriodUs= */ 2_000_123L, // window offset!
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:0\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\"," // mid roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:46.000\"," // snap to 6.111 + 2_000_123
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\"," // mid roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:52.999Z\"," // snap to 12.222 + 2_000_123
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad2-0\"," // mid roll at end of window
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2050-01-02T21:56:04.000Z\"," // snap to 18.333 + 2_000_123
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-2-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n" // 2s offset in period
|
||||
+ "#EXTINF:6.111,\nmain1.0.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain2.0.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain3.0.ts\n")) // window end time at 18.333 -> 21:55:58.333
|
||||
.containsExactly(
|
||||
new AdPlaybackState(
|
||||
"adsId", /* adGroupTimesUs...= */ 8_111_123L, 14_222_123L, 20_333_123L)
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 2, 1)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, "ad1-0")
|
||||
.withAdId(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, "ad2-0")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-1-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 2,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-2-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleContentTimelineChanged_snapIn_snapToClosestSegmentBoundaryOfResumptionPosition()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain1.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain2.ts\n" // segment start at 6.111
|
||||
+ "#EXTINF:6.111,\nmain3.ts\n" // end of window at 18.333
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:39.900\"," // snap to 12.222 - 12.222 -> 0L
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "DURATION=12.222,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:51.222\"," // aligned 12.222 - 3.222 -> 9_000L
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "DURATION=3.222,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad2-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:54.678\"," // snap to end of window - 4.333
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "DURATION=4.333,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-2-0.m3u8\""
|
||||
+ "\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE))
|
||||
.isEqualTo(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 0L, 9_000_000L, 14_000_000L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 2, 1)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 12_222_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 1, 3_222_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, 4_333_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 12_222_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 1, 3_222_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 2, 4_333_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, "ad1-0")
|
||||
.withAdId(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, "ad2-0")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-1-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 2,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-2-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
handleContentTimelineChanged_snapInLive_snapToClosestSegmentBoundaryOfResumptionPosition()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedForLiveAndCaptureAdPlaybackStates(
|
||||
adsLoader,
|
||||
/* startAdsLoader= */ true,
|
||||
/* windowOffsetInFirstPeriodUs= */ 123L,
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:0\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:39.900\"," // snap to (12.222 - 12.222) -> 0L
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "X-RESUME-OFFSET=12.222,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:51.222\"," // snap to (12.222 - 3.22) -> 9_000L
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "X-RESUME-OFFSET=3.222,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad2-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:54.678\"," // snap to (end of window - 4.333)
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "DURATION=4.333,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-2-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain1.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain2.ts\n" // segment start at 6.111
|
||||
+ "#EXTINF:6.111,\nmain3.ts\n")) // segment start at 12.222
|
||||
.containsExactly(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 123L, 9_000_123L, 14_000_123L)
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 2, 1)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 12_222_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 1, 3_222_000L)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, 4_333_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 2, 4_333_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, "ad1-0")
|
||||
.withAdId(/* adGroupIndex= */ 2, /* adIndexInAdGroup= */ 0, "ad2-0")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-1-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 2,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-2-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
handleContentTimelineChanged_snapInFarBeforeOrAfterWindow_snapToStartOfWindowAndPostRoll()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain1.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\"," // pre roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"1990-01-02T00:00:00.000\"," // snap to start of window.
|
||||
+ "DURATION=1.0,"
|
||||
+ "X-RESUME-OFFSET=0.0," // with no offset SNAP_IN => SNAP_OUT
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\"," // ignored
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"1990-01-02T00:00:00.000\"," // snap end to start of window
|
||||
+ "DURATION=1.0," // translate start of ad back to 1s behind window
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad2-0\"," // post roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2050-01-02T21:55:00.900\"," // snap to end of window
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-2-0.m3u8\""
|
||||
+ "\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE))
|
||||
.isEqualTo(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 0L, C.TIME_END_OF_SOURCE)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, "ad2-0")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-2-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
handleContentTimelineChanged_snapInLiveFarBeforeOrAfterWindow_snapToStartAndEndOfWindow()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedForLiveAndCaptureAdPlaybackStates(
|
||||
adsLoader,
|
||||
/* startAdsLoader= */ true,
|
||||
/* windowOffsetInFirstPeriodUs= */ 0,
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:0\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\"," // pre roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"1990-01-02T00:00:00.000\"," // snap to start of window
|
||||
+ "DURATION=1.0,"
|
||||
+ "X-RESUME-OFFSET=0.0," // with no offset SNAP_IN => SNAP_OUT
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\"," // ignore
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"1990-01-02T00:00:00.000\"," // snap to start of window
|
||||
+ "DURATION=1.0," // translate start of ad back to 1s behind window
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad2-0\"," // mid roll at end of window (but not C.TIME_END_OF_SOURCE)
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2050-01-02T21:55:00.900\"," // snap end of window: 12_222_000
|
||||
+ "X-SNAP=\"IN\"," // no duration or offset: SNAP_IN => SNAP_OUT
|
||||
+ "X-ASSET-URI=\"http://example.com/media-2-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain1.0.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain1.0.ts\n" // end of window: 12:222 - 21:55:52.222
|
||||
+ "\n"))
|
||||
.containsExactly(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 0L, 12_222_000L)
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 1_000_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, "ad2-0")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-2-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
handleContentTimelineChanged_snapInOut_snapToSameSegmentBoundaryMergedIntoSameAdGroup()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain1.0.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain2.0.ts\n" // segment start at 6.111 -> 21:55:46.111
|
||||
+ "#EXTINF:6.111,\nmain3.0.ts\n" // segment start at 12.222 -> 21:55:52.222
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\"," // mid roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:45.000\"," // snap tp 6_111_000
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-1\"," // mid roll
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:47.000\"," // snap to 6_111_000
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "DURATION=6.111," // ends at 21:55:53.111 -> 21:55:52.222 - 6.111
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-1.m3u8\""
|
||||
+ "\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE))
|
||||
.isEqualTo(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 6_111_000L)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 2)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 6_111_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, C.TIME_UNSET, 6_111_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1, "ad0-1")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 1,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-1.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
handleContentTimelineChanged_snapInOutLive_snapToSameSegmentBoundaryMergedInSameAdGroup()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedForLiveAndCaptureAdPlaybackStates(
|
||||
adsLoader,
|
||||
/* startAdsLoader= */ true,
|
||||
/* windowOffsetInFirstPeriodUs= */ 0L,
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:0\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:45.000\"," // -> 6_111_000L
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "DURATION=2.222,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-1\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:47.000\"," // -> 6_111_000L
|
||||
+ "X-SNAP=\"IN\","
|
||||
+ "DURATION=6.111,"
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-1.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain1.0.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain2.0.ts\n" // segment start at 6.111 -> 21:55:46.111
|
||||
+ "#EXTINF:6.111,\nmain3.0.ts\n" // segment start at 12.222 -> 21:55:52.222
|
||||
+ "\n"))
|
||||
.containsExactly(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 6_111_000L)
|
||||
.withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ false)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 2)
|
||||
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, 8_333_000L)
|
||||
.withAdDurationsUs(/* adGroupIndex= */ 0, 2_222_000L, 6_111_000L)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1, "ad0-1")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 1,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-1.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleContentTimelineChanged_snapOut_snapToExactTargetDurationBoundaryInWindow()
|
||||
throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6.111,\nmain0.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain1.ts\n"
|
||||
+ "#EXTINF:6.111,\nmain2.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:46.000Z\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad1-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:58.000Z\","
|
||||
+ "X-SNAP=\"OUT\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-1-0.m3u8\""
|
||||
+ "\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE))
|
||||
.isEqualTo(
|
||||
new AdPlaybackState("adsId", /* adGroupTimesUs...= */ 6_111_000L, C.TIME_END_OF_SOURCE)
|
||||
.withAdCount(/* adGroupIndex= */ 0, 1)
|
||||
.withAdCount(/* adGroupIndex= */ 1, 1)
|
||||
.withAdId(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, "ad0-0")
|
||||
.withAdId(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, "ad1-0")
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-0-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build())
|
||||
.withAvailableAdMediaItem(
|
||||
/* adGroupIndex= */ 1,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
new MediaItem.Builder()
|
||||
.setUri("http://example.com/media-1-0.m3u8")
|
||||
.setMimeType(MimeTypes.APPLICATION_M3U8)
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleContentTimelineChanged_noDurationSet_durationTimeUnset() throws IOException {
|
||||
assertThat(
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:6\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
|
||||
+ "#EXTINF:6,\n"
|
||||
+ "main1.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
+ "ID=\"ad0-0\","
|
||||
+ "CLASS=\"com.apple.hls.interstitial\","
|
||||
+ "START-DATE=\"2020-01-02T21:55:41.123Z\","
|
||||
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
|
||||
+ "\n",
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
@ -1467,6 +2157,8 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.ts\n"
|
||||
+ "#EXTINF:81,\n"
|
||||
+ "main0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -1597,6 +2289,8 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:16.001,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -1663,6 +2357,8 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:81,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -1752,8 +2448,10 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "X-ASSET-LIST=\"http://example.com/assetlist-1-0.json\""
|
||||
+ "\n"
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n";
|
||||
+ "#EXTINF:9,\nmain0.0.ts\n"
|
||||
+ "#EXTINF:9,\nmain1.0.ts\n"
|
||||
+ "#EXTINF:9,\nmain2.0.ts\n"
|
||||
+ "#EXTINF:3,\nmain3.0.ts\n";
|
||||
when(mockPlayer.getContentPosition()).thenReturn(0L);
|
||||
contentWindowDefinition =
|
||||
contentWindowDefinition
|
||||
@ -1767,7 +2465,7 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
callHandleContentTimelineChangedAndCaptureAdPlaybackState(
|
||||
playlistString,
|
||||
adsLoader,
|
||||
/* windowIndex= */ 0,
|
||||
/* windowIndex= */ 2,
|
||||
/* windowPositionInPeriodUs= */ 0,
|
||||
/* windowEndPositionInPeriodUs= */ C.TIME_END_OF_SOURCE);
|
||||
|
||||
@ -1891,6 +2589,10 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -1935,6 +2637,8 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:81,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -2194,6 +2898,10 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main1.0.ts\n"
|
||||
+ "#EXTINF:72,\n"
|
||||
+ "main2.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -2306,6 +3014,10 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:00:00.000Z\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXTINF:9,\n"
|
||||
+ "main0.0.ts\n"
|
||||
+ "#EXT-X-ENDLIST"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DATERANGE:"
|
||||
@ -3061,11 +3773,16 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
initialWindows[windowIndex] =
|
||||
contentWindowDefinition
|
||||
.buildUpon()
|
||||
.setPlaceholder(true)
|
||||
.setDynamic(true)
|
||||
.setDurationUs(C.TIME_UNSET)
|
||||
.setDurationUs(durationUs)
|
||||
.setWindowPositionInFirstPeriodUs(windowPositionInPeriodUs)
|
||||
.build();
|
||||
when(mockPlayer.getCurrentTimeline()).thenReturn(new FakeTimeline(initialWindows));
|
||||
when(mockPlayer.getCurrentMediaItem()).thenReturn(contentWindowDefinition.mediaItem);
|
||||
when(mockPlayer.getCurrentMediaItemIndex()).thenReturn(windowIndex);
|
||||
when(mockPlayer.getCurrentPeriodIndex()).thenReturn(windowIndex);
|
||||
// Set the player.
|
||||
adsLoader.setPlayer(mockPlayer);
|
||||
// Start the ad.
|
||||
@ -3096,8 +3813,6 @@ public class HlsInterstitialsAdsLoaderTest {
|
||||
.setAdPlaybackStates(ImmutableList.of(adPlaybackState.getValue()))
|
||||
.build();
|
||||
when(mockPlayer.getCurrentTimeline()).thenReturn(new FakeTimeline(windowsAfterTimelineChange));
|
||||
when(mockPlayer.getCurrentMediaItemIndex()).thenReturn(windowIndex);
|
||||
when(mockPlayer.getCurrentPeriodIndex()).thenReturn(windowIndex);
|
||||
return adPlaybackState.getValue();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user