Support resuming ads

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161778560
This commit is contained in:
andrewlewis 2017-07-13 01:55:33 -07:00 committed by Oliver Woodman
parent 6c74a31556
commit 70c5bf7052
6 changed files with 53 additions and 17 deletions

View file

@ -51,6 +51,11 @@ import java.util.Arrays;
*/
public final Uri[][] adUris;
/**
* The position offset in the first unplayed ad at which to begin playback, in microseconds.
*/
public long adResumePositionUs;
/**
* Creates a new ad playback state with the specified ad group times.
*
@ -69,12 +74,13 @@ import java.util.Arrays;
}
private AdPlaybackState(long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts,
int[] adsPlayedCounts, Uri[][] adUris) {
int[] adsPlayedCounts, Uri[][] adUris, long adResumePositionUs) {
this.adGroupTimesUs = adGroupTimesUs;
this.adCounts = adCounts;
this.adsLoadedCounts = adsLoadedCounts;
this.adsPlayedCounts = adsPlayedCounts;
this.adUris = adUris;
this.adResumePositionUs = adResumePositionUs;
adGroupCount = adGroupTimesUs.length;
}
@ -87,10 +93,8 @@ import java.util.Arrays;
adUris[i] = Arrays.copyOf(this.adUris[i], this.adUris[i].length);
}
return new AdPlaybackState(Arrays.copyOf(adGroupTimesUs, adGroupCount),
Arrays.copyOf(adCounts, adGroupCount),
Arrays.copyOf(adsLoadedCounts, adGroupCount),
Arrays.copyOf(adsPlayedCounts, adGroupCount),
adUris);
Arrays.copyOf(adCounts, adGroupCount), Arrays.copyOf(adsLoadedCounts, adGroupCount),
Arrays.copyOf(adsPlayedCounts, adGroupCount), adUris, adResumePositionUs);
}
/**
@ -114,7 +118,15 @@ import java.util.Arrays;
* Marks the last ad in the specified ad group as played.
*/
public void playedAd(int adGroupIndex) {
adResumePositionUs = 0;
adsPlayedCounts[adGroupIndex]++;
}
/**
* Sets the position offset in the first unplayed ad at which to begin playback, in microseconds.
*/
public void setAdResumePositionUs(long adResumePositionUs) {
this.adResumePositionUs = adResumePositionUs;
}
}

View file

@ -226,7 +226,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye
player.addListener(this);
if (adPlaybackState != null) {
eventListener.onAdPlaybackState(adPlaybackState);
// TODO: Call adsManager.resume if an ad is playing.
if (playingAd) {
adsManager.resume();
}
} else if (adTagUri != null) {
requestAds();
}
@ -239,7 +241,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye
*/
/* package */ void detachPlayer() {
if (player != null) {
if (adsManager != null && player.isPlayingAd()) {
if (adsManager != null && playingAd) {
adPlaybackState.setAdResumePositionUs(C.msToUs(player.getCurrentPosition()));
adsManager.pause();
}
lastAdProgress = getAdProgress();
@ -449,12 +452,14 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye
if (DEBUG) {
Log.d(TAG, "pauseAd");
}
if (player == null || !imaPlayingAd) {
// This method is called after content is resumed, and may also be called after release.
if (!imaPlayingAd) {
// This method is called after content is resumed.
return;
}
imaPausedInAd = true;
player.setPlayWhenReady(false);
if (player != null) {
player.setPlayWhenReady(false);
}
for (VideoAdPlayerCallback callback : adCallbacks) {
callback.onPause();
}

View file

@ -210,7 +210,7 @@ public final class ImaAdsMediaSource implements MediaSource {
if (adPlaybackState != null && contentTimeline != null) {
SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline,
adPlaybackState.adGroupTimesUs, adPlaybackState.adCounts, adPlaybackState.adsLoadedCounts,
adPlaybackState.adsPlayedCounts, adDurationsUs);
adPlaybackState.adsPlayedCounts, adDurationsUs, adPlaybackState.adResumePositionUs);
listener.onSourceInfoRefreshed(timeline, contentManifest);
}
}

View file

@ -30,6 +30,7 @@ public final class SinglePeriodAdTimeline extends Timeline {
private final int[] adsLoadedCounts;
private final int[] adsPlayedCounts;
private final long[][] adDurationsUs;
private final long adResumePositionUs;
/**
* Creates a new timeline with a single period containing the specified ads.
@ -45,9 +46,12 @@ public final class SinglePeriodAdTimeline extends Timeline {
* @param adsPlayedCounts The number of ads played so far in each ad group.
* @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element
* may be {@link C#TIME_UNSET} if the duration is not yet known.
* @param adResumePositionUs The position offset in the earliest unplayed ad at which to begin
* playback, in microseconds.
*/
public SinglePeriodAdTimeline(Timeline contentTimeline, long[] adGroupTimesUs, int[] adCounts,
int[] adsLoadedCounts, int[] adsPlayedCounts, long[][] adDurationsUs) {
int[] adsLoadedCounts, int[] adsPlayedCounts, long[][] adDurationsUs,
long adResumePositionUs) {
Assertions.checkState(contentTimeline.getPeriodCount() == 1);
Assertions.checkState(contentTimeline.getWindowCount() == 1);
this.contentTimeline = contentTimeline;
@ -56,6 +60,7 @@ public final class SinglePeriodAdTimeline extends Timeline {
this.adsLoadedCounts = adsLoadedCounts;
this.adsPlayedCounts = adsPlayedCounts;
this.adDurationsUs = adDurationsUs;
this.adResumePositionUs = adResumePositionUs;
}
@Override
@ -79,7 +84,7 @@ public final class SinglePeriodAdTimeline extends Timeline {
contentTimeline.getPeriod(periodIndex, period, setIds);
period.set(period.id, period.uid, period.windowIndex, period.durationUs,
period.getPositionInWindowUs(), adGroupTimesUs, adCounts, adsLoadedCounts, adsPlayedCounts,
adDurationsUs);
adDurationsUs, adResumePositionUs);
return period;
}

View file

@ -300,8 +300,10 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod);
long durationUs = timeline.getPeriod(id.periodIndex, period)
.getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup);
return new MediaPeriodInfo(id, 0, C.TIME_END_OF_SOURCE, contentPositionUs, durationUs,
isLastInPeriod, isLastInTimeline);
long startPositionUs = adIndexInAdGroup == period.getPlayedAdCount(adGroupIndex)
? period.getAdResumePositionUs() : 0;
return new MediaPeriodInfo(id, startPositionUs, C.TIME_END_OF_SOURCE, contentPositionUs,
durationUs, isLastInPeriod, isLastInTimeline);
}
private MediaPeriodInfo getMediaPeriodInfoForContent(int periodIndex, long startPositionUs,

View file

@ -270,6 +270,7 @@ public abstract class Timeline {
private int[] adsLoadedCounts;
private int[] adsPlayedCounts;
private long[][] adDurationsUs;
private long adResumePositionUs;
/**
* Sets the data held by this period.
@ -287,7 +288,7 @@ public abstract class Timeline {
public Period set(Object id, Object uid, int windowIndex, long durationUs,
long positionInWindowUs) {
return set(id, uid, windowIndex, durationUs, positionInWindowUs, null, null, null, null,
null);
null, C.TIME_UNSET);
}
/**
@ -310,11 +311,13 @@ public abstract class Timeline {
* @param adsPlayedCounts The number of ads played so far in each ad group.
* @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element
* may be {@link C#TIME_UNSET} if the duration is not yet known.
* @param adResumePositionUs The position offset in the first unplayed ad at which to begin
* playback, in microseconds.
* @return This period, for convenience.
*/
public Period set(Object id, Object uid, int windowIndex, long durationUs,
long positionInWindowUs, long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts,
int[] adsPlayedCounts, long[][] adDurationsUs) {
int[] adsPlayedCounts, long[][] adDurationsUs, long adResumePositionUs) {
this.id = id;
this.uid = uid;
this.windowIndex = windowIndex;
@ -325,6 +328,7 @@ public abstract class Timeline {
this.adsLoadedCounts = adsLoadedCounts;
this.adsPlayedCounts = adsPlayedCounts;
this.adDurationsUs = adDurationsUs;
this.adResumePositionUs = adResumePositionUs;
return this;
}
@ -479,6 +483,14 @@ public abstract class Timeline {
return adDurationsUs[adGroupIndex][adIndexInAdGroup];
}
/**
* Returns the position offset in the first unplayed ad at which to begin playback, in
* microseconds.
*/
public long getAdResumePositionUs() {
return adResumePositionUs;
}
}
/**