Drop ads for which we don't have metadata when joining a live stream

When a live stream is joined while ads are already playing, the LOADED event is
missed and we don't have ad information for those ads in the ad group that are
before the ad index at which we joined. This way we can clip the duration when we
receive the LOADED event for the last ad in the group. This fixes the problem of
the playback controls being hidden when content resumes after the ad group.

#minor-release

PiperOrigin-RevId: 431269627
(cherry picked from commit 8e8c59031c328e4c64a16193732078568712a632)
This commit is contained in:
bachinger 2022-02-27 15:18:03 +00:00 committed by Ian Baker
parent bc1bcab553
commit 6f5206cd76

View File

@ -105,11 +105,7 @@ import java.util.Map;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /** MediaSource for IMA server side inserted ad streams. */
* MediaSource for IMA server side inserted ad streams.
*
* <p>TODO(bachinger) add code snippet from PlayerActivity
*/
@UnstableApi @UnstableApi
public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSource<Void> { public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSource<Void> {
@ -119,8 +115,6 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
* *
* <p>Apps can use the {@link ImaServerSideAdInsertionMediaSource.Factory} to customized the * <p>Apps can use the {@link ImaServerSideAdInsertionMediaSource.Factory} to customized the
* {@link DefaultMediaSourceFactory} that is used to build a player: * {@link DefaultMediaSourceFactory} that is used to build a player:
*
* <p>TODO(bachinger) add code snippet from PlayerActivity
*/ */
public static final class Factory implements MediaSource.Factory { public static final class Factory implements MediaSource.Factory {
@ -461,6 +455,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
@Nullable private IOException loadError; @Nullable private IOException loadError;
private @MonotonicNonNull Timeline contentTimeline; private @MonotonicNonNull Timeline contentTimeline;
private AdPlaybackState adPlaybackState; private AdPlaybackState adPlaybackState;
private int firstSeenAdIndexInAdGroup;
private ImaServerSideAdInsertionMediaSource( private ImaServerSideAdInsertionMediaSource(
MediaItem mediaItem, MediaItem mediaItem,
@ -698,18 +693,21 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
return adPlaybackState; return adPlaybackState;
} }
private static AdPlaybackState addLiveAdBreak( private AdPlaybackState addLiveAdBreak(
Ad ad, long currentPeriodPositionUs, AdPlaybackState adPlaybackState) { Ad ad, long currentPeriodPositionUs, AdPlaybackState adPlaybackState) {
AdPodInfo adPodInfo = ad.getAdPodInfo(); AdPodInfo adPodInfo = ad.getAdPodInfo();
long adDurationUs = secToUs(ad.getDuration()); long adDurationUs = secToUs(ad.getDuration());
int adIndexInAdGroup = adPodInfo.getAdPosition() - 1; int adIndexInAdGroup = adPodInfo.getAdPosition() - 1;
// TODO(b/208398934) Support seeking backwards. // TODO(b/208398934) Support seeking backwards.
if (adIndexInAdGroup == 0 || adPlaybackState.adGroupCount == 1) { if (adIndexInAdGroup == 0 || adPlaybackState.adGroupCount == 1) {
firstSeenAdIndexInAdGroup = adIndexInAdGroup;
// Adjust count and ad index in case we joined the live stream within an ad group.
int adCount = adPodInfo.getTotalAds() - firstSeenAdIndexInAdGroup;
adIndexInAdGroup -= firstSeenAdIndexInAdGroup;
// First ad of group. Create a new group with all ads. // First ad of group. Create a new group with all ads.
long[] adDurationsUs = long[] adDurationsUs =
updateAdDurationAndPropagate( updateAdDurationAndPropagate(
new long[adPodInfo.getTotalAds()], new long[adCount],
adIndexInAdGroup, adIndexInAdGroup,
adDurationUs, adDurationUs,
secToUs(adPodInfo.getMaxDuration())); secToUs(adPodInfo.getMaxDuration()));
@ -721,6 +719,11 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
/* adDurationsUs...= */ adDurationsUs); /* adDurationsUs...= */ adDurationsUs);
} else { } else {
int adGroupIndex = adPlaybackState.adGroupCount - 2; int adGroupIndex = adPlaybackState.adGroupCount - 2;
adIndexInAdGroup -= firstSeenAdIndexInAdGroup;
if (adPodInfo.getTotalAds() == adPodInfo.getAdPosition()) {
// Reset the ad index whe we are at the last ad in the group.
firstSeenAdIndexInAdGroup = 0;
}
adPlaybackState = adPlaybackState =
updateAdDurationInAdGroup(adGroupIndex, adIndexInAdGroup, adDurationUs, adPlaybackState); updateAdDurationInAdGroup(adGroupIndex, adIndexInAdGroup, adDurationUs, adPlaybackState);
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex); AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
@ -857,7 +860,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
long positionInWindowUs = long positionInWindowUs =
timeline.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period()) timeline.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period())
.positionInWindowUs; .positionInWindowUs;
long currentPeriodPosition = msToUs(player.getCurrentPosition()) - positionInWindowUs; long currentPeriodPosition = msToUs(player.getContentPosition()) - positionInWindowUs;
newAdPlaybackState = newAdPlaybackState =
addLiveAdBreak( addLiveAdBreak(
event.getAd(), event.getAd(),