Commit 0d0ccadc by tonihei Committed by Oliver Woodman

Add getter for ad groups in AdPlaybackState.

This allows to decouple the data structure from the access. In
a future change, this allows to completely remove old ad groups
(e.g. for live streams where the number of groups would otherwise
grow forever).

Also move the time into the group itself for better encapsulation.

PiperOrigin-RevId: 376170408
parent 4e749e7a
......@@ -602,17 +602,16 @@ import java.util.Map;
}
// Skip ads based on the start position as required.
long[] adGroupTimesUs = adPlaybackState.adGroupTimesUs;
int adGroupForPositionIndex =
adPlaybackState.getAdGroupIndexForPositionUs(
C.msToUs(contentPositionMs), C.msToUs(contentDurationMs));
if (adGroupForPositionIndex != C.INDEX_UNSET) {
boolean playAdWhenStartingPlayback =
configuration.playAdBeforeStartPosition
|| adGroupTimesUs[adGroupForPositionIndex] == C.msToUs(contentPositionMs);
adPlaybackState.getAdGroup(adGroupForPositionIndex).timeUs == C.msToUs(contentPositionMs)
|| configuration.playAdBeforeStartPosition;
if (!playAdWhenStartingPlayback) {
adGroupForPositionIndex++;
} else if (hasMidrollAdGroups(adGroupTimesUs)) {
} else if (hasMidrollAdGroups(adPlaybackState)) {
// Provide the player's initial position to trigger loading and playing the ad. If there are
// no midrolls, we are playing a preroll and any pending content position wouldn't be
// cleared.
......@@ -622,13 +621,14 @@ import java.util.Map;
for (int i = 0; i < adGroupForPositionIndex; i++) {
adPlaybackState = adPlaybackState.withSkippedAdGroup(i);
}
if (adGroupForPositionIndex == adGroupTimesUs.length) {
if (adGroupForPositionIndex == adPlaybackState.adGroupCount) {
// We don't need to play any ads. Because setPlayAdsAfterTime does not discard non-VMAP
// ads, we signal that no ads will render so the caller can destroy the ads manager.
return null;
}
long adGroupForPositionTimeUs = adGroupTimesUs[adGroupForPositionIndex];
long adGroupBeforePositionTimeUs = adGroupTimesUs[adGroupForPositionIndex - 1];
long adGroupForPositionTimeUs = adPlaybackState.getAdGroup(adGroupForPositionIndex).timeUs;
long adGroupBeforePositionTimeUs =
adPlaybackState.getAdGroup(adGroupForPositionIndex - 1).timeUs;
if (adGroupForPositionTimeUs == C.TIME_END_OF_SOURCE) {
// Play the postroll by offsetting the start position just past the last non-postroll ad.
adsRenderingSettings.setPlayAdsAfterTime(
......@@ -786,14 +786,14 @@ import java.util.Map;
if (adGroupIndex == C.INDEX_UNSET) {
return false;
}
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
if (adGroup.count != C.LENGTH_UNSET
&& adGroup.count != 0
&& adGroup.states[0] != AdPlaybackState.AD_STATE_UNAVAILABLE) {
// An ad is available already.
return false;
}
long adGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
long adGroupTimeMs = C.usToMs(adGroup.timeUs);
long contentPositionMs = getContentPeriodPositionMs(player, timeline, period);
long timeUntilAdMs = adGroupTimeMs - contentPositionMs;
return timeUntilAdMs < configuration.adPreloadTimeoutMs;
......@@ -877,13 +877,13 @@ import java.util.Map;
}
}
if (!sentContentComplete && !wasPlayingAd && playingAd && imaAdState == IMA_AD_STATE_NONE) {
int adGroupIndex = player.getCurrentAdGroupIndex();
if (adPlaybackState.adGroupTimesUs[adGroupIndex] == C.TIME_END_OF_SOURCE) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(player.getCurrentAdGroupIndex());
if (adGroup.timeUs == C.TIME_END_OF_SOURCE) {
sendContentComplete();
} else {
// IMA hasn't called playAd yet, so fake the content position.
fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime();
fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
fakeContentProgressOffsetMs = C.usToMs(adGroup.timeUs);
if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) {
fakeContentProgressOffsetMs = contentDurationMs;
}
......@@ -919,11 +919,11 @@ import java.util.Map;
// The ad count may increase on successive loads of ads in the same ad pod, for example, due to
// separate requests for ad tags with multiple ads within the ad pod completing after an earlier
// ad has loaded. See also https://github.com/google/ExoPlayer/issues/7477.
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adInfo.adGroupIndex];
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
adPlaybackState =
adPlaybackState.withAdCount(
adInfo.adGroupIndex, max(adPodInfo.getTotalAds(), adGroup.states.length));
adGroup = adPlaybackState.adGroups[adInfo.adGroupIndex];
adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
for (int i = 0; i < adIndexInAdGroup; i++) {
// Any preceding ads that haven't loaded are not going to load.
if (adGroup.states[i] == AdPlaybackState.AD_STATE_UNAVAILABLE) {
......@@ -1062,10 +1062,10 @@ import java.util.Map;
private void markAdGroupInErrorStateAndClearPendingContentPosition(int adGroupIndex) {
// Update the ad playback state so all ads in the ad group are in the error state.
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
if (adGroup.count == C.LENGTH_UNSET) {
adPlaybackState = adPlaybackState.withAdCount(adGroupIndex, max(1, adGroup.states.length));
adGroup = adPlaybackState.adGroups[adGroupIndex];
adGroup = adPlaybackState.getAdGroup(adGroupIndex);
}
for (int i = 0; i < adGroup.count; i++) {
if (adGroup.states[i] == AdPlaybackState.AD_STATE_UNAVAILABLE) {
......@@ -1094,7 +1094,7 @@ import java.util.Map;
// Send IMA a content position at the ad group so that it will try to play it, at which point
// we can notify that it failed to load.
fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime();
fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.getAdGroup(adGroupIndex).timeUs);
if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) {
fakeContentProgressOffsetMs = contentDurationMs;
}
......@@ -1109,7 +1109,7 @@ import java.util.Map;
adCallbacks.get(i).onEnded(adMediaInfo);
}
}
playingAdIndexInAdGroup = adPlaybackState.adGroups[adGroupIndex].getFirstAdIndexToPlay();
playingAdIndexInAdGroup = adPlaybackState.getAdGroup(adGroupIndex).getFirstAdIndexToPlay();
for (int i = 0; i < adCallbacks.size(); i++) {
adCallbacks.get(i).onError(checkNotNull(adMediaInfo));
}
......@@ -1138,7 +1138,7 @@ import java.util.Map;
Log.d(TAG, "adsLoader.contentComplete");
}
for (int i = 0; i < adPlaybackState.adGroupCount; i++) {
if (adPlaybackState.adGroupTimesUs[i] != C.TIME_END_OF_SOURCE) {
if (adPlaybackState.getAdGroup(i).timeUs != C.TIME_END_OF_SOURCE) {
adPlaybackState = adPlaybackState.withSkippedAdGroup(/* adGroupIndex= */ i);
}
}
......@@ -1213,7 +1213,7 @@ import java.util.Map;
float cuePointTimeSecondsFloat = (float) cuePointTimeSeconds;
long adPodTimeUs = Math.round((double) cuePointTimeSecondsFloat * C.MICROS_PER_SECOND);
for (int adGroupIndex = 0; adGroupIndex < adPlaybackState.adGroupCount; adGroupIndex++) {
long adGroupTimeUs = adPlaybackState.adGroupTimesUs[adGroupIndex];
long adGroupTimeUs = adPlaybackState.getAdGroup(adGroupIndex).timeUs;
if (adGroupTimeUs != C.TIME_END_OF_SOURCE
&& Math.abs(adGroupTimeUs - adPodTimeUs) < THRESHOLD_AD_MATCH_US) {
return adGroupIndex;
......@@ -1242,14 +1242,16 @@ import java.util.Map;
}
}
private static boolean hasMidrollAdGroups(long[] adGroupTimesUs) {
int count = adGroupTimesUs.length;
private static boolean hasMidrollAdGroups(AdPlaybackState adPlaybackState) {
int count = adPlaybackState.adGroupCount;
if (count == 1) {
return adGroupTimesUs[0] != 0 && adGroupTimesUs[0] != C.TIME_END_OF_SOURCE;
long adGroupTimeUs = adPlaybackState.getAdGroup(0).timeUs;
return adGroupTimeUs != 0 && adGroupTimeUs != C.TIME_END_OF_SOURCE;
} else if (count == 2) {
return adGroupTimesUs[0] != 0 || adGroupTimesUs[1] != C.TIME_END_OF_SOURCE;
return adPlaybackState.getAdGroup(0).timeUs != 0
|| adPlaybackState.getAdGroup(1).timeUs != C.TIME_END_OF_SOURCE;
} else {
// There's at least one midroll ad group, as adGroupTimesUs is never empty.
// There's at least one midroll ad group, as adPlaybackState is never empty.
return true;
}
}
......
......@@ -1413,7 +1413,8 @@ public final class ImaAdsLoaderTest {
public void onAdPlaybackState(AdPlaybackState adPlaybackState) {
long[][] adDurationsUs = new long[adPlaybackState.adGroupCount][];
for (int adGroupIndex = 0; adGroupIndex < adPlaybackState.adGroupCount; adGroupIndex++) {
adDurationsUs[adGroupIndex] = new long[adPlaybackState.adGroups[adGroupIndex].uris.length];
adDurationsUs[adGroupIndex] =
new long[adPlaybackState.getAdGroup(adGroupIndex).uris.length];
Arrays.fill(adDurationsUs[adGroupIndex], TEST_AD_DURATION_US);
}
adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs);
......
......@@ -708,7 +708,7 @@ public abstract class Timeline implements Bundleable {
* Period}, in microseconds, or {@link C#TIME_END_OF_SOURCE} for a post-roll ad group.
*/
public long getAdGroupTimeUs(int adGroupIndex) {
return adPlaybackState.adGroupTimesUs[adGroupIndex];
return adPlaybackState.getAdGroup(adGroupIndex).timeUs;
}
/**
......@@ -720,7 +720,7 @@ public abstract class Timeline implements Bundleable {
* if no ads should be played.
*/
public int getFirstAdIndexToPlay(int adGroupIndex) {
return adPlaybackState.adGroups[adGroupIndex].getFirstAdIndexToPlay();
return adPlaybackState.getAdGroup(adGroupIndex).getFirstAdIndexToPlay();
}
/**
......@@ -734,7 +734,7 @@ public abstract class Timeline implements Bundleable {
* if the ad group does not have any ads remaining to play.
*/
public int getNextAdIndexToPlay(int adGroupIndex, int lastPlayedAdIndex) {
return adPlaybackState.adGroups[adGroupIndex].getNextAdIndexToPlay(lastPlayedAdIndex);
return adPlaybackState.getAdGroup(adGroupIndex).getNextAdIndexToPlay(lastPlayedAdIndex);
}
/**
......@@ -746,7 +746,7 @@ public abstract class Timeline implements Bundleable {
* skipped or failed.
*/
public boolean hasPlayedAdGroup(int adGroupIndex) {
return !adPlaybackState.adGroups[adGroupIndex].hasUnplayedAds();
return !adPlaybackState.getAdGroup(adGroupIndex).hasUnplayedAds();
}
/**
......@@ -782,7 +782,7 @@ public abstract class Timeline implements Bundleable {
* @return The number of ads in the ad group, or {@link C#LENGTH_UNSET} if not yet known.
*/
public int getAdCountInAdGroup(int adGroupIndex) {
return adPlaybackState.adGroups[adGroupIndex].count;
return adPlaybackState.getAdGroup(adGroupIndex).count;
}
/**
......@@ -794,7 +794,7 @@ public abstract class Timeline implements Bundleable {
* @return The duration of the ad, or {@link C#TIME_UNSET} if not yet known.
*/
public long getAdDurationUs(int adGroupIndex, int adIndexInAdGroup) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
return adGroup.count != C.LENGTH_UNSET ? adGroup.durationsUs[adIndexInAdGroup] : C.TIME_UNSET;
}
......@@ -814,7 +814,7 @@ public abstract class Timeline implements Bundleable {
* @return Whether this ad group is server-side inserted and part of the content stream.
*/
public boolean isServerSideInsertedAdGroup(int adGroupIndex) {
return adPlaybackState.adGroups[adGroupIndex].isServerSideInserted;
return adPlaybackState.getAdGroup(adGroupIndex).isServerSideInserted;
}
/**
......@@ -825,7 +825,7 @@ public abstract class Timeline implements Bundleable {
* @return The offset that should be added to the content stream, in microseconds.
*/
public long getContentResumeOffsetUs(int adGroupIndex) {
return adPlaybackState.adGroups[adGroupIndex].contentResumeOffsetUs;
return adPlaybackState.getAdGroup(adGroupIndex).contentResumeOffsetUs;
}
@Override
......
......@@ -44,9 +44,9 @@ public class AdPlaybackStateTest {
@Test
public void setAdCount() {
assertThat(state.adGroups[0].count).isEqualTo(C.LENGTH_UNSET);
assertThat(state.getAdGroup(0).count).isEqualTo(C.LENGTH_UNSET);
state = state.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1);
assertThat(state.adGroups[0].count).isEqualTo(1);
assertThat(state.getAdGroup(0).count).isEqualTo(1);
}
@Test
......@@ -54,10 +54,10 @@ public class AdPlaybackStateTest {
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1, TEST_URI);
state = state.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 2);
assertThat(state.adGroups[0].uris[0]).isNull();
assertThat(state.adGroups[0].states[0]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.adGroups[0].uris[1]).isSameInstanceAs(TEST_URI);
assertThat(state.adGroups[0].states[1]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE);
assertThat(state.getAdGroup(0).uris[0]).isNull();
assertThat(state.getAdGroup(0).states[0]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.getAdGroup(0).uris[1]).isSameInstanceAs(TEST_URI);
assertThat(state.getAdGroup(0).states[1]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE);
}
@Test
......@@ -65,10 +65,10 @@ public class AdPlaybackStateTest {
state = state.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
state = state.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 2);
assertThat(state.adGroups[0].uris[0]).isNull();
assertThat(state.adGroups[0].states[0]).isEqualTo(AdPlaybackState.AD_STATE_ERROR);
assertThat(state.getAdGroup(0).uris[0]).isNull();
assertThat(state.getAdGroup(0).states[0]).isEqualTo(AdPlaybackState.AD_STATE_ERROR);
assertThat(state.isAdInErrorState(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)).isTrue();
assertThat(state.adGroups[0].states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.getAdGroup(0).states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.isAdInErrorState(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1)).isFalse();
}
......@@ -82,8 +82,8 @@ public class AdPlaybackStateTest {
.withAdGroupTimeUs(/* adGroupIndex= */ 1, 6_000);
assertThat(state.adGroupCount).isEqualTo(2);
assertThat(state.adGroupTimesUs[0]).isEqualTo(3_000);
assertThat(state.adGroupTimesUs[1]).isEqualTo(6_000);
assertThat(state.getAdGroup(0).timeUs).isEqualTo(3_000);
assertThat(state.getAdGroup(1).timeUs).isEqualTo(6_000);
}
@Test
......@@ -102,13 +102,13 @@ public class AdPlaybackStateTest {
.withNewAdGroup(/* adGroupIndex= */ 4, /* adGroupTimeUs= */ 8_000);
assertThat(state.adGroupCount).isEqualTo(5);
assertThat(state.adGroups[0].count).isEqualTo(C.INDEX_UNSET);
assertThat(state.adGroups[1].count).isEqualTo(2);
assertThat(state.adGroups[1].uris[1]).isSameInstanceAs(TEST_URI);
assertThat(state.adGroups[2].count).isEqualTo(C.INDEX_UNSET);
assertThat(state.adGroups[3].count).isEqualTo(1);
assertThat(state.adGroups[3].states[0]).isEqualTo(AdPlaybackState.AD_STATE_SKIPPED);
assertThat(state.adGroups[4].count).isEqualTo(C.INDEX_UNSET);
assertThat(state.getAdGroup(0).count).isEqualTo(C.INDEX_UNSET);
assertThat(state.getAdGroup(1).count).isEqualTo(2);
assertThat(state.getAdGroup(1).uris[1]).isSameInstanceAs(TEST_URI);
assertThat(state.getAdGroup(2).count).isEqualTo(C.INDEX_UNSET);
assertThat(state.getAdGroup(3).count).isEqualTo(1);
assertThat(state.getAdGroup(3).states[0]).isEqualTo(AdPlaybackState.AD_STATE_SKIPPED);
assertThat(state.getAdGroup(4).count).isEqualTo(C.INDEX_UNSET);
}
@Test
......@@ -121,10 +121,10 @@ public class AdPlaybackStateTest {
state = state.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs...= */ 1_000, 2_000);
assertThat(state.adGroups[0].durationsUs[0]).isEqualTo(5_000);
assertThat(state.adGroups[0].durationsUs[1]).isEqualTo(6_000);
assertThat(state.adGroups[1].durationsUs[0]).isEqualTo(1_000);
assertThat(state.adGroups[1].durationsUs[1]).isEqualTo(2_000);
assertThat(state.getAdGroup(0).durationsUs[0]).isEqualTo(5_000);
assertThat(state.getAdGroup(0).durationsUs[1]).isEqualTo(6_000);
assertThat(state.getAdGroup(1).durationsUs[0]).isEqualTo(1_000);
assertThat(state.getAdGroup(1).durationsUs[1]).isEqualTo(2_000);
}
@Test
......@@ -133,7 +133,7 @@ public class AdPlaybackStateTest {
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 2, TEST_URI);
assertThat(state.adGroups[0].getFirstAdIndexToPlay()).isEqualTo(0);
assertThat(state.getAdGroup(0).getFirstAdIndexToPlay()).isEqualTo(0);
}
@Test
......@@ -144,9 +144,9 @@ public class AdPlaybackStateTest {
state = state.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
assertThat(state.adGroups[0].getFirstAdIndexToPlay()).isEqualTo(1);
assertThat(state.adGroups[0].states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.adGroups[0].states[2]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE);
assertThat(state.getAdGroup(0).getFirstAdIndexToPlay()).isEqualTo(1);
assertThat(state.getAdGroup(0).states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.getAdGroup(0).states[2]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE);
}
@Test
......@@ -157,9 +157,9 @@ public class AdPlaybackStateTest {
state = state.withSkippedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
assertThat(state.adGroups[0].getFirstAdIndexToPlay()).isEqualTo(1);
assertThat(state.adGroups[0].states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.adGroups[0].states[2]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE);
assertThat(state.getAdGroup(0).getFirstAdIndexToPlay()).isEqualTo(1);
assertThat(state.getAdGroup(0).states[1]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
assertThat(state.getAdGroup(0).states[2]).isEqualTo(AdPlaybackState.AD_STATE_AVAILABLE);
}
@Test
......@@ -171,7 +171,7 @@ public class AdPlaybackStateTest {
state = state.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
state = state.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1);
assertThat(state.adGroups[0].getFirstAdIndexToPlay()).isEqualTo(2);
assertThat(state.getAdGroup(0).getFirstAdIndexToPlay()).isEqualTo(2);
}
@Test
......@@ -181,7 +181,7 @@ public class AdPlaybackStateTest {
state = state.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1);
assertThat(state.adGroups[0].getNextAdIndexToPlay(0)).isEqualTo(2);
assertThat(state.getAdGroup(0).getNextAdIndexToPlay(0)).isEqualTo(2);
}
@Test
......@@ -194,7 +194,7 @@ public class AdPlaybackStateTest {
state = state.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
assertThat(state.adGroups[0].getFirstAdIndexToPlay()).isEqualTo(0);
assertThat(state.getAdGroup(0).getFirstAdIndexToPlay()).isEqualTo(0);
}
@Test
......@@ -209,8 +209,8 @@ public class AdPlaybackStateTest {
state = state.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1);
state = state.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 2);
assertThat(state.adGroups[0].getNextAdIndexToPlay(/* lastPlayedAdIndex= */ 0)).isEqualTo(1);
assertThat(state.adGroups[0].getNextAdIndexToPlay(/* lastPlayedAdIndex= */ 1)).isEqualTo(2);
assertThat(state.getAdGroup(0).getNextAdIndexToPlay(/* lastPlayedAdIndex= */ 0)).isEqualTo(1);
assertThat(state.getAdGroup(0).getNextAdIndexToPlay(/* lastPlayedAdIndex= */ 1)).isEqualTo(2);
}
@Test
......@@ -229,8 +229,8 @@ public class AdPlaybackStateTest {
public void skipAllWithoutAdCount() {
state = state.withSkippedAdGroup(0);
state = state.withSkippedAdGroup(1);
assertThat(state.adGroups[0].count).isEqualTo(0);
assertThat(state.adGroups[1].count).isEqualTo(0);
assertThat(state.getAdGroup(0).count).isEqualTo(0);
assertThat(state.getAdGroup(1).count).isEqualTo(0);
}
@Test
......@@ -257,8 +257,9 @@ public class AdPlaybackStateTest {
assertThat(restoredState.adsId).isNull();
assertThat(restoredState.adGroupCount).isEqualTo(originalState.adGroupCount);
assertThat(restoredState.adGroupTimesUs).isEqualTo(originalState.adGroupTimesUs);
assertThat(restoredState.adGroups).isEqualTo(originalState.adGroups);
for (int i = 0; i < restoredState.adGroupCount; i++) {
assertThat(restoredState.getAdGroup(i)).isEqualTo(originalState.getAdGroup(i));
}
assertThat(restoredState.adResumePositionUs).isEqualTo(originalState.adResumePositionUs);
assertThat(restoredState.contentDurationUs).isEqualTo(originalState.contentDurationUs);
}
......@@ -266,7 +267,7 @@ public class AdPlaybackStateTest {
@Test
public void roundTripViaBundle_ofAdGroup_yieldsEqualInstance() {
AdPlaybackState.AdGroup adGroup =
new AdPlaybackState.AdGroup()
new AdPlaybackState.AdGroup(/* timeUs= */ 42)
.withAdCount(2)
.withAdState(AD_STATE_AVAILABLE, /* index= */ 0)
.withAdState(AD_STATE_PLAYED, /* index= */ 1)
......
......@@ -50,7 +50,7 @@ public interface AdsLoader {
/**
* Called when the ad playback state has been updated. The number of {@link
* AdPlaybackState#adGroups ad groups} may not change after the first call.
* AdPlaybackState#adGroupCount ad groups} may not change after the first call.
*
* @param adPlaybackState The new ad playback state.
*/
......
......@@ -305,11 +305,11 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
@Nullable
AdMediaSourceHolder adMediaSourceHolder =
this.adMediaSourceHolders[adGroupIndex][adIndexInAdGroup];
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
if (adMediaSourceHolder != null
&& !adMediaSourceHolder.hasMediaSource()
&& adPlaybackState.adGroups[adGroupIndex] != null
&& adIndexInAdGroup < adPlaybackState.adGroups[adGroupIndex].uris.length) {
@Nullable Uri adUri = adPlaybackState.adGroups[adGroupIndex].uris[adIndexInAdGroup];
&& adIndexInAdGroup < adGroup.uris.length) {
@Nullable Uri adUri = adGroup.uris[adIndexInAdGroup];
if (adUri != null) {
MediaItem.Builder adMediaItem = new MediaItem.Builder().setUri(adUri);
// Propagate the content's DRM config into the ad media source.
......
......@@ -122,13 +122,14 @@ public final class ServerSideInsertedAdsMediaSource extends BaseMediaSource
public void setAdPlaybackState(AdPlaybackState adPlaybackState) {
checkArgument(adPlaybackState.adGroupCount >= this.adPlaybackState.adGroupCount);
for (int i = 0; i < adPlaybackState.adGroupCount; i++) {
checkArgument(adPlaybackState.adGroups[i].isServerSideInserted);
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i);
checkArgument(adGroup.isServerSideInserted);
if (i < this.adPlaybackState.adGroupCount) {
checkArgument(
getAdCountInGroup(adPlaybackState, /* adGroupIndex= */ i)
>= getAdCountInGroup(this.adPlaybackState, /* adGroupIndex= */ i));
}
if (adPlaybackState.adGroupTimesUs[i] == C.TIME_END_OF_SOURCE) {
if (adGroup.timeUs == C.TIME_END_OF_SOURCE) {
checkArgument(getAdCountInGroup(adPlaybackState, /* adGroupIndex= */ i) == 0);
}
}
......@@ -482,14 +483,14 @@ public final class ServerSideInsertedAdsMediaSource extends BaseMediaSource
MediaPeriodImpl mediaPeriod, AdPlaybackState adPlaybackState) {
MediaPeriodId id = mediaPeriod.mediaPeriodId;
if (id.isAd()) {
return adPlaybackState.adGroups[id.adGroupIndex].count == C.LENGTH_UNSET
? 0
: adPlaybackState.adGroups[id.adGroupIndex].durationsUs[id.adIndexInAdGroup];
}
return id.nextAdGroupIndex == C.INDEX_UNSET
|| adPlaybackState.adGroupTimesUs[id.nextAdGroupIndex] == C.TIME_END_OF_SOURCE
? Long.MAX_VALUE
: adPlaybackState.adGroupTimesUs[id.nextAdGroupIndex];
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(id.adGroupIndex);
return adGroup.count == C.LENGTH_UNSET ? 0 : adGroup.durationsUs[id.adIndexInAdGroup];
}
if (id.nextAdGroupIndex == C.INDEX_UNSET) {
return Long.MAX_VALUE;
}
AdPlaybackState.AdGroup nextAdGroup = adPlaybackState.getAdGroup(id.nextAdGroupIndex);
return nextAdGroup.timeUs == C.TIME_END_OF_SOURCE ? Long.MAX_VALUE : nextAdGroup.timeUs;
}
private static MediaLoadData correctMediaLoadData(
......
......@@ -55,8 +55,8 @@ public final class ServerSideInsertedAdsUtil {
fromPositionUs, /* nextAdGroupIndex= */ C.INDEX_UNSET, adPlaybackState);
int insertionIndex = 0;
while (insertionIndex < adPlaybackState.adGroupCount
&& adPlaybackState.adGroupTimesUs[insertionIndex] != C.TIME_END_OF_SOURCE
&& adPlaybackState.adGroupTimesUs[insertionIndex] <= adGroupInsertionPositionUs) {
&& adPlaybackState.getAdGroup(insertionIndex).timeUs != C.TIME_END_OF_SOURCE
&& adPlaybackState.getAdGroup(insertionIndex).timeUs <= adGroupInsertionPositionUs) {
insertionIndex++;
}
long adDurationUs = toPositionUs - fromPositionUs;
......@@ -69,11 +69,11 @@ public final class ServerSideInsertedAdsUtil {
.withContentResumeOffsetUs(insertionIndex, contentResumeOffsetUs);
long followingAdGroupTimeUsOffset = -adDurationUs + contentResumeOffsetUs;
for (int i = insertionIndex + 1; i < adPlaybackState.adGroupCount; i++) {
if (adPlaybackState.adGroupTimesUs[i] != C.TIME_END_OF_SOURCE) {
long adGroupTimeUs = adPlaybackState.getAdGroup(i).timeUs;
if (adGroupTimeUs != C.TIME_END_OF_SOURCE) {
adPlaybackState =
adPlaybackState.withAdGroupTimeUs(
/* adGroupIndex= */ i,
adPlaybackState.adGroupTimesUs[i] + followingAdGroupTimeUsOffset);
/* adGroupIndex= */ i, adGroupTimeUs + followingAdGroupTimeUsOffset);
}
}
return adPlaybackState;
......@@ -182,16 +182,18 @@ public final class ServerSideInsertedAdsUtil {
*/
public static long getStreamPositionUsForAd(
long positionUs, int adGroupIndex, int adIndexInAdGroup, AdPlaybackState adPlaybackState) {
positionUs += adPlaybackState.adGroupTimesUs[adGroupIndex];
AdPlaybackState.AdGroup currentAdGroup = adPlaybackState.getAdGroup(adGroupIndex);
positionUs += currentAdGroup.timeUs;
for (int i = 0; i < adGroupIndex; i++) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i);
for (int j = 0; j < getAdCountInGroup(adPlaybackState, /* adGroupIndex= */ i); j++) {
positionUs += adPlaybackState.adGroups[i].durationsUs[j];
positionUs += adGroup.durationsUs[j];
}
positionUs -= adPlaybackState.adGroups[i].contentResumeOffsetUs;
positionUs -= adGroup.contentResumeOffsetUs;
}
if (adIndexInAdGroup < getAdCountInGroup(adPlaybackState, adGroupIndex)) {
for (int i = 0; i < adIndexInAdGroup; i++) {
positionUs += adPlaybackState.adGroups[adGroupIndex].durationsUs[i];
positionUs += currentAdGroup.durationsUs[i];
}
}
return positionUs;
......@@ -210,16 +212,18 @@ public final class ServerSideInsertedAdsUtil {
*/
public static long getMediaPeriodPositionUsForAd(
long positionUs, int adGroupIndex, int adIndexInAdGroup, AdPlaybackState adPlaybackState) {
positionUs -= adPlaybackState.adGroupTimesUs[adGroupIndex];
AdPlaybackState.AdGroup currentAdGroup = adPlaybackState.getAdGroup(adGroupIndex);
positionUs -= currentAdGroup.timeUs;
for (int i = 0; i < adGroupIndex; i++) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i);
for (int j = 0; j < getAdCountInGroup(adPlaybackState, /* adGroupIndex= */ i); j++) {
positionUs -= adPlaybackState.adGroups[i].durationsUs[j];
positionUs -= adGroup.durationsUs[j];
}
positionUs += adPlaybackState.adGroups[i].contentResumeOffsetUs;
positionUs += adGroup.contentResumeOffsetUs;
}
if (adIndexInAdGroup < getAdCountInGroup(adPlaybackState, adGroupIndex)) {
for (int i = 0; i < adIndexInAdGroup; i++) {
positionUs -= adPlaybackState.adGroups[adGroupIndex].durationsUs[i];
positionUs -= currentAdGroup.durationsUs[i];
}
}
return positionUs;
......@@ -243,18 +247,16 @@ public final class ServerSideInsertedAdsUtil {
nextAdGroupIndex = adPlaybackState.adGroupCount;
}
for (int i = 0; i < nextAdGroupIndex; i++) {
if (adPlaybackState.adGroupTimesUs[i] == C.TIME_END_OF_SOURCE
|| adPlaybackState.adGroupTimesUs[i] > positionUs) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i);
if (adGroup.timeUs == C.TIME_END_OF_SOURCE || adGroup.timeUs > positionUs) {
break;
}
long adGroupStreamStartPositionUs =
adPlaybackState.adGroupTimesUs[i] + totalAdDurationBeforePositionUs;
long adGroupStreamStartPositionUs = adGroup.timeUs + totalAdDurationBeforePositionUs;
for (int j = 0; j < getAdCountInGroup(adPlaybackState, /* adGroupIndex= */ i); j++) {
totalAdDurationBeforePositionUs += adPlaybackState.adGroups[i].durationsUs[j];
totalAdDurationBeforePositionUs += adGroup.durationsUs[j];
}
totalAdDurationBeforePositionUs -= adPlaybackState.adGroups[i].contentResumeOffsetUs;
long adGroupResumePositionUs =
adPlaybackState.adGroupTimesUs[i] + adPlaybackState.adGroups[i].contentResumeOffsetUs;
totalAdDurationBeforePositionUs -= adGroup.contentResumeOffsetUs;
long adGroupResumePositionUs = adGroup.timeUs + adGroup.contentResumeOffsetUs;
if (adGroupResumePositionUs > positionUs) {
// The position is inside the ad group.
return max(adGroupStreamStartPositionUs, positionUs + totalAdDurationBeforePositionUs);
......@@ -282,19 +284,19 @@ public final class ServerSideInsertedAdsUtil {
nextAdGroupIndex = adPlaybackState.adGroupCount;
}
for (int i = 0; i < nextAdGroupIndex; i++) {
if (adPlaybackState.adGroupTimesUs[i] == C.TIME_END_OF_SOURCE
|| adPlaybackState.adGroupTimesUs[i] > positionUs - totalAdDurationBeforePositionUs) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i);
if (adGroup.timeUs == C.TIME_END_OF_SOURCE
|| adGroup.timeUs > positionUs - totalAdDurationBeforePositionUs) {
break;
}
for (int j = 0; j < getAdCountInGroup(adPlaybackState, /* adGroupIndex= */ i); j++) {
totalAdDurationBeforePositionUs += adPlaybackState.adGroups[i].durationsUs[j];
totalAdDurationBeforePositionUs += adGroup.durationsUs[j];
}
totalAdDurationBeforePositionUs -= adPlaybackState.adGroups[i].contentResumeOffsetUs;
long adGroupResumePositionUs =
adPlaybackState.adGroupTimesUs[i] + adPlaybackState.adGroups[i].contentResumeOffsetUs;
totalAdDurationBeforePositionUs -= adGroup.contentResumeOffsetUs;
long adGroupResumePositionUs = adGroup.timeUs + adGroup.contentResumeOffsetUs;
if (adGroupResumePositionUs > positionUs - totalAdDurationBeforePositionUs) {
// The position is inside the ad group.
return max(adPlaybackState.adGroupTimesUs[i], positionUs - totalAdDurationBeforePositionUs);
return max(adGroup.timeUs, positionUs - totalAdDurationBeforePositionUs);
}
}
return positionUs - totalAdDurationBeforePositionUs;
......@@ -308,8 +310,7 @@ public final class ServerSideInsertedAdsUtil {
* @return The number of ads in the ad group.
*/
public static int getAdCountInGroup(AdPlaybackState adPlaybackState, int adGroupIndex) {
return adPlaybackState.adGroups[adGroupIndex].count == C.LENGTH_UNSET
? 0
: adPlaybackState.adGroups[adGroupIndex].count;
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
return adGroup.count == C.LENGTH_UNSET ? 0 : adGroup.count;
}
}
......@@ -797,7 +797,9 @@ public final class MediaPeriodQueueTest {
long[][] newDurations = new long[adPlaybackState.adGroupCount][];
for (int i = 0; i < adPlaybackState.adGroupCount; i++) {
newDurations[i] =
i == adGroupIndex ? new long[] {AD_DURATION_US} : adPlaybackState.adGroups[i].durationsUs;
i == adGroupIndex
? new long[] {AD_DURATION_US}
: adPlaybackState.getAdGroup(i).durationsUs;
}
adPlaybackState =
adPlaybackState
......@@ -808,7 +810,7 @@ public final class MediaPeriodQueueTest {
}
private void setAdGroupPlayed(int adGroupIndex) {
for (int i = 0; i < adPlaybackState.adGroups[adGroupIndex].count; i++) {
for (int i = 0; i < adPlaybackState.getAdGroup(adGroupIndex).count; i++) {
adPlaybackState = adPlaybackState.withPlayedAd(adGroupIndex, /* adIndexInAdGroup= */ i);
}
updateTimeline();
......
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