Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
NotesChapter
ExoPlayer
提交
9830c773
E
ExoPlayer
项目概览
NotesChapter
/
ExoPlayer
与 Fork 源项目一致
从无法访问的项目Fork
通知
6
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
ExoPlayer
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
9830c773
编写于
6月 01, 2020
作者:
O
Oliver Woodman
提交者:
GitHub
6月 01, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #7455 from google/dev-v2-r2.11.5-7193
Merge fix for #7193 into dev-v2-r2.11.5
上级
1062edf5
14575461
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
247 addition
and
67 deletion
+247
-67
library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
...d/exoplayer2/analytics/DefaultPlaybackSessionManager.java
+61
-45
library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackSessionManager.java
.../android/exoplayer2/analytics/PlaybackSessionManager.java
+8
-0
library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
...e/android/exoplayer2/analytics/PlaybackStatsListener.java
+25
-21
library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
...oplayer2/analytics/DefaultPlaybackSessionManagerTest.java
+40
-0
library/core/src/test/java/com/google/android/exoplayer2/analytics/PlaybackStatsListenerTest.java
...droid/exoplayer2/analytics/PlaybackStatsListenerTest.java
+113
-1
未找到文件。
library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
浏览文件 @
9830c773
...
...
@@ -29,7 +29,6 @@ import java.util.HashMap;
import
java.util.Iterator
;
import
java.util.Random
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.RequiresNonNull
;
/**
* Default {@link PlaybackSessionManager} which instantiates a new session for each window in the
...
...
@@ -48,8 +47,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
private
@MonotonicNonNull
Listener
listener
;
private
Timeline
currentTimeline
;
@Nullable
private
MediaPeriodId
currentMediaPeriodId
;
@Nullable
private
String
activeSessionId
;
@Nullable
private
String
currentSessionId
;
/** Creates session manager. */
public
DefaultPlaybackSessionManager
()
{
...
...
@@ -83,22 +81,34 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
@Override
public
synchronized
void
updateSessions
(
EventTime
eventTime
)
{
boolean
isObviouslyFinished
=
eventTime
.
mediaPeriodId
!=
null
&&
currentMediaPeriodId
!=
null
&&
eventTime
.
mediaPeriodId
.
windowSequenceNumber
<
currentMediaPeriodId
.
windowSequenceNumber
;
if
(!
isObviouslyFinished
)
{
SessionDescriptor
descriptor
=
getOrAddSession
(
eventTime
.
windowIndex
,
eventTime
.
mediaPeriodId
);
if
(!
descriptor
.
isCreated
)
{
descriptor
.
isCreated
=
true
;
Assertions
.
checkNotNull
(
listener
).
onSessionCreated
(
eventTime
,
descriptor
.
sessionId
);
if
(
activeSessionId
==
null
)
{
updateActiveSession
(
eventTime
,
descriptor
);
}
Assertions
.
checkNotNull
(
listener
);
@Nullable
SessionDescriptor
currentSession
=
sessions
.
get
(
currentSessionId
);
if
(
eventTime
.
mediaPeriodId
!=
null
&&
currentSession
!=
null
)
{
// If we receive an event associated with a media period, then it needs to be either part of
// the current window if it's the first created media period, or a window that will be played
// in the future. Otherwise, we know that it belongs to a session that was already finished
// and we can ignore the event.
boolean
isAlreadyFinished
=
currentSession
.
windowSequenceNumber
==
C
.
INDEX_UNSET
?
currentSession
.
windowIndex
!=
eventTime
.
windowIndex
:
eventTime
.
mediaPeriodId
.
windowSequenceNumber
<
currentSession
.
windowSequenceNumber
;
if
(
isAlreadyFinished
)
{
return
;
}
}
SessionDescriptor
eventSession
=
getOrAddSession
(
eventTime
.
windowIndex
,
eventTime
.
mediaPeriodId
);
if
(
currentSessionId
==
null
)
{
currentSessionId
=
eventSession
.
sessionId
;
}
if
(!
eventSession
.
isCreated
)
{
eventSession
.
isCreated
=
true
;
listener
.
onSessionCreated
(
eventTime
,
eventSession
.
sessionId
);
}
if
(
eventSession
.
sessionId
.
equals
(
currentSessionId
)
&&
!
eventSession
.
isActive
)
{
eventSession
.
isActive
=
true
;
listener
.
onSessionActive
(
eventTime
,
eventSession
.
sessionId
);
}
}
@Override
...
...
@@ -112,8 +122,8 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
if
(!
session
.
tryResolvingToNewTimeline
(
previousTimeline
,
currentTimeline
))
{
iterator
.
remove
();
if
(
session
.
isCreated
)
{
if
(
session
.
sessionId
.
equals
(
active
SessionId
))
{
active
SessionId
=
null
;
if
(
session
.
sessionId
.
equals
(
current
SessionId
))
{
current
SessionId
=
null
;
}
listener
.
onSessionFinished
(
eventTime
,
session
.
sessionId
,
/* automaticTransitionToNextPlayback= */
false
);
...
...
@@ -136,36 +146,55 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
if
(
session
.
isFinishedAtEventTime
(
eventTime
))
{
iterator
.
remove
();
if
(
session
.
isCreated
)
{
boolean
isRemovingActiveSession
=
session
.
sessionId
.
equals
(
activeSessionId
);
boolean
isAutomaticTransition
=
hasAutomaticTransition
&&
isRemovingActiveSession
;
if
(
isRemovingActiveSession
)
{
activeSessionId
=
null
;
boolean
isRemovingCurrentSession
=
session
.
sessionId
.
equals
(
currentSessionId
);
boolean
isAutomaticTransition
=
hasAutomaticTransition
&&
isRemovingCurrentSession
&&
session
.
isActive
;
if
(
isRemovingCurrentSession
)
{
currentSessionId
=
null
;
}
listener
.
onSessionFinished
(
eventTime
,
session
.
sessionId
,
isAutomaticTransition
);
}
}
}
SessionDescriptor
activeSessionDescriptor
=
@Nullable
SessionDescriptor
previousSessionDescriptor
=
sessions
.
get
(
currentSessionId
);
SessionDescriptor
currentSessionDescriptor
=
getOrAddSession
(
eventTime
.
windowIndex
,
eventTime
.
mediaPeriodId
);
currentSessionId
=
currentSessionDescriptor
.
sessionId
;
if
(
eventTime
.
mediaPeriodId
!=
null
&&
eventTime
.
mediaPeriodId
.
isAd
()
&&
(
currentMediaPeriodId
==
null
||
currentMediaPeriodId
.
windowSequenceNumber
&&
(
previousSessionDescriptor
==
null
||
previousSessionDescriptor
.
windowSequenceNumber
!=
eventTime
.
mediaPeriodId
.
windowSequenceNumber
||
currentMediaPeriodId
.
adGroupIndex
!=
eventTime
.
mediaPeriodId
.
adGroupIndex
||
currentMediaPeriodId
.
adIndexInAdGroup
!=
eventTime
.
mediaPeriodId
.
adIndexInAdGroup
))
{
||
previousSessionDescriptor
.
adMediaPeriodId
==
null
||
previousSessionDescriptor
.
adMediaPeriodId
.
adGroupIndex
!=
eventTime
.
mediaPeriodId
.
adGroupIndex
||
previousSessionDescriptor
.
adMediaPeriodId
.
adIndexInAdGroup
!=
eventTime
.
mediaPeriodId
.
adIndexInAdGroup
))
{
// New ad playback started. Find corresponding content session and notify ad playback started.
MediaPeriodId
contentMediaPeriodId
=
new
MediaPeriodId
(
eventTime
.
mediaPeriodId
.
periodUid
,
eventTime
.
mediaPeriodId
.
windowSequenceNumber
);
SessionDescriptor
contentSession
=
getOrAddSession
(
eventTime
.
windowIndex
,
contentMediaPeriodId
);
if
(
contentSession
.
isCreated
&&
active
SessionDescriptor
.
isCreated
)
{
if
(
contentSession
.
isCreated
&&
current
SessionDescriptor
.
isCreated
)
{
listener
.
onAdPlaybackStarted
(
eventTime
,
contentSession
.
sessionId
,
activeSessionDescriptor
.
sessionId
);
eventTime
,
contentSession
.
sessionId
,
currentSessionDescriptor
.
sessionId
);
}
}
}
@Override
public
void
finishAllSessions
(
EventTime
eventTime
)
{
currentSessionId
=
null
;
Iterator
<
SessionDescriptor
>
iterator
=
sessions
.
values
().
iterator
();
while
(
iterator
.
hasNext
())
{
SessionDescriptor
session
=
iterator
.
next
();
iterator
.
remove
();
if
(
session
.
isCreated
&&
listener
!=
null
)
{
listener
.
onSessionFinished
(
eventTime
,
session
.
sessionId
,
/* automaticTransitionToNextPlayback= */
false
);
}
}
updateActiveSession
(
eventTime
,
activeSessionDescriptor
);
}
private
SessionDescriptor
getOrAddSession
(
...
...
@@ -199,18 +228,6 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
return
bestMatch
;
}
@RequiresNonNull
(
"listener"
)
private
void
updateActiveSession
(
EventTime
eventTime
,
SessionDescriptor
sessionDescriptor
)
{
currentMediaPeriodId
=
eventTime
.
mediaPeriodId
;
if
(
sessionDescriptor
.
isCreated
)
{
activeSessionId
=
sessionDescriptor
.
sessionId
;
if
(!
sessionDescriptor
.
isActive
)
{
sessionDescriptor
.
isActive
=
true
;
listener
.
onSessionActive
(
eventTime
,
sessionDescriptor
.
sessionId
);
}
}
}
private
static
String
generateSessionId
()
{
byte
[]
randomBytes
=
new
byte
[
SESSION_ID_LENGTH
];
RANDOM
.
nextBytes
(
randomBytes
);
...
...
@@ -284,8 +301,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
int
eventWindowIndex
,
@Nullable
MediaPeriodId
eventMediaPeriodId
)
{
if
(
windowSequenceNumber
==
C
.
INDEX_UNSET
&&
eventWindowIndex
==
windowIndex
&&
eventMediaPeriodId
!=
null
&&
!
eventMediaPeriodId
.
isAd
())
{
&&
eventMediaPeriodId
!=
null
)
{
// Set window sequence number for this session as soon as we have one.
windowSequenceNumber
=
eventMediaPeriodId
.
windowSequenceNumber
;
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackSessionManager.java
浏览文件 @
9830c773
...
...
@@ -117,4 +117,12 @@ public interface PlaybackSessionManager {
* @param reason The {@link DiscontinuityReason}.
*/
void
handlePositionDiscontinuity
(
EventTime
eventTime
,
@DiscontinuityReason
int
reason
);
/**
* Finishes all existing sessions and calls their respective {@link
* Listener#onSessionFinished(EventTime, String, boolean)} callback.
*
* @param eventTime The event time at which sessions are finished.
*/
void
finishAllSessions
(
EventTime
eventTime
);
}
library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java
浏览文件 @
9830c773
...
...
@@ -148,7 +148,6 @@ public final class PlaybackStatsListener
// TODO: Add AnalyticsListener.onAttachedToPlayer and onDetachedFromPlayer to auto-release with
// an actual EventTime. Should also simplify other cases where the listener needs to be released
// separately from the player.
HashMap
<
String
,
PlaybackStatsTracker
>
trackerCopy
=
new
HashMap
<>(
playbackStatsTrackers
);
EventTime
dummyEventTime
=
new
EventTime
(
SystemClock
.
elapsedRealtime
(),
...
...
@@ -158,9 +157,7 @@ public final class PlaybackStatsListener
/* eventPlaybackPositionMs= */
0
,
/* currentPlaybackPositionMs= */
0
,
/* totalBufferedDurationMs= */
0
);
for
(
String
session
:
trackerCopy
.
keySet
())
{
onSessionFinished
(
dummyEventTime
,
session
,
/* automaticTransition= */
false
);
}
sessionManager
.
finishAllSessions
(
dummyEventTime
);
}
// PlaybackSessionManager.Listener implementation.
...
...
@@ -243,7 +240,7 @@ public final class PlaybackStatsListener
EventTime
eventTime
,
boolean
playWhenReady
,
@Player
.
State
int
playbackState
)
{
this
.
playWhenReady
=
playWhenReady
;
this
.
playbackState
=
playbackState
;
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
boolean
belongsToPlayback
=
sessionManager
.
belongsToSession
(
eventTime
,
session
);
playbackStatsTrackers
...
...
@@ -256,7 +253,7 @@ public final class PlaybackStatsListener
public
void
onPlaybackSuppressionReasonChanged
(
EventTime
eventTime
,
int
playbackSuppressionReason
)
{
isSuppressed
=
playbackSuppressionReason
!=
Player
.
PLAYBACK_SUPPRESSION_REASON_NONE
;
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
boolean
belongsToPlayback
=
sessionManager
.
belongsToSession
(
eventTime
,
session
);
playbackStatsTrackers
...
...
@@ -268,7 +265,7 @@ public final class PlaybackStatsListener
@Override
public
void
onTimelineChanged
(
EventTime
eventTime
,
int
reason
)
{
sessionManager
.
handleTimelineUpdate
(
eventTime
);
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onPositionDiscontinuity
(
eventTime
);
...
...
@@ -279,7 +276,7 @@ public final class PlaybackStatsListener
@Override
public
void
onPositionDiscontinuity
(
EventTime
eventTime
,
int
reason
)
{
sessionManager
.
handlePositionDiscontinuity
(
eventTime
,
reason
);
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onPositionDiscontinuity
(
eventTime
);
...
...
@@ -289,7 +286,7 @@ public final class PlaybackStatsListener
@Override
public
void
onSeekStarted
(
EventTime
eventTime
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onSeekStarted
(
eventTime
);
...
...
@@ -299,7 +296,7 @@ public final class PlaybackStatsListener
@Override
public
void
onSeekProcessed
(
EventTime
eventTime
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onSeekProcessed
(
eventTime
);
...
...
@@ -309,7 +306,7 @@ public final class PlaybackStatsListener
@Override
public
void
onPlayerError
(
EventTime
eventTime
,
ExoPlaybackException
error
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onFatalError
(
eventTime
,
error
);
...
...
@@ -321,7 +318,7 @@ public final class PlaybackStatsListener
public
void
onPlaybackParametersChanged
(
EventTime
eventTime
,
PlaybackParameters
playbackParameters
)
{
playbackSpeed
=
playbackParameters
.
speed
;
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
PlaybackStatsTracker
tracker
:
playbackStatsTrackers
.
values
())
{
tracker
.
onPlaybackSpeedChanged
(
eventTime
,
playbackSpeed
);
}
...
...
@@ -330,7 +327,7 @@ public final class PlaybackStatsListener
@Override
public
void
onTracksChanged
(
EventTime
eventTime
,
TrackGroupArray
trackGroups
,
TrackSelectionArray
trackSelections
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onTracksChanged
(
eventTime
,
trackSelections
);
...
...
@@ -341,7 +338,7 @@ public final class PlaybackStatsListener
@Override
public
void
onLoadStarted
(
EventTime
eventTime
,
LoadEventInfo
loadEventInfo
,
MediaLoadData
mediaLoadData
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onLoadStarted
(
eventTime
);
...
...
@@ -351,7 +348,7 @@ public final class PlaybackStatsListener
@Override
public
void
onDownstreamFormatChanged
(
EventTime
eventTime
,
MediaLoadData
mediaLoadData
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onDownstreamFormatChanged
(
eventTime
,
mediaLoadData
);
...
...
@@ -366,7 +363,7 @@ public final class PlaybackStatsListener
int
height
,
int
unappliedRotationDegrees
,
float
pixelWidthHeightRatio
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onVideoSizeChanged
(
eventTime
,
width
,
height
);
...
...
@@ -377,7 +374,7 @@ public final class PlaybackStatsListener
@Override
public
void
onBandwidthEstimate
(
EventTime
eventTime
,
int
totalLoadTimeMs
,
long
totalBytesLoaded
,
long
bitrateEstimate
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onBandwidthData
(
totalLoadTimeMs
,
totalBytesLoaded
);
...
...
@@ -388,7 +385,7 @@ public final class PlaybackStatsListener
@Override
public
void
onAudioUnderrun
(
EventTime
eventTime
,
int
bufferSize
,
long
bufferSizeMs
,
long
elapsedSinceLastFeedMs
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onAudioUnderrun
();
...
...
@@ -398,7 +395,7 @@ public final class PlaybackStatsListener
@Override
public
void
onDroppedVideoFrames
(
EventTime
eventTime
,
int
droppedFrames
,
long
elapsedMs
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onDroppedVideoFrames
(
droppedFrames
);
...
...
@@ -413,7 +410,7 @@ public final class PlaybackStatsListener
MediaLoadData
mediaLoadData
,
IOException
error
,
boolean
wasCanceled
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onNonFatalError
(
eventTime
,
error
);
...
...
@@ -423,7 +420,7 @@ public final class PlaybackStatsListener
@Override
public
void
onDrmSessionManagerError
(
EventTime
eventTime
,
Exception
error
)
{
sessionManager
.
updateSessions
(
eventTime
);
maybeAddSession
(
eventTime
);
for
(
String
session
:
playbackStatsTrackers
.
keySet
())
{
if
(
sessionManager
.
belongsToSession
(
eventTime
,
session
))
{
playbackStatsTrackers
.
get
(
session
).
onNonFatalError
(
eventTime
,
error
);
...
...
@@ -431,6 +428,13 @@ public final class PlaybackStatsListener
}
}
private
void
maybeAddSession
(
EventTime
eventTime
)
{
boolean
isCompletelyIdle
=
eventTime
.
timeline
.
isEmpty
()
&&
playbackState
==
Player
.
STATE_IDLE
;
if
(!
isCompletelyIdle
)
{
sessionManager
.
updateSessions
(
eventTime
);
}
}
/** Tracker for playback stats of a single playback. */
private
static
final
class
PlaybackStatsTracker
{
...
...
library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
浏览文件 @
9830c773
...
...
@@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import
static
org
.
mockito
.
ArgumentMatchers
.
anyString
;
import
static
org
.
mockito
.
ArgumentMatchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
verifyNoMoreInteractions
;
...
...
@@ -501,6 +502,7 @@ public final class DefaultPlaybackSessionManagerTest {
createEventTime
(
timeline
,
/* windowIndex= */
0
,
/* mediaPeriodId= */
null
);
sessionManager
.
handleTimelineUpdate
(
newTimelineEventTime
);
sessionManager
.
updateSessions
(
newTimelineEventTime
);
ArgumentCaptor
<
String
>
sessionId1
=
ArgumentCaptor
.
forClass
(
String
.
class
);
ArgumentCaptor
<
String
>
sessionId2
=
ArgumentCaptor
.
forClass
(
String
.
class
);
...
...
@@ -657,6 +659,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
handlePositionDiscontinuity
(
eventTime2
,
Player
.
DISCONTINUITY_REASON_PERIOD_TRANSITION
);
sessionManager
.
updateSessions
(
eventTime2
);
verify
(
mockListener
).
onSessionCreated
(
eq
(
eventTime1
),
anyString
());
verify
(
mockListener
).
onSessionActive
(
eq
(
eventTime1
),
anyString
());
...
...
@@ -688,6 +691,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
handlePositionDiscontinuity
(
eventTime2
,
Player
.
DISCONTINUITY_REASON_PERIOD_TRANSITION
);
sessionManager
.
updateSessions
(
eventTime2
);
verify
(
mockListener
).
onSessionCreated
(
eventTime1
,
sessionId1
);
verify
(
mockListener
).
onSessionActive
(
eventTime1
,
sessionId1
);
...
...
@@ -722,6 +726,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
getSessionForMediaPeriodId
(
timeline
,
eventTime2
.
mediaPeriodId
);
sessionManager
.
handlePositionDiscontinuity
(
eventTime2
,
Player
.
DISCONTINUITY_REASON_SEEK
);
sessionManager
.
updateSessions
(
eventTime2
);
verify
(
mockListener
).
onSessionCreated
(
eventTime1
,
sessionId1
);
verify
(
mockListener
).
onSessionActive
(
eventTime1
,
sessionId1
);
...
...
@@ -748,6 +753,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
updateSessions
(
eventTime2
);
sessionManager
.
handlePositionDiscontinuity
(
eventTime2
,
Player
.
DISCONTINUITY_REASON_SEEK
);
sessionManager
.
updateSessions
(
eventTime2
);
verify
(
mockListener
,
never
()).
onSessionFinished
(
any
(),
anyString
(),
anyBoolean
());
}
...
...
@@ -790,6 +796,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
getSessionForMediaPeriodId
(
timeline
,
eventTime2
.
mediaPeriodId
);
sessionManager
.
handlePositionDiscontinuity
(
eventTime3
,
Player
.
DISCONTINUITY_REASON_SEEK
);
sessionManager
.
updateSessions
(
eventTime3
);
verify
(
mockListener
).
onSessionCreated
(
eventTime1
,
sessionId1
);
verify
(
mockListener
).
onSessionActive
(
eventTime1
,
sessionId1
);
...
...
@@ -851,6 +858,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
handlePositionDiscontinuity
(
contentEventTime
,
Player
.
DISCONTINUITY_REASON_AD_INSERTION
);
sessionManager
.
updateSessions
(
contentEventTime
);
verify
(
mockListener
).
onSessionCreated
(
adEventTime1
,
adSessionId1
);
verify
(
mockListener
).
onSessionActive
(
adEventTime1
,
adSessionId1
);
...
...
@@ -858,6 +866,8 @@ public final class DefaultPlaybackSessionManagerTest {
verify
(
mockListener
)
.
onSessionFinished
(
contentEventTime
,
adSessionId1
,
/* automaticTransitionToNextPlayback= */
true
);
verify
(
mockListener
).
onSessionCreated
(
eq
(
contentEventTime
),
anyString
());
verify
(
mockListener
).
onSessionActive
(
eq
(
contentEventTime
),
anyString
());
verifyNoMoreInteractions
(
mockListener
);
}
...
...
@@ -908,6 +918,7 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
handlePositionDiscontinuity
(
adEventTime1
,
Player
.
DISCONTINUITY_REASON_AD_INSERTION
);
sessionManager
.
updateSessions
(
adEventTime1
);
verify
(
mockListener
,
never
()).
onSessionFinished
(
any
(),
anyString
(),
anyBoolean
());
}
...
...
@@ -964,7 +975,9 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
handlePositionDiscontinuity
(
adEventTime1
,
Player
.
DISCONTINUITY_REASON_AD_INSERTION
);
sessionManager
.
updateSessions
(
adEventTime1
);
sessionManager
.
handlePositionDiscontinuity
(
adEventTime2
,
Player
.
DISCONTINUITY_REASON_SEEK
);
sessionManager
.
updateSessions
(
adEventTime2
);
verify
(
mockListener
).
onSessionCreated
(
eq
(
contentEventTime
),
anyString
());
verify
(
mockListener
).
onSessionActive
(
eq
(
contentEventTime
),
anyString
());
...
...
@@ -1034,8 +1047,10 @@ public final class DefaultPlaybackSessionManagerTest {
sessionManager
.
updateSessions
(
adEventTime1
);
sessionManager
.
handlePositionDiscontinuity
(
adEventTime1
,
Player
.
DISCONTINUITY_REASON_AD_INSERTION
);
sessionManager
.
updateSessions
(
adEventTime1
);
sessionManager
.
handlePositionDiscontinuity
(
contentEventTime2
,
Player
.
DISCONTINUITY_REASON_AD_INSERTION
);
sessionManager
.
updateSessions
(
contentEventTime2
);
String
adSessionId2
=
sessionManager
.
getSessionForMediaPeriodId
(
adTimeline
,
adEventTime2
.
mediaPeriodId
);
...
...
@@ -1044,6 +1059,31 @@ public final class DefaultPlaybackSessionManagerTest {
verify
(
mockListener
,
never
()).
onSessionActive
(
any
(),
eq
(
adSessionId2
));
}
@Test
public
void
finishAllSessions_callsOnSessionFinishedForAllCreatedSessions
()
{
Timeline
timeline
=
new
FakeTimeline
(
/* windowCount= */
4
);
EventTime
eventTimeWindow0
=
createEventTime
(
timeline
,
/* windowIndex= */
0
,
/* mediaPeriodId= */
null
);
EventTime
eventTimeWindow2
=
createEventTime
(
timeline
,
/* windowIndex= */
2
,
/* mediaPeriodId= */
null
);
// Actually create sessions for window 0 and 2.
sessionManager
.
updateSessions
(
eventTimeWindow0
);
sessionManager
.
updateSessions
(
eventTimeWindow2
);
// Query information about session for window 1, but don't create it.
sessionManager
.
getSessionForMediaPeriodId
(
timeline
,
new
MediaPeriodId
(
timeline
.
getPeriod
(
/* periodIndex= */
1
,
new
Timeline
.
Period
(),
/* setIds= */
true
).
uid
,
/* windowSequenceNumber= */
123
));
verify
(
mockListener
,
times
(
2
)).
onSessionCreated
(
any
(),
anyString
());
EventTime
finishEventTime
=
createEventTime
(
Timeline
.
EMPTY
,
/* windowIndex= */
0
,
/* mediaPeriodId= */
null
);
sessionManager
.
finishAllSessions
(
finishEventTime
);
verify
(
mockListener
,
times
(
2
)).
onSessionFinished
(
eq
(
finishEventTime
),
anyString
(),
eq
(
false
));
}
private
static
EventTime
createEventTime
(
Timeline
timeline
,
int
windowIndex
,
@Nullable
MediaPeriodId
mediaPeriodId
)
{
return
new
EventTime
(
...
...
library/core/src/test/java/com/google/android/exoplayer2/analytics/PlaybackStatsListenerTest.java
浏览文件 @
9830c773
...
...
@@ -16,11 +16,20 @@
package
com.google.android.exoplayer2.analytics
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
ArgumentMatchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
times
;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
android.os.SystemClock
;
import
androidx.annotation.Nullable
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.source.MediaSource
;
import
com.google.android.exoplayer2.testutil.FakeTimeline
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
...
...
@@ -28,7 +37,7 @@ import org.junit.runner.RunWith;
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
PlaybackStatsListenerTest
{
private
static
final
AnalyticsListener
.
EventTime
TEST
_EVENT_TIME
=
private
static
final
AnalyticsListener
.
EventTime
EMPTY_TIMELINE
_EVENT_TIME
=
new
AnalyticsListener
.
EventTime
(
/* realtimeMs= */
500
,
Timeline
.
EMPTY
,
...
...
@@ -37,6 +46,41 @@ public final class PlaybackStatsListenerTest {
/* eventPlaybackPositionMs= */
0
,
/* currentPlaybackPositionMs= */
0
,
/* totalBufferedDurationMs= */
0
);
private
static
final
Timeline
TEST_TIMELINE
=
new
FakeTimeline
(
/* windowCount= */
1
);
private
static
final
AnalyticsListener
.
EventTime
TEST_EVENT_TIME
=
new
AnalyticsListener
.
EventTime
(
/* realtimeMs= */
500
,
TEST_TIMELINE
,
/* windowIndex= */
0
,
new
MediaSource
.
MediaPeriodId
(
TEST_TIMELINE
.
getPeriod
(
/* periodIndex= */
0
,
new
Timeline
.
Period
(),
/* setIds= */
true
)
.
uid
,
/* windowSequenceNumber= */
42
),
/* eventPlaybackPositionMs= */
123
,
/* currentPlaybackPositionMs= */
123
,
/* totalBufferedDurationMs= */
456
);
@Test
public
void
stateChangeEvent_toNonIdle_createsInitialPlaybackStats
()
{
PlaybackStatsListener
playbackStatsListener
=
new
PlaybackStatsListener
(
/* keepHistory= */
true
,
/* callback= */
null
);
playbackStatsListener
.
onPlayerStateChanged
(
EMPTY_TIMELINE_EVENT_TIME
,
/* playWhenReady= */
false
,
Player
.
STATE_BUFFERING
);
assertThat
(
playbackStatsListener
.
getPlaybackStats
()).
isNotNull
();
}
@Test
public
void
timelineChangeEvent_toNonEmpty_createsInitialPlaybackStats
()
{
PlaybackStatsListener
playbackStatsListener
=
new
PlaybackStatsListener
(
/* keepHistory= */
true
,
/* callback= */
null
);
playbackStatsListener
.
onTimelineChanged
(
TEST_EVENT_TIME
,
Player
.
TIMELINE_CHANGE_REASON_DYNAMIC
);
assertThat
(
playbackStatsListener
.
getPlaybackStats
()).
isNotNull
();
}
@Test
public
void
playback_withKeepHistory_updatesStats
()
{
...
...
@@ -71,4 +115,72 @@ public final class PlaybackStatsListenerTest {
assertThat
(
playbackStats
).
isNotNull
();
assertThat
(
playbackStats
.
endedCount
).
isEqualTo
(
1
);
}
@Test
public
void
finishedSession_callsCallback
()
{
PlaybackStatsListener
.
Callback
callback
=
mock
(
PlaybackStatsListener
.
Callback
.
class
);
PlaybackStatsListener
playbackStatsListener
=
new
PlaybackStatsListener
(
/* keepHistory= */
true
,
callback
);
// Create session with an event and finish it by simulating removal from playlist.
playbackStatsListener
.
onPlayerStateChanged
(
TEST_EVENT_TIME
,
/* playWhenReady= */
false
,
Player
.
STATE_BUFFERING
);
verify
(
callback
,
never
()).
onPlaybackStatsReady
(
any
(),
any
());
playbackStatsListener
.
onTimelineChanged
(
EMPTY_TIMELINE_EVENT_TIME
,
Player
.
TIMELINE_CHANGE_REASON_DYNAMIC
);
verify
(
callback
).
onPlaybackStatsReady
(
eq
(
TEST_EVENT_TIME
),
any
());
}
@Test
public
void
finishAllSessions_callsAllPendingCallbacks
()
{
AnalyticsListener
.
EventTime
eventTimeWindow0
=
new
AnalyticsListener
.
EventTime
(
/* realtimeMs= */
0
,
Timeline
.
EMPTY
,
/* windowIndex= */
0
,
/* mediaPeriodId= */
null
,
/* eventPlaybackPositionMs= */
0
,
/* currentPlaybackPositionMs= */
0
,
/* totalBufferedDurationMs= */
0
);
AnalyticsListener
.
EventTime
eventTimeWindow1
=
new
AnalyticsListener
.
EventTime
(
/* realtimeMs= */
0
,
Timeline
.
EMPTY
,
/* windowIndex= */
1
,
/* mediaPeriodId= */
null
,
/* eventPlaybackPositionMs= */
0
,
/* currentPlaybackPositionMs= */
0
,
/* totalBufferedDurationMs= */
0
);
PlaybackStatsListener
.
Callback
callback
=
mock
(
PlaybackStatsListener
.
Callback
.
class
);
PlaybackStatsListener
playbackStatsListener
=
new
PlaybackStatsListener
(
/* keepHistory= */
true
,
callback
);
playbackStatsListener
.
onPlayerStateChanged
(
eventTimeWindow0
,
/* playWhenReady= */
false
,
Player
.
STATE_BUFFERING
);
playbackStatsListener
.
onPlayerStateChanged
(
eventTimeWindow1
,
/* playWhenReady= */
false
,
Player
.
STATE_BUFFERING
);
playbackStatsListener
.
finishAllSessions
();
verify
(
callback
,
times
(
2
)).
onPlaybackStatsReady
(
any
(),
any
());
verify
(
callback
).
onPlaybackStatsReady
(
eq
(
eventTimeWindow0
),
any
());
verify
(
callback
).
onPlaybackStatsReady
(
eq
(
eventTimeWindow1
),
any
());
}
@Test
public
void
finishAllSessions_doesNotCallCallbackAgainWhenSessionWouldBeAutomaticallyFinished
()
{
PlaybackStatsListener
.
Callback
callback
=
mock
(
PlaybackStatsListener
.
Callback
.
class
);
PlaybackStatsListener
playbackStatsListener
=
new
PlaybackStatsListener
(
/* keepHistory= */
true
,
callback
);
playbackStatsListener
.
onPlayerStateChanged
(
TEST_EVENT_TIME
,
/* playWhenReady= */
false
,
Player
.
STATE_BUFFERING
);
SystemClock
.
setCurrentTimeMillis
(
TEST_EVENT_TIME
.
realtimeMs
+
100
);
playbackStatsListener
.
finishAllSessions
();
// Simulate removing the playback item to ensure the session would finish if it hadn't already.
playbackStatsListener
.
onTimelineChanged
(
EMPTY_TIMELINE_EVENT_TIME
,
Player
.
TIMELINE_CHANGE_REASON_DYNAMIC
);
verify
(
callback
).
onPlaybackStatsReady
(
any
(),
any
());
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录