Commit 6796c4d0 by andrewlewis Committed by Ian Baker

Add a setting for enabling continuous playback

Issue: #3750
PiperOrigin-RevId: 346079830
parent dd782ef9
...@@ -45,6 +45,8 @@ ...@@ -45,6 +45,8 @@
([#3750](https://github.com/google/ExoPlayer/issues/3750)). ([#3750](https://github.com/google/ExoPlayer/issues/3750)).
* Fix a condition where playback can get stuck before an empty ad * Fix a condition where playback can get stuck before an empty ad
([#8205](https://github.com/google/ExoPlayer/issues/8205)). ([#8205](https://github.com/google/ExoPlayer/issues/8205)).
* Add `ImaAdsLoader.Builder.setEnableContinuousPlayback` for setting
whether to request ads for continuous playback.
* Metadata retriever: * Metadata retriever:
* Parse Google Photos HEIC motion photos metadata. * Parse Google Photos HEIC motion photos metadata.
* FFmpeg extension: * FFmpeg extension:
......
...@@ -517,6 +517,9 @@ import java.util.Map; ...@@ -517,6 +517,9 @@ import java.util.Map;
} }
pendingAdRequestContext = new Object(); pendingAdRequestContext = new Object();
request.setUserRequestContext(pendingAdRequestContext); request.setUserRequestContext(pendingAdRequestContext);
if (configuration.enableContinuousPlayback != null) {
request.setContinuousPlayback(configuration.enableContinuousPlayback);
}
if (configuration.vastLoadTimeoutMs != TIMEOUT_UNSET) { if (configuration.vastLoadTimeoutMs != TIMEOUT_UNSET) {
request.setVastLoadTimeout(configuration.vastLoadTimeoutMs); request.setVastLoadTimeout(configuration.vastLoadTimeoutMs);
} }
......
...@@ -114,6 +114,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { ...@@ -114,6 +114,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
@Nullable private List<String> adMediaMimeTypes; @Nullable private List<String> adMediaMimeTypes;
@Nullable private Set<UiElement> adUiElements; @Nullable private Set<UiElement> adUiElements;
@Nullable private Collection<CompanionAdSlot> companionAdSlots; @Nullable private Collection<CompanionAdSlot> companionAdSlots;
@Nullable private Boolean enableContinuousPlayback;
private long adPreloadTimeoutMs; private long adPreloadTimeoutMs;
private int vastLoadTimeoutMs; private int vastLoadTimeoutMs;
private int mediaLoadTimeoutMs; private int mediaLoadTimeoutMs;
...@@ -236,6 +237,20 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { ...@@ -236,6 +237,20 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
} }
/** /**
* Sets whether to enable continuous playback. Pass {@code true} if content videos will be
* played continuously, similar to a TV broadcast. This setting may modify the ads request but
* does not affect ad playback behavior. The requested value is unknown by default.
*
* @param enableContinuousPlayback Whether to enable continuous playback.
* @return This builder, for convenience.
* @see AdsRequest#setContinuousPlayback(boolean)
*/
public Builder setEnableContinuousPlayback(boolean enableContinuousPlayback) {
this.enableContinuousPlayback = enableContinuousPlayback;
return this;
}
/**
* Sets the duration in milliseconds for which the player must buffer while preloading an ad * Sets the duration in milliseconds for which the player must buffer while preloading an ad
* group before that ad group is skipped and marked as having failed to load. Pass {@link * group before that ad group is skipped and marked as having failed to load. Pass {@link
* C#TIME_UNSET} if there should be no such timeout. The default value is {@value * C#TIME_UNSET} if there should be no such timeout. The default value is {@value
...@@ -354,6 +369,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { ...@@ -354,6 +369,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
focusSkipButtonWhenAvailable, focusSkipButtonWhenAvailable,
playAdBeforeStartPosition, playAdBeforeStartPosition,
mediaBitrate, mediaBitrate,
enableContinuousPlayback,
adMediaMimeTypes, adMediaMimeTypes,
adUiElements, adUiElements,
companionAdSlots, companionAdSlots,
......
...@@ -89,6 +89,7 @@ import java.util.Set; ...@@ -89,6 +89,7 @@ import java.util.Set;
public final boolean focusSkipButtonWhenAvailable; public final boolean focusSkipButtonWhenAvailable;
public final boolean playAdBeforeStartPosition; public final boolean playAdBeforeStartPosition;
public final int mediaBitrate; public final int mediaBitrate;
@Nullable public final Boolean enableContinuousPlayback;
@Nullable public final List<String> adMediaMimeTypes; @Nullable public final List<String> adMediaMimeTypes;
@Nullable public final Set<UiElement> adUiElements; @Nullable public final Set<UiElement> adUiElements;
@Nullable public final Collection<CompanionAdSlot> companionAdSlots; @Nullable public final Collection<CompanionAdSlot> companionAdSlots;
...@@ -105,6 +106,7 @@ import java.util.Set; ...@@ -105,6 +106,7 @@ import java.util.Set;
boolean focusSkipButtonWhenAvailable, boolean focusSkipButtonWhenAvailable,
boolean playAdBeforeStartPosition, boolean playAdBeforeStartPosition,
int mediaBitrate, int mediaBitrate,
@Nullable Boolean enableContinuousPlayback,
@Nullable List<String> adMediaMimeTypes, @Nullable List<String> adMediaMimeTypes,
@Nullable Set<UiElement> adUiElements, @Nullable Set<UiElement> adUiElements,
@Nullable Collection<CompanionAdSlot> companionAdSlots, @Nullable Collection<CompanionAdSlot> companionAdSlots,
...@@ -119,6 +121,7 @@ import java.util.Set; ...@@ -119,6 +121,7 @@ import java.util.Set;
this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable; this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable;
this.playAdBeforeStartPosition = playAdBeforeStartPosition; this.playAdBeforeStartPosition = playAdBeforeStartPosition;
this.mediaBitrate = mediaBitrate; this.mediaBitrate = mediaBitrate;
this.enableContinuousPlayback = enableContinuousPlayback;
this.adMediaMimeTypes = adMediaMimeTypes; this.adMediaMimeTypes = adMediaMimeTypes;
this.adUiElements = adUiElements; this.adUiElements = adUiElements;
this.companionAdSlots = companionAdSlots; this.companionAdSlots = companionAdSlots;
......
...@@ -19,6 +19,7 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext; ...@@ -19,6 +19,7 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.android.exoplayer2.ext.ima.ImaUtil.getAdGroupTimesUsForCuePoints; import static com.google.android.exoplayer2.ext.ima.ImaUtil.getAdGroupTimesUsForCuePoints;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyDouble; import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
...@@ -1128,6 +1129,57 @@ public final class ImaAdsLoaderTest { ...@@ -1128,6 +1129,57 @@ public final class ImaAdsLoaderTest {
.isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs...= */ 0)); .isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs...= */ 0));
} }
@Test
public void buildWithDefaultEnableContinuousPlayback_doesNotSetAdsRequestProperty() {
imaAdsLoader =
new ImaAdsLoader.Builder(getApplicationContext())
.setImaFactory(mockImaFactory)
.setImaSdkSettings(mockImaSdkSettings)
.build();
imaAdsLoader.setPlayer(fakePlayer);
adsMediaSource =
new AdsMediaSource(
new FakeMediaSource(CONTENT_TIMELINE),
TEST_DATA_SPEC,
TEST_ADS_ID,
new DefaultMediaSourceFactory((Context) getApplicationContext()),
imaAdsLoader,
adViewProvider);
when(mockAdsManager.getAdCuePoints()).thenReturn(PREROLL_CUE_POINTS_SECONDS);
imaAdsLoader.setSupportedContentTypes(C.TYPE_OTHER);
imaAdsLoader.start(
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
verify(mockAdsRequest, never()).setContinuousPlayback(anyBoolean());
}
@Test
public void buildWithEnableContinuousPlayback_setsAdsRequestProperty() {
imaAdsLoader =
new ImaAdsLoader.Builder(getApplicationContext())
.setEnableContinuousPlayback(true)
.setImaFactory(mockImaFactory)
.setImaSdkSettings(mockImaSdkSettings)
.build();
imaAdsLoader.setPlayer(fakePlayer);
adsMediaSource =
new AdsMediaSource(
new FakeMediaSource(CONTENT_TIMELINE),
TEST_DATA_SPEC,
TEST_ADS_ID,
new DefaultMediaSourceFactory((Context) getApplicationContext()),
imaAdsLoader,
adViewProvider);
when(mockAdsManager.getAdCuePoints()).thenReturn(PREROLL_CUE_POINTS_SECONDS);
imaAdsLoader.setSupportedContentTypes(C.TYPE_OTHER);
imaAdsLoader.start(
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
verify(mockAdsRequest).setContinuousPlayback(true);
}
private void setupMocks() { private void setupMocks() {
ArgumentCaptor<Object> userRequestContextCaptor = ArgumentCaptor.forClass(Object.class); ArgumentCaptor<Object> userRequestContextCaptor = ArgumentCaptor.forClass(Object.class);
doNothing().when(mockAdsRequest).setUserRequestContext(userRequestContextCaptor.capture()); doNothing().when(mockAdsRequest).setUserRequestContext(userRequestContextCaptor.capture());
......
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