40
40
import com .google .common .collect .ImmutableList ;
41
41
import java .io .ByteArrayInputStream ;
42
42
import java .io .IOException ;
43
+ import java .util .ArrayList ;
44
+ import java .util .List ;
45
+ import java .util .concurrent .atomic .AtomicBoolean ;
43
46
import java .util .concurrent .atomic .AtomicReference ;
44
47
import org .junit .Test ;
45
48
import org .junit .runner .RunWith ;
@@ -57,6 +60,10 @@ public final class DashMediaSourceTest {
57
60
"media/mpd/sample_mpd_live_with_complete_service_description" ;
58
61
private static final String SAMPLE_MPD_LIVE_WITH_OFFSET_INSIDE_WINDOW =
59
62
"media/mpd/sample_mpd_live_with_offset_inside_window" ;
63
+ private static final String SAMPLE_MPD_LIVE_WITH_TIME_SHIFT_BUFFER_16_SECS =
64
+ "media/mpd/sample_mpd_live_with_time_shift_buffer_16_secs" ;
65
+ private static final String SAMPLE_MPD_LIVE_WITH_TIME_SHIFT_BUFFER_60_SECS =
66
+ "media/mpd/sample_mpd_live_with_time_shift_buffer_60_secs" ;
60
67
private static final String SAMPLE_MPD_LIVE_WITH_OFFSET_TOO_SHORT =
61
68
"media/mpd/sample_mpd_live_with_offset_too_short" ;
62
69
private static final String SAMPLE_MPD_LIVE_WITH_OFFSET_TOO_LONG =
@@ -442,6 +449,45 @@ public void prepare_targetLiveOffsetTooShort_correctedTargetOffsetAndAlignedWind
442
449
assertThat (window .liveConfiguration .targetOffsetMs ).isEqualTo (60_000 - 16_000 );
443
450
}
444
451
452
+ @ Test
453
+ public void prepare_targetLiveOffsetConstrainedByManifest_resetByRelease () throws Exception {
454
+ LiveConfiguration mediaItemLiveConfiguration =
455
+ new LiveConfiguration .Builder ().setTargetOffsetMs (25_000L ).build ();
456
+ AtomicBoolean hasCreatedFirstDataSource = new AtomicBoolean ();
457
+ DashMediaSource mediaSource =
458
+ new DashMediaSource .Factory (
459
+ () -> {
460
+ if (!hasCreatedFirstDataSource .getAndSet (true )) {
461
+ // Delivers a manifest with a window duration shorter than the declared offset.
462
+ return createSampleMpdDataSource (
463
+ SAMPLE_MPD_LIVE_WITH_TIME_SHIFT_BUFFER_16_SECS );
464
+ }
465
+ // Delivers a manifest with a window duration larger than the declared offset.
466
+ return createSampleMpdDataSource (SAMPLE_MPD_LIVE_WITH_TIME_SHIFT_BUFFER_60_SECS );
467
+ })
468
+ .createMediaSource (
469
+ new MediaItem .Builder ()
470
+ .setUri (Uri .EMPTY )
471
+ .setLiveConfiguration (mediaItemLiveConfiguration )
472
+ .build ());
473
+ List <Window > capturedWindows = new ArrayList <>();
474
+ MediaSource .MediaSourceCaller mediaSourceCaller =
475
+ (source , timeline ) ->
476
+ capturedWindows .add (timeline .getWindow (/* windowIndex= */ 0 , new Window ()));
477
+
478
+ mediaSource .prepareSource (mediaSourceCaller , /* mediaTransferListener= */ null , PlayerId .UNSET );
479
+
480
+ RobolectricUtil .runMainLooperUntil (() -> capturedWindows .size () == 1 );
481
+ // Assert that the offset defined by the media item was overridden.
482
+ assertThat (capturedWindows .get (0 ).liveConfiguration .targetOffsetMs ).isEqualTo (9_000L );
483
+
484
+ mediaSource .releaseSource (mediaSourceCaller );
485
+ mediaSource .prepareSource (mediaSourceCaller , /* mediaTransferListener= */ null , PlayerId .UNSET );
486
+
487
+ RobolectricUtil .runMainLooperUntil (() -> capturedWindows .size () == 2 );
488
+ assertThat (capturedWindows .get (1 ).liveConfiguration .targetOffsetMs ).isEqualTo (25_000L );
489
+ }
490
+
445
491
@ Test
446
492
public void canUpdateMediaItem_withIrrelevantFieldsChanged_returnsTrue () {
447
493
MediaItem initialMediaItem =
@@ -545,28 +591,6 @@ public void canUpdateMediaItem_withChangedDrmConfiguration_returnsFalse() {
545
591
assertThat (canUpdateMediaItem ).isFalse ();
546
592
}
547
593
548
- @ Test
549
- public void canUpdateMediaItem_withChangedLiveConfiguration_returnsFalse () {
550
- MediaItem initialMediaItem =
551
- new MediaItem .Builder ()
552
- .setUri ("http://test.test" )
553
- .setLiveConfiguration (new LiveConfiguration .Builder ().setTargetOffsetMs (2000 ).build ())
554
- .build ();
555
- MediaItem updatedMediaItem =
556
- new MediaItem .Builder ()
557
- .setUri ("http://test.test" )
558
- .setLiveConfiguration (new LiveConfiguration .Builder ().setTargetOffsetMs (5000 ).build ())
559
- .build ();
560
- MediaSource mediaSource =
561
- new DashMediaSource .Factory (
562
- () -> createSampleMpdDataSource (SAMPLE_MPD_LIVE_WITHOUT_LIVE_CONFIGURATION ))
563
- .createMediaSource (initialMediaItem );
564
-
565
- boolean canUpdateMediaItem = mediaSource .canUpdateMediaItem (updatedMediaItem );
566
-
567
- assertThat (canUpdateMediaItem ).isFalse ();
568
- }
569
-
570
594
@ Test
571
595
public void updateMediaItem_createsTimelineWithUpdatedItem () throws Exception {
572
596
MediaItem initialMediaItem =
@@ -584,6 +608,45 @@ public void updateMediaItem_createsTimelineWithUpdatedItem() throws Exception {
584
608
assertThat (window .mediaItem ).isEqualTo (updatedMediaItem );
585
609
}
586
610
611
+ @ Test
612
+ public void updateMediaItem_targetLiveOffsetConstrainedByManifest_resetByUpdatedMediaItem ()
613
+ throws Exception {
614
+ // A live configuration with a target offset larger than the window duration.
615
+ LiveConfiguration initialLiveConfiguration =
616
+ new LiveConfiguration .Builder ().setTargetOffsetMs (25_000L ).build ();
617
+ DashMediaSource mediaSource =
618
+ new DashMediaSource .Factory (
619
+ () -> createSampleMpdDataSource (SAMPLE_MPD_LIVE_WITH_TIME_SHIFT_BUFFER_16_SECS ))
620
+ .createMediaSource (
621
+ new MediaItem .Builder ()
622
+ .setUri (Uri .EMPTY )
623
+ .setLiveConfiguration (initialLiveConfiguration )
624
+ .build ());
625
+ List <Window > capturedWindows = new ArrayList <>();
626
+ MediaSource .MediaSourceCaller mediaSourceCaller =
627
+ (source , timeline ) ->
628
+ capturedWindows .add (timeline .getWindow (/* windowIndex= */ 0 , new Window ()));
629
+
630
+ mediaSource .prepareSource (mediaSourceCaller , /* mediaTransferListener= */ null , PlayerId .UNSET );
631
+
632
+ RobolectricUtil .runMainLooperUntil (() -> capturedWindows .size () == 1 );
633
+ // Assert that the offset defined by the media item was overridden.
634
+ assertThat (capturedWindows .get (0 ).liveConfiguration .targetOffsetMs ).isEqualTo (9_000L );
635
+
636
+ mediaSource .releaseSource (mediaSourceCaller );
637
+ // Set a new live configuration with a target offset within the window duration.
638
+ mediaSource .updateMediaItem (
639
+ new MediaItem .Builder ()
640
+ .setUri (Uri .EMPTY )
641
+ .setLiveConfiguration (new LiveConfiguration .Builder ().setTargetOffsetMs (5_000L ).build ())
642
+ .build ());
643
+
644
+ mediaSource .prepareSource (mediaSourceCaller , /* mediaTransferListener= */ null , PlayerId .UNSET );
645
+
646
+ RobolectricUtil .runMainLooperUntil (() -> capturedWindows .size () == 2 );
647
+ assertThat (capturedWindows .get (1 ).liveConfiguration .targetOffsetMs ).isEqualTo (5_000L );
648
+ }
649
+
587
650
private static Window prepareAndWaitForTimelineRefresh (MediaSource mediaSource ) throws Exception {
588
651
AtomicReference <Timeline .Window > windowReference = new AtomicReference <>();
589
652
mediaSource .prepareSource (
0 commit comments