Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
05c928f9
authored
Dec 10, 2020
by
bachinger
Committed by
Ian Baker
Dec 14, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add live configuration to Timeline.Window
Issue: #5011 PiperOrigin-RevId: 346828103
parent
392b3ab5
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
190 additions
and
167 deletions
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java
library/common/src/main/java/com/google/android/exoplayer2/Timeline.java
library/core/src/main/java/com/google/android/exoplayer2/BasePlayer.java
library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
library/core/src/main/java/com/google/android/exoplayer2/Player.java
library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java
library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
library/core/src/test/java/com/google/android/exoplayer2/TimelineTest.java
library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java
library/core/src/test/java/com/google/android/exoplayer2/source/SinglePeriodTimelineTest.java
library/core/src/test/java/com/google/android/exoplayer2/source/ads/AdsMediaSourceTest.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaSourceTest.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaSourceTest.java
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java
View file @
05c928f9
...
...
@@ -126,16 +126,18 @@ import java.util.Arrays;
public
Window
getWindow
(
int
windowIndex
,
Window
window
,
long
defaultPositionProjectionUs
)
{
long
durationUs
=
durationsUs
[
windowIndex
];
boolean
isDynamic
=
durationUs
==
C
.
TIME_UNSET
;
MediaItem
mediaItem
=
new
MediaItem
.
Builder
().
setUri
(
Uri
.
EMPTY
).
setTag
(
ids
[
windowIndex
]).
build
();
return
window
.
set
(
/* uid= */
ids
[
windowIndex
],
/* mediaItem= */
new
MediaItem
.
Builder
().
setUri
(
Uri
.
EMPTY
).
setTag
(
ids
[
windowIndex
]).
build
()
,
/* mediaItem= */
mediaItem
,
/* manifest= */
null
,
/* presentationStartTimeMs= */
C
.
TIME_UNSET
,
/* windowStartTimeMs= */
C
.
TIME_UNSET
,
/* elapsedRealtimeEpochOffsetMs= */
C
.
TIME_UNSET
,
/* isSeekable= */
!
isDynamic
,
isDynamic
,
isLive
[
windowIndex
],
isLive
[
windowIndex
]
?
mediaItem
.
liveConfiguration
:
null
,
defaultPositionsUs
[
windowIndex
],
durationUs
,
/* firstPeriodIndex= */
windowIndex
,
...
...
library/common/src/main/java/com/google/android/exoplayer2/Timeline.java
View file @
05c928f9
...
...
@@ -15,6 +15,8 @@
*/
package
com
.
google
.
android
.
exoplayer2
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
android.net.Uri
;
import
android.os.SystemClock
;
import
android.util.Pair
;
...
...
@@ -74,10 +76,10 @@ import com.google.android.exoplayer2.util.Util;
* <p>A timeline for a live stream consists of a period whose duration is unknown, since it's
* continually extending as more content is broadcast. If content only remains available for a
* limited period of time then the window may start at a non-zero position, defining the region of
* content that can still be played. The window will
have {@link Window#isLive} set to true
to
* indicate it's a live stream and {@link Window#isDynamic}
set to true as long as we expect changes
*
to the live window. Its default position is typically near to the live edge (indicated by the
* black dot in the figure above).
* content that can still be played. The window will
return true from {@link Window#isLive()}
to
* indicate it's a live stream and {@link Window#isDynamic}
will be set to true as long as we expect
*
changes to the live window. Its default position is typically near to the live edge (indicated by
*
the
black dot in the figure above).
*
* <h3>Live stream with indefinite availability</h3>
*
...
...
@@ -191,12 +193,14 @@ public abstract class Timeline {
/** Whether this window may change when the timeline is updated. */
public
boolean
isDynamic
;
/** @deprecated Use {@link #isLive()} instead. */
@Deprecated
public
boolean
isLive
;
/**
* Whether the media in this window is live. For informational purposes only.
*
* <p>Check {@link #isDynamic} to know whether this window may still change.
* The {@link MediaItem.LiveConfiguration} that is used or null if {@link #isLive()} returns
* false.
*/
public
boolean
isLive
;
@Nullable
public
MediaItem
.
LiveConfiguration
liveConfiguration
;
/**
* Whether this window contains placeholder information because the real information has yet to
...
...
@@ -248,7 +252,7 @@ public abstract class Timeline {
long
elapsedRealtimeEpochOffsetMs
,
boolean
isSeekable
,
boolean
isDynamic
,
boolean
isLive
,
@Nullable
MediaItem
.
LiveConfiguration
liveConfiguration
,
long
defaultPositionUs
,
long
durationUs
,
int
firstPeriodIndex
,
...
...
@@ -266,7 +270,8 @@ public abstract class Timeline {
this
.
elapsedRealtimeEpochOffsetMs
=
elapsedRealtimeEpochOffsetMs
;
this
.
isSeekable
=
isSeekable
;
this
.
isDynamic
=
isDynamic
;
this
.
isLive
=
isLive
;
this
.
isLive
=
liveConfiguration
!=
null
;
this
.
liveConfiguration
=
liveConfiguration
;
this
.
defaultPositionUs
=
defaultPositionUs
;
this
.
durationUs
=
durationUs
;
this
.
firstPeriodIndex
=
firstPeriodIndex
;
...
...
@@ -336,6 +341,14 @@ public abstract class Timeline {
return
Util
.
getNowUnixTimeMs
(
elapsedRealtimeEpochOffsetMs
);
}
/** Returns whether this is a live stream. */
// Verifies whether the deprecated isLive member field is in a correct state.
@SuppressWarnings
(
"deprecation"
)
public
boolean
isLive
()
{
checkState
(
isLive
==
(
liveConfiguration
!=
null
));
return
liveConfiguration
!=
null
;
}
// Provide backward compatibility for tag.
@Override
public
boolean
equals
(
@Nullable
Object
obj
)
{
...
...
@@ -349,12 +362,12 @@ public abstract class Timeline {
return
Util
.
areEqual
(
uid
,
that
.
uid
)
&&
Util
.
areEqual
(
mediaItem
,
that
.
mediaItem
)
&&
Util
.
areEqual
(
manifest
,
that
.
manifest
)
&&
Util
.
areEqual
(
liveConfiguration
,
that
.
liveConfiguration
)
&&
presentationStartTimeMs
==
that
.
presentationStartTimeMs
&&
windowStartTimeMs
==
that
.
windowStartTimeMs
&&
elapsedRealtimeEpochOffsetMs
==
that
.
elapsedRealtimeEpochOffsetMs
&&
isSeekable
==
that
.
isSeekable
&&
isDynamic
==
that
.
isDynamic
&&
isLive
==
that
.
isLive
&&
isPlaceholder
==
that
.
isPlaceholder
&&
defaultPositionUs
==
that
.
defaultPositionUs
&&
durationUs
==
that
.
durationUs
...
...
@@ -370,6 +383,7 @@ public abstract class Timeline {
result
=
31
*
result
+
uid
.
hashCode
();
result
=
31
*
result
+
mediaItem
.
hashCode
();
result
=
31
*
result
+
(
manifest
==
null
?
0
:
manifest
.
hashCode
());
result
=
31
*
result
+
(
liveConfiguration
==
null
?
0
:
liveConfiguration
.
hashCode
());
result
=
31
*
result
+
(
int
)
(
presentationStartTimeMs
^
(
presentationStartTimeMs
>>>
32
));
result
=
31
*
result
+
(
int
)
(
windowStartTimeMs
^
(
windowStartTimeMs
>>>
32
));
result
=
...
...
@@ -377,7 +391,6 @@ public abstract class Timeline {
+
(
int
)
(
elapsedRealtimeEpochOffsetMs
^
(
elapsedRealtimeEpochOffsetMs
>>>
32
));
result
=
31
*
result
+
(
isSeekable
?
1
:
0
);
result
=
31
*
result
+
(
isDynamic
?
1
:
0
);
result
=
31
*
result
+
(
isLive
?
1
:
0
);
result
=
31
*
result
+
(
isPlaceholder
?
1
:
0
);
result
=
31
*
result
+
(
int
)
(
defaultPositionUs
^
(
defaultPositionUs
>>>
32
));
result
=
31
*
result
+
(
int
)
(
durationUs
^
(
durationUs
>>>
32
));
...
...
library/core/src/main/java/com/google/android/exoplayer2/BasePlayer.java
View file @
05c928f9
...
...
@@ -214,7 +214,7 @@ public abstract class BasePlayer implements Player {
@Override
public
final
boolean
isCurrentWindowLive
()
{
Timeline
timeline
=
getCurrentTimeline
();
return
!
timeline
.
isEmpty
()
&&
timeline
.
getWindow
(
getCurrentWindowIndex
(),
window
).
isLive
;
return
!
timeline
.
isEmpty
()
&&
timeline
.
getWindow
(
getCurrentWindowIndex
(),
window
).
isLive
()
;
}
@Override
...
...
library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java
View file @
05c928f9
...
...
@@ -99,7 +99,7 @@ public class DefaultControlDispatcher implements ControlDispatcher {
int
nextWindowIndex
=
player
.
getNextWindowIndex
();
if
(
nextWindowIndex
!=
C
.
INDEX_UNSET
)
{
player
.
seekTo
(
nextWindowIndex
,
C
.
TIME_UNSET
);
}
else
if
(
timeline
.
getWindow
(
windowIndex
,
window
).
isLive
)
{
}
else
if
(
timeline
.
getWindow
(
windowIndex
,
window
).
isLive
()
)
{
player
.
seekTo
(
windowIndex
,
C
.
TIME_UNSET
);
}
return
true
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
View file @
05c928f9
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer2
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Util
.
castNonNull
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
min
;
...
...
@@ -1050,7 +1051,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private
long
getLiveOffsetUs
(
Timeline
timeline
,
Object
periodUid
,
long
periodPositionUs
)
{
int
windowIndex
=
timeline
.
getPeriodByUid
(
periodUid
,
period
).
windowIndex
;
timeline
.
getWindow
(
windowIndex
,
window
);
if
(
window
.
windowStartTimeMs
==
C
.
TIME_UNSET
||
!
window
.
isLive
||
!
window
.
isDynamic
)
{
if
(
window
.
windowStartTimeMs
==
C
.
TIME_UNSET
||
!
window
.
isLive
()
||
!
window
.
isDynamic
)
{
return
C
.
TIME_UNSET
;
}
return
C
.
msToUs
(
window
.
getCurrentUnixTimeMs
()
-
window
.
windowStartTimeMs
)
...
...
@@ -1067,7 +1068,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
int
windowIndex
=
timeline
.
getPeriodByUid
(
mediaPeriodId
.
periodUid
,
period
).
windowIndex
;
timeline
.
getWindow
(
windowIndex
,
window
);
return
window
.
isLive
&&
window
.
isDynamic
;
return
window
.
isLive
()
&&
window
.
isDynamic
;
}
private
void
scheduleNextWork
(
long
thisOperationStartTimeMs
,
long
intervalMs
)
{
...
...
@@ -1838,7 +1839,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
int
windowIndex
=
newTimeline
.
getPeriodByUid
(
newPeriodId
.
periodUid
,
period
).
windowIndex
;
newTimeline
.
getWindow
(
windowIndex
,
window
);
livePlaybackSpeedControl
.
setLiveConfiguration
(
window
.
mediaItem
.
liveConfiguration
);
livePlaybackSpeedControl
.
setLiveConfiguration
(
castNonNull
(
window
.
liveConfiguration
)
);
if
(
positionForTargetOffsetOverrideUs
!=
C
.
TIME_UNSET
)
{
livePlaybackSpeedControl
.
setTargetLiveOffsetOverrideUs
(
getLiveOffsetUs
(
newTimeline
,
newPeriodId
.
periodUid
,
positionForTargetOffsetOverrideUs
));
...
...
library/core/src/main/java/com/google/android/exoplayer2/Player.java
View file @
05c928f9
...
...
@@ -1570,7 +1570,7 @@ public interface Player {
/**
* Returns whether the current window is live, or {@code false} if the {@link Timeline} is empty.
*
* @see Timeline.Window#isLive
* @see Timeline.Window#isLive
()
*/
boolean
isCurrentWindowLive
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadHelper.java
View file @
05c928f9
...
...
@@ -1003,7 +1003,7 @@ public final class DownloadHelper {
// Ignore dynamic updates.
return
;
}
if
(
timeline
.
getWindow
(
/* windowIndex= */
0
,
new
Timeline
.
Window
()).
isLive
)
{
if
(
timeline
.
getWindow
(
/* windowIndex= */
0
,
new
Timeline
.
Window
()).
isLive
()
)
{
downloadHelperHandler
.
obtainMessage
(
DOWNLOAD_HELPER_CALLBACK_MESSAGE_FAILED
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java
View file @
05c928f9
...
...
@@ -374,7 +374,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
/* isSeekable= */
false
,
// Dynamic window to indicate pending timeline updates.
/* isDynamic= */
true
,
/*
isLive= */
false
,
/*
liveConfiguration= */
null
,
/* defaultPositionUs= */
0
,
/* durationUs= */
C
.
TIME_UNSET
,
/* firstPeriodIndex= */
0
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaSource.java
View file @
05c928f9
...
...
@@ -336,7 +336,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
timelineDurationUs
,
timelineIsSeekable
,
/* isDynamic= */
false
,
/*
isLive
= */
timelineIsLive
,
/*
useLiveConfiguration
= */
timelineIsLive
,
/* manifest= */
null
,
mediaItem
);
if
(
timelineIsPlaceholder
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java
View file @
05c928f9
...
...
@@ -132,7 +132,7 @@ public final class SilenceMediaSource extends BaseMediaSource {
durationUs
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
mediaItem
));
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java
View file @
05c928f9
...
...
@@ -45,9 +45,9 @@ public final class SinglePeriodTimeline extends Timeline {
private
final
long
windowDefaultStartPositionUs
;
private
final
boolean
isSeekable
;
private
final
boolean
isDynamic
;
private
final
boolean
isLive
;
@Nullable
private
final
Object
manifest
;
@Nullable
private
final
MediaItem
mediaItem
;
@Nullable
private
final
MediaItem
.
LiveConfiguration
liveConfiguration
;
/**
* @deprecated Use {@link #SinglePeriodTimeline(long, boolean, boolean, boolean, Object,
...
...
@@ -81,7 +81,8 @@ public final class SinglePeriodTimeline extends Timeline {
* @param durationUs The duration of the period, in microseconds.
* @param isSeekable Whether seeking is supported within the period.
* @param isDynamic Whether the window may change when the timeline is updated.
* @param isLive Whether the window is live.
* @param useLiveConfiguration Whether the window is live and {@link MediaItem#liveConfiguration}
* is used to configure live playback behaviour.
* @param manifest The manifest. May be {@code null}.
* @param mediaItem A media item used for {@link Window#mediaItem}.
*/
...
...
@@ -89,7 +90,7 @@ public final class SinglePeriodTimeline extends Timeline {
long
durationUs
,
boolean
isSeekable
,
boolean
isDynamic
,
boolean
isLive
,
boolean
useLiveConfiguration
,
@Nullable
Object
manifest
,
MediaItem
mediaItem
)
{
this
(
...
...
@@ -99,7 +100,7 @@ public final class SinglePeriodTimeline extends Timeline {
/* windowDefaultStartPositionUs= */
0
,
isSeekable
,
isDynamic
,
isLive
,
useLiveConfiguration
,
manifest
,
mediaItem
);
}
...
...
@@ -148,7 +149,8 @@ public final class SinglePeriodTimeline extends Timeline {
* which to begin playback, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
* @param isDynamic Whether the window may change when the timeline is updated.
* @param isLive Whether the window is live.
* @param useLiveConfiguration Whether the window is live and {@link MediaItem#liveConfiguration}
* is used to configure live playback behaviour.
* @param manifest The manifest. May be (@code null}.
* @param mediaItem A media item used for {@link Timeline.Window#mediaItem}.
*/
...
...
@@ -159,7 +161,7 @@ public final class SinglePeriodTimeline extends Timeline {
long
windowDefaultStartPositionUs
,
boolean
isSeekable
,
boolean
isDynamic
,
boolean
isLive
,
boolean
useLiveConfiguration
,
@Nullable
Object
manifest
,
MediaItem
mediaItem
)
{
this
(
...
...
@@ -172,14 +174,14 @@ public final class SinglePeriodTimeline extends Timeline {
windowDefaultStartPositionUs
,
isSeekable
,
isDynamic
,
isLive
,
manifest
,
mediaItem
);
mediaItem
,
useLiveConfiguration
?
mediaItem
.
liveConfiguration
:
null
);
}
/**
* @deprecated Use {@link #SinglePeriodTimeline(long, long, long, long, long, long, long, boolean,
* boolean,
boolean, Object, MediaItem
)} instead.
* boolean,
Object, MediaItem, MediaItem.LiveConfiguration
)} instead.
*/
@Deprecated
public
SinglePeriodTimeline
(
...
...
@@ -205,9 +207,9 @@ public final class SinglePeriodTimeline extends Timeline {
windowDefaultStartPositionUs
,
isSeekable
,
isDynamic
,
isLive
,
manifest
,
MEDIA_ITEM
.
buildUpon
().
setTag
(
tag
).
build
());
MEDIA_ITEM
.
buildUpon
().
setTag
(
tag
).
build
(),
isLive
?
MEDIA_ITEM
.
liveConfiguration
:
null
);
}
/**
...
...
@@ -229,9 +231,10 @@ public final class SinglePeriodTimeline extends Timeline {
* which to begin playback, in microseconds.
* @param isSeekable Whether seeking is supported within the window.
* @param isDynamic Whether the window may change when the timeline is updated.
* @param isLive Whether the window is live.
* @param manifest The manifest. May be {@code null}.
* @param mediaItem A media item used for {@link Timeline.Window#mediaItem}.
* @param liveConfiguration The configuration for live playback behaviour, or {@code null} if the
* window is not live.
*/
public
SinglePeriodTimeline
(
long
presentationStartTimeMs
,
...
...
@@ -243,9 +246,9 @@ public final class SinglePeriodTimeline extends Timeline {
long
windowDefaultStartPositionUs
,
boolean
isSeekable
,
boolean
isDynamic
,
boolean
isLive
,
@Nullable
Object
manifest
,
MediaItem
mediaItem
)
{
MediaItem
mediaItem
,
@Nullable
MediaItem
.
LiveConfiguration
liveConfiguration
)
{
this
.
presentationStartTimeMs
=
presentationStartTimeMs
;
this
.
windowStartTimeMs
=
windowStartTimeMs
;
this
.
elapsedRealtimeEpochOffsetMs
=
elapsedRealtimeEpochOffsetMs
;
...
...
@@ -255,9 +258,9 @@ public final class SinglePeriodTimeline extends Timeline {
this
.
windowDefaultStartPositionUs
=
windowDefaultStartPositionUs
;
this
.
isSeekable
=
isSeekable
;
this
.
isDynamic
=
isDynamic
;
this
.
isLive
=
isLive
;
this
.
manifest
=
manifest
;
this
.
mediaItem
=
checkNotNull
(
mediaItem
);
this
.
liveConfiguration
=
liveConfiguration
;
}
@Override
...
...
@@ -291,7 +294,7 @@ public final class SinglePeriodTimeline extends Timeline {
elapsedRealtimeEpochOffsetMs
,
isSeekable
,
isDynamic
,
isLive
,
liveConfiguration
,
windowDefaultStartPositionUs
,
windowDurationUs
,
/* firstPeriodIndex= */
0
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java
View file @
05c928f9
...
...
@@ -291,7 +291,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
durationUs
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
mediaItem
);
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
View file @
05c928f9
...
...
@@ -54,7 +54,7 @@ public final class MediaPeriodQueueTest {
CONTENT_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
private
static
final
Uri
AD_URI
=
Uri
.
EMPTY
;
...
...
library/core/src/test/java/com/google/android/exoplayer2/TimelineTest.java
View file @
05c928f9
...
...
@@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import
androidx.annotation.Nullable
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.MediaItem.LiveConfiguration
;
import
com.google.android.exoplayer2.testutil.FakeTimeline
;
import
com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition
;
import
com.google.android.exoplayer2.testutil.TimelineAsserts
;
...
...
@@ -91,7 +92,7 @@ public class TimelineTest {
assertThat
(
window
).
isNotEqualTo
(
otherWindow
);
otherWindow
=
new
Timeline
.
Window
();
otherWindow
.
isLive
=
true
;
otherWindow
.
liveConfiguration
=
LiveConfiguration
.
UNSET
;
assertThat
(
window
).
isNotEqualTo
(
otherWindow
);
otherWindow
=
new
Timeline
.
Window
();
...
...
@@ -129,7 +130,7 @@ public class TimelineTest {
window
.
elapsedRealtimeEpochOffsetMs
,
window
.
isSeekable
,
window
.
isDynamic
,
window
.
isLive
,
window
.
liveConfiguration
,
window
.
defaultPositionUs
,
window
.
durationUs
,
window
.
firstPeriodIndex
,
...
...
library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java
View file @
05c928f9
...
...
@@ -69,7 +69,7 @@ public final class ClippingMediaSourceTest {
TEST_PERIOD_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -90,7 +90,7 @@ public final class ClippingMediaSourceTest {
TEST_PERIOD_DURATION_US
,
/* isSeekable= */
false
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -112,7 +112,7 @@ public final class ClippingMediaSourceTest {
/* durationUs= */
C
.
TIME_UNSET
,
/* isSeekable= */
false
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -134,7 +134,7 @@ public final class ClippingMediaSourceTest {
TEST_PERIOD_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -153,7 +153,7 @@ public final class ClippingMediaSourceTest {
TEST_PERIOD_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -189,7 +189,7 @@ public final class ClippingMediaSourceTest {
/* durationUs= */
TEST_PERIOD_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -208,7 +208,7 @@ public final class ClippingMediaSourceTest {
/* durationUs= */
C
.
TIME_UNSET
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -226,7 +226,7 @@ public final class ClippingMediaSourceTest {
TEST_PERIOD_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -249,7 +249,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -272,7 +272,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
Timeline
timeline2
=
...
...
@@ -283,7 +283,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -323,7 +323,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
Timeline
timeline2
=
...
...
@@ -334,7 +334,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -374,7 +374,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
Timeline
timeline2
=
...
...
@@ -385,7 +385,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -426,7 +426,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
Timeline
timeline2
=
...
...
@@ -437,7 +437,7 @@ public final class ClippingMediaSourceTest {
/* windowDefaultStartPositionUs= */
TEST_CLIP_AMOUNT_US
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
...
...
@@ -556,7 +556,7 @@ public final class ClippingMediaSourceTest {
TEST_PERIOD_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
FakeMediaSource
fakeMediaSource
=
...
...
library/core/src/test/java/com/google/android/exoplayer2/source/SinglePeriodTimelineTest.java
View file @
05c928f9
...
...
@@ -71,7 +71,7 @@ public final class SinglePeriodTimelineTest {
/* windowDefaultStartPositionUs= */
0
,
/* isSeekable= */
false
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
// Should return null with a positive position projection beyond window duration.
...
...
library/core/src/test/java/com/google/android/exoplayer2/source/ads/AdsMediaSourceTest.java
View file @
05c928f9
...
...
@@ -58,7 +58,7 @@ public final class AdsMediaSourceTest {
PREROLL_AD_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
private
static
final
Object
PREROLL_AD_PERIOD_UID
=
...
...
@@ -70,7 +70,7 @@ public final class AdsMediaSourceTest {
CONTENT_DURATION_US
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
/* manifest= */
null
,
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
private
static
final
Object
CONTENT_PERIOD_UID
=
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
View file @
05c928f9
...
...
@@ -16,6 +16,7 @@
package
com
.
google
.
android
.
exoplayer2
.
source
.
dash
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Util
.
castNonNull
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
min
;
...
...
@@ -427,7 +428,7 @@ public final class DashMediaSource extends BaseMediaSource {
private
static
final
String
TAG
=
"DashMediaSource"
;
private
final
MediaItem
originalM
ediaItem
;
private
final
MediaItem
m
ediaItem
;
private
final
boolean
sideloadedManifest
;
private
final
DataSource
.
Factory
manifestDataSourceFactory
;
private
final
DashChunkSource
.
Factory
chunkSourceFactory
;
...
...
@@ -452,7 +453,7 @@ public final class DashMediaSource extends BaseMediaSource {
private
IOException
manifestFatalError
;
private
Handler
handler
;
private
MediaItem
updatedMediaItem
;
private
MediaItem
.
LiveConfiguration
liveConfiguration
;
private
Uri
manifestUri
;
private
Uri
initialManifestUri
;
private
DashManifest
manifest
;
...
...
@@ -476,8 +477,8 @@ public final class DashMediaSource extends BaseMediaSource {
DrmSessionManager
drmSessionManager
,
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
,
long
fallbackTargetLiveOffsetMs
)
{
this
.
originalM
ediaItem
=
mediaItem
;
this
.
updatedMediaItem
=
mediaItem
;
this
.
m
ediaItem
=
mediaItem
;
this
.
liveConfiguration
=
mediaItem
.
liveConfiguration
;
this
.
manifestUri
=
checkNotNull
(
mediaItem
.
playbackProperties
).
uri
;
this
.
initialManifestUri
=
mediaItem
.
playbackProperties
.
uri
;
this
.
manifest
=
manifest
;
...
...
@@ -531,12 +532,12 @@ public final class DashMediaSource extends BaseMediaSource {
@Override
@Nullable
public
Object
getTag
()
{
return
castNonNull
(
updatedM
ediaItem
.
playbackProperties
).
tag
;
return
castNonNull
(
m
ediaItem
.
playbackProperties
).
tag
;
}
@Override
public
MediaItem
getMediaItem
()
{
return
updatedM
ediaItem
;
return
m
ediaItem
;
}
@Override
...
...
@@ -938,8 +939,7 @@ public final class DashMediaSource extends BaseMediaSource {
/* windowStartPeriodTimeUs= */
currentStartTimeUs
,
/* windowEndPeriodTimeUs= */
currentEndTimeUs
);
windowDefaultStartPositionUs
=
nowUnixTimeUs
-
C
.
msToUs
(
windowStartTimeMs
+
updatedMediaItem
.
liveConfiguration
.
targetOffsetMs
);
nowUnixTimeUs
-
C
.
msToUs
(
windowStartTimeMs
+
liveConfiguration
.
targetOffsetMs
);
long
minimumDefaultStartPositionUs
=
min
(
MIN_LIVE_DEFAULT_START_POSITION_US
,
windowDurationUs
/
2
);
if
(
windowDefaultStartPositionUs
<
minimumDefaultStartPositionUs
)
{
...
...
@@ -959,7 +959,8 @@ public final class DashMediaSource extends BaseMediaSource {
windowDurationUs
,
windowDefaultStartPositionUs
,
manifest
,
updatedMediaItem
);
mediaItem
,
manifest
.
dynamic
?
liveConfiguration
:
null
);
refreshSourceInfo
(
timeline
);
if
(!
sideloadedManifest
)
{
...
...
@@ -996,8 +997,8 @@ public final class DashMediaSource extends BaseMediaSource {
private
void
updateMediaItemLiveConfiguration
(
long
nowPeriodTimeUs
,
long
windowStartPeriodTimeUs
,
long
windowEndPeriodTimeUs
)
{
long
maxLiveOffsetMs
;
if
(
originalM
ediaItem
.
liveConfiguration
.
maxOffsetMs
!=
C
.
TIME_UNSET
)
{
maxLiveOffsetMs
=
originalM
ediaItem
.
liveConfiguration
.
maxOffsetMs
;
if
(
m
ediaItem
.
liveConfiguration
.
maxOffsetMs
!=
C
.
TIME_UNSET
)
{
maxLiveOffsetMs
=
m
ediaItem
.
liveConfiguration
.
maxOffsetMs
;
}
else
if
(
manifest
.
serviceDescription
!=
null
&&
manifest
.
serviceDescription
.
maxOffsetMs
!=
C
.
TIME_UNSET
)
{
maxLiveOffsetMs
=
manifest
.
serviceDescription
.
maxOffsetMs
;
...
...
@@ -1005,8 +1006,8 @@ public final class DashMediaSource extends BaseMediaSource {
maxLiveOffsetMs
=
C
.
usToMs
(
nowPeriodTimeUs
-
windowStartPeriodTimeUs
);
}
long
minLiveOffsetMs
;
if
(
originalM
ediaItem
.
liveConfiguration
.
minOffsetMs
!=
C
.
TIME_UNSET
)
{
minLiveOffsetMs
=
originalM
ediaItem
.
liveConfiguration
.
minOffsetMs
;
if
(
m
ediaItem
.
liveConfiguration
.
minOffsetMs
!=
C
.
TIME_UNSET
)
{
minLiveOffsetMs
=
m
ediaItem
.
liveConfiguration
.
minOffsetMs
;
}
else
if
(
manifest
.
serviceDescription
!=
null
&&
manifest
.
serviceDescription
.
minOffsetMs
!=
C
.
TIME_UNSET
)
{
minLiveOffsetMs
=
manifest
.
serviceDescription
.
minOffsetMs
;
...
...
@@ -1022,9 +1023,9 @@ public final class DashMediaSource extends BaseMediaSource {
}
}
long
targetOffsetMs
;
if
(
updatedMediaItem
.
liveConfiguration
.
targetOffsetMs
!=
C
.
TIME_UNSET
)
{
if
(
liveConfiguration
.
targetOffsetMs
!=
C
.
TIME_UNSET
)
{
// Keep existing target offset even if the media configuration changes.
targetOffsetMs
=
updatedMediaItem
.
liveConfiguration
.
targetOffsetMs
;
targetOffsetMs
=
liveConfiguration
.
targetOffsetMs
;
}
else
if
(
manifest
.
serviceDescription
!=
null
&&
manifest
.
serviceDescription
.
targetOffsetMs
!=
C
.
TIME_UNSET
)
{
targetOffsetMs
=
manifest
.
serviceDescription
.
targetOffsetMs
;
...
...
@@ -1048,26 +1049,20 @@ public final class DashMediaSource extends BaseMediaSource {
maxTargetOffsetForSafeDistanceToWindowStartMs
,
minLiveOffsetMs
,
maxLiveOffsetMs
);
}
float
minPlaybackSpeed
=
C
.
RATE_UNSET
;
if
(
originalM
ediaItem
.
liveConfiguration
.
minPlaybackSpeed
!=
C
.
RATE_UNSET
)
{
minPlaybackSpeed
=
originalM
ediaItem
.
liveConfiguration
.
minPlaybackSpeed
;
if
(
m
ediaItem
.
liveConfiguration
.
minPlaybackSpeed
!=
C
.
RATE_UNSET
)
{
minPlaybackSpeed
=
m
ediaItem
.
liveConfiguration
.
minPlaybackSpeed
;
}
else
if
(
manifest
.
serviceDescription
!=
null
)
{
minPlaybackSpeed
=
manifest
.
serviceDescription
.
minPlaybackSpeed
;
}
float
maxPlaybackSpeed
=
C
.
RATE_UNSET
;
if
(
originalM
ediaItem
.
liveConfiguration
.
maxPlaybackSpeed
!=
C
.
RATE_UNSET
)
{
maxPlaybackSpeed
=
originalM
ediaItem
.
liveConfiguration
.
maxPlaybackSpeed
;
if
(
m
ediaItem
.
liveConfiguration
.
maxPlaybackSpeed
!=
C
.
RATE_UNSET
)
{
maxPlaybackSpeed
=
m
ediaItem
.
liveConfiguration
.
maxPlaybackSpeed
;
}
else
if
(
manifest
.
serviceDescription
!=
null
)
{
maxPlaybackSpeed
=
manifest
.
serviceDescription
.
maxPlaybackSpeed
;
}
updatedMediaItem
=
originalMediaItem
.
buildUpon
()
.
setLiveTargetOffsetMs
(
targetOffsetMs
)
.
setLiveMinOffsetMs
(
minLiveOffsetMs
)
.
setLiveMaxOffsetMs
(
maxLiveOffsetMs
)
.
setLiveMinPlaybackSpeed
(
minPlaybackSpeed
)
.
setLiveMaxPlaybackSpeed
(
maxPlaybackSpeed
)
.
build
();
liveConfiguration
=
new
MediaItem
.
LiveConfiguration
(
targetOffsetMs
,
minLiveOffsetMs
,
maxLiveOffsetMs
,
minPlaybackSpeed
,
maxPlaybackSpeed
);
}
private
void
scheduleManifestRefresh
(
long
delayUntilNextLoadMs
)
{
...
...
@@ -1232,6 +1227,7 @@ public final class DashMediaSource extends BaseMediaSource {
private
final
long
windowDefaultStartPositionUs
;
private
final
DashManifest
manifest
;
private
final
MediaItem
mediaItem
;
@Nullable
private
final
MediaItem
.
LiveConfiguration
liveConfiguration
;
public
DashTimeline
(
long
presentationStartTimeMs
,
...
...
@@ -1242,7 +1238,9 @@ public final class DashMediaSource extends BaseMediaSource {
long
windowDurationUs
,
long
windowDefaultStartPositionUs
,
DashManifest
manifest
,
MediaItem
mediaItem
)
{
MediaItem
mediaItem
,
@Nullable
MediaItem
.
LiveConfiguration
liveConfiguration
)
{
checkState
(
manifest
.
dynamic
==
(
liveConfiguration
!=
null
));
this
.
presentationStartTimeMs
=
presentationStartTimeMs
;
this
.
windowStartTimeMs
=
windowStartTimeMs
;
this
.
elapsedRealtimeEpochOffsetMs
=
elapsedRealtimeEpochOffsetMs
;
...
...
@@ -1252,6 +1250,7 @@ public final class DashMediaSource extends BaseMediaSource {
this
.
windowDefaultStartPositionUs
=
windowDefaultStartPositionUs
;
this
.
manifest
=
manifest
;
this
.
mediaItem
=
mediaItem
;
this
.
liveConfiguration
=
liveConfiguration
;
}
@Override
...
...
@@ -1288,7 +1287,7 @@ public final class DashMediaSource extends BaseMediaSource {
elapsedRealtimeEpochOffsetMs
,
/* isSeekable= */
true
,
/* isDynamic= */
isMovingLiveWindow
(
manifest
),
/* isLive= */
manifest
.
dynamic
,
liveConfiguration
,
windowDefaultStartPositionUs
,
windowDurationUs
,
/* firstPeriodIndex= */
0
,
...
...
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaSourceTest.java
View file @
05c928f9
...
...
@@ -287,14 +287,15 @@ public final class DashMediaSourceTest {
()
->
createSampleMpdDataSource
(
SAMPLE_MPD_LIVE_WITHOUT_LIVE_CONFIGURATION
))
.
createMediaSource
(
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
MediaItem
mediaItemFromSource
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
mediaItem
;
MediaItem
.
LiveConfiguration
liveConfiguration
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
liveConfiguration
;
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
targetOffsetMs
)
assertThat
(
liveConfiguration
.
targetOffsetMs
)
.
isEqualTo
(
DashMediaSource
.
DEFAULT_FALLBACK_TARGET_LIVE_OFFSET_MS
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
0L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
58_000L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
0L
);
assertThat
(
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
58_000L
);
assertThat
(
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
}
@Test
...
...
@@ -306,13 +307,14 @@ public final class DashMediaSourceTest {
.
setFallbackTargetLiveOffsetMs
(
1234L
)
.
createMediaSource
(
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
MediaItem
mediaItemFromSource
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
mediaItem
;
MediaItem
.
LiveConfiguration
liveConfiguration
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
liveConfiguration
;
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
1234L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
0L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
58_000L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
1234L
);
assertThat
(
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
0L
);
assertThat
(
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
58_000L
);
assertThat
(
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
}
@Test
...
...
@@ -333,13 +335,10 @@ public final class DashMediaSourceTest {
.
setFallbackTargetLiveOffsetMs
(
1234L
)
.
createMediaSource
(
mediaItem
);
MediaItem
mediaItemFromSource
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
mediaItem
;
MediaItem
.
LiveConfiguration
liveConfiguration
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
liveConfiguration
;
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
876L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
500L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
20_000L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
23
f
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
42
f
);
assertThat
(
liveConfiguration
).
isEqualTo
(
mediaItem
.
liveConfiguration
);
}
@Test
...
...
@@ -353,13 +352,14 @@ public final class DashMediaSourceTest {
.
setFallbackTargetLiveOffsetMs
(
1234L
)
.
createMediaSource
(
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
MediaItem
mediaItem
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
mediaItem
;
MediaItem
.
LiveConfiguration
liveConfiguration
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
liveConfiguration
;
assertThat
(
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
2_000L
);
assertThat
(
mediaItem
.
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
500L
);
assertThat
(
mediaItem
.
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
58_000L
);
assertThat
(
mediaItem
.
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
mediaItem
.
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
2_000L
);
assertThat
(
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
500L
);
assertThat
(
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
58_000L
);
assertThat
(
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
assertThat
(
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
C
.
RATE_UNSET
);
}
@Test
...
...
@@ -383,13 +383,14 @@ public final class DashMediaSourceTest {
.
setFallbackTargetLiveOffsetMs
(
1234L
)
.
createMediaSource
(
mediaItem
);
MediaItem
mediaItemFromSource
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
mediaItem
;
MediaItem
.
LiveConfiguration
liveConfiguration
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
liveConfiguration
;
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
876L
);
assertThat
(
mediaItem
.
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
200L
);
assertThat
(
mediaItem
.
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
999L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
23
f
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
42
f
);
assertThat
(
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
876L
);
assertThat
(
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
200L
);
assertThat
(
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
999L
);
assertThat
(
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
23
f
);
assertThat
(
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
42
f
);
}
@Test
...
...
@@ -401,13 +402,14 @@ public final class DashMediaSourceTest {
.
setFallbackTargetLiveOffsetMs
(
1234L
)
.
createMediaSource
(
MediaItem
.
fromUri
(
Uri
.
EMPTY
));
MediaItem
mediaItem
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
mediaItem
;
MediaItem
.
LiveConfiguration
liveConfiguration
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
liveConfiguration
;
assertThat
(
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
4_000L
);
assertThat
(
mediaItem
.
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
2_000L
);
assertThat
(
mediaItem
.
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
6_000L
);
assertThat
(
mediaItem
.
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
0.96f
);
assertThat
(
mediaItem
.
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
1.04f
);
assertThat
(
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
4_000L
);
assertThat
(
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
2_000L
);
assertThat
(
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
6_000L
);
assertThat
(
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
0.96f
);
assertThat
(
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
1.04f
);
}
@Test
...
...
@@ -428,13 +430,14 @@ public final class DashMediaSourceTest {
.
setFallbackTargetLiveOffsetMs
(
1234L
)
.
createMediaSource
(
mediaItem
);
MediaItem
mediaItemFromSource
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
mediaItem
;
MediaItem
.
LiveConfiguration
liveConfiguration
=
prepareAndWaitForTimelineRefresh
(
mediaSource
).
liveConfiguration
;
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
876L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
100L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
999L
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
23
f
);
assertThat
(
mediaItemFromSource
.
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
42
f
);
assertThat
(
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
876L
);
assertThat
(
liveConfiguration
.
minOffsetMs
).
isEqualTo
(
100L
);
assertThat
(
liveConfiguration
.
maxOffsetMs
).
isEqualTo
(
999L
);
assertThat
(
liveConfiguration
.
minPlaybackSpeed
).
isEqualTo
(
23
f
);
assertThat
(
liveConfiguration
.
maxPlaybackSpeed
).
isEqualTo
(
42
f
);
}
@Test
...
...
@@ -448,7 +451,7 @@ public final class DashMediaSourceTest {
Window
window
=
prepareAndWaitForTimelineRefresh
(
mediaSource
);
// Expect the target live offset as defined in the manifest.
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
3000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
3000
);
// Expect the default position at the first segment start before the live edge.
assertThat
(
window
.
getDefaultPositionMs
()).
isEqualTo
(
2_000
);
}
...
...
@@ -466,7 +469,7 @@ public final class DashMediaSourceTest {
// Expect the default position at the first segment start below the minimum live start position.
assertThat
(
window
.
getDefaultPositionMs
()).
isEqualTo
(
4_000
);
// Expect the target live offset reaching from now time to the minimum live start position.
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
9000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
9000
);
}
@Test
...
...
@@ -483,7 +486,7 @@ public final class DashMediaSourceTest {
// Expect the default position at the start of the last segment.
assertThat
(
window
.
getDefaultPositionMs
()).
isEqualTo
(
12_000
);
// Expect the target live offset reaching from now time to the end of the window.
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
60_000
-
16_000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
60_000
-
16_000
);
}
private
static
Window
prepareAndWaitForTimelineRefresh
(
MediaSource
mediaSource
)
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
View file @
05c928f9
...
...
@@ -405,8 +405,9 @@ public final class HlsMediaSource extends BaseMediaSource
private
final
boolean
useSessionKeys
;
private
final
HlsPlaylistTracker
playlistTracker
;
private
final
long
elapsedRealTimeOffsetMs
;
private
final
MediaItem
mediaItem
;
private
MediaItem
mediaItem
;
private
MediaItem
.
LiveConfiguration
liveConfiguration
;
@Nullable
private
TransferListener
mediaTransferListener
;
private
HlsMediaSource
(
...
...
@@ -423,6 +424,7 @@ public final class HlsMediaSource extends BaseMediaSource
boolean
useSessionKeys
)
{
this
.
playbackProperties
=
checkNotNull
(
mediaItem
.
playbackProperties
);
this
.
mediaItem
=
mediaItem
;
this
.
liveConfiguration
=
mediaItem
.
liveConfiguration
;
this
.
dataSourceFactory
=
dataSourceFactory
;
this
.
extractorFactory
=
extractorFactory
;
this
.
compositeSequenceableLoaderFactory
=
compositeSequenceableLoaderFactory
;
...
...
@@ -515,8 +517,8 @@ public final class HlsMediaSource extends BaseMediaSource
if
(
playlistTracker
.
isLive
())
{
long
liveEdgeOffsetUs
=
getLiveEdgeOffsetUs
(
playlist
);
long
targetLiveOffsetUs
=
mediaItem
.
liveConfiguration
.
targetOffsetMs
!=
C
.
TIME_UNSET
?
C
.
msToUs
(
mediaItem
.
liveConfiguration
.
targetOffsetMs
)
liveConfiguration
.
targetOffsetMs
!=
C
.
TIME_UNSET
?
C
.
msToUs
(
liveConfiguration
.
targetOffsetMs
)
:
getTargetLiveOffsetUs
(
playlist
,
liveEdgeOffsetUs
);
// Ensure target live offset is within the live window and greater than the live edge offset.
targetLiveOffsetUs
=
...
...
@@ -546,9 +548,9 @@ public final class HlsMediaSource extends BaseMediaSource
windowDefaultStartPositionUs
,
/* isSeekable= */
true
,
/* isDynamic= */
!
playlist
.
hasEndTag
,
/* isLive= */
true
,
manifest
,
mediaItem
);
mediaItem
,
liveConfiguration
);
}
else
/* not live */
{
if
(
windowDefaultStartPositionUs
==
C
.
TIME_UNSET
)
{
windowDefaultStartPositionUs
=
0
;
...
...
@@ -564,9 +566,9 @@ public final class HlsMediaSource extends BaseMediaSource
windowDefaultStartPositionUs
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/* isLive= */
false
,
manifest
,
mediaItem
);
mediaItem
,
/* liveConfiguration= */
null
);
}
refreshSourceInfo
(
timeline
);
}
...
...
@@ -581,9 +583,7 @@ public final class HlsMediaSource extends BaseMediaSource
List
<
HlsMediaPlaylist
.
Segment
>
segments
=
playlist
.
segments
;
int
segmentIndex
=
segments
.
size
()
-
1
;
long
minStartPositionUs
=
playlist
.
durationUs
+
liveEdgeOffsetUs
-
C
.
msToUs
(
mediaItem
.
liveConfiguration
.
targetOffsetMs
);
playlist
.
durationUs
+
liveEdgeOffsetUs
-
C
.
msToUs
(
liveConfiguration
.
targetOffsetMs
);
while
(
segmentIndex
>
0
&&
segments
.
get
(
segmentIndex
).
relativeStartTimeUs
>
minStartPositionUs
)
{
segmentIndex
--;
...
...
@@ -593,8 +593,9 @@ public final class HlsMediaSource extends BaseMediaSource
private
void
maybeUpdateMediaItem
(
long
targetLiveOffsetUs
)
{
long
targetLiveOffsetMs
=
C
.
usToMs
(
targetLiveOffsetUs
);
if
(
targetLiveOffsetMs
!=
mediaItem
.
liveConfiguration
.
targetOffsetMs
)
{
mediaItem
=
mediaItem
.
buildUpon
().
setLiveTargetOffsetMs
(
targetLiveOffsetMs
).
build
();
if
(
targetLiveOffsetMs
!=
liveConfiguration
.
targetOffsetMs
)
{
liveConfiguration
=
mediaItem
.
buildUpon
().
setLiveTargetOffsetMs
(
targetLiveOffsetMs
).
build
().
liveConfiguration
;
}
}
...
...
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaSourceTest.java
View file @
05c928f9
...
...
@@ -183,7 +183,7 @@ public class HlsMediaSourceTest {
Timeline
.
Window
window
=
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
());
// The target live offset is picked from target duration (3 * 4 = 12 seconds) and then expressed
// in relation to the live edge (12 + 1 seconds).
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
13000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
13000
);
assertThat
(
window
.
defaultPositionUs
).
isEqualTo
(
4000000
);
}
...
...
@@ -219,7 +219,7 @@ public class HlsMediaSourceTest {
Timeline
.
Window
window
=
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
());
// The target live offset is picked from hold back and then expressed in relation to the live
// edge (+1 seconds).
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
13000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
13000
);
assertThat
(
window
.
defaultPositionUs
).
isEqualTo
(
4000000
);
}
...
...
@@ -257,7 +257,7 @@ public class HlsMediaSourceTest {
Timeline
.
Window
window
=
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
());
// The target live offset is picked from hold back and then expressed in relation to the live
// edge (+1 seconds).
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
13000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
13000
);
assertThat
(
window
.
defaultPositionUs
).
isEqualTo
(
4000000
);
}
...
...
@@ -288,7 +288,7 @@ public class HlsMediaSourceTest {
Timeline
.
Window
window
=
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
());
// The target live offset is picked from part hold back and then expressed in relation to the
// live edge (+1 seconds).
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
4000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
4000
);
assertThat
(
window
.
defaultPositionUs
).
isEqualTo
(
0
);
}
...
...
@@ -318,7 +318,7 @@ public class HlsMediaSourceTest {
Timeline
.
Window
window
=
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
());
// The target live offset is picked from the media item and not adjusted.
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
1000
);
assertThat
(
window
.
liveConfiguration
).
isEqualTo
(
mediaItem
.
liveConfiguration
);
assertThat
(
window
.
defaultPositionUs
).
isEqualTo
(
0
);
}
...
...
@@ -351,7 +351,7 @@ public class HlsMediaSourceTest {
Timeline
.
Window
window
=
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
());
assertThat
(
mediaItem
.
liveConfiguration
.
targetOffsetMs
)
.
isGreaterThan
(
C
.
usToMs
(
window
.
durationUs
));
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
9000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
9000
);
}
@Test
...
...
@@ -385,7 +385,7 @@ public class HlsMediaSourceTest {
Timeline
.
Window
window
=
timeline
.
getWindow
(
0
,
new
Timeline
.
Window
());
// The target live offset is not adjusted to the live edge because the list does not have
// program date time.
assertThat
(
window
.
mediaItem
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
12000
);
assertThat
(
window
.
liveConfiguration
.
targetOffsetMs
).
isEqualTo
(
12000
);
assertThat
(
window
.
defaultPositionUs
).
isEqualTo
(
4000000
);
}
...
...
@@ -475,13 +475,13 @@ public class HlsMediaSourceTest {
runMainLooperUntil
(()
->
timelines
.
size
()
==
4
);
Timeline
.
Window
window
=
new
Timeline
.
Window
();
assertThat
(
timelines
.
get
(
0
).
getWindow
(
0
,
window
).
mediaItem
.
liveConfiguration
.
targetOffsetMs
)
assertThat
(
timelines
.
get
(
0
).
getWindow
(
0
,
window
).
liveConfiguration
.
targetOffsetMs
)
.
isEqualTo
(
12000
);
assertThat
(
timelines
.
get
(
1
).
getWindow
(
0
,
window
).
mediaItem
.
liveConfiguration
.
targetOffsetMs
)
assertThat
(
timelines
.
get
(
1
).
getWindow
(
0
,
window
).
liveConfiguration
.
targetOffsetMs
)
.
isEqualTo
(
12000
);
assertThat
(
timelines
.
get
(
2
).
getWindow
(
0
,
window
).
mediaItem
.
liveConfiguration
.
targetOffsetMs
)
assertThat
(
timelines
.
get
(
2
).
getWindow
(
0
,
window
).
liveConfiguration
.
targetOffsetMs
)
.
isEqualTo
(
8000
);
assertThat
(
timelines
.
get
(
3
).
getWindow
(
0
,
window
).
mediaItem
.
liveConfiguration
.
targetOffsetMs
)
assertThat
(
timelines
.
get
(
3
).
getWindow
(
0
,
window
).
liveConfiguration
.
targetOffsetMs
)
.
isEqualTo
(
8000
);
}
...
...
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
View file @
05c928f9
...
...
@@ -594,7 +594,7 @@ public final class SsMediaSource extends BaseMediaSource
/* windowDefaultStartPositionUs= */
0
,
/* isSeekable= */
true
,
/* isDynamic= */
manifest
.
isLive
,
/*
isLive
= */
manifest
.
isLive
,
/*
useLiveConfiguration
= */
manifest
.
isLive
,
manifest
,
mediaItem
);
}
else
if
(
manifest
.
isLive
)
{
...
...
@@ -617,7 +617,7 @@ public final class SsMediaSource extends BaseMediaSource
defaultStartPositionUs
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/*
isLive
= */
true
,
/*
useLiveConfiguration
= */
true
,
manifest
,
mediaItem
);
}
else
{
...
...
@@ -631,7 +631,7 @@ public final class SsMediaSource extends BaseMediaSource
/* windowDefaultStartPositionUs= */
0
,
/* isSeekable= */
true
,
/* isDynamic= */
false
,
/*
isLive
= */
false
,
/*
useLiveConfiguration
= */
false
,
manifest
,
mediaItem
);
}
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java
View file @
05c928f9
...
...
@@ -329,7 +329,7 @@ public final class FakeTimeline extends Timeline {
/* elapsedRealtimeEpochOffsetMs= */
windowDefinition
.
isLive
?
0
:
C
.
TIME_UNSET
,
windowDefinition
.
isSeekable
,
windowDefinition
.
isDynamic
,
windowDefinition
.
isLive
,
windowDefinition
.
isLive
?
windowDefinition
.
mediaItem
.
liveConfiguration
:
null
,
windowDefinition
.
defaultPositionUs
,
windowDefinition
.
durationUs
,
periodOffsets
[
windowIndex
],
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment