Commit 70c5bf70 by andrewlewis Committed by Oliver Woodman

Support resuming ads

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161778560
parent 6c74a315
...@@ -52,6 +52,11 @@ import java.util.Arrays; ...@@ -52,6 +52,11 @@ import java.util.Arrays;
public final Uri[][] adUris; 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. * Creates a new ad playback state with the specified ad group times.
* *
* @param adGroupTimesUs The times of ad groups in microseconds. A final element with the value * @param adGroupTimesUs The times of ad groups in microseconds. A final element with the value
...@@ -69,12 +74,13 @@ import java.util.Arrays; ...@@ -69,12 +74,13 @@ import java.util.Arrays;
} }
private AdPlaybackState(long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts, private AdPlaybackState(long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts,
int[] adsPlayedCounts, Uri[][] adUris) { int[] adsPlayedCounts, Uri[][] adUris, long adResumePositionUs) {
this.adGroupTimesUs = adGroupTimesUs; this.adGroupTimesUs = adGroupTimesUs;
this.adCounts = adCounts; this.adCounts = adCounts;
this.adsLoadedCounts = adsLoadedCounts; this.adsLoadedCounts = adsLoadedCounts;
this.adsPlayedCounts = adsPlayedCounts; this.adsPlayedCounts = adsPlayedCounts;
this.adUris = adUris; this.adUris = adUris;
this.adResumePositionUs = adResumePositionUs;
adGroupCount = adGroupTimesUs.length; adGroupCount = adGroupTimesUs.length;
} }
...@@ -87,10 +93,8 @@ import java.util.Arrays; ...@@ -87,10 +93,8 @@ import java.util.Arrays;
adUris[i] = Arrays.copyOf(this.adUris[i], this.adUris[i].length); adUris[i] = Arrays.copyOf(this.adUris[i], this.adUris[i].length);
} }
return new AdPlaybackState(Arrays.copyOf(adGroupTimesUs, adGroupCount), return new AdPlaybackState(Arrays.copyOf(adGroupTimesUs, adGroupCount),
Arrays.copyOf(adCounts, adGroupCount), Arrays.copyOf(adCounts, adGroupCount), Arrays.copyOf(adsLoadedCounts, adGroupCount),
Arrays.copyOf(adsLoadedCounts, adGroupCount), Arrays.copyOf(adsPlayedCounts, adGroupCount), adUris, adResumePositionUs);
Arrays.copyOf(adsPlayedCounts, adGroupCount),
adUris);
} }
/** /**
...@@ -114,7 +118,15 @@ import java.util.Arrays; ...@@ -114,7 +118,15 @@ import java.util.Arrays;
* Marks the last ad in the specified ad group as played. * Marks the last ad in the specified ad group as played.
*/ */
public void playedAd(int adGroupIndex) { public void playedAd(int adGroupIndex) {
adResumePositionUs = 0;
adsPlayedCounts[adGroupIndex]++; 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;
}
} }
...@@ -226,7 +226,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye ...@@ -226,7 +226,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye
player.addListener(this); player.addListener(this);
if (adPlaybackState != null) { if (adPlaybackState != null) {
eventListener.onAdPlaybackState(adPlaybackState); eventListener.onAdPlaybackState(adPlaybackState);
// TODO: Call adsManager.resume if an ad is playing. if (playingAd) {
adsManager.resume();
}
} else if (adTagUri != null) { } else if (adTagUri != null) {
requestAds(); requestAds();
} }
...@@ -239,7 +241,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye ...@@ -239,7 +241,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye
*/ */
/* package */ void detachPlayer() { /* package */ void detachPlayer() {
if (player != null) { if (player != null) {
if (adsManager != null && player.isPlayingAd()) { if (adsManager != null && playingAd) {
adPlaybackState.setAdResumePositionUs(C.msToUs(player.getCurrentPosition()));
adsManager.pause(); adsManager.pause();
} }
lastAdProgress = getAdProgress(); lastAdProgress = getAdProgress();
...@@ -449,12 +452,14 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye ...@@ -449,12 +452,14 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "pauseAd"); Log.d(TAG, "pauseAd");
} }
if (player == null || !imaPlayingAd) { if (!imaPlayingAd) {
// This method is called after content is resumed, and may also be called after release. // This method is called after content is resumed.
return; return;
} }
imaPausedInAd = true; imaPausedInAd = true;
if (player != null) {
player.setPlayWhenReady(false); player.setPlayWhenReady(false);
}
for (VideoAdPlayerCallback callback : adCallbacks) { for (VideoAdPlayerCallback callback : adCallbacks) {
callback.onPause(); callback.onPause();
} }
......
...@@ -210,7 +210,7 @@ public final class ImaAdsMediaSource implements MediaSource { ...@@ -210,7 +210,7 @@ public final class ImaAdsMediaSource implements MediaSource {
if (adPlaybackState != null && contentTimeline != null) { if (adPlaybackState != null && contentTimeline != null) {
SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline, SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline,
adPlaybackState.adGroupTimesUs, adPlaybackState.adCounts, adPlaybackState.adsLoadedCounts, adPlaybackState.adGroupTimesUs, adPlaybackState.adCounts, adPlaybackState.adsLoadedCounts,
adPlaybackState.adsPlayedCounts, adDurationsUs); adPlaybackState.adsPlayedCounts, adDurationsUs, adPlaybackState.adResumePositionUs);
listener.onSourceInfoRefreshed(timeline, contentManifest); listener.onSourceInfoRefreshed(timeline, contentManifest);
} }
} }
......
...@@ -30,6 +30,7 @@ public final class SinglePeriodAdTimeline extends Timeline { ...@@ -30,6 +30,7 @@ public final class SinglePeriodAdTimeline extends Timeline {
private final int[] adsLoadedCounts; private final int[] adsLoadedCounts;
private final int[] adsPlayedCounts; private final int[] adsPlayedCounts;
private final long[][] adDurationsUs; private final long[][] adDurationsUs;
private final long adResumePositionUs;
/** /**
* Creates a new timeline with a single period containing the specified ads. * Creates a new timeline with a single period containing the specified ads.
...@@ -45,9 +46,12 @@ public final class SinglePeriodAdTimeline extends Timeline { ...@@ -45,9 +46,12 @@ public final class SinglePeriodAdTimeline extends Timeline {
* @param adsPlayedCounts The number of ads played so far in each ad group. * @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 * @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. * 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, 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.getPeriodCount() == 1);
Assertions.checkState(contentTimeline.getWindowCount() == 1); Assertions.checkState(contentTimeline.getWindowCount() == 1);
this.contentTimeline = contentTimeline; this.contentTimeline = contentTimeline;
...@@ -56,6 +60,7 @@ public final class SinglePeriodAdTimeline extends Timeline { ...@@ -56,6 +60,7 @@ public final class SinglePeriodAdTimeline extends Timeline {
this.adsLoadedCounts = adsLoadedCounts; this.adsLoadedCounts = adsLoadedCounts;
this.adsPlayedCounts = adsPlayedCounts; this.adsPlayedCounts = adsPlayedCounts;
this.adDurationsUs = adDurationsUs; this.adDurationsUs = adDurationsUs;
this.adResumePositionUs = adResumePositionUs;
} }
@Override @Override
...@@ -79,7 +84,7 @@ public final class SinglePeriodAdTimeline extends Timeline { ...@@ -79,7 +84,7 @@ public final class SinglePeriodAdTimeline extends Timeline {
contentTimeline.getPeriod(periodIndex, period, setIds); contentTimeline.getPeriod(periodIndex, period, setIds);
period.set(period.id, period.uid, period.windowIndex, period.durationUs, period.set(period.id, period.uid, period.windowIndex, period.durationUs,
period.getPositionInWindowUs(), adGroupTimesUs, adCounts, adsLoadedCounts, adsPlayedCounts, period.getPositionInWindowUs(), adGroupTimesUs, adCounts, adsLoadedCounts, adsPlayedCounts,
adDurationsUs); adDurationsUs, adResumePositionUs);
return period; return period;
} }
......
...@@ -300,8 +300,10 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; ...@@ -300,8 +300,10 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod);
long durationUs = timeline.getPeriod(id.periodIndex, period) long durationUs = timeline.getPeriod(id.periodIndex, period)
.getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup); .getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup);
return new MediaPeriodInfo(id, 0, C.TIME_END_OF_SOURCE, contentPositionUs, durationUs, long startPositionUs = adIndexInAdGroup == period.getPlayedAdCount(adGroupIndex)
isLastInPeriod, isLastInTimeline); ? period.getAdResumePositionUs() : 0;
return new MediaPeriodInfo(id, startPositionUs, C.TIME_END_OF_SOURCE, contentPositionUs,
durationUs, isLastInPeriod, isLastInTimeline);
} }
private MediaPeriodInfo getMediaPeriodInfoForContent(int periodIndex, long startPositionUs, private MediaPeriodInfo getMediaPeriodInfoForContent(int periodIndex, long startPositionUs,
......
...@@ -270,6 +270,7 @@ public abstract class Timeline { ...@@ -270,6 +270,7 @@ public abstract class Timeline {
private int[] adsLoadedCounts; private int[] adsLoadedCounts;
private int[] adsPlayedCounts; private int[] adsPlayedCounts;
private long[][] adDurationsUs; private long[][] adDurationsUs;
private long adResumePositionUs;
/** /**
* Sets the data held by this period. * Sets the data held by this period.
...@@ -287,7 +288,7 @@ public abstract class Timeline { ...@@ -287,7 +288,7 @@ public abstract class Timeline {
public Period set(Object id, Object uid, int windowIndex, long durationUs, public Period set(Object id, Object uid, int windowIndex, long durationUs,
long positionInWindowUs) { long positionInWindowUs) {
return set(id, uid, windowIndex, durationUs, positionInWindowUs, null, null, null, null, return set(id, uid, windowIndex, durationUs, positionInWindowUs, null, null, null, null,
null); null, C.TIME_UNSET);
} }
/** /**
...@@ -310,11 +311,13 @@ public abstract class Timeline { ...@@ -310,11 +311,13 @@ public abstract class Timeline {
* @param adsPlayedCounts The number of ads played so far in each ad group. * @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 * @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. * 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. * @return This period, for convenience.
*/ */
public Period set(Object id, Object uid, int windowIndex, long durationUs, public Period set(Object id, Object uid, int windowIndex, long durationUs,
long positionInWindowUs, long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts, long positionInWindowUs, long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts,
int[] adsPlayedCounts, long[][] adDurationsUs) { int[] adsPlayedCounts, long[][] adDurationsUs, long adResumePositionUs) {
this.id = id; this.id = id;
this.uid = uid; this.uid = uid;
this.windowIndex = windowIndex; this.windowIndex = windowIndex;
...@@ -325,6 +328,7 @@ public abstract class Timeline { ...@@ -325,6 +328,7 @@ public abstract class Timeline {
this.adsLoadedCounts = adsLoadedCounts; this.adsLoadedCounts = adsLoadedCounts;
this.adsPlayedCounts = adsPlayedCounts; this.adsPlayedCounts = adsPlayedCounts;
this.adDurationsUs = adDurationsUs; this.adDurationsUs = adDurationsUs;
this.adResumePositionUs = adResumePositionUs;
return this; return this;
} }
...@@ -479,6 +483,14 @@ public abstract class Timeline { ...@@ -479,6 +483,14 @@ public abstract class Timeline {
return adDurationsUs[adGroupIndex][adIndexInAdGroup]; 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;
}
} }
/** /**
......
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