Skip to content

Commit

Permalink
Fix splitting ad playback state for partial ad group when joining
Browse files Browse the repository at this point in the history
This change addresses the case when the user joins the live stream
on an ad period but the metadata for the ad period is not emitted.
This results in inserting a partial ad group.

In this case the ad group duration is longer than the partial ad
group. If now the partial ad group ends at the period before the
last period of the window (unknown duration), the splitting algorithm
didn't recognize that the ad group already ended and made the last
period wrongly an ad period.

This change handles this edge case by counting the mapped ads in
the partial ad group to detect this situation and stops splitting.

#minor-release

PiperOrigin-RevId: 539102785
  • Loading branch information
marcbaechinger authored and tof-tof committed Jun 10, 2023
1 parent edf3043 commit cd604e7
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ public static ImmutableMap<Object, AdPlaybackState> splitAdPlaybackStateForPerio
Map<Object, AdPlaybackState> adPlaybackStates = new HashMap<>();
for (int i = adPlaybackState.removedAdGroupCount; i < adPlaybackState.adGroupCount; i++) {
AdGroup adGroup = adPlaybackState.getAdGroup(/* adGroupIndex= */ i);
int mappedAdCount = 0;
if (adGroup.timeUs == C.TIME_END_OF_SOURCE) {
checkState(i == adPlaybackState.adGroupCount - 1);
// The last ad group is a placeholder for a potential post roll. We can just stop here.
Expand Down Expand Up @@ -454,8 +455,10 @@ public static ImmutableMap<Object, AdPlaybackState> splitAdPlaybackStateForPerio
adsId, adGroup, periodStartUs, periodDurationUs, window.isLive()));
// Current period added as an ad period. Advance and look at the next period.
periodIndex++;
mappedAdCount++;
elapsedAdGroupAdDurationUs += periodDurationUs;
if (periodStartUs + periodDurationUs == adGroup.timeUs + adGroupDurationUs) {
if ((adGroup.originalCount > adGroup.count && adGroup.count == mappedAdCount)
|| periodStartUs + periodDurationUs == adGroup.timeUs + adGroupDurationUs) {
// Periods have consumed the ad group. We're at the end of the ad group.
if (window.isLive()) {
// Add elapsed ad duration to elapsed content duration for live streams to account
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,46 @@ public void splitAdPlaybackStateForPeriods_earlyMidrollAdGroupStartTimeUs_adGrou
assertThat(adPlaybackStates.get("uid-14[a]").adGroupCount).isEqualTo(2);
}

@Test
public void
splitAdPlaybackStateForPeriods_partialAdGroupEndingAtPeriodBeforeLast_adPeriodsCorrectlyDetected() {
AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ "adsId", C.TIME_END_OF_SOURCE)
.withIsServerSideInserted(/* adGroupIndex= */ 0, true);
FakeMultiPeriodLiveTimeline liveTimeline =
new FakeMultiPeriodLiveTimeline(
/* availabilityStartTimeMs= */ 0,
/* liveWindowDurationUs= */ 60_000_000,
/* nowUs= */ 70_000_000,
/* adSequencePattern= */ new boolean[] {false, true, true, true},
/* periodDurationMsPattern= */ new long[] {30_000, 10_000, 10_000, 10_000},
/* isContentTimeline= */ true,
/* populateAds= */ false,
/* playedAds= */ false);
// Ad event received from SDK around 30s.
adPlaybackState =
addLiveAdBreak(
/* currentContentPeriodPositionUs= */ 40_000_000,
/* adDurationUs= */ 10_000_000,
/* adPositionInAdPod= */ 2,
/* totalAdDurationUs= */ 30_000_000,
/* totalAdsInAdPod= */ 3,
adPlaybackState);

ImmutableMap<Object, AdPlaybackState> splitAdPlaybackStates =
ImaUtil.splitAdPlaybackStateForPeriods(adPlaybackState, liveTimeline);

assertThat(liveTimeline.getPeriodCount()).isEqualTo(5);
assertThat(splitAdPlaybackStates).hasSize(5);
assertThat(liveTimeline.getWindow(0, new Window()).windowStartTimeMs).isEqualTo(10_000L);
assertThat(liveTimeline.getPeriod(0, new Period()).positionInWindowUs).isEqualTo(-10_000_000L);
assertThat(splitAdPlaybackStates.get("uid-0[c]").adGroupCount).isEqualTo(1);
assertThat(splitAdPlaybackStates.get("uid-1[a]").adGroupCount).isEqualTo(1);
assertThat(splitAdPlaybackStates.get("uid-2[a]").adGroupCount).isEqualTo(2);
assertThat(splitAdPlaybackStates.get("uid-3[a]").adGroupCount).isEqualTo(2);
assertThat(splitAdPlaybackStates.get("uid-4[c]").adGroupCount).isEqualTo(1);
}

@Test
public void
splitAdPlaybackStateForPeriods_fullAdGroupAtBeginOfWindow_adPeriodsCorrectlyDetected() {
Expand Down

0 comments on commit cd604e7

Please sign in to comment.