Get the next ad index to play in MediaPeriodQueue

The ad index in the ad group may need to skip over ads that failed to load, so
it can't just be incremented any more.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=184812556
This commit is contained in:
andrewlewis 2018-02-07 02:44:23 -08:00 committed by Oliver Woodman
parent fea75f2e42
commit 84a105b031
5 changed files with 81 additions and 32 deletions

View File

@ -887,7 +887,7 @@ public final class ImaAdsLoader extends Player.DefaultEventListener implements A
private void stopAdInternal() {
Assertions.checkState(imaAdState != IMA_AD_STATE_NONE);
imaAdState = IMA_AD_STATE_NONE;
int adIndexInAdGroup = adPlaybackState.adGroups[adGroupIndex].nextAdIndexToPlay;
int adIndexInAdGroup = adPlaybackState.adGroups[adGroupIndex].getFirstAdIndexToPlay();
// TODO: Handle the skipped event so the ad can be marked as skipped rather than played.
adPlaybackState =
adPlaybackState.withPlayedAd(adGroupIndex, adIndexInAdGroup).withAdResumePositionUs(0);

View File

@ -372,7 +372,7 @@ import com.google.android.exoplayer2.util.Assertions;
if (adGroupIndex == C.INDEX_UNSET) {
return new MediaPeriodId(periodIndex);
} else {
int adIndexInAdGroup = period.getNextAdIndexToPlay(adGroupIndex);
int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex);
return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup);
}
}
@ -496,19 +496,20 @@ import com.google.android.exoplayer2.util.Assertions;
MediaPeriodId currentPeriodId = mediaPeriodInfo.id;
timeline.getPeriod(currentPeriodId.periodIndex, period);
if (currentPeriodId.isAd()) {
int currentAdGroupIndex = currentPeriodId.adGroupIndex;
int adCountInCurrentAdGroup = period.getAdCountInAdGroup(currentAdGroupIndex);
int adGroupIndex = currentPeriodId.adGroupIndex;
int adCountInCurrentAdGroup = period.getAdCountInAdGroup(adGroupIndex);
if (adCountInCurrentAdGroup == C.LENGTH_UNSET) {
return null;
}
int nextAdIndexInAdGroup = currentPeriodId.adIndexInAdGroup + 1;
int nextAdIndexInAdGroup =
period.getNextAdIndexToPlay(adGroupIndex, currentPeriodId.adIndexInAdGroup);
if (nextAdIndexInAdGroup < adCountInCurrentAdGroup) {
// Play the next ad in the ad group if it's available.
return !period.isAdAvailable(currentAdGroupIndex, nextAdIndexInAdGroup)
return !period.isAdAvailable(adGroupIndex, nextAdIndexInAdGroup)
? null
: getMediaPeriodInfoForAd(
currentPeriodId.periodIndex,
currentAdGroupIndex,
adGroupIndex,
nextAdIndexInAdGroup,
mediaPeriodInfo.contentPositionUs);
} else {
@ -524,22 +525,32 @@ import com.google.android.exoplayer2.util.Assertions;
return getMediaPeriodInfoForContent(
currentPeriodId.periodIndex, mediaPeriodInfo.endPositionUs);
}
return !period.isAdAvailable(nextAdGroupIndex, 0)
int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex);
return !period.isAdAvailable(nextAdGroupIndex, adIndexInAdGroup)
? null
: getMediaPeriodInfoForAd(
currentPeriodId.periodIndex, nextAdGroupIndex, 0, mediaPeriodInfo.endPositionUs);
currentPeriodId.periodIndex,
nextAdGroupIndex,
adIndexInAdGroup,
mediaPeriodInfo.endPositionUs);
} else {
// Check if the postroll ad should be played.
int adGroupCount = period.getAdGroupCount();
if (adGroupCount == 0
|| period.getAdGroupTimeUs(adGroupCount - 1) != C.TIME_END_OF_SOURCE
|| period.hasPlayedAdGroup(adGroupCount - 1)
|| !period.isAdAvailable(adGroupCount - 1, 0)) {
if (adGroupCount == 0) {
return null;
}
int adGroupIndex = adGroupCount - 1;
if (period.getAdGroupTimeUs(adGroupIndex) != C.TIME_END_OF_SOURCE
|| period.hasPlayedAdGroup(adGroupIndex)) {
return null;
}
int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex);
if (!period.isAdAvailable(adGroupIndex, adIndexInAdGroup)) {
return null;
}
long contentDurationUs = period.getDurationUs();
return getMediaPeriodInfoForAd(
currentPeriodId.periodIndex, adGroupCount - 1, 0, contentDurationUs);
currentPeriodId.periodIndex, adGroupIndex, adIndexInAdGroup, contentDurationUs);
}
}
@ -587,7 +598,7 @@ import com.google.android.exoplayer2.util.Assertions;
.getPeriod(id.periodIndex, period)
.getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup);
long startPositionUs =
adIndexInAdGroup == period.getNextAdIndexToPlay(adGroupIndex)
adIndexInAdGroup == period.getFirstAdIndexToPlay(adGroupIndex)
? period.getAdResumePositionUs()
: 0;
return new MediaPeriodInfo(
@ -636,7 +647,7 @@ import com.google.android.exoplayer2.util.Assertions;
boolean isLastAd =
isAd && id.adGroupIndex == lastAdGroupIndex && id.adIndexInAdGroup == postrollAdCount - 1;
return isLastAd || (!isAd && period.getNextAdIndexToPlay(lastAdGroupIndex) == postrollAdCount);
return isLastAd || (!isAd && period.getFirstAdIndexToPlay(lastAdGroupIndex) == postrollAdCount);
}
private boolean isLastInTimeline(MediaPeriodId id, boolean isLastMediaPeriodInPeriod) {

View File

@ -381,15 +381,29 @@ public abstract class Timeline {
}
/**
* Returns the index of the next ad to play in the specified ad group, or the number of ads in
* the ad group if the ad group does not have any ads remaining to play.
* Returns the index of the first ad in the specified ad group that should be played, or the
* number of ads in the ad group if no ads should be played.
*
* @param adGroupIndex The ad group index.
* @return The index of the first ad that should be played, or the number of ads in the ad group
* if no ads should be played.
*/
public int getFirstAdIndexToPlay(int adGroupIndex) {
return adPlaybackState.adGroups[adGroupIndex].getFirstAdIndexToPlay();
}
/**
* Returns the index of the next ad in the specified ad group that should be played after
* playing {@code adIndexInAdGroup}, or the number of ads in the ad group if no later ads should
* be played.
*
* @param adGroupIndex The ad group index.
* @param lastPlayedAdIndex The last played ad index in the ad group.
* @return The index of the next ad that should be played, or the number of ads in the ad group
* if the ad group does not have any ads remaining to play.
*/
public int getNextAdIndexToPlay(int adGroupIndex) {
return adPlaybackState.adGroups[adGroupIndex].nextAdIndexToPlay;
public int getNextAdIndexToPlay(int adGroupIndex, int lastPlayedAdIndex) {
return adPlaybackState.adGroups[adGroupIndex].getNextAdIndexToPlay(lastPlayedAdIndex);
}
/**
@ -400,7 +414,7 @@ public abstract class Timeline {
*/
public boolean hasPlayedAdGroup(int adGroupIndex) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
return adGroup.nextAdIndexToPlay == adGroup.count;
return adGroup.getFirstAdIndexToPlay() == adGroup.count;
}
/**

View File

@ -49,8 +49,6 @@ public final class AdPlaybackState {
public final @AdState int[] states;
/** The durations of each ad in the ad group, in microseconds. */
public final long[] durationsUs;
/** The index of the next ad that should be played, or {@link #count} if all ads were played. */
public final int nextAdIndexToPlay;
/** Creates a new ad group with an unspecified number of ads. */
public AdGroup() {
@ -67,14 +65,30 @@ public final class AdPlaybackState {
this.states = states;
this.uris = uris;
this.durationsUs = durationsUs;
int nextAdIndexToPlay;
for (nextAdIndexToPlay = 0; nextAdIndexToPlay < states.length; nextAdIndexToPlay++) {
}
/**
* Returns the index of the first ad in the ad group that should be played, or {@link #count} if
* no ads should be played.
*/
public int getFirstAdIndexToPlay() {
return getNextAdIndexToPlay(-1);
}
/**
* Returns the index of the next ad in the ad group that should be played after playing {@code
* lastPlayedAdIndex}, or {@link #count} if no later ads should be played.
*/
public int getNextAdIndexToPlay(int lastPlayedAdIndex) {
int nextAdIndexToPlay = lastPlayedAdIndex + 1;
while (nextAdIndexToPlay < states.length) {
if (states[nextAdIndexToPlay] == AD_STATE_UNAVAILABLE
|| states[nextAdIndexToPlay] == AD_STATE_AVAILABLE) {
break;
}
nextAdIndexToPlay++;
}
this.nextAdIndexToPlay = nextAdIndexToPlay;
return nextAdIndexToPlay;
}
/**

View File

@ -70,29 +70,29 @@ public final class AdPlaybackStateTest {
}
@Test
public void testInitialNextAdIndexToPlay() {
public void testGetFirstAdIndexToPlayIsZero() {
state = state.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 3);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 2, TEST_URI);
assertThat(state.adGroups[0].nextAdIndexToPlay).isEqualTo(0);
assertThat(state.adGroups[0].getFirstAdIndexToPlay()).isEqualTo(0);
}
@Test
public void testNextAdIndexToPlayWithPlayedAd() {
public void testGetFirstAdIndexToPlaySkipsPlayedAd() {
state = state.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 3);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 2, TEST_URI);
state = state.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
assertThat(state.adGroups[0].nextAdIndexToPlay).isEqualTo(1);
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);
}
@Test
public void testNextAdIndexToPlaySkipsErrorAds() {
public void testGetFirstAdIndexToPlaySkipsErrorAds() {
state = state.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 3);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 2, TEST_URI);
@ -100,7 +100,17 @@ public final class AdPlaybackStateTest {
state = state.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
state = state.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1);
assertThat(state.adGroups[0].nextAdIndexToPlay).isEqualTo(2);
assertThat(state.adGroups[0].getFirstAdIndexToPlay()).isEqualTo(2);
}
@Test
public void testGetNextAdIndexToPlaySkipsErrorAds() {
state = state.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 3);
state = state.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1, TEST_URI);
state = state.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 1);
assertThat(state.adGroups[0].getNextAdIndexToPlay(0)).isEqualTo(2);
}
@Test