Search in sources :

Example 1 with AdPlaybackState

use of com.google.android.exoplayer2.source.ads.AdPlaybackState in project ExoPlayer by google.

the class AdTagLoader method loadAdInternal.

private void loadAdInternal(AdMediaInfo adMediaInfo, AdPodInfo adPodInfo) {
    if (adsManager == null) {
        // Drop events after release.
        if (configuration.debugModeEnabled) {
            Log.d(TAG, "loadAd after release " + getAdMediaInfoString(adMediaInfo) + ", ad pod " + adPodInfo);
        }
        return;
    }
    int adGroupIndex = getAdGroupIndexForAdPod(adPodInfo);
    int adIndexInAdGroup = adPodInfo.getAdPosition() - 1;
    AdInfo adInfo = new AdInfo(adGroupIndex, adIndexInAdGroup);
    // The ad URI may already be known, so force put to update it if needed.
    adInfoByAdMediaInfo.forcePut(adMediaInfo, adInfo);
    if (configuration.debugModeEnabled) {
        Log.d(TAG, "loadAd " + getAdMediaInfoString(adMediaInfo));
    }
    if (adPlaybackState.isAdInErrorState(adGroupIndex, adIndexInAdGroup)) {
        // timeout after its media load timeout.
        return;
    }
    // The ad count may increase on successive loads of ads in the same ad pod, for example, due to
    // separate requests for ad tags with multiple ads within the ad pod completing after an earlier
    // ad has loaded. See also https://github.com/google/ExoPlayer/issues/7477.
    AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
    adPlaybackState = adPlaybackState.withAdCount(adInfo.adGroupIndex, max(adPodInfo.getTotalAds(), adGroup.states.length));
    adGroup = adPlaybackState.getAdGroup(adInfo.adGroupIndex);
    for (int i = 0; i < adIndexInAdGroup; i++) {
        // Any preceding ads that haven't loaded are not going to load.
        if (adGroup.states[i] == AdPlaybackState.AD_STATE_UNAVAILABLE) {
            adPlaybackState = adPlaybackState.withAdLoadError(adGroupIndex, /* adIndexInAdGroup= */
            i);
        }
    }
    Uri adUri = Uri.parse(adMediaInfo.getUrl());
    adPlaybackState = adPlaybackState.withAdUri(adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adUri);
    updateAdPlaybackState();
}
Also used : AdPlaybackState(com.google.android.exoplayer2.source.ads.AdPlaybackState) Uri(android.net.Uri)

Example 2 with AdPlaybackState

use of com.google.android.exoplayer2.source.ads.AdPlaybackState in project ExoPlayer by google.

the class ImaServerSideAdInsertionMediaSource method setContentUri.

// Internal methods (called on the playback thread).
private void setContentUri(Uri contentUri) {
    if (serverSideAdInsertionMediaSource != null) {
        return;
    }
    MediaItem contentMediaItem = new MediaItem.Builder().setUri(contentUri).setDrmConfiguration(checkNotNull(mediaItem.localConfiguration).drmConfiguration).setLiveConfiguration(mediaItem.liveConfiguration).setCustomCacheKey(mediaItem.localConfiguration.customCacheKey).setStreamKeys(mediaItem.localConfiguration.streamKeys).build();
    ServerSideAdInsertionMediaSource serverSideAdInsertionMediaSource = new ServerSideAdInsertionMediaSource(contentMediaSourceFactory.createMediaSource(contentMediaItem), componentListener);
    this.serverSideAdInsertionMediaSource = serverSideAdInsertionMediaSource;
    if (isLiveStream) {
        AdPlaybackState liveAdPlaybackState = new AdPlaybackState(adsId).withNewAdGroup(/* adGroupIndex= */
        0, /* adGroupTimeUs= */
        C.TIME_END_OF_SOURCE).withIsServerSideInserted(/* adGroupIndex= */
        0, true);
        mainHandler.post(() -> setAdPlaybackState(liveAdPlaybackState));
    }
    prepareChildSource(/* id= */
    null, serverSideAdInsertionMediaSource);
}
Also used : ServerSideAdInsertionMediaSource(com.google.android.exoplayer2.source.ads.ServerSideAdInsertionMediaSource) ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState(com.google.android.exoplayer2.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState) AdPlaybackState(com.google.android.exoplayer2.source.ads.AdPlaybackState) MediaItem(com.google.android.exoplayer2.MediaItem)

Example 3 with AdPlaybackState

use of com.google.android.exoplayer2.source.ads.AdPlaybackState in project ExoPlayer by google.

the class ImaUtil method splitAdPlaybackStateForPeriods.

/**
 * Splits an {@link AdPlaybackState} into a separate {@link AdPlaybackState} for each period of a
 * content timeline.
 *
 * <p>If a period is enclosed by an ad group, the period is considered an ad period. Splitting
 * results in a separate {@link AdPlaybackState ad playback state} for each period that has either
 * no ads or a single ad. In the latter case, the duration of the single ad is set to the duration
 * of the period consuming the entire duration of the period. Accordingly an ad period does not
 * contribute to the duration of the containing window.
 *
 * @param adPlaybackState The ad playback state to be split.
 * @param contentTimeline The content timeline for each period of which to create an {@link
 *     AdPlaybackState}.
 * @return A map of ad playback states for each period UID in the content timeline.
 */
public static ImmutableMap<Object, AdPlaybackState> splitAdPlaybackStateForPeriods(AdPlaybackState adPlaybackState, Timeline contentTimeline) {
    Timeline.Period period = new Timeline.Period();
    if (contentTimeline.getPeriodCount() == 1) {
        // A single period gets the entire ad playback state that may contain multiple ad groups.
        return ImmutableMap.of(checkNotNull(contentTimeline.getPeriod(/* periodIndex= */
        0, period, /* setIds= */
        true).uid), adPlaybackState);
    }
    int periodIndex = 0;
    long totalElapsedContentDurationUs = 0;
    Object adsId = checkNotNull(adPlaybackState.adsId);
    AdPlaybackState contentOnlyAdPlaybackState = new AdPlaybackState(adsId);
    Map<Object, AdPlaybackState> adPlaybackStates = new HashMap<>();
    for (int i = adPlaybackState.removedAdGroupCount; i < adPlaybackState.adGroupCount; i++) {
        AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(/* adGroupIndex= */
        i);
        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.
            break;
        }
        // The ad group start timeUs is in content position. We need to add the ad
        // duration before the ad group to translate the start time to the position in the period.
        long adGroupDurationUs = sum(adGroup.durationsUs);
        long elapsedAdGroupAdDurationUs = 0;
        for (int j = periodIndex; j < contentTimeline.getPeriodCount(); j++) {
            contentTimeline.getPeriod(j, period, /* setIds= */
            true);
            // Subtract one microsecond to work around rounding errors with adGroup.timeUs.
            if (totalElapsedContentDurationUs < adGroup.timeUs - 1) {
                // Period starts before the ad group, so it is a content period.
                adPlaybackStates.put(checkNotNull(period.uid), contentOnlyAdPlaybackState);
                totalElapsedContentDurationUs += period.durationUs;
            } else {
                long periodStartUs = totalElapsedContentDurationUs + elapsedAdGroupAdDurationUs;
                // Add one microsecond to work around rounding errors with adGroup.timeUs.
                if (periodStartUs + period.durationUs <= adGroup.timeUs + adGroupDurationUs + 1) {
                    // The period ends before the end of the ad group, so it is an ad period (Note: A VOD ad
                    // reported by the IMA SDK spans multiple periods before the LOADED event arrives).
                    adPlaybackStates.put(checkNotNull(period.uid), splitAdGroupForPeriod(adsId, adGroup, periodStartUs, period.durationUs));
                    elapsedAdGroupAdDurationUs += period.durationUs;
                } else {
                    // Period is after the current ad group. Continue with next ad group.
                    break;
                }
            }
            // Increment the period index to the next unclassified period.
            periodIndex++;
        }
    }
    // The remaining periods end after the last ad group, so these are content periods.
    for (int i = periodIndex; i < contentTimeline.getPeriodCount(); i++) {
        contentTimeline.getPeriod(i, period, /* setIds= */
        true);
        adPlaybackStates.put(checkNotNull(period.uid), contentOnlyAdPlaybackState);
    }
    return ImmutableMap.copyOf(adPlaybackStates);
}
Also used : Timeline(com.google.android.exoplayer2.Timeline) AdPlaybackState(com.google.android.exoplayer2.source.ads.AdPlaybackState) HashMap(java.util.HashMap)

Example 4 with AdPlaybackState

use of com.google.android.exoplayer2.source.ads.AdPlaybackState in project ExoPlayer by google.

the class ImaAdsLoaderTest method playback_withMidrollFetchError_marksAdAsInErrorState.

@Test
public void playback_withMidrollFetchError_marksAdAsInErrorState() {
    AdEvent mockMidrollFetchErrorAdEvent = mock(AdEvent.class);
    when(mockMidrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
    when(mockMidrollFetchErrorAdEvent.getAdData()).thenReturn(ImmutableMap.of("adBreakTime", "20.5"));
    when(mockAdsManager.getAdCuePoints()).thenReturn(ImmutableList.of(20.5f));
    // Simulate loading an empty midroll ad.
    imaAdsLoader.start(adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
    adEventListener.onAdEvent(mockMidrollFetchErrorAdEvent);
    assertThat(getAdPlaybackState(/* periodIndex= */
    0)).isEqualTo(new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */
    20_500_000).withContentDurationUs(CONTENT_PERIOD_DURATION_US).withAdDurationsUs(new long[][] { { TEST_AD_DURATION_US } }).withAdCount(/* adGroupIndex= */
    0, /* adCount= */
    1).withAdLoadError(/* adGroupIndex= */
    0, /* adIndexInAdGroup= */
    0));
}
Also used : AdPlaybackState(com.google.android.exoplayer2.source.ads.AdPlaybackState) AdEvent(com.google.ads.interactivemedia.v3.api.AdEvent) Test(org.junit.Test)

Example 5 with AdPlaybackState

use of com.google.android.exoplayer2.source.ads.AdPlaybackState in project ExoPlayer by google.

the class ImaAdsLoaderTest method resumePlaybackAtMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll.

@Test
public void resumePlaybackAtMidroll_withoutPlayAdBeforeStartPosition_skipsPreroll() {
    imaAdsLoader = new ImaAdsLoader.Builder(getApplicationContext()).setPlayAdBeforeStartPosition(false).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);
    long midrollWindowTimeUs = 2 * C.MICROS_PER_SECOND;
    long midrollPeriodTimeUs = midrollWindowTimeUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
    ImmutableList<Float> cuePoints = ImmutableList.of(0f, (float) midrollPeriodTimeUs / C.MICROS_PER_SECOND);
    when(mockAdsManager.getAdCuePoints()).thenReturn(cuePoints);
    fakePlayer.setPlayingContentPosition(/* periodIndex= */
    0, Util.usToMs(midrollWindowTimeUs));
    imaAdsLoader.start(adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener);
    ArgumentCaptor<Double> playAdsAfterTimeCaptor = ArgumentCaptor.forClass(Double.class);
    verify(mockAdsRenderingSettings).setPlayAdsAfterTime(playAdsAfterTimeCaptor.capture());
    double expectedPlayAdsAfterTimeUs = midrollPeriodTimeUs / 2d;
    assertThat(playAdsAfterTimeCaptor.getValue()).isWithin(0.1d).of(expectedPlayAdsAfterTimeUs / C.MICROS_PER_SECOND);
    assertThat(getAdPlaybackState(/* periodIndex= */
    0)).isEqualTo(new AdPlaybackState(TEST_ADS_ID, getAdGroupTimesUsForCuePoints(cuePoints)).withContentDurationUs(CONTENT_PERIOD_DURATION_US).withSkippedAdGroup(/* adGroupIndex= */
    0));
}
Also used : FakeMediaSource(com.google.android.exoplayer2.testutil.FakeMediaSource) DefaultMediaSourceFactory(com.google.android.exoplayer2.source.DefaultMediaSourceFactory) AdPlaybackState(com.google.android.exoplayer2.source.ads.AdPlaybackState) AdsMediaSource(com.google.android.exoplayer2.source.ads.AdsMediaSource) ArgumentMatchers.anyDouble(org.mockito.ArgumentMatchers.anyDouble) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)89 AdPlaybackState (com.google.android.exoplayer2.source.ads.AdPlaybackState)87 FakeTimeline (com.google.android.exoplayer2.testutil.FakeTimeline)51 ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState (com.google.android.exoplayer2.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState)35 FakeMediaSource (com.google.android.exoplayer2.testutil.FakeMediaSource)32 TimelineWindowDefinition (com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition)27 Pair (android.util.Pair)19 TestExoPlayerBuilder (com.google.android.exoplayer2.testutil.TestExoPlayerBuilder)17 Timeline (com.google.android.exoplayer2.Timeline)15 SinglePeriodTimeline (com.google.android.exoplayer2.source.SinglePeriodTimeline)14 NoUidTimeline (com.google.android.exoplayer2.testutil.NoUidTimeline)14 MediaPeriodId (com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)13 DefaultMediaSourceFactory (com.google.android.exoplayer2.source.DefaultMediaSourceFactory)12 AtomicReference (java.util.concurrent.atomic.AtomicReference)11 Listener (com.google.android.exoplayer2.Player.Listener)10 Context (android.content.Context)9 AnalyticsListener (com.google.android.exoplayer2.analytics.AnalyticsListener)9 ActionSchedule (com.google.android.exoplayer2.testutil.ActionSchedule)8 SurfaceTexture (android.graphics.SurfaceTexture)7 Surface (android.view.Surface)7