mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix ad progress updates after rebuffering an ad
Issue: #8239 #exofixit #minor-release PiperOrigin-RevId: 344211877
This commit is contained in:
parent
87e141d376
commit
ee36e648e3
3 changed files with 88 additions and 4 deletions
|
|
@ -81,6 +81,9 @@
|
||||||
([#7832](https://github.com/google/ExoPlayer/issues/7832)).
|
([#7832](https://github.com/google/ExoPlayer/issues/7832)).
|
||||||
* Fix a bug that caused multiple ads in an ad pod to be skipped when one
|
* Fix a bug that caused multiple ads in an ad pod to be skipped when one
|
||||||
ad in the ad pod was skipped.
|
ad in the ad pod was skipped.
|
||||||
|
* Fix a bug that caused ad progress not to be updated if the player
|
||||||
|
resumed after buffering during an ad
|
||||||
|
([#8239](https://github.com/google/ExoPlayer/issues/8239)).
|
||||||
* Fix passing an ads response to the `ImaAdsLoader` builder.
|
* Fix passing an ads response to the `ImaAdsLoader` builder.
|
||||||
* Set the overlay language based on the device locale by default.
|
* Set the overlay language based on the device locale by default.
|
||||||
* Cronet extension:
|
* Cronet extension:
|
||||||
|
|
|
||||||
|
|
@ -769,6 +769,7 @@ import java.util.Map;
|
||||||
private void handlePlayerStateChanged(boolean playWhenReady, @Player.State int playbackState) {
|
private void handlePlayerStateChanged(boolean playWhenReady, @Player.State int playbackState) {
|
||||||
if (playingAd && imaAdState == IMA_AD_STATE_PLAYING) {
|
if (playingAd && imaAdState == IMA_AD_STATE_PLAYING) {
|
||||||
if (!bufferingAd && playbackState == Player.STATE_BUFFERING) {
|
if (!bufferingAd && playbackState == Player.STATE_BUFFERING) {
|
||||||
|
bufferingAd = true;
|
||||||
AdMediaInfo adMediaInfo = checkNotNull(imaAdMediaInfo);
|
AdMediaInfo adMediaInfo = checkNotNull(imaAdMediaInfo);
|
||||||
for (int i = 0; i < adCallbacks.size(); i++) {
|
for (int i = 0; i < adCallbacks.size(); i++) {
|
||||||
adCallbacks.get(i).onBuffering(adMediaInfo);
|
adCallbacks.get(i).onBuffering(adMediaInfo);
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,11 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Looper;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
@ -117,6 +119,7 @@ public final class ImaAdsLoaderTest {
|
||||||
@Mock private AdsRequest mockAdsRequest;
|
@Mock private AdsRequest mockAdsRequest;
|
||||||
@Mock private AdsManagerLoadedEvent mockAdsManagerLoadedEvent;
|
@Mock private AdsManagerLoadedEvent mockAdsManagerLoadedEvent;
|
||||||
@Mock private com.google.ads.interactivemedia.v3.api.AdsLoader mockAdsLoader;
|
@Mock private com.google.ads.interactivemedia.v3.api.AdsLoader mockAdsLoader;
|
||||||
|
@Mock private VideoAdPlayer.VideoAdPlayerCallback mockVideoAdPlayerCallback;
|
||||||
@Mock private FriendlyObstruction mockFriendlyObstruction;
|
@Mock private FriendlyObstruction mockFriendlyObstruction;
|
||||||
@Mock private ImaFactory mockImaFactory;
|
@Mock private ImaFactory mockImaFactory;
|
||||||
@Mock private AdPodInfo mockAdPodInfo;
|
@Mock private AdPodInfo mockAdPodInfo;
|
||||||
|
|
@ -168,6 +171,7 @@ public final class ImaAdsLoaderTest {
|
||||||
new ImaAdsLoader.Builder(getApplicationContext())
|
new ImaAdsLoader.Builder(getApplicationContext())
|
||||||
.setImaFactory(mockImaFactory)
|
.setImaFactory(mockImaFactory)
|
||||||
.setImaSdkSettings(mockImaSdkSettings)
|
.setImaSdkSettings(mockImaSdkSettings)
|
||||||
|
.setVideoAdPlayerCallback(mockVideoAdPlayerCallback)
|
||||||
.build();
|
.build();
|
||||||
imaAdsLoader.setPlayer(fakePlayer);
|
imaAdsLoader.setPlayer(fakePlayer);
|
||||||
adsMediaSource =
|
adsMediaSource =
|
||||||
|
|
@ -257,7 +261,7 @@ public final class ImaAdsLoaderTest {
|
||||||
imaAdsLoader.start(
|
imaAdsLoader.start(
|
||||||
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, /* positionMs= */ 0);
|
fakePlayer.setPlayingContentPosition(/* periodIndex= */ 0, /* positionMs= */ 0);
|
||||||
fakePlayer.setState(Player.STATE_READY, true);
|
fakePlayer.setState(Player.STATE_READY, /* playWhenReady= */ true);
|
||||||
|
|
||||||
// If callbacks are invoked there is no crash.
|
// If callbacks are invoked there is no crash.
|
||||||
// Note: we can't currently call getContentProgress/getAdProgress as a VerifyError is thrown
|
// Note: we can't currently call getContentProgress/getAdProgress as a VerifyError is thrown
|
||||||
|
|
@ -295,7 +299,7 @@ public final class ImaAdsLoaderTest {
|
||||||
/* adIndexInAdGroup= */ 0,
|
/* adIndexInAdGroup= */ 0,
|
||||||
/* position= */ 0,
|
/* position= */ 0,
|
||||||
/* contentPosition= */ 0);
|
/* contentPosition= */ 0);
|
||||||
fakePlayer.setState(Player.STATE_READY, true);
|
fakePlayer.setState(Player.STATE_READY, /* playWhenReady= */ true);
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
||||||
|
|
@ -441,6 +445,82 @@ public final class ImaAdsLoaderTest {
|
||||||
.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0));
|
.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bufferingDuringAd_callsOnBuffering() {
|
||||||
|
// Load the preroll ad.
|
||||||
|
imaAdsLoader.start(
|
||||||
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.LOADED, mockPrerollSingleAd));
|
||||||
|
videoAdPlayer.loadAd(TEST_AD_MEDIA_INFO, mockAdPodInfo);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_PAUSE_REQUESTED, mockPrerollSingleAd));
|
||||||
|
|
||||||
|
// Play the preroll ad then simulate buffering.
|
||||||
|
videoAdPlayer.playAd(TEST_AD_MEDIA_INFO);
|
||||||
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adGroupIndex= */ 0,
|
||||||
|
/* adIndexInAdGroup= */ 0,
|
||||||
|
/* positionMs= */ 0,
|
||||||
|
/* contentPositionMs= */ 0);
|
||||||
|
fakePlayer.setState(Player.STATE_READY, /* playWhenReady= */ true);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
||||||
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adGroupIndex= */ 0,
|
||||||
|
/* adIndexInAdGroup= */ 0,
|
||||||
|
/* positionMs= */ 1_000,
|
||||||
|
/* contentPositionMs= */ 0);
|
||||||
|
fakePlayer.setState(Player.STATE_BUFFERING, /* playWhenReady= */ true);
|
||||||
|
|
||||||
|
verify(mockVideoAdPlayerCallback).onBuffering(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void resumeAfterBufferingDuringAd_updatesPosition() {
|
||||||
|
// Load the preroll ad.
|
||||||
|
imaAdsLoader.start(
|
||||||
|
adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.LOADED, mockPrerollSingleAd));
|
||||||
|
videoAdPlayer.loadAd(TEST_AD_MEDIA_INFO, mockAdPodInfo);
|
||||||
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_PAUSE_REQUESTED, mockPrerollSingleAd));
|
||||||
|
|
||||||
|
// Play the preroll ad.
|
||||||
|
videoAdPlayer.playAd(TEST_AD_MEDIA_INFO);
|
||||||
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adGroupIndex= */ 0,
|
||||||
|
/* adIndexInAdGroup= */ 0,
|
||||||
|
/* positionMs= */ 0,
|
||||||
|
/* contentPositionMs= */ 0);
|
||||||
|
fakePlayer.setState(Player.STATE_READY, /* playWhenReady= */ true);
|
||||||
|
|
||||||
|
// Simulate buffering.
|
||||||
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adGroupIndex= */ 0,
|
||||||
|
/* adIndexInAdGroup= */ 0,
|
||||||
|
/* positionMs= */ 2_000,
|
||||||
|
/* contentPositionMs= */ 0);
|
||||||
|
fakePlayer.setState(Player.STATE_BUFFERING, /* playWhenReady= */ true);
|
||||||
|
|
||||||
|
// Simulate resuming and force pending ad progress updates to happen immediately.
|
||||||
|
int newPlayerPositionMs = 3_000;
|
||||||
|
fakePlayer.setState(Player.STATE_READY, /* playWhenReady= */ true);
|
||||||
|
fakePlayer.setPlayingAdPosition(
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adGroupIndex= */ 0,
|
||||||
|
/* adIndexInAdGroup= */ 0,
|
||||||
|
newPlayerPositionMs,
|
||||||
|
/* contentPositionMs= */ 0);
|
||||||
|
shadowOf(Looper.getMainLooper()).runToEndOfTasks();
|
||||||
|
|
||||||
|
verify(mockVideoAdPlayerCallback)
|
||||||
|
.onAdProgress(
|
||||||
|
TEST_AD_MEDIA_INFO,
|
||||||
|
new VideoProgressUpdate(newPlayerPositionMs, C.usToMs(TEST_AD_DURATION_US)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resumePlaybackBeforeMidroll_playsPreroll() {
|
public void resumePlaybackBeforeMidroll_playsPreroll() {
|
||||||
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
|
||||||
|
|
@ -955,7 +1035,7 @@ public final class ImaAdsLoaderTest {
|
||||||
/* adIndexInAdGroup= */ 0,
|
/* adIndexInAdGroup= */ 0,
|
||||||
/* position= */ 0,
|
/* position= */ 0,
|
||||||
/* contentPosition= */ 0);
|
/* contentPosition= */ 0);
|
||||||
fakePlayer.setState(Player.STATE_READY, true);
|
fakePlayer.setState(Player.STATE_READY, /* playWhenReady= */ true);
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
||||||
|
|
@ -1012,7 +1092,7 @@ public final class ImaAdsLoaderTest {
|
||||||
/* adIndexInAdGroup= */ 0,
|
/* adIndexInAdGroup= */ 0,
|
||||||
/* position= */ 0,
|
/* position= */ 0,
|
||||||
/* contentPosition= */ 0);
|
/* contentPosition= */ 0);
|
||||||
fakePlayer.setState(Player.STATE_READY, true);
|
fakePlayer.setState(Player.STATE_READY, /* playWhenReady= */ true);
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.STARTED, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, mockPrerollSingleAd));
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.MIDPOINT, mockPrerollSingleAd));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue