Fix handling of fetch errors for post-rolls
The ad break time in seconds from IMA was "-1" for postrolls, but this didn't match C.TIME_END_OF_SOURCE in the ad group times array. Handle an ad break time of -1 directly by mapping it onto the last ad group, instead of trying to look it up in the array. PiperOrigin-RevId: 312064886
This commit is contained in:
parent
786edf8ecd
commit
ef615754db
@ -50,6 +50,7 @@ dependencies {
|
|||||||
androidTestImplementation 'com.android.support:multidex:1.0.3'
|
androidTestImplementation 'com.android.support:multidex:1.0.3'
|
||||||
androidTestCompileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
androidTestCompileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
|
||||||
testImplementation project(modulePrefix + 'testutils')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
|
testImplementation 'com.google.guava:guava:' + guavaVersion
|
||||||
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,8 +1114,10 @@ public final class ImaAdsLoader
|
|||||||
}
|
}
|
||||||
int adGroupTimeSeconds = Integer.parseInt(adGroupTimeSecondsString);
|
int adGroupTimeSeconds = Integer.parseInt(adGroupTimeSecondsString);
|
||||||
int adGroupIndex =
|
int adGroupIndex =
|
||||||
Arrays.binarySearch(
|
adGroupTimeSeconds == -1
|
||||||
adPlaybackState.adGroupTimesUs, C.MICROS_PER_SECOND * adGroupTimeSeconds);
|
? adPlaybackState.adGroupCount - 1
|
||||||
|
: Util.linearSearch(
|
||||||
|
adPlaybackState.adGroupTimesUs, C.MICROS_PER_SECOND * adGroupTimeSeconds);
|
||||||
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
|
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
|
||||||
if (adGroup.count == C.LENGTH_UNSET) {
|
if (adGroup.count == C.LENGTH_UNSET) {
|
||||||
adPlaybackState =
|
adPlaybackState =
|
||||||
|
@ -56,6 +56,7 @@ import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline;
|
|||||||
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
||||||
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
|
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -105,6 +106,7 @@ public final class ImaAdsLoaderTest {
|
|||||||
@Mock private ImaFactory mockImaFactory;
|
@Mock private ImaFactory mockImaFactory;
|
||||||
@Mock private AdPodInfo mockAdPodInfo;
|
@Mock private AdPodInfo mockAdPodInfo;
|
||||||
@Mock private Ad mockPrerollSingleAd;
|
@Mock private Ad mockPrerollSingleAd;
|
||||||
|
@Mock private AdEvent mockPostrollFetchErrorAdEvent;
|
||||||
|
|
||||||
private ViewGroup adViewGroup;
|
private ViewGroup adViewGroup;
|
||||||
private View adOverlayView;
|
private View adOverlayView;
|
||||||
@ -252,6 +254,23 @@ public final class ImaAdsLoaderTest {
|
|||||||
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
|
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void playback_withPostrollFetchError_marksAdAsInErrorState() {
|
||||||
|
setupPlayback(CONTENT_TIMELINE, ADS_DURATIONS_US, new Float[] {-1f});
|
||||||
|
|
||||||
|
// Simulate loading an empty postroll ad.
|
||||||
|
imaAdsLoader.start(adsLoaderListener, adViewProvider);
|
||||||
|
imaAdsLoader.onAdEvent(mockPostrollFetchErrorAdEvent);
|
||||||
|
|
||||||
|
assertThat(adsLoaderListener.adPlaybackState)
|
||||||
|
.isEqualTo(
|
||||||
|
new AdPlaybackState(/* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE)
|
||||||
|
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
|
||||||
|
.withAdDurationsUs(ADS_DURATIONS_US)
|
||||||
|
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||||
|
.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void playback_withAdNotPreloadingBeforeTimeout_hasNoError() {
|
public void playback_withAdNotPreloadingBeforeTimeout_hasNoError() {
|
||||||
// Simulate an ad at 2 seconds.
|
// Simulate an ad at 2 seconds.
|
||||||
@ -378,6 +397,10 @@ public final class ImaAdsLoaderTest {
|
|||||||
when(mockAdPodInfo.getAdPosition()).thenReturn(1);
|
when(mockAdPodInfo.getAdPosition()).thenReturn(1);
|
||||||
|
|
||||||
when(mockPrerollSingleAd.getAdPodInfo()).thenReturn(mockAdPodInfo);
|
when(mockPrerollSingleAd.getAdPodInfo()).thenReturn(mockAdPodInfo);
|
||||||
|
|
||||||
|
when(mockPostrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
||||||
|
when(mockPostrollFetchErrorAdEvent.getAdData())
|
||||||
|
.thenReturn(ImmutableMap.of("adBreakTime", "-1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AdEvent getAdEvent(AdEventType adEventType, @Nullable Ad ad) {
|
private static AdEvent getAdEvent(AdEventType adEventType, @Nullable Ad ad) {
|
||||||
|
@ -767,6 +767,24 @@ public final class Util {
|
|||||||
return C.INDEX_UNSET;
|
return C.INDEX_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the first occurrence of {@code value} in {@code array}, or {@link
|
||||||
|
* C#INDEX_UNSET} if {@code value} is not contained in {@code array}.
|
||||||
|
*
|
||||||
|
* @param array The array to search.
|
||||||
|
* @param value The value to search for.
|
||||||
|
* @return The index of the first occurrence of value in {@code array}, or {@link C#INDEX_UNSET}
|
||||||
|
* if {@code value} is not contained in {@code array}.
|
||||||
|
*/
|
||||||
|
public static int linearSearch(long[] array, long value) {
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
if (array[i] == value) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return C.INDEX_UNSET;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the index of the largest element in {@code array} that is less than (or optionally
|
* Returns the index of the largest element in {@code array} that is less than (or optionally
|
||||||
* equal to) a specified {@code value}.
|
* equal to) a specified {@code value}.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user