mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Handle ad skipping and content resume
SKIPPED can't be handled as CONTENT_RESUME_REQUESTED because after skipping an ad there may be further ads to play in its ad group. Remove workaround for handling unexpected playAd without stopAd, as the player can instead recover when IMA sends CONTENT_RESUME_REQUESTED. This in turn fixes handling of the case where playAd is called twice but IMA expects only the first ad to play, when skipping a particular ad. (Add an ad tag where this occurs to internal samples.) Check whether a currently playing ad has been marked as played in ExoPlayerImplInternal, and handle this case as a seek. This ensures that any loaded ad periods are discarded in the case of CONTENT_RESUME_REQUESTED. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162610621
This commit is contained in:
parent
94b08b27e9
commit
07de4d1b2c
@ -122,6 +122,17 @@ import java.util.Arrays;
|
||||
adsPlayedCounts[adGroupIndex]++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all ads in the specified ad group as played.
|
||||
*/
|
||||
public void playedAdGroup(int adGroupIndex) {
|
||||
adResumePositionUs = 0;
|
||||
if (adCounts[adGroupIndex] == C.LENGTH_UNSET) {
|
||||
adCounts[adGroupIndex] = 0;
|
||||
}
|
||||
adsPlayedCounts[adGroupIndex] = adCounts[adGroupIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position offset in the first unplayed ad at which to begin playback, in microseconds.
|
||||
*/
|
||||
|
@ -337,7 +337,6 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer,
|
||||
imaPausedContent = true;
|
||||
pauseContentInternal();
|
||||
break;
|
||||
case SKIPPED: // Fall through.
|
||||
case CONTENT_RESUME_REQUESTED:
|
||||
imaPausedContent = false;
|
||||
resumeContentInternal();
|
||||
@ -432,9 +431,8 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer,
|
||||
}
|
||||
if (imaPlayingAd && !imaPausedInAd) {
|
||||
// Work around an issue where IMA does not always call stopAd before resuming content.
|
||||
// See [Internal: b/38354028].
|
||||
// See [Internal: b/38354028, b/63320878].
|
||||
Log.w(TAG, "Unexpected playAd without stopAd");
|
||||
stopAdInternal();
|
||||
}
|
||||
if (!imaPlayingAd) {
|
||||
imaPlayingAd = true;
|
||||
@ -497,8 +495,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer,
|
||||
Assertions.checkArgument(timeline.getPeriodCount() == 1);
|
||||
this.timeline = timeline;
|
||||
contentDurationMs = C.usToMs(timeline.getPeriod(0, period).durationUs);
|
||||
playingAd = player.isPlayingAd();
|
||||
playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET;
|
||||
updateImaStateForPlayerState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -547,9 +544,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer,
|
||||
if (adsManager == null) {
|
||||
return;
|
||||
}
|
||||
boolean wasPlayingAd = playingAd;
|
||||
playingAd = player.isPlayingAd();
|
||||
if (!wasPlayingAd && !playingAd) {
|
||||
if (!playingAd && !player.isPlayingAd()) {
|
||||
long positionUs = C.msToUs(player.getCurrentPosition());
|
||||
int adGroupIndex = timeline.getPeriod(0, period).getAdGroupIndexForPositionUs(positionUs);
|
||||
if (adGroupIndex != C.INDEX_UNSET) {
|
||||
@ -558,32 +553,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer,
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!playingAd && playWhenReadyOverriddenForAds) {
|
||||
playWhenReadyOverriddenForAds = false;
|
||||
player.setPlayWhenReady(false);
|
||||
}
|
||||
if (!sentContentComplete) {
|
||||
boolean adFinished =
|
||||
!playingAd || playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup();
|
||||
if (adFinished) {
|
||||
// IMA is waiting for the ad playback to finish so invoke the callback now.
|
||||
// Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again.
|
||||
for (VideoAdPlayerCallback callback : adCallbacks) {
|
||||
callback.onEnded();
|
||||
}
|
||||
}
|
||||
if (playingAd && !wasPlayingAd) {
|
||||
int adGroupIndex = player.getCurrentAdGroupIndex();
|
||||
// IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position.
|
||||
Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET);
|
||||
fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime();
|
||||
fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
|
||||
if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) {
|
||||
fakeContentProgressOffsetMs = contentDurationMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET;
|
||||
updateImaStateForPlayerState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -601,14 +571,47 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer,
|
||||
adsLoader.requestAds(request);
|
||||
}
|
||||
|
||||
private void updateImaStateForPlayerState() {
|
||||
boolean wasPlayingAd = playingAd;
|
||||
playingAd = player.isPlayingAd();
|
||||
if (!playingAd && playWhenReadyOverriddenForAds) {
|
||||
playWhenReadyOverriddenForAds = false;
|
||||
player.setPlayWhenReady(false);
|
||||
}
|
||||
if (!sentContentComplete) {
|
||||
boolean adFinished = (wasPlayingAd && !playingAd)
|
||||
|| playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup();
|
||||
if (adFinished) {
|
||||
// IMA is waiting for the ad playback to finish so invoke the callback now.
|
||||
// Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again.
|
||||
for (VideoAdPlayerCallback callback : adCallbacks) {
|
||||
callback.onEnded();
|
||||
}
|
||||
}
|
||||
if (!wasPlayingAd && playingAd) {
|
||||
int adGroupIndex = player.getCurrentAdGroupIndex();
|
||||
// IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position.
|
||||
Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET);
|
||||
fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime();
|
||||
fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
|
||||
if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) {
|
||||
fakeContentProgressOffsetMs = contentDurationMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
private void resumeContentInternal() {
|
||||
if (contentDurationMs != C.TIME_UNSET && imaPlayingAd) {
|
||||
// Work around an issue where IMA does not always call stopAd before resuming content.
|
||||
// See [Internal: b/38354028].
|
||||
if (imaPlayingAd) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd");
|
||||
}
|
||||
stopAdInternal();
|
||||
}
|
||||
if (playingAd && adGroupIndex != C.INDEX_UNSET) {
|
||||
adPlaybackState.playedAdGroup(adGroupIndex);
|
||||
adGroupIndex = C.INDEX_UNSET;
|
||||
updateAdPlaybackState();
|
||||
}
|
||||
clearFlags();
|
||||
}
|
||||
|
@ -1054,6 +1054,19 @@ import java.io.IOException;
|
||||
return;
|
||||
}
|
||||
|
||||
// If playing an ad, check that it hasn't been marked as played. If it has, skip forward.
|
||||
if (playbackInfo.periodId.isAd()) {
|
||||
MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex,
|
||||
playbackInfo.contentPositionUs);
|
||||
if (!periodId.isAd() || periodId.adIndexInAdGroup != playbackInfo.periodId.adIndexInAdGroup) {
|
||||
long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.contentPositionUs);
|
||||
long contentPositionUs = periodId.isAd() ? playbackInfo.contentPositionUs : C.TIME_UNSET;
|
||||
playbackInfo = new PlaybackInfo(periodId, newPositionUs, contentPositionUs);
|
||||
notifySourceInfoRefresh(manifest, processedInitialSeekCount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The current period is in the new timeline. Update the holder and playbackInfo.
|
||||
periodHolder = updatePeriodInfo(periodHolder, periodIndex);
|
||||
if (periodIndex != playbackInfo.periodId.periodIndex) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user