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
30cfc3c6
authored
Nov 02, 2021
by
tonihei
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge branch 'dev-v2' of
https://github.com/google/ExoPlayer
into dev-v2
parents
42ec358c
623be98d
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
717 additions
and
527 deletions
RELEASENOTES.md
demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java
demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakeExoPlayer.java
extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java
extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java
library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
library/core/src/main/java/com/google/android/exoplayer2/PlayerMessage.java
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java
library/core/src/main/java/com/google/android/exoplayer2/util/DebugTextViewHelper.java
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java
robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
RELEASENOTES.md
View file @
30cfc3c6
...
...
@@ -85,6 +85,10 @@
*
RTMP extension:
*
Upgrade to
`io.antmedia:rtmp_client`
, which does not rely on
`jcenter()`
(
[
#9591
](
https://github.com/google/ExoPlayer/issues/9591
)
).
*
MediaSession extension:
*
Rename
`MediaSessionConnector.QueueNavigator#onCurrentWindowIndexChanged`
to
`onCurrentMediaItemIndexChanged`
.
*
Remove deprecated symbols:
*
Remove
`Renderer.VIDEO_SCALING_MODE_*`
constants. Use identically named
constants in
`C`
instead.
...
...
demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java
View file @
30cfc3c6
...
...
@@ -261,7 +261,7 @@ import java.util.ArrayList;
int
playbackState
=
currentPlayer
.
getPlaybackState
();
maybeSetCurrentItemAndNotify
(
playbackState
!=
Player
.
STATE_IDLE
&&
playbackState
!=
Player
.
STATE_ENDED
?
currentPlayer
.
getCurrent
Window
Index
()
?
currentPlayer
.
getCurrent
MediaItem
Index
()
:
C
.
INDEX_UNSET
);
}
...
...
@@ -281,7 +281,7 @@ import java.util.ArrayList;
// Player state management.
long
playbackPositionMs
=
C
.
TIME_UNSET
;
int
window
Index
=
C
.
INDEX_UNSET
;
int
currentItem
Index
=
C
.
INDEX_UNSET
;
boolean
playWhenReady
=
false
;
Player
previousPlayer
=
this
.
currentPlayer
;
...
...
@@ -291,10 +291,10 @@ import java.util.ArrayList;
if
(
playbackState
!=
Player
.
STATE_ENDED
)
{
playbackPositionMs
=
previousPlayer
.
getCurrentPosition
();
playWhenReady
=
previousPlayer
.
getPlayWhenReady
();
windowIndex
=
previousPlayer
.
getCurrentWindow
Index
();
if
(
windowIndex
!=
currentItemIndex
)
{
currentItemIndex
=
previousPlayer
.
getCurrentMediaItem
Index
();
if
(
currentItemIndex
!=
this
.
currentItemIndex
)
{
playbackPositionMs
=
C
.
TIME_UNSET
;
windowIndex
=
currentItemIndex
;
currentItemIndex
=
this
.
currentItemIndex
;
}
}
previousPlayer
.
stop
();
...
...
@@ -304,7 +304,7 @@ import java.util.ArrayList;
this
.
currentPlayer
=
currentPlayer
;
// Media queue management.
currentPlayer
.
setMediaItems
(
mediaQueue
,
window
Index
,
playbackPositionMs
);
currentPlayer
.
setMediaItems
(
mediaQueue
,
currentItem
Index
,
playbackPositionMs
);
currentPlayer
.
setPlayWhenReady
(
playWhenReady
);
currentPlayer
.
prepare
();
}
...
...
demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
View file @
30cfc3c6
...
...
@@ -65,7 +65,7 @@ public class PlayerActivity extends AppCompatActivity
// Saved instance state keys.
private
static
final
String
KEY_TRACK_SELECTION_PARAMETERS
=
"track_selection_parameters"
;
private
static
final
String
KEY_
WINDOW
=
"window
"
;
private
static
final
String
KEY_
ITEM_INDEX
=
"item_index
"
;
private
static
final
String
KEY_POSITION
=
"position"
;
private
static
final
String
KEY_AUTO_PLAY
=
"auto_play"
;
...
...
@@ -83,7 +83,7 @@ public class PlayerActivity extends AppCompatActivity
private
DebugTextViewHelper
debugViewHelper
;
private
TracksInfo
lastSeenTracksInfo
;
private
boolean
startAutoPlay
;
private
int
start
Window
;
private
int
start
ItemIndex
;
private
long
startPosition
;
// For ad playback only.
...
...
@@ -114,7 +114,7 @@ public class PlayerActivity extends AppCompatActivity
DefaultTrackSelector
.
Parameters
.
CREATOR
.
fromBundle
(
savedInstanceState
.
getBundle
(
KEY_TRACK_SELECTION_PARAMETERS
));
startAutoPlay
=
savedInstanceState
.
getBoolean
(
KEY_AUTO_PLAY
);
start
Window
=
savedInstanceState
.
getInt
(
KEY_WINDOW
);
start
ItemIndex
=
savedInstanceState
.
getInt
(
KEY_ITEM_INDEX
);
startPosition
=
savedInstanceState
.
getLong
(
KEY_POSITION
);
}
else
{
trackSelectionParameters
=
...
...
@@ -206,7 +206,7 @@ public class PlayerActivity extends AppCompatActivity
updateStartPosition
();
outState
.
putBundle
(
KEY_TRACK_SELECTION_PARAMETERS
,
trackSelectionParameters
.
toBundle
());
outState
.
putBoolean
(
KEY_AUTO_PLAY
,
startAutoPlay
);
outState
.
putInt
(
KEY_
WINDOW
,
startWindow
);
outState
.
putInt
(
KEY_
ITEM_INDEX
,
startItemIndex
);
outState
.
putLong
(
KEY_POSITION
,
startPosition
);
}
...
...
@@ -282,9 +282,9 @@ public class PlayerActivity extends AppCompatActivity
debugViewHelper
=
new
DebugTextViewHelper
(
player
,
debugTextView
);
debugViewHelper
.
start
();
}
boolean
haveStartPosition
=
start
Window
!=
C
.
INDEX_UNSET
;
boolean
haveStartPosition
=
start
ItemIndex
!=
C
.
INDEX_UNSET
;
if
(
haveStartPosition
)
{
player
.
seekTo
(
start
Window
,
startPosition
);
player
.
seekTo
(
start
ItemIndex
,
startPosition
);
}
player
.
setMediaItems
(
mediaItems
,
/* resetPosition= */
!
haveStartPosition
);
player
.
prepare
();
...
...
@@ -382,14 +382,14 @@ public class PlayerActivity extends AppCompatActivity
private
void
updateStartPosition
()
{
if
(
player
!=
null
)
{
startAutoPlay
=
player
.
getPlayWhenReady
();
start
Window
=
player
.
getCurrentWindow
Index
();
start
ItemIndex
=
player
.
getCurrentMediaItem
Index
();
startPosition
=
Math
.
max
(
0
,
player
.
getContentPosition
());
}
}
protected
void
clearStartPosition
()
{
startAutoPlay
=
true
;
start
Window
=
C
.
INDEX_UNSET
;
start
ItemIndex
=
C
.
INDEX_UNSET
;
startPosition
=
C
.
TIME_UNSET
;
}
...
...
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
View file @
30cfc3c6
...
...
@@ -318,9 +318,9 @@ public final class CastPlayer extends BasePlayer {
@Override
public
void
setMediaItems
(
List
<
MediaItem
>
mediaItems
,
boolean
resetPosition
)
{
int
windowIndex
=
resetPosition
?
0
:
getCurrentWindow
Index
();
int
mediaItemIndex
=
resetPosition
?
0
:
getCurrentMediaItem
Index
();
long
startPositionMs
=
resetPosition
?
C
.
TIME_UNSET
:
getContentPosition
();
setMediaItems
(
mediaItems
,
window
Index
,
startPositionMs
);
setMediaItems
(
mediaItems
,
mediaItem
Index
,
startPositionMs
);
}
@Override
...
...
@@ -443,7 +443,7 @@ public final class CastPlayer extends BasePlayer {
// in RemoteMediaClient.
positionMs
=
positionMs
!=
C
.
TIME_UNSET
?
positionMs
:
0
;
if
(
mediaStatus
!=
null
)
{
if
(
getCurrent
Window
Index
()
!=
mediaItemIndex
)
{
if
(
getCurrent
MediaItem
Index
()
!=
mediaItemIndex
)
{
remoteMediaClient
.
queueJumpToItem
(
(
int
)
currentTimeline
.
getPeriod
(
mediaItemIndex
,
period
).
uid
,
positionMs
,
null
)
...
...
@@ -636,7 +636,7 @@ public final class CastPlayer extends BasePlayer {
@Override
public
int
getCurrentPeriodIndex
()
{
return
getCurrent
Window
Index
();
return
getCurrent
MediaItem
Index
();
}
@Override
...
...
@@ -1103,15 +1103,15 @@ public final class CastPlayer extends BasePlayer {
@Nullable
private
PendingResult
<
MediaChannelResult
>
setMediaItemsInternal
(
MediaQueueItem
[]
mediaQueueItems
,
int
start
Window
Index
,
int
startIndex
,
long
startPositionMs
,
@RepeatMode
int
repeatMode
)
{
if
(
remoteMediaClient
==
null
||
mediaQueueItems
.
length
==
0
)
{
return
null
;
}
startPositionMs
=
startPositionMs
==
C
.
TIME_UNSET
?
0
:
startPositionMs
;
if
(
start
Window
Index
==
C
.
INDEX_UNSET
)
{
start
WindowIndex
=
getCurrentWindow
Index
();
if
(
startIndex
==
C
.
INDEX_UNSET
)
{
start
Index
=
getCurrentMediaItem
Index
();
startPositionMs
=
getCurrentPosition
();
}
Timeline
currentTimeline
=
getCurrentTimeline
();
...
...
@@ -1120,7 +1120,7 @@ public final class CastPlayer extends BasePlayer {
}
return
remoteMediaClient
.
queueLoad
(
mediaQueueItems
,
min
(
start
Window
Index
,
mediaQueueItems
.
length
-
1
),
min
(
startIndex
,
mediaQueueItems
.
length
-
1
),
getCastRepeatMode
(
repeatMode
),
startPositionMs
,
/* customData= */
null
);
...
...
@@ -1180,7 +1180,7 @@ public final class CastPlayer extends BasePlayer {
}
return
new
PositionInfo
(
newWindowUid
,
getCurrent
Window
Index
(),
getCurrent
MediaItem
Index
(),
newMediaItem
,
newPeriodUid
,
getCurrentPeriodIndex
(),
...
...
extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakeExoPlayer.java
View file @
30cfc3c6
...
...
@@ -279,7 +279,7 @@ import com.google.android.exoplayer2.util.Util;
timeline
.
getPeriod
(
0
,
period
).
getAdDurationUs
(
adGroupIndex
,
adIndexInAdGroup
);
return
Util
.
usToMs
(
adDurationUs
);
}
else
{
return
timeline
.
getWindow
(
getCurrent
Window
Index
(),
window
).
getDurationMs
();
return
timeline
.
getWindow
(
getCurrent
MediaItem
Index
(),
window
).
getDurationMs
();
}
}
...
...
extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java
View file @
30cfc3c6
...
...
@@ -141,7 +141,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_IDLE
)
{
player
.
prepare
();
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
player
.
seekToDefaultPosition
(
player
.
getCurrent
Window
Index
());
player
.
seekToDefaultPosition
(
player
.
getCurrent
MediaItem
Index
());
}
if
(
player
.
isCommandAvailable
(
Player
.
COMMAND_PLAY_PAUSE
))
{
player
.
play
();
...
...
extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java
View file @
30cfc3c6
...
...
@@ -253,8 +253,8 @@ import java.util.List;
// checkIndex() throws IndexOutOfBoundsException which maps the RESULT_ERROR_BAD_VALUE
// but RESULT_ERROR_INVALID_STATE with IllegalStateException is expected here.
Assertions
.
checkState
(
0
<=
index
&&
index
<
timeline
.
getWindowCount
());
int
windowIndex
=
player
.
getCurrentWindow
Index
();
if
(
window
Index
==
index
||
!
player
.
isCommandAvailable
(
COMMAND_SEEK_TO_MEDIA_ITEM
))
{
int
currentIndex
=
player
.
getCurrentMediaItem
Index
();
if
(
current
Index
==
index
||
!
player
.
isCommandAvailable
(
COMMAND_SEEK_TO_MEDIA_ITEM
))
{
return
false
;
}
player
.
seekToDefaultPosition
(
index
);
...
...
@@ -301,7 +301,7 @@ import java.util.List;
}
public
int
getCurrentMediaItemIndex
()
{
return
media2Playlist
.
isEmpty
()
?
C
.
INDEX_UNSET
:
player
.
getCurrent
Window
Index
();
return
media2Playlist
.
isEmpty
()
?
C
.
INDEX_UNSET
:
player
.
getCurrent
MediaItem
Index
();
}
public
int
getPreviousMediaItemIndex
()
{
...
...
@@ -331,7 +331,7 @@ import java.util.List;
if
(!
player
.
isCommandAvailable
(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
))
{
return
false
;
}
player
.
seekTo
(
player
.
getCurrent
Window
Index
(),
/* positionMs= */
0
);
player
.
seekTo
(
player
.
getCurrent
MediaItem
Index
(),
/* positionMs= */
0
);
}
boolean
playWhenReady
=
player
.
getPlayWhenReady
();
int
suppressReason
=
player
.
getPlaybackSuppressionReason
();
...
...
@@ -358,7 +358,7 @@ import java.util.List;
if
(!
player
.
isCommandAvailable
(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
))
{
return
false
;
}
player
.
seekTo
(
player
.
getCurrent
Window
Index
(),
position
);
player
.
seekTo
(
player
.
getCurrent
MediaItem
Index
(),
position
);
return
true
;
}
...
...
@@ -493,7 +493,7 @@ import java.util.List;
public
boolean
isCurrentMediaItemSeekable
()
{
return
getCurrentMediaItem
()
!=
null
&&
!
player
.
isPlayingAd
()
&&
player
.
isCurrent
Window
Seekable
();
&&
player
.
isCurrent
MediaItem
Seekable
();
}
public
boolean
canSkipToPlaylistItem
()
{
...
...
@@ -502,11 +502,11 @@ import java.util.List;
}
public
boolean
canSkipToPreviousPlaylistItem
()
{
return
player
.
hasPrevious
Window
();
return
player
.
hasPrevious
MediaItem
();
}
public
boolean
canSkipToNextPlaylistItem
()
{
return
player
.
hasNext
Window
();
return
player
.
hasNext
MediaItem
();
}
public
boolean
hasError
()
{
...
...
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
View file @
30cfc3c6
...
...
@@ -263,12 +263,13 @@ public final class MediaSessionConnector {
* @param player The player connected to the media session.
*/
void
onTimelineChanged
(
Player
player
);
/**
* Called when the current
window
index changed.
* Called when the current
media item
index changed.
*
* @param player The player connected to the media session.
*/
void
onCurrentWindowIndexChanged
(
Player
player
);
default
void
onCurrentMediaItemIndexChanged
(
Player
player
)
{}
/**
* Gets the id of the currently active queue item, or {@link
* MediaSessionCompat.QueueItem#UNKNOWN_ID} if the active item is unknown.
...
...
@@ -969,8 +970,8 @@ public final class MediaSessionConnector {
return
player
!=
null
&&
mediaButtonEventHandler
!=
null
;
}
private
void
seekTo
(
Player
player
,
int
window
Index
,
long
positionMs
)
{
player
.
seekTo
(
window
Index
,
positionMs
);
private
void
seekTo
(
Player
player
,
int
mediaItem
Index
,
long
positionMs
)
{
player
.
seekTo
(
mediaItem
Index
,
positionMs
);
}
private
static
int
getMediaSessionPlaybackState
(
...
...
@@ -1023,7 +1024,7 @@ public final class MediaSessionConnector {
}
builder
.
putLong
(
MediaMetadataCompat
.
METADATA_KEY_DURATION
,
player
.
isCurrent
Window
Dynamic
()
||
player
.
getDuration
()
==
C
.
TIME_UNSET
player
.
isCurrent
MediaItem
Dynamic
()
||
player
.
getDuration
()
==
C
.
TIME_UNSET
?
-
1
:
player
.
getDuration
());
long
activeQueueItemId
=
mediaController
.
getPlaybackState
().
getActiveQueueItemId
();
...
...
@@ -1097,7 +1098,7 @@ public final class MediaSessionConnector {
private
class
ComponentListener
extends
MediaSessionCompat
.
Callback
implements
Player
.
Listener
{
private
int
current
Window
Index
;
private
int
current
MediaItem
Index
;
private
int
currentWindowCount
;
// Player.Listener implementation.
...
...
@@ -1107,9 +1108,9 @@ public final class MediaSessionConnector {
boolean
invalidatePlaybackState
=
false
;
boolean
invalidateMetadata
=
false
;
if
(
events
.
contains
(
Player
.
EVENT_POSITION_DISCONTINUITY
))
{
if
(
current
WindowIndex
!=
player
.
getCurrentWindow
Index
())
{
if
(
current
MediaItemIndex
!=
player
.
getCurrentMediaItem
Index
())
{
if
(
queueNavigator
!=
null
)
{
queueNavigator
.
onCurrent
Window
IndexChanged
(
player
);
queueNavigator
.
onCurrent
MediaItem
IndexChanged
(
player
);
}
invalidateMetadata
=
true
;
}
...
...
@@ -1118,11 +1119,11 @@ public final class MediaSessionConnector {
if
(
events
.
contains
(
Player
.
EVENT_TIMELINE_CHANGED
))
{
int
windowCount
=
player
.
getCurrentTimeline
().
getWindowCount
();
int
windowIndex
=
player
.
getCurrentWindow
Index
();
int
mediaItemIndex
=
player
.
getCurrentMediaItem
Index
();
if
(
queueNavigator
!=
null
)
{
queueNavigator
.
onTimelineChanged
(
player
);
invalidatePlaybackState
=
true
;
}
else
if
(
currentWindowCount
!=
windowCount
||
current
WindowIndex
!=
window
Index
)
{
}
else
if
(
currentWindowCount
!=
windowCount
||
current
MediaItemIndex
!=
mediaItem
Index
)
{
// active queue item and queue navigation actions may need to be updated
invalidatePlaybackState
=
true
;
}
...
...
@@ -1130,8 +1131,8 @@ public final class MediaSessionConnector {
invalidateMetadata
=
true
;
}
// Update current
Window
Index after comparisons above.
current
WindowIndex
=
player
.
getCurrentWindow
Index
();
// Update current
MediaItem
Index after comparisons above.
current
MediaItemIndex
=
player
.
getCurrentMediaItem
Index
();
if
(
events
.
containsAny
(
EVENT_PLAYBACK_STATE_CHANGED
,
...
...
@@ -1170,7 +1171,7 @@ public final class MediaSessionConnector {
player
.
prepare
();
}
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
seekTo
(
player
,
player
.
getCurrent
Window
Index
(),
C
.
TIME_UNSET
);
seekTo
(
player
,
player
.
getCurrent
MediaItem
Index
(),
C
.
TIME_UNSET
);
}
Assertions
.
checkNotNull
(
player
).
play
();
}
...
...
@@ -1186,7 +1187,7 @@ public final class MediaSessionConnector {
@Override
public
void
onSeekTo
(
long
positionMs
)
{
if
(
canDispatchPlaybackAction
(
PlaybackStateCompat
.
ACTION_SEEK_TO
))
{
seekTo
(
player
,
player
.
getCurrent
Window
Index
(),
positionMs
);
seekTo
(
player
,
player
.
getCurrent
MediaItem
Index
(),
positionMs
);
}
}
...
...
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java
View file @
30cfc3c6
...
...
@@ -98,7 +98,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
boolean
enableNext
=
false
;
Timeline
timeline
=
player
.
getCurrentTimeline
();
if
(!
timeline
.
isEmpty
()
&&
!
player
.
isPlayingAd
())
{
timeline
.
getWindow
(
player
.
getCurrent
Window
Index
(),
window
);
timeline
.
getWindow
(
player
.
getCurrent
MediaItem
Index
(),
window
);
enableSkipTo
=
timeline
.
getWindowCount
()
>
1
;
enablePrevious
=
player
.
isCommandAvailable
(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
)
...
...
@@ -128,12 +128,12 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
}
@Override
public
final
void
onCurrent
Window
IndexChanged
(
Player
player
)
{
public
final
void
onCurrent
MediaItem
IndexChanged
(
Player
player
)
{
if
(
activeQueueItemId
==
MediaSessionCompat
.
QueueItem
.
UNKNOWN_ID
||
player
.
getCurrentTimeline
().
getWindowCount
()
>
maxQueueSize
)
{
publishFloatingQueueWindow
(
player
);
}
else
if
(!
player
.
getCurrentTimeline
().
isEmpty
())
{
activeQueueItemId
=
player
.
getCurrent
Window
Index
();
activeQueueItemId
=
player
.
getCurrent
MediaItem
Index
();
}
}
...
...
@@ -185,40 +185,40 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
int
queueSize
=
min
(
maxQueueSize
,
timeline
.
getWindowCount
());
// Add the active queue item.
int
current
WindowIndex
=
player
.
getCurrentWindow
Index
();
int
current
MediaItemIndex
=
player
.
getCurrentMediaItem
Index
();
queue
.
add
(
new
MediaSessionCompat
.
QueueItem
(
getMediaDescription
(
player
,
current
WindowIndex
),
currentWindow
Index
));
getMediaDescription
(
player
,
current
MediaItemIndex
),
currentMediaItem
Index
));
// Fill queue alternating with next and/or previous queue items.
int
first
WindowIndex
=
currentWindow
Index
;
int
last
WindowIndex
=
currentWindow
Index
;
int
first
MediaItemIndex
=
currentMediaItem
Index
;
int
last
MediaItemIndex
=
currentMediaItem
Index
;
boolean
shuffleModeEnabled
=
player
.
getShuffleModeEnabled
();
while
((
first
WindowIndex
!=
C
.
INDEX_UNSET
||
lastWindow
Index
!=
C
.
INDEX_UNSET
)
while
((
first
MediaItemIndex
!=
C
.
INDEX_UNSET
||
lastMediaItem
Index
!=
C
.
INDEX_UNSET
)
&&
queue
.
size
()
<
queueSize
)
{
// Begin with next to have a longer tail than head if an even sized queue needs to be trimmed.
if
(
last
Window
Index
!=
C
.
INDEX_UNSET
)
{
last
Window
Index
=
if
(
last
MediaItem
Index
!=
C
.
INDEX_UNSET
)
{
last
MediaItem
Index
=
timeline
.
getNextWindowIndex
(
last
Window
Index
,
Player
.
REPEAT_MODE_OFF
,
shuffleModeEnabled
);
if
(
last
Window
Index
!=
C
.
INDEX_UNSET
)
{
last
MediaItem
Index
,
Player
.
REPEAT_MODE_OFF
,
shuffleModeEnabled
);
if
(
last
MediaItem
Index
!=
C
.
INDEX_UNSET
)
{
queue
.
add
(
new
MediaSessionCompat
.
QueueItem
(
getMediaDescription
(
player
,
last
WindowIndex
),
lastWindow
Index
));
getMediaDescription
(
player
,
last
MediaItemIndex
),
lastMediaItem
Index
));
}
}
if
(
first
Window
Index
!=
C
.
INDEX_UNSET
&&
queue
.
size
()
<
queueSize
)
{
first
Window
Index
=
if
(
first
MediaItem
Index
!=
C
.
INDEX_UNSET
&&
queue
.
size
()
<
queueSize
)
{
first
MediaItem
Index
=
timeline
.
getPreviousWindowIndex
(
first
Window
Index
,
Player
.
REPEAT_MODE_OFF
,
shuffleModeEnabled
);
if
(
first
Window
Index
!=
C
.
INDEX_UNSET
)
{
first
MediaItem
Index
,
Player
.
REPEAT_MODE_OFF
,
shuffleModeEnabled
);
if
(
first
MediaItem
Index
!=
C
.
INDEX_UNSET
)
{
queue
.
addFirst
(
new
MediaSessionCompat
.
QueueItem
(
getMediaDescription
(
player
,
first
WindowIndex
),
firstWindow
Index
));
getMediaDescription
(
player
,
first
MediaItemIndex
),
firstMediaItem
Index
));
}
}
}
mediaSession
.
setQueue
(
new
ArrayList
<>(
queue
));
activeQueueItemId
=
current
Window
Index
;
activeQueueItemId
=
current
MediaItem
Index
;
}
}
library/common/src/main/java/com/google/android/exoplayer2/BasePlayer.java
View file @
30cfc3c6
...
...
@@ -118,7 +118,7 @@ public abstract class BasePlayer implements Player {
@Override
public
final
void
seekToDefaultPosition
()
{
seekToDefaultPosition
(
getCurrent
Window
Index
());
seekToDefaultPosition
(
getCurrent
MediaItem
Index
());
}
@Override
...
...
@@ -128,7 +128,7 @@ public abstract class BasePlayer implements Player {
@Override
public
final
void
seekTo
(
long
positionMs
)
{
seekTo
(
getCurrent
Window
Index
(),
positionMs
);
seekTo
(
getCurrent
MediaItem
Index
(),
positionMs
);
}
@Override
...
...
@@ -184,13 +184,13 @@ public abstract class BasePlayer implements Player {
if
(
timeline
.
isEmpty
()
||
isPlayingAd
())
{
return
;
}
boolean
hasPrevious
Window
=
hasPreviousWindow
();
if
(
isCurrent
WindowLive
()
&&
!
isCurrentWindow
Seekable
())
{
if
(
hasPrevious
Window
)
{
seekToPrevious
Window
();
boolean
hasPrevious
MediaItem
=
hasPreviousMediaItem
();
if
(
isCurrent
MediaItemLive
()
&&
!
isCurrentMediaItem
Seekable
())
{
if
(
hasPrevious
MediaItem
)
{
seekToPrevious
MediaItem
();
}
}
else
if
(
hasPrevious
Window
&&
getCurrentPosition
()
<=
getMaxSeekToPreviousPosition
())
{
seekToPrevious
Window
();
}
else
if
(
hasPrevious
MediaItem
&&
getCurrentPosition
()
<=
getMaxSeekToPreviousPosition
())
{
seekToPrevious
MediaItem
();
}
else
{
seekTo
(
/* positionMs= */
0
);
}
...
...
@@ -239,9 +239,9 @@ public abstract class BasePlayer implements Player {
if
(
timeline
.
isEmpty
()
||
isPlayingAd
())
{
return
;
}
if
(
hasNext
Window
())
{
seekToNext
Window
();
}
else
if
(
isCurrent
WindowLive
()
&&
isCurrentWindow
Dynamic
())
{
if
(
hasNext
MediaItem
())
{
seekToNext
MediaItem
();
}
else
if
(
isCurrent
MediaItemLive
()
&&
isCurrentMediaItem
Dynamic
())
{
seekToDefaultPosition
();
}
}
...
...
@@ -293,7 +293,7 @@ public abstract class BasePlayer implements Player {
Timeline
timeline
=
getCurrentTimeline
();
return
timeline
.
isEmpty
()
?
null
:
timeline
.
getWindow
(
getCurrent
Window
Index
(),
window
).
mediaItem
;
:
timeline
.
getWindow
(
getCurrent
MediaItem
Index
(),
window
).
mediaItem
;
}
@Override
...
...
@@ -310,7 +310,9 @@ public abstract class BasePlayer implements Player {
@Nullable
public
final
Object
getCurrentManifest
()
{
Timeline
timeline
=
getCurrentTimeline
();
return
timeline
.
isEmpty
()
?
null
:
timeline
.
getWindow
(
getCurrentWindowIndex
(),
window
).
manifest
;
return
timeline
.
isEmpty
()
?
null
:
timeline
.
getWindow
(
getCurrentMediaItemIndex
(),
window
).
manifest
;
}
@Override
...
...
@@ -352,7 +354,8 @@ public abstract class BasePlayer implements Player {
if
(
timeline
.
isEmpty
())
{
return
C
.
TIME_UNSET
;
}
long
windowStartTimeMs
=
timeline
.
getWindow
(
getCurrentWindowIndex
(),
window
).
windowStartTimeMs
;
long
windowStartTimeMs
=
timeline
.
getWindow
(
getCurrentMediaItemIndex
(),
window
).
windowStartTimeMs
;
if
(
windowStartTimeMs
==
C
.
TIME_UNSET
)
{
return
C
.
TIME_UNSET
;
}
...
...
@@ -376,7 +379,7 @@ public abstract class BasePlayer implements Player {
Timeline
timeline
=
getCurrentTimeline
();
return
timeline
.
isEmpty
()
?
C
.
TIME_UNSET
:
timeline
.
getWindow
(
getCurrent
Window
Index
(),
window
).
getDurationMs
();
:
timeline
.
getWindow
(
getCurrent
MediaItem
Index
(),
window
).
getDurationMs
();
}
/**
...
...
@@ -389,22 +392,24 @@ public abstract class BasePlayer implements Player {
return
new
Commands
.
Builder
()
.
addAll
(
permanentAvailableCommands
)
.
addIf
(
COMMAND_SEEK_TO_DEFAULT_POSITION
,
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
,
isCurrent
Window
Seekable
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM
,
hasPrevious
Window
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
,
isCurrent
MediaItem
Seekable
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM
,
hasPrevious
MediaItem
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_TO_PREVIOUS
,
!
getCurrentTimeline
().
isEmpty
()
&&
(
hasPreviousWindow
()
||
!
isCurrentWindowLive
()
||
isCurrentWindowSeekable
())
&&
(
hasPreviousMediaItem
()
||
!
isCurrentMediaItemLive
()
||
isCurrentMediaItemSeekable
())
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM
,
hasNext
Window
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM
,
hasNext
MediaItem
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_TO_NEXT
,
!
getCurrentTimeline
().
isEmpty
()
&&
(
hasNext
Window
()
||
(
isCurrentWindowLive
()
&&
isCurrentWindow
Dynamic
()))
&&
(
hasNext
MediaItem
()
||
(
isCurrentMediaItemLive
()
&&
isCurrentMediaItem
Dynamic
()))
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_TO_MEDIA_ITEM
,
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_BACK
,
isCurrent
Window
Seekable
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_FORWARD
,
isCurrent
Window
Seekable
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_BACK
,
isCurrent
MediaItem
Seekable
()
&&
!
isPlayingAd
())
.
addIf
(
COMMAND_SEEK_FORWARD
,
isCurrent
MediaItem
Seekable
()
&&
!
isPlayingAd
())
.
build
();
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
View file @
30cfc3c6
...
...
@@ -1126,7 +1126,7 @@ public interface ExoPlayer extends Player {
* @param mediaSources The new {@link MediaSource MediaSources}.
* @param resetPosition Whether the playback position should be reset to the default position in
* the first {@link Timeline.Window}. If false, playback will start from the position defined
* by {@link #getCurrent
Window
Index()} and {@link #getCurrentPosition()}.
* by {@link #getCurrent
MediaItem
Index()} and {@link #getCurrentPosition()}.
*/
void
setMediaSources
(
List
<
MediaSource
>
mediaSources
,
boolean
resetPosition
);
...
...
@@ -1134,14 +1134,15 @@ public interface ExoPlayer extends Player {
* Clears the playlist and adds the specified {@link MediaSource MediaSources}.
*
* @param mediaSources The new {@link MediaSource MediaSources}.
* @param start
WindowIndex The window index to start playback from. If {@link C#INDEX_UNSET} is
* passed, the current position is not reset.
* @param start
MediaItemIndex The media item index to start playback from. If {@link
*
C#INDEX_UNSET} is
passed, the current position is not reset.
* @param startPositionMs The position in milliseconds to start playback from. If {@link
* C#TIME_UNSET} is passed, the default position of the given
window is used. In any case, if
*
{@code startWindowIndex} is set to {@link C#INDEX_UNSET}, this parameter is ignored and the
* position is not reset at all.
* C#TIME_UNSET} is passed, the default position of the given
media item is used. In any case,
*
if {@code startMediaItemIndex} is set to {@link C#INDEX_UNSET}, this parameter is ignored
*
and the
position is not reset at all.
*/
void
setMediaSources
(
List
<
MediaSource
>
mediaSources
,
int
startWindowIndex
,
long
startPositionMs
);
void
setMediaSources
(
List
<
MediaSource
>
mediaSources
,
int
startMediaItemIndex
,
long
startPositionMs
);
/**
* Clears the playlist, adds the specified {@link MediaSource} and resets the position to the
...
...
@@ -1164,7 +1165,7 @@ public interface ExoPlayer extends Player {
*
* @param mediaSource The new {@link MediaSource}.
* @param resetPosition Whether the playback position should be reset to the default position. If
* false, playback will start from the position defined by {@link #getCurrent
Window
Index()}
* false, playback will start from the position defined by {@link #getCurrent
MediaItem
Index()}
* and {@link #getCurrentPosition()}.
*/
void
setMediaSource
(
MediaSource
mediaSource
,
boolean
resetPosition
);
...
...
@@ -1331,9 +1332,9 @@ public interface ExoPlayer extends Player {
* will be delivered immediately without blocking on the playback thread. The default {@link
* PlayerMessage#getType()} is 0 and the default {@link PlayerMessage#getPayload()} is null. If a
* position is specified with {@link PlayerMessage#setPosition(long)}, the message will be
* delivered at this position in the current
window defined by {@link #getCurrentWindowIndex()}.
*
Alternatively, the message can be sent at a specific window using {@link
* PlayerMessage#setPosition(int, long)}.
* delivered at this position in the current
media item defined by {@link
*
#getCurrentMediaItemIndex()}. Alternatively, the message can be sent at a specific mediaItem
*
using {@link
PlayerMessage#setPosition(int, long)}.
*/
PlayerMessage
createMessage
(
PlayerMessage
.
Target
target
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
View file @
30cfc3c6
...
...
@@ -537,7 +537,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
playbackInfo
,
timeline
,
getPeriodPositionOrMaskWindowPosition
(
timeline
,
getCurrent
Window
Index
(),
getCurrentPosition
()));
timeline
,
getCurrent
MediaItem
Index
(),
getCurrentPosition
()));
pendingOperationAcks
++;
this
.
shuffleOrder
=
shuffleOrder
;
internalPlayer
.
setShuffleOrder
(
shuffleOrder
);
...
...
@@ -662,7 +662,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Player
.
State
int
newPlaybackState
=
getPlaybackState
()
==
Player
.
STATE_IDLE
?
Player
.
STATE_IDLE
:
Player
.
STATE_BUFFERING
;
int
oldMasking
WindowIndex
=
getCurrentWindow
Index
();
int
oldMasking
MediaItemIndex
=
getCurrentMediaItem
Index
();
PlaybackInfo
newPlaybackInfo
=
playbackInfo
.
copyWithPlaybackState
(
newPlaybackState
);
newPlaybackInfo
=
maskTimelineAndPosition
(
...
...
@@ -678,7 +678,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* positionDiscontinuity= */
true
,
/* positionDiscontinuityReason= */
DISCONTINUITY_REASON_SEEK
,
/* discontinuityWindowStartPositionUs= */
getCurrentPositionUsInternal
(
newPlaybackInfo
),
oldMasking
Window
Index
);
oldMasking
MediaItem
Index
);
}
@Override
...
...
@@ -839,7 +839,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
internalPlayer
,
target
,
playbackInfo
.
timeline
,
getCurrent
Window
Index
(),
getCurrent
MediaItem
Index
(),
clock
,
internalPlayer
.
getPlaybackLooper
());
}
...
...
@@ -910,7 +910,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
if
(
isPlayingAd
())
{
playbackInfo
.
timeline
.
getPeriodByUid
(
playbackInfo
.
periodId
.
periodUid
,
period
);
return
playbackInfo
.
requestedContentPositionUs
==
C
.
TIME_UNSET
?
playbackInfo
.
timeline
.
getWindow
(
getCurrentWindowIndex
(),
window
).
getDefaultPositionMs
()
?
playbackInfo
.
timeline
.
getWindow
(
getCurrentMediaItemIndex
(),
window
)
.
getDefaultPositionMs
()
:
period
.
getPositionInWindowMs
()
+
Util
.
usToMs
(
playbackInfo
.
requestedContentPositionUs
);
}
else
{
return
getCurrentPosition
();
...
...
@@ -924,7 +927,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
if
(
playbackInfo
.
loadingMediaPeriodId
.
windowSequenceNumber
!=
playbackInfo
.
periodId
.
windowSequenceNumber
)
{
return
playbackInfo
.
timeline
.
getWindow
(
getCurrent
Window
Index
(),
window
).
getDurationMs
();
return
playbackInfo
.
timeline
.
getWindow
(
getCurrent
MediaItem
Index
(),
window
).
getDurationMs
();
}
long
contentBufferedPositionUs
=
playbackInfo
.
bufferedPositionUs
;
if
(
playbackInfo
.
loadingMediaPeriodId
.
isAd
())
{
...
...
@@ -1218,7 +1221,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
boolean
positionDiscontinuity
,
@DiscontinuityReason
int
positionDiscontinuityReason
,
long
discontinuityWindowStartPositionUs
,
int
oldMasking
Window
Index
)
{
int
oldMasking
MediaItem
Index
)
{
// Assign playback info immediately such that all getters return the right values, but keep
// snapshot of previous and new state so that listener invocations are triggered correctly.
...
...
@@ -1267,7 +1270,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
if
(
positionDiscontinuity
)
{
PositionInfo
previousPositionInfo
=
getPreviousPositionInfo
(
positionDiscontinuityReason
,
previousPlaybackInfo
,
oldMasking
Window
Index
);
positionDiscontinuityReason
,
previousPlaybackInfo
,
oldMasking
MediaItem
Index
);
PositionInfo
positionInfo
=
getPositionInfo
(
discontinuityWindowStartPositionUs
);
listeners
.
queueEvent
(
Player
.
EVENT_POSITION_DISCONTINUITY
,
...
...
@@ -1378,19 +1381,19 @@ import java.util.concurrent.CopyOnWriteArraySet;
private
PositionInfo
getPreviousPositionInfo
(
@DiscontinuityReason
int
positionDiscontinuityReason
,
PlaybackInfo
oldPlaybackInfo
,
int
oldMasking
Window
Index
)
{
int
oldMasking
MediaItem
Index
)
{
@Nullable
Object
oldWindowUid
=
null
;
@Nullable
Object
oldPeriodUid
=
null
;
int
old
WindowIndex
=
oldMaskingWindow
Index
;
int
old
MediaItemIndex
=
oldMaskingMediaItem
Index
;
int
oldPeriodIndex
=
C
.
INDEX_UNSET
;
@Nullable
MediaItem
oldMediaItem
=
null
;
Timeline
.
Period
oldPeriod
=
new
Timeline
.
Period
();
if
(!
oldPlaybackInfo
.
timeline
.
isEmpty
())
{
oldPeriodUid
=
oldPlaybackInfo
.
periodId
.
periodUid
;
oldPlaybackInfo
.
timeline
.
getPeriodByUid
(
oldPeriodUid
,
oldPeriod
);
old
Window
Index
=
oldPeriod
.
windowIndex
;
old
MediaItem
Index
=
oldPeriod
.
windowIndex
;
oldPeriodIndex
=
oldPlaybackInfo
.
timeline
.
getIndexOfPeriod
(
oldPeriodUid
);
oldWindowUid
=
oldPlaybackInfo
.
timeline
.
getWindow
(
old
Window
Index
,
window
).
uid
;
oldWindowUid
=
oldPlaybackInfo
.
timeline
.
getWindow
(
old
MediaItem
Index
,
window
).
uid
;
oldMediaItem
=
window
.
mediaItem
;
}
long
oldPositionUs
;
...
...
@@ -1421,7 +1424,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
return
new
PositionInfo
(
oldWindowUid
,
old
Window
Index
,
old
MediaItem
Index
,
oldMediaItem
,
oldPeriodUid
,
oldPeriodIndex
,
...
...
@@ -1434,20 +1437,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
private
PositionInfo
getPositionInfo
(
long
discontinuityWindowStartPositionUs
)
{
@Nullable
Object
newWindowUid
=
null
;
@Nullable
Object
newPeriodUid
=
null
;
int
new
WindowIndex
=
getCurrentWindow
Index
();
int
new
MediaItemIndex
=
getCurrentMediaItem
Index
();
int
newPeriodIndex
=
C
.
INDEX_UNSET
;
@Nullable
MediaItem
newMediaItem
=
null
;
if
(!
playbackInfo
.
timeline
.
isEmpty
())
{
newPeriodUid
=
playbackInfo
.
periodId
.
periodUid
;
playbackInfo
.
timeline
.
getPeriodByUid
(
newPeriodUid
,
period
);
newPeriodIndex
=
playbackInfo
.
timeline
.
getIndexOfPeriod
(
newPeriodUid
);
newWindowUid
=
playbackInfo
.
timeline
.
getWindow
(
new
Window
Index
,
window
).
uid
;
newWindowUid
=
playbackInfo
.
timeline
.
getWindow
(
new
MediaItem
Index
,
window
).
uid
;
newMediaItem
=
window
.
mediaItem
;
}
long
positionMs
=
Util
.
usToMs
(
discontinuityWindowStartPositionUs
);
return
new
PositionInfo
(
newWindowUid
,
new
Window
Index
,
new
MediaItem
Index
,
newMediaItem
,
newPeriodUid
,
newPeriodIndex
,
...
...
@@ -1601,7 +1604,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private
PlaybackInfo
removeMediaItemsInternal
(
int
fromIndex
,
int
toIndex
)
{
Assertions
.
checkArgument
(
fromIndex
>=
0
&&
toIndex
>=
fromIndex
&&
toIndex
<=
mediaSourceHolderSnapshots
.
size
());
int
current
WindowIndex
=
getCurrentWindow
Index
();
int
current
Index
=
getCurrentMediaItem
Index
();
Timeline
oldTimeline
=
getCurrentTimeline
();
int
currentMediaSourceCount
=
mediaSourceHolderSnapshots
.
size
();
pendingOperationAcks
++;
...
...
@@ -1618,7 +1621,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
&&
newPlaybackInfo
.
playbackState
!=
STATE_ENDED
&&
fromIndex
<
toIndex
&&
toIndex
==
currentMediaSourceCount
&&
current
Window
Index
>=
newPlaybackInfo
.
timeline
.
getWindowCount
();
&&
currentIndex
>=
newPlaybackInfo
.
timeline
.
getWindowCount
();
if
(
transitionsToEnded
)
{
newPlaybackInfo
=
newPlaybackInfo
.
copyWithPlaybackState
(
STATE_ENDED
);
}
...
...
@@ -1753,11 +1756,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
isCleared
?
C
.
INDEX_UNSET
:
getCurrentWindowIndexInternal
(),
isCleared
?
C
.
TIME_UNSET
:
currentPositionMs
);
}
int
current
WindowIndex
=
getCurrentWindow
Index
();
int
current
MediaItemIndex
=
getCurrentMediaItem
Index
();
@Nullable
Pair
<
Object
,
Long
>
oldPeriodPosition
=
oldTimeline
.
getPeriodPosition
(
window
,
period
,
current
Window
Index
,
Util
.
msToUs
(
currentPositionMs
));
window
,
period
,
current
MediaItem
Index
,
Util
.
msToUs
(
currentPositionMs
));
Object
periodUid
=
castNonNull
(
oldPeriodPosition
).
first
;
if
(
newTimeline
.
getIndexOfPeriod
(
periodUid
)
!=
C
.
INDEX_UNSET
)
{
// The old period position is still available in the new timeline.
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
View file @
30cfc3c6
...
...
@@ -2718,7 +2718,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
newTimeline
,
new
SeekPosition
(
pendingMessageInfo
.
message
.
getTimeline
(),
pendingMessageInfo
.
message
.
get
Window
Index
(),
pendingMessageInfo
.
message
.
get
MediaItem
Index
(),
requestPositionUs
),
/* trySubsequentPeriods= */
false
,
repeatMode
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/PlayerMessage.java
View file @
30cfc3c6
...
...
@@ -63,7 +63,7 @@ public final class PlayerMessage {
private
int
type
;
@Nullable
private
Object
payload
;
private
Looper
looper
;
private
int
window
Index
;
private
int
mediaItem
Index
;
private
long
positionMs
;
private
boolean
deleteAfterDelivery
;
private
boolean
isSent
;
...
...
@@ -78,8 +78,8 @@ public final class PlayerMessage {
* @param target The {@link Target} the message is sent to.
* @param timeline The timeline used when setting the position with {@link #setPosition(long)}. If
* set to {@link Timeline#EMPTY}, any position can be specified.
* @param default
WindowIndex The default window index in the {@code timeline} when no other window
* index is specified.
* @param default
MediaItemIndex The default media item index in the {@code timeline} when no other
*
media item
index is specified.
* @param clock The {@link Clock}.
* @param defaultLooper The default {@link Looper} to send the message on when no other looper is
* specified.
...
...
@@ -88,7 +88,7 @@ public final class PlayerMessage {
Sender
sender
,
Target
target
,
Timeline
timeline
,
int
default
Window
Index
,
int
default
MediaItem
Index
,
Clock
clock
,
Looper
defaultLooper
)
{
this
.
sender
=
sender
;
...
...
@@ -96,7 +96,7 @@ public final class PlayerMessage {
this
.
timeline
=
timeline
;
this
.
looper
=
defaultLooper
;
this
.
clock
=
clock
;
this
.
windowIndex
=
defaultWindow
Index
;
this
.
mediaItemIndex
=
defaultMediaItem
Index
;
this
.
positionMs
=
C
.
TIME_UNSET
;
this
.
deleteAfterDelivery
=
true
;
}
...
...
@@ -173,21 +173,21 @@ public final class PlayerMessage {
}
/**
* Returns position in
window at {@link #getWindowIndex()} at which the message will be delivered,
*
in milliseconds. If {@link C#TIME_UNSET}, the message will be delivered immediately. If {@link
*
C#TIME_END_OF_SOURCE}, the message will be delivered at the end of the window at {@link
*
#getWindow
Index()}.
* Returns position in
the media item at {@link #getMediaItemIndex()} at which the message will be
*
delivered, in milliseconds. If {@link C#TIME_UNSET}, the message will be delivered immediately.
*
If {@link C#TIME_END_OF_SOURCE}, the message will be delivered at the end of the media item at
*
{@link #getMediaItem
Index()}.
*/
public
long
getPositionMs
()
{
return
positionMs
;
}
/**
* Sets a position in the current
window
at which the message will be delivered.
* Sets a position in the current
media item
at which the message will be delivered.
*
* @param positionMs The position in the current
window
at which the message will be sent, in
* @param positionMs The position in the current
media item
at which the message will be sent, in
* milliseconds, or {@link C#TIME_END_OF_SOURCE} to deliver the message at the end of the
* current
window
.
* current
media item
.
* @return This message.
* @throws IllegalStateException If {@link #send()} has already been called.
*/
...
...
@@ -198,31 +198,32 @@ public final class PlayerMessage {
}
/**
* Sets a position in a
window
at which the message will be delivered.
* Sets a position in a
media item
at which the message will be delivered.
*
* @param
windowIndex The index of the window
at which the message will be sent.
* @param positionMs The position in the
window with index {@code window
Index} at which the
* @param
mediaItemIndex The index of the media item
at which the message will be sent.
* @param positionMs The position in the
media item with index {@code mediaItem
Index} at which the
* message will be sent, in milliseconds, or {@link C#TIME_END_OF_SOURCE} to deliver the
* message at the end of the
window with index {@code window
Index}.
* message at the end of the
media item with index {@code mediaItem
Index}.
* @return This message.
* @throws IllegalSeekPositionException If the timeline returned by {@link #getTimeline()} is not
* empty and the provided
window
index is not within the bounds of the timeline.
* empty and the provided
media item
index is not within the bounds of the timeline.
* @throws IllegalStateException If {@link #send()} has already been called.
*/
public
PlayerMessage
setPosition
(
int
window
Index
,
long
positionMs
)
{
public
PlayerMessage
setPosition
(
int
mediaItem
Index
,
long
positionMs
)
{
Assertions
.
checkState
(!
isSent
);
Assertions
.
checkArgument
(
positionMs
!=
C
.
TIME_UNSET
);
if
(
windowIndex
<
0
||
(!
timeline
.
isEmpty
()
&&
windowIndex
>=
timeline
.
getWindowCount
()))
{
throw
new
IllegalSeekPositionException
(
timeline
,
windowIndex
,
positionMs
);
if
(
mediaItemIndex
<
0
||
(!
timeline
.
isEmpty
()
&&
mediaItemIndex
>=
timeline
.
getWindowCount
()))
{
throw
new
IllegalSeekPositionException
(
timeline
,
mediaItemIndex
,
positionMs
);
}
this
.
windowIndex
=
window
Index
;
this
.
mediaItemIndex
=
mediaItem
Index
;
this
.
positionMs
=
positionMs
;
return
this
;
}
/** Returns
window
index at which the message will be delivered. */
public
int
get
Window
Index
()
{
return
window
Index
;
/** Returns
media item
index at which the message will be delivered. */
public
int
get
MediaItem
Index
()
{
return
mediaItem
Index
;
}
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
View file @
30cfc3c6
...
...
@@ -1110,9 +1110,9 @@ public class SimpleExoPlayer extends BasePlayer
@Override
public
void
setMediaSources
(
List
<
MediaSource
>
mediaSources
,
int
start
Window
Index
,
long
startPositionMs
)
{
List
<
MediaSource
>
mediaSources
,
int
start
MediaItem
Index
,
long
startPositionMs
)
{
verifyApplicationThread
();
player
.
setMediaSources
(
mediaSources
,
start
Window
Index
,
startPositionMs
);
player
.
setMediaSources
(
mediaSources
,
start
MediaItem
Index
,
startPositionMs
);
}
@Override
...
...
@@ -1419,7 +1419,7 @@ public class SimpleExoPlayer extends BasePlayer
@Override
public
int
getCurrentMediaItemIndex
()
{
verifyApplicationThread
();
return
player
.
getCurrent
Window
Index
();
return
player
.
getCurrent
MediaItem
Index
();
}
@Override
...
...
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
View file @
30cfc3c6
...
...
@@ -914,7 +914,7 @@ public class AnalyticsCollector
long
eventPositionMs
;
boolean
isInCurrentWindow
=
timeline
.
equals
(
player
.
getCurrentTimeline
())
&&
windowIndex
==
player
.
getCurrent
Window
Index
();
&&
windowIndex
==
player
.
getCurrent
MediaItem
Index
();
if
(
mediaPeriodId
!=
null
&&
mediaPeriodId
.
isAd
())
{
boolean
isCurrentAd
=
isInCurrentWindow
...
...
@@ -939,7 +939,7 @@ public class AnalyticsCollector
mediaPeriodId
,
eventPositionMs
,
player
.
getCurrentTimeline
(),
player
.
getCurrent
Window
Index
(),
player
.
getCurrent
MediaItem
Index
(),
currentMediaPeriodId
,
player
.
getCurrentPosition
(),
player
.
getTotalBufferedDuration
());
...
...
@@ -962,7 +962,7 @@ public class AnalyticsCollector
?
null
:
mediaPeriodQueueTracker
.
getMediaPeriodIdTimeline
(
mediaPeriodId
);
if
(
mediaPeriodId
==
null
||
knownTimeline
==
null
)
{
int
windowIndex
=
player
.
getCurrent
Window
Index
();
int
windowIndex
=
player
.
getCurrent
MediaItem
Index
();
Timeline
timeline
=
player
.
getCurrentTimeline
();
boolean
windowIsInTimeline
=
windowIndex
<
timeline
.
getWindowCount
();
return
generateEventTime
(
...
...
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
View file @
30cfc3c6
...
...
@@ -382,7 +382,7 @@ public interface AnalyticsListener {
/**
* The current window index in {@link #currentTimeline} at the time of the event, or the
* prospective window index if the timeline is not yet known and empty (equivalent to {@link
* Player#getCurrent
Window
Index()}).
* Player#getCurrent
MediaItem
Index()}).
*/
public
final
int
currentWindowIndex
;
...
...
@@ -419,7 +419,7 @@ public interface AnalyticsListener {
* {@link Player#getCurrentTimeline()}).
* @param currentWindowIndex The current window index in {@code currentTimeline} at the time of
* the event, or the prospective window index if the timeline is not yet known and empty
* (equivalent to {@link Player#getCurrent
Window
Index()}).
* (equivalent to {@link Player#getCurrent
MediaItem
Index()}).
* @param currentMediaPeriodId {@link MediaPeriodId Media period identifier} for the currently
* playing media period at the time of the event, or {@code null} if no current media period
* identifier is available.
...
...
@@ -1204,9 +1204,9 @@ public interface AnalyticsListener {
* {@link Player#seekTo(long)} after a {@link
* AnalyticsListener#onMediaItemTransition(EventTime, MediaItem, int)}).
* <li>They intend to use multiple state values together or in combination with {@link Player}
* getter methods. For example using {@link Player#getCurrent
WindowIndex()} with the {@cod
e
*
timeline} provided in {@link #onTimelineChanged(EventTime, int)} is only safe from within
* this method.
* getter methods. For example using {@link Player#getCurrent
MediaItemIndex()} with th
e
*
{@code timeline} provided in {@link #onTimelineChanged(EventTime, int)} is only safe from
*
within
this method.
* <li>They are interested in events that logically happened together (e.g {@link
* #onPlaybackStateChanged(EventTime, int)} to {@link Player#STATE_BUFFERING} because of
* {@link #onMediaItemTransition(EventTime, MediaItem, int)}).
...
...
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
View file @
30cfc3c6
...
...
@@ -182,6 +182,8 @@ public final class FrameworkMediaDrm implements ExoMediaDrm {
mediaDrm
.
closeSession
(
sessionId
);
}
// Return values of MediaDrm.KeyRequest.getRequestType are equal to KeyRequest.RequestType.
@SuppressLint
(
"WrongConstant"
)
@Override
public
KeyRequest
getKeyRequest
(
byte
[]
scope
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java
View file @
30cfc3c6
...
...
@@ -26,10 +26,8 @@ import com.google.android.exoplayer2.util.NetworkTypeObserver;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.base.Ascii
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.ImmutableListMultimap
;
import
com.google.common.collect.ImmutableMap
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
/**
...
...
@@ -42,13 +40,6 @@ import java.util.Map;
*/
public
final
class
DefaultBandwidthMeter
implements
BandwidthMeter
,
TransferListener
{
/**
* Country groups used to determine the default initial bitrate estimate. The group assignment for
* each country is a list for [Wifi, 2G, 3G, 4G, 5G_NSA, 5G_SA].
*/
public
static
final
ImmutableListMultimap
<
String
,
Integer
>
DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS
=
createInitialBitrateCountryGroupAssignment
();
/** Default initial Wifi bitrate estimate in bits per second. */
public
static
final
ImmutableList
<
Long
>
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
=
ImmutableList
.
of
(
5_400_000L
,
3_300_000L
,
2_000_000L
,
1_300_000L
,
760_000L
);
...
...
@@ -82,17 +73,35 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
/** Default maximum weight for the sliding window. */
public
static
final
int
DEFAULT_SLIDING_WINDOW_MAX_WEIGHT
=
2000
;
/** Index for the Wifi group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
/**
* Index for the Wifi group index in the array returned by {@link
* #getInitialBitrateCountryGroupAssignment}.
*/
private
static
final
int
COUNTRY_GROUP_INDEX_WIFI
=
0
;
/** Index for the 2G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
/**
* Index for the 2G group index in the array returned by {@link
* #getInitialBitrateCountryGroupAssignment}.
*/
private
static
final
int
COUNTRY_GROUP_INDEX_2G
=
1
;
/** Index for the 3G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
/**
* Index for the 3G group index in the array returned by {@link
* #getInitialBitrateCountryGroupAssignment}.
*/
private
static
final
int
COUNTRY_GROUP_INDEX_3G
=
2
;
/** Index for the 4G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
/**
* Index for the 4G group index in the array returned by {@link
* #getInitialBitrateCountryGroupAssignment}.
*/
private
static
final
int
COUNTRY_GROUP_INDEX_4G
=
3
;
/** Index for the 5G-NSA group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
/**
* Index for the 5G-NSA group index in the array returned by {@link
* #getInitialBitrateCountryGroupAssignment}.
*/
private
static
final
int
COUNTRY_GROUP_INDEX_5G_NSA
=
4
;
/** Index for the 5G-SA group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
/**
* Index for the 5G-SA group index in the array returned by {@link
* #getInitialBitrateCountryGroupAssignment}.
*/
private
static
final
int
COUNTRY_GROUP_INDEX_5G_SA
=
5
;
@Nullable
private
static
DefaultBandwidthMeter
singletonInstance
;
...
...
@@ -212,40 +221,33 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
}
private
static
Map
<
Integer
,
Long
>
getInitialBitrateEstimatesForCountry
(
String
countryCode
)
{
List
<
Integer
>
groupIndices
=
getCountryGroupIndices
(
countryCode
);
int
[]
groupIndices
=
getInitialBitrateCountryGroupAssignment
(
countryCode
);
Map
<
Integer
,
Long
>
result
=
new
HashMap
<>(
/* initialCapacity= */
8
);
result
.
put
(
C
.
NETWORK_TYPE_UNKNOWN
,
DEFAULT_INITIAL_BITRATE_ESTIMATE
);
result
.
put
(
C
.
NETWORK_TYPE_WIFI
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_WIFI
)
));
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
.
get
(
groupIndices
[
COUNTRY_GROUP_INDEX_WIFI
]
));
result
.
put
(
C
.
NETWORK_TYPE_2G
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_2G
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_2G
)
));
DEFAULT_INITIAL_BITRATE_ESTIMATES_2G
.
get
(
groupIndices
[
COUNTRY_GROUP_INDEX_2G
]
));
result
.
put
(
C
.
NETWORK_TYPE_3G
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_3G
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_3G
)
));
DEFAULT_INITIAL_BITRATE_ESTIMATES_3G
.
get
(
groupIndices
[
COUNTRY_GROUP_INDEX_3G
]
));
result
.
put
(
C
.
NETWORK_TYPE_4G
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_4G
)
));
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G
.
get
(
groupIndices
[
COUNTRY_GROUP_INDEX_4G
]
));
result
.
put
(
C
.
NETWORK_TYPE_5G_NSA
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_5G_NSA
)));
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA
.
get
(
groupIndices
[
COUNTRY_GROUP_INDEX_5G_NSA
]));
result
.
put
(
C
.
NETWORK_TYPE_5G_SA
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_SA
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_5G_SA
)
));
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_SA
.
get
(
groupIndices
[
COUNTRY_GROUP_INDEX_5G_SA
]
));
// Assume default Wifi speed for Ethernet to prevent using the slower fallback.
result
.
put
(
C
.
NETWORK_TYPE_ETHERNET
,
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
.
get
(
groupIndices
.
get
(
COUNTRY_GROUP_INDEX_WIFI
)
));
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI
.
get
(
groupIndices
[
COUNTRY_GROUP_INDEX_WIFI
]
));
return
result
;
}
private
static
ImmutableList
<
Integer
>
getCountryGroupIndices
(
String
countryCode
)
{
ImmutableList
<
Integer
>
groupIndices
=
DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS
.
get
(
countryCode
);
// Assume median group if not found.
return
groupIndices
.
isEmpty
()
?
ImmutableList
.
of
(
2
,
2
,
2
,
2
,
2
,
2
)
:
groupIndices
;
}
}
/**
...
...
@@ -461,250 +463,411 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
return
isNetwork
&&
!
dataSpec
.
isFlagSet
(
DataSpec
.
FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED
);
}
private
static
ImmutableListMultimap
<
String
,
Integer
>
createInitialBitrateCountryGroupAssignment
()
{
return
ImmutableListMultimap
.<
String
,
Integer
>
builder
()
.
putAll
(
"AD"
,
1
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"AE"
,
1
,
4
,
4
,
4
,
3
,
2
)
.
putAll
(
"AF"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"AG"
,
2
,
3
,
1
,
2
,
2
,
2
)
.
putAll
(
"AI"
,
1
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"AL"
,
1
,
2
,
0
,
1
,
2
,
2
)
.
putAll
(
"AM"
,
2
,
3
,
2
,
4
,
2
,
2
)
.
putAll
(
"AO"
,
3
,
4
,
3
,
2
,
2
,
2
)
.
putAll
(
"AQ"
,
4
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"AR"
,
2
,
4
,
1
,
1
,
2
,
2
)
.
putAll
(
"AS"
,
2
,
2
,
2
,
3
,
2
,
2
)
.
putAll
(
"AT"
,
0
,
0
,
0
,
0
,
0
,
2
)
.
putAll
(
"AU"
,
0
,
1
,
0
,
1
,
2
,
2
)
.
putAll
(
"AW"
,
1
,
2
,
4
,
4
,
2
,
2
)
.
putAll
(
"AX"
,
0
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"AZ"
,
3
,
2
,
4
,
4
,
2
,
2
)
.
putAll
(
"BA"
,
1
,
2
,
0
,
1
,
2
,
2
)
.
putAll
(
"BB"
,
0
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"BD"
,
2
,
1
,
3
,
3
,
2
,
2
)
.
putAll
(
"BE"
,
0
,
0
,
3
,
3
,
2
,
2
)
.
putAll
(
"BF"
,
4
,
3
,
4
,
3
,
2
,
2
)
.
putAll
(
"BG"
,
0
,
0
,
0
,
0
,
1
,
2
)
.
putAll
(
"BH"
,
1
,
2
,
2
,
4
,
4
,
2
)
.
putAll
(
"BI"
,
4
,
3
,
4
,
4
,
2
,
2
)
.
putAll
(
"BJ"
,
4
,
4
,
3
,
4
,
2
,
2
)
.
putAll
(
"BL"
,
1
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"BM"
,
1
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"BN"
,
3
,
2
,
1
,
1
,
2
,
2
)
.
putAll
(
"BO"
,
1
,
3
,
3
,
2
,
2
,
2
)
.
putAll
(
"BQ"
,
1
,
2
,
2
,
0
,
2
,
2
)
.
putAll
(
"BR"
,
2
,
3
,
2
,
2
,
2
,
2
)
.
putAll
(
"BS"
,
4
,
2
,
2
,
3
,
2
,
2
)
.
putAll
(
"BT"
,
3
,
1
,
3
,
2
,
2
,
2
)
.
putAll
(
"BW"
,
3
,
4
,
1
,
0
,
2
,
2
)
.
putAll
(
"BY"
,
0
,
1
,
1
,
3
,
2
,
2
)
.
putAll
(
"BZ"
,
2
,
4
,
2
,
2
,
2
,
2
)
.
putAll
(
"CA"
,
0
,
2
,
1
,
2
,
4
,
1
)
.
putAll
(
"CD"
,
4
,
2
,
3
,
1
,
2
,
2
)
.
putAll
(
"CF"
,
4
,
2
,
3
,
2
,
2
,
2
)
.
putAll
(
"CG"
,
2
,
4
,
3
,
4
,
2
,
2
)
.
putAll
(
"CH"
,
0
,
0
,
0
,
0
,
0
,
2
)
.
putAll
(
"CI"
,
3
,
3
,
3
,
4
,
2
,
2
)
.
putAll
(
"CK"
,
2
,
2
,
2
,
1
,
2
,
2
)
.
putAll
(
"CL"
,
1
,
1
,
2
,
2
,
3
,
2
)
.
putAll
(
"CM"
,
3
,
4
,
3
,
2
,
2
,
2
)
.
putAll
(
"CN"
,
2
,
0
,
2
,
2
,
3
,
1
)
.
putAll
(
"CO"
,
2
,
2
,
4
,
2
,
2
,
2
)
.
putAll
(
"CR"
,
2
,
2
,
4
,
4
,
2
,
2
)
.
putAll
(
"CU"
,
4
,
4
,
3
,
2
,
2
,
2
)
.
putAll
(
"CV"
,
2
,
3
,
1
,
0
,
2
,
2
)
.
putAll
(
"CW"
,
2
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"CX"
,
1
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"CY"
,
1
,
0
,
0
,
0
,
1
,
2
)
.
putAll
(
"CZ"
,
0
,
0
,
0
,
0
,
1
,
2
)
.
putAll
(
"DE"
,
0
,
0
,
2
,
2
,
1
,
2
)
.
putAll
(
"DJ"
,
4
,
1
,
4
,
4
,
2
,
2
)
.
putAll
(
"DK"
,
0
,
0
,
1
,
0
,
0
,
2
)
.
putAll
(
"DM"
,
1
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"DO"
,
3
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"DZ"
,
4
,
3
,
4
,
4
,
2
,
2
)
.
putAll
(
"EC"
,
2
,
4
,
2
,
1
,
2
,
2
)
.
putAll
(
"EE"
,
0
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"EG"
,
3
,
4
,
2
,
3
,
2
,
2
)
.
putAll
(
"EH"
,
2
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"ER"
,
4
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"ES"
,
0
,
1
,
1
,
1
,
2
,
2
)
.
putAll
(
"ET"
,
4
,
4
,
3
,
1
,
2
,
2
)
.
putAll
(
"FI"
,
0
,
0
,
0
,
1
,
0
,
2
)
.
putAll
(
"FJ"
,
3
,
1
,
3
,
3
,
2
,
2
)
.
putAll
(
"FK"
,
3
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"FM"
,
3
,
2
,
4
,
2
,
2
,
2
)
.
putAll
(
"FO"
,
0
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"FR"
,
1
,
1
,
2
,
1
,
1
,
1
)
.
putAll
(
"GA"
,
2
,
3
,
1
,
1
,
2
,
2
)
.
putAll
(
"GB"
,
0
,
0
,
1
,
1
,
2
,
3
)
.
putAll
(
"GD"
,
1
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"GE"
,
1
,
1
,
1
,
3
,
2
,
2
)
.
putAll
(
"GF"
,
2
,
1
,
2
,
3
,
2
,
2
)
.
putAll
(
"GG"
,
0
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"GH"
,
3
,
2
,
3
,
2
,
2
,
2
)
.
putAll
(
"GI"
,
0
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"GL"
,
1
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"GM"
,
4
,
2
,
2
,
4
,
2
,
2
)
.
putAll
(
"GN"
,
4
,
3
,
4
,
2
,
2
,
2
)
.
putAll
(
"GP"
,
2
,
1
,
2
,
3
,
2
,
2
)
.
putAll
(
"GQ"
,
4
,
2
,
3
,
4
,
2
,
2
)
.
putAll
(
"GR"
,
1
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"GT"
,
2
,
3
,
2
,
1
,
2
,
2
)
.
putAll
(
"GU"
,
1
,
2
,
4
,
4
,
2
,
2
)
.
putAll
(
"GW"
,
3
,
4
,
3
,
3
,
2
,
2
)
.
putAll
(
"GY"
,
3
,
4
,
1
,
0
,
2
,
2
)
.
putAll
(
"HK"
,
0
,
1
,
2
,
3
,
2
,
0
)
.
putAll
(
"HN"
,
3
,
2
,
3
,
3
,
2
,
2
)
.
putAll
(
"HR"
,
1
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"HT"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"HU"
,
0
,
0
,
0
,
1
,
3
,
2
)
.
putAll
(
"ID"
,
3
,
2
,
3
,
3
,
3
,
2
)
.
putAll
(
"IE"
,
0
,
1
,
1
,
1
,
2
,
2
)
.
putAll
(
"IL"
,
1
,
1
,
2
,
3
,
4
,
2
)
.
putAll
(
"IM"
,
0
,
2
,
0
,
1
,
2
,
2
)
.
putAll
(
"IN"
,
1
,
1
,
3
,
2
,
4
,
3
)
.
putAll
(
"IO"
,
4
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"IQ"
,
3
,
3
,
3
,
3
,
2
,
2
)
.
putAll
(
"IR"
,
3
,
0
,
1
,
1
,
3
,
0
)
.
putAll
(
"IS"
,
0
,
0
,
0
,
0
,
0
,
2
)
.
putAll
(
"IT"
,
0
,
1
,
0
,
1
,
1
,
2
)
.
putAll
(
"JE"
,
3
,
2
,
1
,
2
,
2
,
2
)
.
putAll
(
"JM"
,
3
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"JO"
,
1
,
0
,
0
,
1
,
2
,
2
)
.
putAll
(
"JP"
,
0
,
1
,
0
,
1
,
1
,
1
)
.
putAll
(
"KE"
,
3
,
3
,
2
,
2
,
2
,
2
)
.
putAll
(
"KG"
,
2
,
1
,
1
,
1
,
2
,
2
)
.
putAll
(
"KH"
,
1
,
1
,
4
,
2
,
2
,
2
)
.
putAll
(
"KI"
,
4
,
2
,
4
,
3
,
2
,
2
)
.
putAll
(
"KM"
,
4
,
2
,
4
,
3
,
2
,
2
)
.
putAll
(
"KN"
,
2
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"KP"
,
3
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"KR"
,
0
,
0
,
1
,
3
,
4
,
4
)
.
putAll
(
"KW"
,
1
,
1
,
0
,
0
,
0
,
2
)
.
putAll
(
"KY"
,
1
,
2
,
0
,
1
,
2
,
2
)
.
putAll
(
"KZ"
,
1
,
1
,
2
,
2
,
2
,
2
)
.
putAll
(
"LA"
,
2
,
2
,
1
,
2
,
2
,
2
)
.
putAll
(
"LB"
,
3
,
2
,
1
,
4
,
2
,
2
)
.
putAll
(
"LC"
,
1
,
2
,
0
,
0
,
2
,
2
)
.
putAll
(
"LI"
,
0
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"LK"
,
3
,
1
,
3
,
4
,
4
,
2
)
.
putAll
(
"LR"
,
3
,
4
,
4
,
3
,
2
,
2
)
.
putAll
(
"LS"
,
3
,
3
,
4
,
3
,
2
,
2
)
.
putAll
(
"LT"
,
0
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"LU"
,
1
,
0
,
2
,
2
,
2
,
2
)
.
putAll
(
"LV"
,
0
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"LY"
,
4
,
2
,
4
,
3
,
2
,
2
)
.
putAll
(
"MA"
,
3
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"MC"
,
0
,
2
,
2
,
0
,
2
,
2
)
.
putAll
(
"MD"
,
1
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"ME"
,
1
,
0
,
0
,
1
,
2
,
2
)
.
putAll
(
"MF"
,
1
,
2
,
1
,
0
,
2
,
2
)
.
putAll
(
"MG"
,
3
,
4
,
2
,
2
,
2
,
2
)
.
putAll
(
"MH"
,
3
,
2
,
2
,
4
,
2
,
2
)
.
putAll
(
"MK"
,
1
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"ML"
,
4
,
3
,
3
,
1
,
2
,
2
)
.
putAll
(
"MM"
,
2
,
4
,
3
,
3
,
2
,
2
)
.
putAll
(
"MN"
,
2
,
0
,
1
,
2
,
2
,
2
)
.
putAll
(
"MO"
,
0
,
2
,
4
,
4
,
2
,
2
)
.
putAll
(
"MP"
,
0
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"MQ"
,
2
,
1
,
2
,
3
,
2
,
2
)
.
putAll
(
"MR"
,
4
,
1
,
3
,
4
,
2
,
2
)
.
putAll
(
"MS"
,
1
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"MT"
,
0
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"MU"
,
3
,
1
,
1
,
2
,
2
,
2
)
.
putAll
(
"MV"
,
3
,
4
,
1
,
4
,
2
,
2
)
.
putAll
(
"MW"
,
4
,
2
,
1
,
0
,
2
,
2
)
.
putAll
(
"MX"
,
2
,
4
,
3
,
4
,
2
,
2
)
.
putAll
(
"MY"
,
2
,
1
,
3
,
3
,
2
,
2
)
.
putAll
(
"MZ"
,
3
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"NA"
,
4
,
3
,
2
,
2
,
2
,
2
)
.
putAll
(
"NC"
,
3
,
2
,
4
,
4
,
2
,
2
)
.
putAll
(
"NE"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"NF"
,
2
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"NG"
,
3
,
4
,
1
,
1
,
2
,
2
)
.
putAll
(
"NI"
,
2
,
3
,
4
,
3
,
2
,
2
)
.
putAll
(
"NL"
,
0
,
0
,
3
,
2
,
0
,
4
)
.
putAll
(
"NO"
,
0
,
0
,
2
,
0
,
0
,
2
)
.
putAll
(
"NP"
,
2
,
1
,
4
,
3
,
2
,
2
)
.
putAll
(
"NR"
,
3
,
2
,
2
,
0
,
2
,
2
)
.
putAll
(
"NU"
,
4
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"NZ"
,
1
,
0
,
1
,
2
,
4
,
2
)
.
putAll
(
"OM"
,
2
,
3
,
1
,
3
,
4
,
2
)
.
putAll
(
"PA"
,
1
,
3
,
3
,
3
,
2
,
2
)
.
putAll
(
"PE"
,
2
,
3
,
4
,
4
,
4
,
2
)
.
putAll
(
"PF"
,
2
,
3
,
3
,
1
,
2
,
2
)
.
putAll
(
"PG"
,
4
,
4
,
3
,
2
,
2
,
2
)
.
putAll
(
"PH"
,
2
,
2
,
3
,
3
,
3
,
2
)
.
putAll
(
"PK"
,
3
,
2
,
3
,
3
,
2
,
2
)
.
putAll
(
"PL"
,
1
,
1
,
2
,
2
,
3
,
2
)
.
putAll
(
"PM"
,
0
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"PR"
,
2
,
3
,
2
,
2
,
3
,
3
)
.
putAll
(
"PS"
,
3
,
4
,
1
,
2
,
2
,
2
)
.
putAll
(
"PT"
,
0
,
1
,
0
,
0
,
2
,
2
)
.
putAll
(
"PW"
,
2
,
2
,
4
,
1
,
2
,
2
)
.
putAll
(
"PY"
,
2
,
2
,
3
,
2
,
2
,
2
)
.
putAll
(
"QA"
,
2
,
4
,
2
,
4
,
4
,
2
)
.
putAll
(
"RE"
,
1
,
1
,
1
,
2
,
2
,
2
)
.
putAll
(
"RO"
,
0
,
0
,
1
,
1
,
1
,
2
)
.
putAll
(
"RS"
,
1
,
0
,
0
,
0
,
2
,
2
)
.
putAll
(
"RU"
,
0
,
0
,
0
,
1
,
2
,
2
)
.
putAll
(
"RW"
,
3
,
4
,
3
,
0
,
2
,
2
)
.
putAll
(
"SA"
,
2
,
2
,
1
,
1
,
2
,
2
)
.
putAll
(
"SB"
,
4
,
2
,
4
,
3
,
2
,
2
)
.
putAll
(
"SC"
,
4
,
3
,
0
,
2
,
2
,
2
)
.
putAll
(
"SD"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"SE"
,
0
,
0
,
0
,
0
,
0
,
2
)
.
putAll
(
"SG"
,
1
,
1
,
2
,
3
,
1
,
4
)
.
putAll
(
"SH"
,
4
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"SI"
,
0
,
0
,
0
,
0
,
1
,
2
)
.
putAll
(
"SJ"
,
0
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"SK"
,
0
,
0
,
0
,
0
,
0
,
2
)
.
putAll
(
"SL"
,
4
,
3
,
4
,
1
,
2
,
2
)
.
putAll
(
"SM"
,
0
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"SN"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"SO"
,
3
,
2
,
3
,
3
,
2
,
2
)
.
putAll
(
"SR"
,
2
,
3
,
2
,
2
,
2
,
2
)
.
putAll
(
"SS"
,
4
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"ST"
,
3
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"SV"
,
2
,
2
,
3
,
3
,
2
,
2
)
.
putAll
(
"SX"
,
2
,
2
,
1
,
0
,
2
,
2
)
.
putAll
(
"SY"
,
4
,
3
,
4
,
4
,
2
,
2
)
.
putAll
(
"SZ"
,
4
,
3
,
2
,
4
,
2
,
2
)
.
putAll
(
"TC"
,
2
,
2
,
1
,
0
,
2
,
2
)
.
putAll
(
"TD"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"TG"
,
3
,
3
,
2
,
0
,
2
,
2
)
.
putAll
(
"TH"
,
0
,
3
,
2
,
3
,
3
,
0
)
.
putAll
(
"TJ"
,
4
,
2
,
4
,
4
,
2
,
2
)
.
putAll
(
"TL"
,
4
,
3
,
4
,
4
,
2
,
2
)
.
putAll
(
"TM"
,
4
,
2
,
4
,
2
,
2
,
2
)
.
putAll
(
"TN"
,
2
,
2
,
1
,
1
,
2
,
2
)
.
putAll
(
"TO"
,
4
,
2
,
3
,
3
,
2
,
2
)
.
putAll
(
"TR"
,
1
,
1
,
0
,
1
,
2
,
2
)
.
putAll
(
"TT"
,
1
,
4
,
1
,
1
,
2
,
2
)
.
putAll
(
"TV"
,
4
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"TW"
,
0
,
0
,
0
,
0
,
0
,
0
)
.
putAll
(
"TZ"
,
3
,
4
,
3
,
3
,
2
,
2
)
.
putAll
(
"UA"
,
0
,
3
,
1
,
1
,
2
,
2
)
.
putAll
(
"UG"
,
3
,
3
,
3
,
3
,
2
,
2
)
.
putAll
(
"US"
,
1
,
1
,
2
,
2
,
3
,
2
)
.
putAll
(
"UY"
,
2
,
2
,
1
,
2
,
2
,
2
)
.
putAll
(
"UZ"
,
2
,
2
,
3
,
4
,
2
,
2
)
.
putAll
(
"VC"
,
1
,
2
,
2
,
2
,
2
,
2
)
.
putAll
(
"VE"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"VG"
,
2
,
2
,
1
,
1
,
2
,
2
)
.
putAll
(
"VI"
,
1
,
2
,
1
,
3
,
2
,
2
)
.
putAll
(
"VN"
,
0
,
3
,
3
,
4
,
2
,
2
)
.
putAll
(
"VU"
,
4
,
2
,
2
,
1
,
2
,
2
)
.
putAll
(
"WF"
,
4
,
2
,
2
,
4
,
2
,
2
)
.
putAll
(
"WS"
,
3
,
1
,
2
,
1
,
2
,
2
)
.
putAll
(
"XK"
,
1
,
1
,
1
,
1
,
2
,
2
)
.
putAll
(
"YE"
,
4
,
4
,
4
,
4
,
2
,
2
)
.
putAll
(
"YT"
,
4
,
1
,
1
,
1
,
2
,
2
)
.
putAll
(
"ZA"
,
3
,
3
,
1
,
1
,
1
,
2
)
.
putAll
(
"ZM"
,
3
,
3
,
4
,
2
,
2
,
2
)
.
putAll
(
"ZW"
,
3
,
2
,
4
,
3
,
2
,
2
)
.
build
();
/**
* Returns initial bitrate group assignments for a {@code country}. The initial bitrate is a list
* of indexes for [Wifi, 2G, 3G, 4G, 5G_NSA, 5G_SA].
*/
private
static
int
[]
getInitialBitrateCountryGroupAssignment
(
String
country
)
{
switch
(
country
)
{
case
"AE"
:
return
new
int
[]
{
1
,
4
,
4
,
4
,
3
,
2
};
case
"AG"
:
return
new
int
[]
{
2
,
3
,
1
,
2
,
2
,
2
};
case
"AM"
:
return
new
int
[]
{
2
,
3
,
2
,
4
,
2
,
2
};
case
"AR"
:
return
new
int
[]
{
2
,
4
,
1
,
1
,
2
,
2
};
case
"AS"
:
return
new
int
[]
{
2
,
2
,
2
,
3
,
2
,
2
};
case
"AU"
:
return
new
int
[]
{
0
,
1
,
0
,
1
,
2
,
2
};
case
"BE"
:
return
new
int
[]
{
0
,
0
,
3
,
3
,
2
,
2
};
case
"BF"
:
return
new
int
[]
{
4
,
3
,
4
,
3
,
2
,
2
};
case
"BH"
:
return
new
int
[]
{
1
,
2
,
2
,
4
,
4
,
2
};
case
"BJ"
:
return
new
int
[]
{
4
,
4
,
3
,
4
,
2
,
2
};
case
"BN"
:
return
new
int
[]
{
3
,
2
,
1
,
1
,
2
,
2
};
case
"BO"
:
return
new
int
[]
{
1
,
3
,
3
,
2
,
2
,
2
};
case
"BQ"
:
return
new
int
[]
{
1
,
2
,
2
,
0
,
2
,
2
};
case
"BS"
:
return
new
int
[]
{
4
,
2
,
2
,
3
,
2
,
2
};
case
"BT"
:
return
new
int
[]
{
3
,
1
,
3
,
2
,
2
,
2
};
case
"BY"
:
return
new
int
[]
{
0
,
1
,
1
,
3
,
2
,
2
};
case
"BZ"
:
return
new
int
[]
{
2
,
4
,
2
,
2
,
2
,
2
};
case
"CA"
:
return
new
int
[]
{
0
,
2
,
1
,
2
,
4
,
1
};
case
"CD"
:
return
new
int
[]
{
4
,
2
,
3
,
1
,
2
,
2
};
case
"CF"
:
return
new
int
[]
{
4
,
2
,
3
,
2
,
2
,
2
};
case
"CI"
:
return
new
int
[]
{
3
,
3
,
3
,
4
,
2
,
2
};
case
"CK"
:
return
new
int
[]
{
2
,
2
,
2
,
1
,
2
,
2
};
case
"AO"
:
case
"CM"
:
return
new
int
[]
{
3
,
4
,
3
,
2
,
2
,
2
};
case
"CN"
:
return
new
int
[]
{
2
,
0
,
2
,
2
,
3
,
1
};
case
"CO"
:
return
new
int
[]
{
2
,
2
,
4
,
2
,
2
,
2
};
case
"CR"
:
return
new
int
[]
{
2
,
2
,
4
,
4
,
2
,
2
};
case
"CV"
:
return
new
int
[]
{
2
,
3
,
1
,
0
,
2
,
2
};
case
"CW"
:
return
new
int
[]
{
2
,
2
,
0
,
0
,
2
,
2
};
case
"CY"
:
return
new
int
[]
{
1
,
0
,
0
,
0
,
1
,
2
};
case
"DE"
:
return
new
int
[]
{
0
,
0
,
2
,
2
,
1
,
2
};
case
"DJ"
:
return
new
int
[]
{
4
,
1
,
4
,
4
,
2
,
2
};
case
"DK"
:
return
new
int
[]
{
0
,
0
,
1
,
0
,
0
,
2
};
case
"EC"
:
return
new
int
[]
{
2
,
4
,
2
,
1
,
2
,
2
};
case
"EG"
:
return
new
int
[]
{
3
,
4
,
2
,
3
,
2
,
2
};
case
"ET"
:
return
new
int
[]
{
4
,
4
,
3
,
1
,
2
,
2
};
case
"FI"
:
return
new
int
[]
{
0
,
0
,
0
,
1
,
0
,
2
};
case
"FJ"
:
return
new
int
[]
{
3
,
1
,
3
,
3
,
2
,
2
};
case
"FM"
:
return
new
int
[]
{
3
,
2
,
4
,
2
,
2
,
2
};
case
"FR"
:
return
new
int
[]
{
1
,
1
,
2
,
1
,
1
,
1
};
case
"GA"
:
return
new
int
[]
{
2
,
3
,
1
,
1
,
2
,
2
};
case
"GB"
:
return
new
int
[]
{
0
,
0
,
1
,
1
,
2
,
3
};
case
"GE"
:
return
new
int
[]
{
1
,
1
,
1
,
3
,
2
,
2
};
case
"BB"
:
case
"FO"
:
case
"GG"
:
return
new
int
[]
{
0
,
2
,
0
,
0
,
2
,
2
};
case
"GH"
:
return
new
int
[]
{
3
,
2
,
3
,
2
,
2
,
2
};
case
"GN"
:
return
new
int
[]
{
4
,
3
,
4
,
2
,
2
,
2
};
case
"GQ"
:
return
new
int
[]
{
4
,
2
,
3
,
4
,
2
,
2
};
case
"GT"
:
return
new
int
[]
{
2
,
3
,
2
,
1
,
2
,
2
};
case
"AW"
:
case
"GU"
:
return
new
int
[]
{
1
,
2
,
4
,
4
,
2
,
2
};
case
"BW"
:
case
"GY"
:
return
new
int
[]
{
3
,
4
,
1
,
0
,
2
,
2
};
case
"HK"
:
return
new
int
[]
{
0
,
1
,
2
,
3
,
2
,
0
};
case
"HU"
:
return
new
int
[]
{
0
,
0
,
0
,
1
,
3
,
2
};
case
"ID"
:
return
new
int
[]
{
3
,
2
,
3
,
3
,
3
,
2
};
case
"ES"
:
case
"IE"
:
return
new
int
[]
{
0
,
1
,
1
,
1
,
2
,
2
};
case
"IL"
:
return
new
int
[]
{
1
,
1
,
2
,
3
,
4
,
2
};
case
"IM"
:
return
new
int
[]
{
0
,
2
,
0
,
1
,
2
,
2
};
case
"IN"
:
return
new
int
[]
{
1
,
1
,
3
,
2
,
4
,
3
};
case
"IR"
:
return
new
int
[]
{
3
,
0
,
1
,
1
,
3
,
0
};
case
"IT"
:
return
new
int
[]
{
0
,
1
,
0
,
1
,
1
,
2
};
case
"JE"
:
return
new
int
[]
{
3
,
2
,
1
,
2
,
2
,
2
};
case
"DO"
:
case
"JM"
:
return
new
int
[]
{
3
,
4
,
4
,
4
,
2
,
2
};
case
"JP"
:
return
new
int
[]
{
0
,
1
,
0
,
1
,
1
,
1
};
case
"KE"
:
return
new
int
[]
{
3
,
3
,
2
,
2
,
2
,
2
};
case
"KG"
:
return
new
int
[]
{
2
,
1
,
1
,
1
,
2
,
2
};
case
"KH"
:
return
new
int
[]
{
1
,
1
,
4
,
2
,
2
,
2
};
case
"KR"
:
return
new
int
[]
{
0
,
0
,
1
,
3
,
4
,
4
};
case
"KW"
:
return
new
int
[]
{
1
,
1
,
0
,
0
,
0
,
2
};
case
"AL"
:
case
"BA"
:
case
"KY"
:
return
new
int
[]
{
1
,
2
,
0
,
1
,
2
,
2
};
case
"KZ"
:
return
new
int
[]
{
1
,
1
,
2
,
2
,
2
,
2
};
case
"LB"
:
return
new
int
[]
{
3
,
2
,
1
,
4
,
2
,
2
};
case
"AD"
:
case
"BM"
:
case
"GL"
:
case
"LC"
:
return
new
int
[]
{
1
,
2
,
0
,
0
,
2
,
2
};
case
"LK"
:
return
new
int
[]
{
3
,
1
,
3
,
4
,
4
,
2
};
case
"LR"
:
return
new
int
[]
{
3
,
4
,
4
,
3
,
2
,
2
};
case
"LS"
:
return
new
int
[]
{
3
,
3
,
4
,
3
,
2
,
2
};
case
"LU"
:
return
new
int
[]
{
1
,
0
,
2
,
2
,
2
,
2
};
case
"MC"
:
return
new
int
[]
{
0
,
2
,
2
,
0
,
2
,
2
};
case
"JO"
:
case
"ME"
:
return
new
int
[]
{
1
,
0
,
0
,
1
,
2
,
2
};
case
"MF"
:
return
new
int
[]
{
1
,
2
,
1
,
0
,
2
,
2
};
case
"MG"
:
return
new
int
[]
{
3
,
4
,
2
,
2
,
2
,
2
};
case
"MH"
:
return
new
int
[]
{
3
,
2
,
2
,
4
,
2
,
2
};
case
"ML"
:
return
new
int
[]
{
4
,
3
,
3
,
1
,
2
,
2
};
case
"MM"
:
return
new
int
[]
{
2
,
4
,
3
,
3
,
2
,
2
};
case
"MN"
:
return
new
int
[]
{
2
,
0
,
1
,
2
,
2
,
2
};
case
"MO"
:
return
new
int
[]
{
0
,
2
,
4
,
4
,
2
,
2
};
case
"GF"
:
case
"GP"
:
case
"MQ"
:
return
new
int
[]
{
2
,
1
,
2
,
3
,
2
,
2
};
case
"MR"
:
return
new
int
[]
{
4
,
1
,
3
,
4
,
2
,
2
};
case
"EE"
:
case
"LT"
:
case
"LV"
:
case
"MT"
:
return
new
int
[]
{
0
,
0
,
0
,
0
,
2
,
2
};
case
"MU"
:
return
new
int
[]
{
3
,
1
,
1
,
2
,
2
,
2
};
case
"MV"
:
return
new
int
[]
{
3
,
4
,
1
,
4
,
2
,
2
};
case
"MW"
:
return
new
int
[]
{
4
,
2
,
1
,
0
,
2
,
2
};
case
"CG"
:
case
"MX"
:
return
new
int
[]
{
2
,
4
,
3
,
4
,
2
,
2
};
case
"BD"
:
case
"MY"
:
return
new
int
[]
{
2
,
1
,
3
,
3
,
2
,
2
};
case
"NA"
:
return
new
int
[]
{
4
,
3
,
2
,
2
,
2
,
2
};
case
"AZ"
:
case
"NC"
:
return
new
int
[]
{
3
,
2
,
4
,
4
,
2
,
2
};
case
"NG"
:
return
new
int
[]
{
3
,
4
,
1
,
1
,
2
,
2
};
case
"NI"
:
return
new
int
[]
{
2
,
3
,
4
,
3
,
2
,
2
};
case
"NL"
:
return
new
int
[]
{
0
,
0
,
3
,
2
,
0
,
4
};
case
"NO"
:
return
new
int
[]
{
0
,
0
,
2
,
0
,
0
,
2
};
case
"NP"
:
return
new
int
[]
{
2
,
1
,
4
,
3
,
2
,
2
};
case
"NR"
:
return
new
int
[]
{
3
,
2
,
2
,
0
,
2
,
2
};
case
"NZ"
:
return
new
int
[]
{
1
,
0
,
1
,
2
,
4
,
2
};
case
"OM"
:
return
new
int
[]
{
2
,
3
,
1
,
3
,
4
,
2
};
case
"PA"
:
return
new
int
[]
{
1
,
3
,
3
,
3
,
2
,
2
};
case
"PE"
:
return
new
int
[]
{
2
,
3
,
4
,
4
,
4
,
2
};
case
"PF"
:
return
new
int
[]
{
2
,
3
,
3
,
1
,
2
,
2
};
case
"CU"
:
case
"PG"
:
return
new
int
[]
{
4
,
4
,
3
,
2
,
2
,
2
};
case
"PH"
:
return
new
int
[]
{
2
,
2
,
3
,
3
,
3
,
2
};
case
"PR"
:
return
new
int
[]
{
2
,
3
,
2
,
2
,
3
,
3
};
case
"PS"
:
return
new
int
[]
{
3
,
4
,
1
,
2
,
2
,
2
};
case
"PT"
:
return
new
int
[]
{
0
,
1
,
0
,
0
,
2
,
2
};
case
"PW"
:
return
new
int
[]
{
2
,
2
,
4
,
1
,
2
,
2
};
case
"PY"
:
return
new
int
[]
{
2
,
2
,
3
,
2
,
2
,
2
};
case
"QA"
:
return
new
int
[]
{
2
,
4
,
2
,
4
,
4
,
2
};
case
"RE"
:
return
new
int
[]
{
1
,
1
,
1
,
2
,
2
,
2
};
case
"RO"
:
return
new
int
[]
{
0
,
0
,
1
,
1
,
1
,
2
};
case
"GR"
:
case
"HR"
:
case
"MD"
:
case
"MK"
:
case
"RS"
:
return
new
int
[]
{
1
,
0
,
0
,
0
,
2
,
2
};
case
"RU"
:
return
new
int
[]
{
0
,
0
,
0
,
1
,
2
,
2
};
case
"RW"
:
return
new
int
[]
{
3
,
4
,
3
,
0
,
2
,
2
};
case
"KI"
:
case
"KM"
:
case
"LY"
:
case
"SB"
:
return
new
int
[]
{
4
,
2
,
4
,
3
,
2
,
2
};
case
"SC"
:
return
new
int
[]
{
4
,
3
,
0
,
2
,
2
,
2
};
case
"SG"
:
return
new
int
[]
{
1
,
1
,
2
,
3
,
1
,
4
};
case
"BG"
:
case
"CZ"
:
case
"SI"
:
return
new
int
[]
{
0
,
0
,
0
,
0
,
1
,
2
};
case
"AT"
:
case
"CH"
:
case
"IS"
:
case
"SE"
:
case
"SK"
:
return
new
int
[]
{
0
,
0
,
0
,
0
,
0
,
2
};
case
"SL"
:
return
new
int
[]
{
4
,
3
,
4
,
1
,
2
,
2
};
case
"AX"
:
case
"GI"
:
case
"LI"
:
case
"MP"
:
case
"PM"
:
case
"SJ"
:
case
"SM"
:
return
new
int
[]
{
0
,
2
,
2
,
2
,
2
,
2
};
case
"HN"
:
case
"PK"
:
case
"SO"
:
return
new
int
[]
{
3
,
2
,
3
,
3
,
2
,
2
};
case
"BR"
:
case
"SR"
:
return
new
int
[]
{
2
,
3
,
2
,
2
,
2
,
2
};
case
"FK"
:
case
"KP"
:
case
"MA"
:
case
"MZ"
:
case
"ST"
:
return
new
int
[]
{
3
,
2
,
2
,
2
,
2
,
2
};
case
"SV"
:
return
new
int
[]
{
2
,
2
,
3
,
3
,
2
,
2
};
case
"SZ"
:
return
new
int
[]
{
4
,
3
,
2
,
4
,
2
,
2
};
case
"SX"
:
case
"TC"
:
return
new
int
[]
{
2
,
2
,
1
,
0
,
2
,
2
};
case
"TG"
:
return
new
int
[]
{
3
,
3
,
2
,
0
,
2
,
2
};
case
"TH"
:
return
new
int
[]
{
0
,
3
,
2
,
3
,
3
,
0
};
case
"TJ"
:
return
new
int
[]
{
4
,
2
,
4
,
4
,
2
,
2
};
case
"BI"
:
case
"DZ"
:
case
"SY"
:
case
"TL"
:
return
new
int
[]
{
4
,
3
,
4
,
4
,
2
,
2
};
case
"TM"
:
return
new
int
[]
{
4
,
2
,
4
,
2
,
2
,
2
};
case
"TO"
:
return
new
int
[]
{
4
,
2
,
3
,
3
,
2
,
2
};
case
"TR"
:
return
new
int
[]
{
1
,
1
,
0
,
1
,
2
,
2
};
case
"TT"
:
return
new
int
[]
{
1
,
4
,
1
,
1
,
2
,
2
};
case
"AQ"
:
case
"ER"
:
case
"IO"
:
case
"NU"
:
case
"SH"
:
case
"SS"
:
case
"TV"
:
return
new
int
[]
{
4
,
2
,
2
,
2
,
2
,
2
};
case
"TW"
:
return
new
int
[]
{
0
,
0
,
0
,
0
,
0
,
0
};
case
"GW"
:
case
"TZ"
:
return
new
int
[]
{
3
,
4
,
3
,
3
,
2
,
2
};
case
"UA"
:
return
new
int
[]
{
0
,
3
,
1
,
1
,
2
,
2
};
case
"IQ"
:
case
"UG"
:
return
new
int
[]
{
3
,
3
,
3
,
3
,
2
,
2
};
case
"CL"
:
case
"PL"
:
case
"US"
:
return
new
int
[]
{
1
,
1
,
2
,
2
,
3
,
2
};
case
"LA"
:
case
"UY"
:
return
new
int
[]
{
2
,
2
,
1
,
2
,
2
,
2
};
case
"UZ"
:
return
new
int
[]
{
2
,
2
,
3
,
4
,
2
,
2
};
case
"AI"
:
case
"BL"
:
case
"CX"
:
case
"DM"
:
case
"GD"
:
case
"MS"
:
case
"VC"
:
return
new
int
[]
{
1
,
2
,
2
,
2
,
2
,
2
};
case
"SA"
:
case
"TN"
:
case
"VG"
:
return
new
int
[]
{
2
,
2
,
1
,
1
,
2
,
2
};
case
"VI"
:
return
new
int
[]
{
1
,
2
,
1
,
3
,
2
,
2
};
case
"VN"
:
return
new
int
[]
{
0
,
3
,
3
,
4
,
2
,
2
};
case
"VU"
:
return
new
int
[]
{
4
,
2
,
2
,
1
,
2
,
2
};
case
"GM"
:
case
"WF"
:
return
new
int
[]
{
4
,
2
,
2
,
4
,
2
,
2
};
case
"WS"
:
return
new
int
[]
{
3
,
1
,
2
,
1
,
2
,
2
};
case
"XK"
:
return
new
int
[]
{
1
,
1
,
1
,
1
,
2
,
2
};
case
"AF"
:
case
"HT"
:
case
"NE"
:
case
"SD"
:
case
"SN"
:
case
"TD"
:
case
"VE"
:
case
"YE"
:
return
new
int
[]
{
4
,
4
,
4
,
4
,
2
,
2
};
case
"YT"
:
return
new
int
[]
{
4
,
1
,
1
,
1
,
2
,
2
};
case
"ZA"
:
return
new
int
[]
{
3
,
3
,
1
,
1
,
1
,
2
};
case
"ZM"
:
return
new
int
[]
{
3
,
3
,
4
,
2
,
2
,
2
};
case
"ZW"
:
return
new
int
[]
{
3
,
2
,
4
,
3
,
2
,
2
};
default
:
return
new
int
[]
{
2
,
2
,
2
,
2
,
2
,
2
};
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/util/DebugTextViewHelper.java
View file @
30cfc3c6
...
...
@@ -138,8 +138,8 @@ public class DebugTextViewHelper implements Player.Listener, Runnable {
break
;
}
return
String
.
format
(
"playWhenReady:%s playbackState:%s
window
:%s"
,
player
.
getPlayWhenReady
(),
playbackStateString
,
player
.
getCurrent
Window
Index
());
"playWhenReady:%s playbackState:%s
item
:%s"
,
player
.
getPlayWhenReady
(),
playbackStateString
,
player
.
getCurrent
MediaItem
Index
());
}
/** Returns a string containing video debugging information. */
...
...
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
View file @
30cfc3c6
This diff could not be displayed because it is too large.
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
View file @
30cfc3c6
...
...
@@ -950,7 +950,7 @@ public class PlayerControlView extends FrameLayout {
int
adGroupCount
=
0
;
Timeline
timeline
=
player
.
getCurrentTimeline
();
if
(!
timeline
.
isEmpty
())
{
int
currentWindowIndex
=
player
.
getCurrent
Window
Index
();
int
currentWindowIndex
=
player
.
getCurrent
MediaItem
Index
();
int
firstWindowIndex
=
multiWindowTimeBar
?
0
:
currentWindowIndex
;
int
lastWindowIndex
=
multiWindowTimeBar
?
timeline
.
getWindowCount
()
-
1
:
currentWindowIndex
;
for
(
int
i
=
firstWindowIndex
;
i
<=
lastWindowIndex
;
i
++)
{
...
...
@@ -1110,7 +1110,7 @@ public class PlayerControlView extends FrameLayout {
windowIndex
++;
}
}
else
{
windowIndex
=
player
.
getCurrent
Window
Index
();
windowIndex
=
player
.
getCurrent
MediaItem
Index
();
}
seekTo
(
player
,
windowIndex
,
positionMs
);
updateProgress
();
...
...
@@ -1228,7 +1228,7 @@ public class PlayerControlView extends FrameLayout {
if
(
state
==
Player
.
STATE_IDLE
)
{
player
.
prepare
();
}
else
if
(
state
==
Player
.
STATE_ENDED
)
{
seekTo
(
player
,
player
.
getCurrent
Window
Index
(),
C
.
TIME_UNSET
);
seekTo
(
player
,
player
.
getCurrent
MediaItem
Index
(),
C
.
TIME_UNSET
);
}
player
.
play
();
}
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
View file @
30cfc3c6
...
...
@@ -605,9 +605,9 @@ public class PlayerNotificationManager {
public
static
final
String
ACTION_PLAY
=
"com.google.android.exoplayer.play"
;
/** The action which pauses playback. */
public
static
final
String
ACTION_PAUSE
=
"com.google.android.exoplayer.pause"
;
/** The action which skips to the previous
window
. */
/** The action which skips to the previous
media item
. */
public
static
final
String
ACTION_PREVIOUS
=
"com.google.android.exoplayer.prev"
;
/** The action which skips to the next
window
. */
/** The action which skips to the next
media item
. */
public
static
final
String
ACTION_NEXT
=
"com.google.android.exoplayer.next"
;
/** The action which fast forwards. */
public
static
final
String
ACTION_FAST_FORWARD
=
"com.google.android.exoplayer.ffwd"
;
...
...
@@ -1095,7 +1095,7 @@ public class PlayerNotificationManager {
*
* <ul>
* <li>The media is {@link Player#isPlaying() actively playing}.
* <li>The media is not {@link Player#isCurrent
Window
Dynamic() dynamically changing its
* <li>The media is not {@link Player#isCurrent
MediaItem
Dynamic() dynamically changing its
* duration} (like for example a live stream).
* <li>The media is not {@link Player#isPlayingAd() interrupted by an ad}.
* <li>The media is played at {@link Player#getPlaybackParameters() regular speed}.
...
...
@@ -1253,7 +1253,7 @@ public class PlayerNotificationManager {
&&
useChronometer
&&
player
.
isPlaying
()
&&
!
player
.
isPlayingAd
()
&&
!
player
.
isCurrent
Window
Dynamic
()
&&
!
player
.
isCurrent
MediaItem
Dynamic
()
&&
player
.
getPlaybackParameters
().
speed
==
1
f
)
{
builder
.
setWhen
(
System
.
currentTimeMillis
()
-
player
.
getContentPosition
())
...
...
@@ -1531,7 +1531,7 @@ public class PlayerNotificationManager {
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_IDLE
)
{
player
.
prepare
();
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
player
.
seekToDefaultPosition
(
player
.
getCurrent
Window
Index
());
player
.
seekToDefaultPosition
(
player
.
getCurrent
MediaItem
Index
());
}
player
.
play
();
}
else
if
(
ACTION_PAUSE
.
equals
(
action
))
{
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
View file @
30cfc3c6
...
...
@@ -1501,8 +1501,8 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
if
(
lastPeriodIndexWithTracks
!=
C
.
INDEX_UNSET
)
{
int
lastWindowIndexWithTracks
=
timeline
.
getPeriod
(
lastPeriodIndexWithTracks
,
period
).
windowIndex
;
if
(
player
.
getCurrent
Window
Index
()
==
lastWindowIndexWithTracks
)
{
// We're in the same
window
. Suppress the update.
if
(
player
.
getCurrent
MediaItem
Index
()
==
lastWindowIndexWithTracks
)
{
// We're in the same
media item
. Suppress the update.
return
;
}
}
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
View file @
30cfc3c6
...
...
@@ -1269,7 +1269,7 @@ public class StyledPlayerControlView extends FrameLayout {
int
adGroupCount
=
0
;
Timeline
timeline
=
player
.
getCurrentTimeline
();
if
(!
timeline
.
isEmpty
())
{
int
currentWindowIndex
=
player
.
getCurrent
Window
Index
();
int
currentWindowIndex
=
player
.
getCurrent
MediaItem
Index
();
int
firstWindowIndex
=
multiWindowTimeBar
?
0
:
currentWindowIndex
;
int
lastWindowIndex
=
multiWindowTimeBar
?
timeline
.
getWindowCount
()
-
1
:
currentWindowIndex
;
for
(
int
i
=
firstWindowIndex
;
i
<=
lastWindowIndex
;
i
++)
{
...
...
@@ -1453,7 +1453,7 @@ public class StyledPlayerControlView extends FrameLayout {
windowIndex
++;
}
}
else
{
windowIndex
=
player
.
getCurrent
Window
Index
();
windowIndex
=
player
.
getCurrent
MediaItem
Index
();
}
seekTo
(
player
,
windowIndex
,
positionMs
);
updateProgress
();
...
...
@@ -1616,13 +1616,12 @@ public class StyledPlayerControlView extends FrameLayout {
}
}
@SuppressWarnings
(
"deprecation"
)
private
void
dispatchPlay
(
Player
player
)
{
@State
int
state
=
player
.
getPlaybackState
();
if
(
state
==
Player
.
STATE_IDLE
)
{
player
.
prepare
();
}
else
if
(
state
==
Player
.
STATE_ENDED
)
{
seekTo
(
player
,
player
.
getCurrent
Window
Index
(),
C
.
TIME_UNSET
);
seekTo
(
player
,
player
.
getCurrent
MediaItem
Index
(),
C
.
TIME_UNSET
);
}
player
.
play
();
}
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java
View file @
30cfc3c6
...
...
@@ -1540,8 +1540,8 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
if
(
lastPeriodIndexWithTracks
!=
C
.
INDEX_UNSET
)
{
int
lastWindowIndexWithTracks
=
timeline
.
getPeriod
(
lastPeriodIndexWithTracks
,
period
).
windowIndex
;
if
(
player
.
getCurrent
Window
Index
()
==
lastWindowIndexWithTracks
)
{
// We're in the same
window
. Suppress the update.
if
(
player
.
getCurrent
MediaItem
Index
()
==
lastWindowIndexWithTracks
)
{
// We're in the same
media item
. Suppress the update.
return
;
}
}
...
...
robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java
View file @
30cfc3c6
...
...
@@ -284,12 +284,12 @@ public class TestPlayerRunHelper {
* <p>If a playback error occurs it will be thrown wrapped in an {@link IllegalStateException}.
*
* @param player The {@link Player}.
* @param
windowIndex The window
.
* @param positionMs The position within the
window
, in milliseconds.
* @param
mediaItemIndex The index of the media item
.
* @param positionMs The position within the
media item
, in milliseconds.
* @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded.
*/
public
static
void
playUntilPosition
(
ExoPlayer
player
,
int
window
Index
,
long
positionMs
)
public
static
void
playUntilPosition
(
ExoPlayer
player
,
int
mediaItem
Index
,
long
positionMs
)
throws
TimeoutException
{
verifyMainTestThread
(
player
);
Looper
applicationLooper
=
Util
.
getCurrentOrMainLooper
();
...
...
@@ -315,7 +315,7 @@ public class TestPlayerRunHelper {
// Ignore.
}
})
.
setPosition
(
window
Index
,
positionMs
)
.
setPosition
(
mediaItem
Index
,
positionMs
)
.
send
();
player
.
play
();
runMainLooperUntil
(()
->
messageHandled
.
get
()
||
player
.
getPlayerError
()
!=
null
);
...
...
@@ -326,18 +326,19 @@ public class TestPlayerRunHelper {
/**
* Calls {@link Player#play()}, runs tasks of the main {@link Looper} until the {@code player}
* reaches the specified window or a playback error occurs, and then pauses the {@code player}.
* reaches the specified media item or a playback error occurs, and then pauses the {@code
* player}.
*
* <p>If a playback error occurs it will be thrown wrapped in an {@link IllegalStateException}.
*
* @param player The {@link Player}.
* @param
windowIndex The window
.
* @param
mediaItemIndex The index of the media item
.
* @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded.
*/
public
static
void
playUntilStartOf
Window
(
ExoPlayer
player
,
int
window
Index
)
public
static
void
playUntilStartOf
MediaItem
(
ExoPlayer
player
,
int
mediaItem
Index
)
throws
TimeoutException
{
playUntilPosition
(
player
,
window
Index
,
/* positionMs= */
0
);
playUntilPosition
(
player
,
mediaItem
Index
,
/* positionMs= */
0
);
}
/**
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java
View file @
30cfc3c6
...
...
@@ -121,7 +121,7 @@ public abstract class Action {
/** Calls {@link Player#seekTo(long)} or {@link Player#seekTo(int, long)}. */
public
static
final
class
Seek
extends
Action
{
@Nullable
private
final
Integer
window
Index
;
@Nullable
private
final
Integer
mediaItem
Index
;
private
final
long
positionMs
;
private
final
boolean
catchIllegalSeekException
;
...
...
@@ -133,7 +133,7 @@ public abstract class Action {
*/
public
Seek
(
String
tag
,
long
positionMs
)
{
super
(
tag
,
"Seek:"
+
positionMs
);
this
.
window
Index
=
null
;
this
.
mediaItem
Index
=
null
;
this
.
positionMs
=
positionMs
;
catchIllegalSeekException
=
false
;
}
...
...
@@ -142,14 +142,15 @@ public abstract class Action {
* Action calls {@link Player#seekTo(int, long)}.
*
* @param tag A tag to use for logging.
* @param
windowIndex The window
to seek to.
* @param
mediaItemIndex The media item
to seek to.
* @param positionMs The seek position.
* @param catchIllegalSeekException Whether {@link IllegalSeekPositionException} should be
* silently caught or not.
*/
public
Seek
(
String
tag
,
int
windowIndex
,
long
positionMs
,
boolean
catchIllegalSeekException
)
{
public
Seek
(
String
tag
,
int
mediaItemIndex
,
long
positionMs
,
boolean
catchIllegalSeekException
)
{
super
(
tag
,
"Seek:"
+
positionMs
);
this
.
windowIndex
=
window
Index
;
this
.
mediaItemIndex
=
mediaItem
Index
;
this
.
positionMs
=
positionMs
;
this
.
catchIllegalSeekException
=
catchIllegalSeekException
;
}
...
...
@@ -158,10 +159,10 @@ public abstract class Action {
protected
void
doActionImpl
(
ExoPlayer
player
,
DefaultTrackSelector
trackSelector
,
@Nullable
Surface
surface
)
{
try
{
if
(
window
Index
==
null
)
{
if
(
mediaItem
Index
==
null
)
{
player
.
seekTo
(
positionMs
);
}
else
{
player
.
seekTo
(
window
Index
,
positionMs
);
player
.
seekTo
(
mediaItem
Index
,
positionMs
);
}
}
catch
(
IllegalSeekPositionException
e
)
{
if
(!
catchIllegalSeekException
)
{
...
...
@@ -174,20 +175,20 @@ public abstract class Action {
/** Calls {@link ExoPlayer#setMediaSources(List, int, long)}. */
public
static
final
class
SetMediaItems
extends
Action
{
private
final
int
window
Index
;
private
final
int
mediaItem
Index
;
private
final
long
positionMs
;
private
final
MediaSource
[]
mediaSources
;
/**
* @param tag A tag to use for logging.
* @param
windowIndex The window
index to start playback from.
* @param
mediaItemIndex The media item
index to start playback from.
* @param positionMs The position in milliseconds to start playback from.
* @param mediaSources The media sources to populate the playlist with.
*/
public
SetMediaItems
(
String
tag
,
int
window
Index
,
long
positionMs
,
MediaSource
...
mediaSources
)
{
String
tag
,
int
mediaItem
Index
,
long
positionMs
,
MediaSource
...
mediaSources
)
{
super
(
tag
,
"SetMediaItems"
);
this
.
windowIndex
=
window
Index
;
this
.
mediaItemIndex
=
mediaItem
Index
;
this
.
positionMs
=
positionMs
;
this
.
mediaSources
=
mediaSources
;
}
...
...
@@ -195,7 +196,7 @@ public abstract class Action {
@Override
protected
void
doActionImpl
(
ExoPlayer
player
,
DefaultTrackSelector
trackSelector
,
@Nullable
Surface
surface
)
{
player
.
setMediaSources
(
Arrays
.
asList
(
mediaSources
),
window
Index
,
positionMs
);
player
.
setMediaSources
(
Arrays
.
asList
(
mediaSources
),
mediaItem
Index
,
positionMs
);
}
}
...
...
@@ -553,7 +554,7 @@ public abstract class Action {
public
static
final
class
SendMessages
extends
Action
{
private
final
Target
target
;
private
final
int
window
Index
;
private
final
int
mediaItem
Index
;
private
final
long
positionMs
;
private
final
boolean
deleteAfterDelivery
;
...
...
@@ -566,7 +567,7 @@ public abstract class Action {
this
(
tag
,
target
,
/*
window
Index= */
C
.
INDEX_UNSET
,
/*
mediaItem
Index= */
C
.
INDEX_UNSET
,
positionMs
,
/* deleteAfterDelivery= */
true
);
}
...
...
@@ -574,16 +575,20 @@ public abstract class Action {
/**
* @param tag A tag to use for logging.
* @param target A message target.
* @param
windowIndex The window
index at which the message should be sent, or {@link
* C#INDEX_UNSET} for the current
window
.
* @param
mediaItemIndex The media item
index at which the message should be sent, or {@link
* C#INDEX_UNSET} for the current
media item
.
* @param positionMs The position at which the message should be sent, in milliseconds.
* @param deleteAfterDelivery Whether the message will be deleted after delivery.
*/
public
SendMessages
(
String
tag
,
Target
target
,
int
windowIndex
,
long
positionMs
,
boolean
deleteAfterDelivery
)
{
String
tag
,
Target
target
,
int
mediaItemIndex
,
long
positionMs
,
boolean
deleteAfterDelivery
)
{
super
(
tag
,
"SendMessages"
);
this
.
target
=
target
;
this
.
windowIndex
=
window
Index
;
this
.
mediaItemIndex
=
mediaItem
Index
;
this
.
positionMs
=
positionMs
;
this
.
deleteAfterDelivery
=
deleteAfterDelivery
;
}
...
...
@@ -595,8 +600,8 @@ public abstract class Action {
((
PlayerTarget
)
target
).
setPlayer
(
player
);
}
PlayerMessage
message
=
player
.
createMessage
(
target
);
if
(
window
Index
!=
C
.
INDEX_UNSET
)
{
message
.
setPosition
(
window
Index
,
positionMs
);
if
(
mediaItem
Index
!=
C
.
INDEX_UNSET
)
{
message
.
setPosition
(
mediaItem
Index
,
positionMs
);
}
else
{
message
.
setPosition
(
positionMs
);
}
...
...
@@ -661,17 +666,17 @@ public abstract class Action {
*/
public
static
final
class
PlayUntilPosition
extends
Action
{
private
final
int
window
Index
;
private
final
int
mediaItem
Index
;
private
final
long
positionMs
;
/**
* @param tag A tag to use for logging.
* @param
windowIndex The window
index at which the player should be paused again.
* @param positionMs The position in that
window
at which the player should be paused again.
* @param
mediaItemIndex The media item
index at which the player should be paused again.
* @param positionMs The position in that
media item
at which the player should be paused again.
*/
public
PlayUntilPosition
(
String
tag
,
int
window
Index
,
long
positionMs
)
{
super
(
tag
,
"PlayUntilPosition:"
+
window
Index
+
":"
+
positionMs
);
this
.
windowIndex
=
window
Index
;
public
PlayUntilPosition
(
String
tag
,
int
mediaItem
Index
,
long
positionMs
)
{
super
(
tag
,
"PlayUntilPosition:"
+
mediaItem
Index
+
":"
+
positionMs
);
this
.
mediaItemIndex
=
mediaItem
Index
;
this
.
positionMs
=
positionMs
;
}
...
...
@@ -704,7 +709,7 @@ public abstract class Action {
// Ignore.
}
})
.
setPosition
(
window
Index
,
positionMs
)
.
setPosition
(
mediaItem
Index
,
positionMs
)
.
send
();
if
(
nextAction
!=
null
)
{
// Schedule another message on this test thread to continue action schedule.
...
...
@@ -712,7 +717,7 @@ public abstract class Action {
.
createMessage
(
(
messageType
,
payload
)
->
nextAction
.
schedule
(
player
,
trackSelector
,
surface
,
handler
))
.
setPosition
(
window
Index
,
positionMs
)
.
setPosition
(
mediaItem
Index
,
positionMs
)
.
setLooper
(
applicationLooper
)
.
send
();
}
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java
View file @
30cfc3c6
...
...
@@ -161,24 +161,25 @@ public final class ActionSchedule {
/**
* Schedules a seek action.
*
* @param
windowIndex The window
to seek to.
* @param
mediaItemIndex The media item
to seek to.
* @param positionMs The seek position.
* @return The builder, for convenience.
*/
public
Builder
seek
(
int
windowIndex
,
long
positionMs
)
{
return
apply
(
new
Seek
(
tag
,
windowIndex
,
positionMs
,
/* catchIllegalSeekException= */
false
));
public
Builder
seek
(
int
mediaItemIndex
,
long
positionMs
)
{
return
apply
(
new
Seek
(
tag
,
mediaItemIndex
,
positionMs
,
/* catchIllegalSeekException= */
false
));
}
/**
* Schedules a seek action to be executed.
*
* @param
windowIndex The window
to seek to.
* @param
mediaItemIndex The media item
to seek to.
* @param positionMs The seek position.
* @param catchIllegalSeekException Whether an illegal seek position should be caught or not.
* @return The builder, for convenience.
*/
public
Builder
seek
(
int
window
Index
,
long
positionMs
,
boolean
catchIllegalSeekException
)
{
return
apply
(
new
Seek
(
tag
,
window
Index
,
positionMs
,
catchIllegalSeekException
));
public
Builder
seek
(
int
mediaItem
Index
,
long
positionMs
,
boolean
catchIllegalSeekException
)
{
return
apply
(
new
Seek
(
tag
,
mediaItem
Index
,
positionMs
,
catchIllegalSeekException
));
}
/**
...
...
@@ -247,23 +248,23 @@ public final class ActionSchedule {
* Schedules a play action, waits until the player reaches the specified position, and pauses
* the player again.
*
* @param
windowIndex The window
index at which the player should be paused again.
* @param positionMs The position in that
window
at which the player should be paused again.
* @param
mediaItemIndex The media item
index at which the player should be paused again.
* @param positionMs The position in that
media item
at which the player should be paused again.
* @return The builder, for convenience.
*/
public
Builder
playUntilPosition
(
int
window
Index
,
long
positionMs
)
{
return
apply
(
new
PlayUntilPosition
(
tag
,
window
Index
,
positionMs
));
public
Builder
playUntilPosition
(
int
mediaItem
Index
,
long
positionMs
)
{
return
apply
(
new
PlayUntilPosition
(
tag
,
mediaItem
Index
,
positionMs
));
}
/**
* Schedules a play action, waits until the player reaches the start of the specified
window,
* and pauses the player again.
* Schedules a play action, waits until the player reaches the start of the specified
media
*
item,
and pauses the player again.
*
* @param
windowIndex The window
index at which the player should be paused again.
* @param
mediaItemIndex The media item
index at which the player should be paused again.
* @return The builder, for convenience.
*/
public
Builder
playUntilStartOf
Window
(
int
window
Index
)
{
return
apply
(
new
PlayUntilPosition
(
tag
,
window
Index
,
/* positionMs= */
0
));
public
Builder
playUntilStartOf
MediaItem
(
int
mediaItem
Index
)
{
return
apply
(
new
PlayUntilPosition
(
tag
,
mediaItem
Index
,
/* positionMs= */
0
));
}
/**
...
...
@@ -323,16 +324,16 @@ public final class ActionSchedule {
/**
* Schedules a set media items action to be executed.
*
* @param
windowIndex The window index to start playback from or {@link C#INDEX_UNSET} if the
* playback position should not be reset.
* @param
mediaItemIndex The media item index to start playback from or {@link C#INDEX_UNSET} if
*
the
playback position should not be reset.
* @param positionMs The position in milliseconds from where playback should start. If {@link
* C#TIME_UNSET} is passed the default position is used. In any case, if {@code
windowIndex}
*
is set to {@link C#INDEX_UNSET} the position is not reset at all and this parameter
is
* ignored.
* C#TIME_UNSET} is passed the default position is used. In any case, if {@code
*
mediaItemIndex} is set to {@link C#INDEX_UNSET} the position is not reset at all and th
is
*
parameter is
ignored.
* @return The builder, for convenience.
*/
public
Builder
setMediaSources
(
int
window
Index
,
long
positionMs
,
MediaSource
...
sources
)
{
return
apply
(
new
Action
.
SetMediaItems
(
tag
,
window
Index
,
positionMs
,
sources
));
public
Builder
setMediaSources
(
int
mediaItem
Index
,
long
positionMs
,
MediaSource
...
sources
)
{
return
apply
(
new
Action
.
SetMediaItems
(
tag
,
mediaItem
Index
,
positionMs
,
sources
));
}
/**
...
...
@@ -354,7 +355,10 @@ public final class ActionSchedule {
public
Builder
setMediaSources
(
MediaSource
...
mediaSources
)
{
return
apply
(
new
Action
.
SetMediaItems
(
tag
,
/* windowIndex= */
C
.
INDEX_UNSET
,
/* positionMs= */
C
.
TIME_UNSET
,
mediaSources
));
tag
,
/* mediaItemIndex= */
C
.
INDEX_UNSET
,
/* positionMs= */
C
.
TIME_UNSET
,
mediaSources
));
}
/**
* Schedules a add media items action to be executed.
...
...
@@ -447,8 +451,8 @@ public final class ActionSchedule {
/**
* Schedules sending a {@link PlayerMessage}.
*
* @param positionMs The position in the current
window at which the message should be sent, in
* milliseconds.
* @param positionMs The position in the current
media item at which the message should be sent,
*
in
milliseconds.
* @return The builder, for convenience.
*/
public
Builder
sendMessage
(
Target
target
,
long
positionMs
)
{
...
...
@@ -459,27 +463,28 @@ public final class ActionSchedule {
* Schedules sending a {@link PlayerMessage}.
*
* @param target A message target.
* @param
windowIndex The window
index at which the message should be sent.
* @param
mediaItemIndex The media item
index at which the message should be sent.
* @param positionMs The position at which the message should be sent, in milliseconds.
* @return The builder, for convenience.
*/
public
Builder
sendMessage
(
Target
target
,
int
window
Index
,
long
positionMs
)
{
public
Builder
sendMessage
(
Target
target
,
int
mediaItem
Index
,
long
positionMs
)
{
return
apply
(
new
SendMessages
(
tag
,
target
,
windowIndex
,
positionMs
,
/* deleteAfterDelivery= */
true
));
new
SendMessages
(
tag
,
target
,
mediaItemIndex
,
positionMs
,
/* deleteAfterDelivery= */
true
));
}
/**
* Schedules to send a {@link PlayerMessage}.
*
* @param target A message target.
* @param
windowIndex The window
index at which the message should be sent.
* @param
mediaItemIndex The media item
index at which the message should be sent.
* @param positionMs The position at which the message should be sent, in milliseconds.
* @param deleteAfterDelivery Whether the message will be deleted after delivery.
* @return The builder, for convenience.
*/
public
Builder
sendMessage
(
Target
target
,
int
window
Index
,
long
positionMs
,
boolean
deleteAfterDelivery
)
{
return
apply
(
new
SendMessages
(
tag
,
target
,
window
Index
,
positionMs
,
deleteAfterDelivery
));
Target
target
,
int
mediaItem
Index
,
long
positionMs
,
boolean
deleteAfterDelivery
)
{
return
apply
(
new
SendMessages
(
tag
,
target
,
mediaItem
Index
,
positionMs
,
deleteAfterDelivery
));
}
/**
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java
View file @
30cfc3c6
...
...
@@ -85,7 +85,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
private
AnalyticsListener
analyticsListener
;
private
Integer
expectedPlayerEndedCount
;
private
boolean
pauseAtEndOfMediaItems
;
private
int
initial
Window
Index
;
private
int
initial
MediaItem
Index
;
private
long
initialPositionMs
;
private
boolean
skipSettingMediaSources
;
...
...
@@ -93,7 +93,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
testPlayerBuilder
=
new
TestExoPlayerBuilder
(
context
);
mediaSources
=
new
ArrayList
<>();
supportedFormats
=
new
Format
[]
{
VIDEO_FORMAT
};
initial
Window
Index
=
C
.
INDEX_UNSET
;
initial
MediaItem
Index
=
C
.
INDEX_UNSET
;
initialPositionMs
=
C
.
TIME_UNSET
;
}
...
...
@@ -133,12 +133,12 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
/**
* Seeks before setting the media sources and preparing the player.
*
* @param
windowIndex The window
index to seek to.
* @param
mediaItemIndex The media item
index to seek to.
* @param positionMs The position in milliseconds to seek to.
* @return This builder.
*/
public
Builder
initialSeek
(
int
window
Index
,
long
positionMs
)
{
this
.
initial
WindowIndex
=
window
Index
;
public
Builder
initialSeek
(
int
mediaItem
Index
,
long
positionMs
)
{
this
.
initial
MediaItemIndex
=
mediaItem
Index
;
this
.
initialPositionMs
=
positionMs
;
return
this
;
}
...
...
@@ -343,7 +343,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
testPlayerBuilder
,
mediaSources
,
skipSettingMediaSources
,
initial
Window
Index
,
initial
MediaItem
Index
,
initialPositionMs
,
surface
,
actionSchedule
,
...
...
@@ -357,7 +357,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
private
final
TestExoPlayerBuilder
playerBuilder
;
private
final
List
<
MediaSource
>
mediaSources
;
private
final
boolean
skipSettingMediaSources
;
private
final
int
initial
Window
Index
;
private
final
int
initial
MediaItem
Index
;
private
final
long
initialPositionMs
;
@Nullable
private
final
Surface
surface
;
@Nullable
private
final
ActionSchedule
actionSchedule
;
...
...
@@ -386,7 +386,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
TestExoPlayerBuilder
playerBuilder
,
List
<
MediaSource
>
mediaSources
,
boolean
skipSettingMediaSources
,
int
initial
Window
Index
,
int
initial
MediaItem
Index
,
long
initialPositionMs
,
@Nullable
Surface
surface
,
@Nullable
ActionSchedule
actionSchedule
,
...
...
@@ -397,7 +397,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
this
.
playerBuilder
=
playerBuilder
;
this
.
mediaSources
=
mediaSources
;
this
.
skipSettingMediaSources
=
skipSettingMediaSources
;
this
.
initial
WindowIndex
=
initialWindow
Index
;
this
.
initial
MediaItemIndex
=
initialMediaItem
Index
;
this
.
initialPositionMs
=
initialPositionMs
;
this
.
surface
=
surface
;
this
.
actionSchedule
=
actionSchedule
;
...
...
@@ -466,8 +466,8 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
handler
,
/* callback= */
ExoPlayerTestRunner
.
this
);
}
if
(
initial
Window
Index
!=
C
.
INDEX_UNSET
)
{
player
.
seekTo
(
initial
Window
Index
,
initialPositionMs
);
if
(
initial
MediaItem
Index
!=
C
.
INDEX_UNSET
)
{
player
.
seekTo
(
initial
MediaItem
Index
,
initialPositionMs
);
}
if
(!
skipSettingMediaSources
)
{
player
.
setMediaSources
(
mediaSources
,
/* resetPosition= */
false
);
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
View file @
30cfc3c6
...
...
@@ -162,7 +162,7 @@ public class StubExoPlayer extends StubPlayer implements ExoPlayer {
@Override
public
void
setMediaSources
(
List
<
MediaSource
>
mediaSources
,
int
start
Window
Index
,
long
startPositionMs
)
{
List
<
MediaSource
>
mediaSources
,
int
start
MediaItem
Index
,
long
startPositionMs
)
{
throw
new
UnsupportedOperationException
();
}
...
...
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