@@ -346,7 +346,7 @@ public void playAds_midRollsWithAndWithoutDuration_clippedOrNotClippedAccordingl
346346 Timeline primaryContentTimeline =
347347 new FakeTimeline (new TimelineWindowDefinition .Builder ().setDurationUs (60_000_000L ).build ());
348348 AdPlaybackState adPlaybackState =
349- new AdPlaybackState ("adsId" , 133_000_000L , 143_000_000L )
349+ new AdPlaybackState ("adsId" , 10_000_000L , 20_000_000L )
350350 .withAdCount (/* adGroupIndex= */ 0 , /* adCount= */ 1 )
351351 .withAvailableAdMediaItem (
352352 /* adGroupIndex= */ 0 ,
@@ -1057,6 +1057,7 @@ public void adInMovingLiveWindow_keepsContentPosition() throws Exception {
10571057 assertThat (contentPositionAfterLiveWindowUpdateMs ).isEqualTo (2000 );
10581058 }
10591059
1060+
10601061 @ Test
10611062 public void addMediaSource_whilePlayingAd_correctMasking () throws Exception {
10621063 long contentDurationMs = 10_000 ;
@@ -1879,6 +1880,7 @@ protected MediaPeriod createMediaPeriod(
18791880 player .release ();
18801881 }
18811882
1883+
18821884 @ Test
18831885 public void play_withPreMidAndPostRollAd_callsOnDiscontinuityCorrectly () throws Exception {
18841886 ExoPlayer player = parameterizeTestExoPlayerBuilder (new TestExoPlayerBuilder (context )).build ();
@@ -2291,6 +2293,7 @@ public void play_multiItemPlaylistWidthAds_callsOnDiscontinuityCorrectly() throw
22912293 player .release ();
22922294 }
22932295
2296+
22942297 @ Test
22952298 public void newServerSideInsertedAdAtPlaybackPosition_keepsRenderersEnabled () throws Exception {
22962299 // Injecting renderer to count number of renderer resets.
@@ -2317,6 +2320,7 @@ public void newServerSideInsertedAdAtPlaybackPosition_keepsRenderersEnabled() th
23172320 new TimelineWindowDefinition .Builder ()
23182321 .setDynamic (true )
23192322 .setDurationUs (C .TIME_UNSET )
2323+
23202324 .setAdPlaybackStates (ImmutableList .of (initialAdPlaybackState ))
23212325 .build ();
23222326 Timeline initialTimeline = new FakeTimeline (initialTimelineWindowDefinition );
@@ -2361,4 +2365,103 @@ public void newServerSideInsertedAdAtPlaybackPosition_keepsRenderersEnabled() th
23612365 assertThat (timeline .getPeriod (0 , new Timeline .Period ()).adPlaybackState .adGroupCount )
23622366 .isEqualTo (2 );
23632367 }
2368+
2369+ @ Test
2370+ public void playAds_midRollsInMultiPeriodContent_playedSuccessfully ()
2371+ throws PlaybackException , TimeoutException {
2372+ Timeline primaryContentTimeline =
2373+ new FakeTimeline (
2374+ new TimelineWindowDefinition .Builder ()
2375+ .setPeriodCount (2 )
2376+ .setDurationUs (60_000_000L )
2377+ .setWindowPositionInFirstPeriodUs (0 )
2378+ .build ());
2379+ AdPlaybackState adPlaybackState =
2380+ new AdPlaybackState ("adsId" , 10_000_000L , 40_000_000L )
2381+ .withAdCount (/* adGroupIndex= */ 0 , /* adCount= */ 1 )
2382+ .withAvailableAdMediaItem (
2383+ /* adGroupIndex= */ 0 ,
2384+ /* adIndexInAdGroup= */ 0 ,
2385+ MediaItem .fromUri ("http://example.com/ad_0_0" ))
2386+ .withAdCount (/* adGroupIndex= */ 1 , /* adCount= */ 1 )
2387+ .withAvailableAdMediaItem (
2388+ /* adGroupIndex= */ 1 ,
2389+ /* adIndexInAdGroup= */ 0 ,
2390+ MediaItem .fromUri ("http://example.com/ad_1_0" ));
2391+ FakeAdsLoader fakeAdsLoader = new FakeAdsLoader ();
2392+ AdsMediaSource adsMediaSource =
2393+ new AdsMediaSource (
2394+ new FakeMediaSource (primaryContentTimeline , ExoPlayerTestRunner .VIDEO_FORMAT ),
2395+ new DataSpec (Uri .EMPTY ),
2396+ "adsId" ,
2397+ /* adMediaSourceFactory= */ new FakeMediaSourceFactory (
2398+ new TimelineWindowDefinition .Builder ()
2399+ .setDurationUs (10_000_000L )
2400+ .setWindowPositionInFirstPeriodUs (0 )),
2401+ fakeAdsLoader ,
2402+ /* adViewProvider= */ () -> null ,
2403+ /* useLazyContentSourcePreparation= */ true ,
2404+ /* useAdMediaSourceClipping= */ true );
2405+ ExoPlayer player = parameterizeTestExoPlayerBuilder (new TestExoPlayerBuilder (context )).build ();
2406+ Player .Listener mockListener = mock (Player .Listener .class );
2407+ player .addListener (mockListener );
2408+ player .setMediaSource (adsMediaSource );
2409+ player .prepare ();
2410+ advance (player )
2411+ .untilBackgroundThreadCondition (
2412+ (Supplier <Boolean >) () -> fakeAdsLoader .eventListeners .get ("adsId" ) != null );
2413+ fakeAdsLoader .eventListeners .get ("adsId" ).onAdPlaybackState (adPlaybackState );
2414+
2415+ player .play ();
2416+ // Play past midroll 0 (at 10s) but before midroll 1 (at 40s) and period transition (at 30s)
2417+ advance (player ).untilPositionAtLeast (/* mediaItemIndex= */ 0 , /* positionMs= */ 15_000L );
2418+ // Mark midroll 0 as played.
2419+ adPlaybackState =
2420+ adPlaybackState .withPlayedAd (/* adGroupIndex= */ 0 , /* adIndexInAdGroup= */ 0 );
2421+ fakeAdsLoader .eventListeners .get ("adsId" ).onAdPlaybackState (adPlaybackState );
2422+
2423+ advance (player ).untilState (Player .STATE_ENDED );
2424+ player .release ();
2425+
2426+ ArgumentCaptor <PositionInfo > oldPositionsCaptor = ArgumentCaptor .forClass (PositionInfo .class );
2427+ ArgumentCaptor <PositionInfo > newPositionsCaptor = ArgumentCaptor .forClass (PositionInfo .class );
2428+ ArgumentCaptor <Integer > reasonsCaptor = ArgumentCaptor .forClass (Integer .class );
2429+ verify (mockListener , times (5 ))
2430+ .onPositionDiscontinuity (
2431+ oldPositionsCaptor .capture (), newPositionsCaptor .capture (), reasonsCaptor .capture ());
2432+ assertThat (reasonsCaptor .getAllValues ())
2433+ .containsExactly (
2434+ DISCONTINUITY_REASON_AUTO_TRANSITION , // content to midroll 0
2435+ DISCONTINUITY_REASON_AUTO_TRANSITION , // midroll 0 to content
2436+ DISCONTINUITY_REASON_AUTO_TRANSITION , // period transition
2437+ DISCONTINUITY_REASON_AUTO_TRANSITION , // content to midroll 1
2438+ DISCONTINUITY_REASON_AUTO_TRANSITION ); // midroll 1 to content
2439+
2440+ List <PositionInfo > oldPositions = oldPositionsCaptor .getAllValues ();
2441+ List <PositionInfo > newPositions = newPositionsCaptor .getAllValues ();
2442+
2443+ // midroll 0 to content
2444+ assertThat (oldPositions .get (1 ).adGroupIndex ).isEqualTo (0 );
2445+ assertThat (oldPositions .get (1 ).positionMs ).isEqualTo (10_000L ); // ad duration
2446+ assertThat (oldPositions .get (1 ).contentPositionMs ).isEqualTo (10_000L );
2447+ assertThat (newPositions .get (1 ).adGroupIndex ).isEqualTo (C .INDEX_UNSET );
2448+ assertThat (newPositions .get (1 ).positionMs ).isEqualTo (10_000L );
2449+ assertThat (newPositions .get (1 ).contentPositionMs ).isEqualTo (10_000L );
2450+
2451+ // period transition
2452+ assertThat (oldPositions .get (2 ).periodIndex ).isEqualTo (0 );
2453+ assertThat (oldPositions .get (2 ).adGroupIndex ).isEqualTo (C .INDEX_UNSET );
2454+ assertThat (oldPositions .get (2 ).positionMs ).isEqualTo (30_000L );
2455+ assertThat (newPositions .get (2 ).periodIndex ).isEqualTo (1 );
2456+ assertThat (newPositions .get (2 ).adGroupIndex ).isEqualTo (C .INDEX_UNSET );
2457+ assertThat (newPositions .get (2 ).positionMs ).isEqualTo (30_000L );
2458+
2459+ // midroll 1 to content
2460+ assertThat (oldPositions .get (4 ).adGroupIndex ).isEqualTo (1 );
2461+ assertThat (oldPositions .get (4 ).positionMs ).isEqualTo (10_000L ); // ad duration
2462+ assertThat (oldPositions .get (4 ).contentPositionMs ).isEqualTo (40_000L );
2463+ assertThat (newPositions .get (4 ).adGroupIndex ).isEqualTo (C .INDEX_UNSET );
2464+ assertThat (newPositions .get (4 ).positionMs ).isEqualTo (40_000L );
2465+ assertThat (newPositions .get (4 ).contentPositionMs ).isEqualTo (40_000L );
2466+ }
23642467}
0 commit comments