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
d930e07a
authored
Aug 27, 2021
by
bachinger
Committed by
Christos Tsilopoulos
Sep 16, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Implement setPlaybackParameters for CastPlayer
Issue: #6784 PiperOrigin-RevId: 393374139
parent
8909f201
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
155 additions
and
7 deletions
RELEASENOTES.md
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/CastPlayerTest.java
RELEASENOTES.md
View file @
d930e07a
...
...
@@ -12,6 +12,10 @@
*
Request smaller decoder input buffers for Dolby Vision. This fixes an
issue that could cause UHD Dolby Vision playbacks to fail on some
devices, including Amazon Fire TV 4K.
*
Cast extension:
*
Implement
`CastPlayer.setPlaybackParameters(PlaybackParameters)`
to
support setting the playback speed
(
[
#6784
](
https://github.com/google/ExoPlayer/issues/6784
)
).
### 2.15.0 (2021-08-10)
...
...
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
View file @
d930e07a
...
...
@@ -95,6 +95,7 @@ public final class CastPlayer extends BasePlayer {
COMMAND_SEEK_TO_DEFAULT_POSITION
,
COMMAND_SEEK_TO_WINDOW
,
COMMAND_SET_REPEAT_MODE
,
COMMAND_SET_SPEED_AND_PITCH
,
COMMAND_GET_CURRENT_MEDIA_ITEM
,
COMMAND_GET_TIMELINE
,
COMMAND_GET_MEDIA_ITEMS_METADATA
,
...
...
@@ -102,6 +103,9 @@ public final class CastPlayer extends BasePlayer {
COMMAND_CHANGE_MEDIA_ITEMS
)
.
build
();
public
static
final
float
MIN_SPEED_SUPPORTED
=
0.5f
;
public
static
final
float
MAX_SPEED_SUPPORTED
=
2.0f
;
private
static
final
String
TAG
=
"CastPlayer"
;
private
static
final
int
RENDERER_COUNT
=
3
;
...
...
@@ -132,6 +136,7 @@ public final class CastPlayer extends BasePlayer {
// Internal state.
private
final
StateHolder
<
Boolean
>
playWhenReady
;
private
final
StateHolder
<
Integer
>
repeatMode
;
private
final
StateHolder
<
PlaybackParameters
>
playbackParameters
;
@Nullable
private
RemoteMediaClient
remoteMediaClient
;
private
CastTimeline
currentTimeline
;
private
TrackGroupArray
currentTrackGroups
;
...
...
@@ -208,6 +213,7 @@ public final class CastPlayer extends BasePlayer {
(
listener
,
flags
)
->
listener
.
onEvents
(
/* player= */
this
,
new
Events
(
flags
)));
playWhenReady
=
new
StateHolder
<>(
false
);
repeatMode
=
new
StateHolder
<>(
REPEAT_MODE_OFF
);
playbackParameters
=
new
StateHolder
<>(
PlaybackParameters
.
DEFAULT
);
playbackState
=
STATE_IDLE
;
currentTimeline
=
CastTimeline
.
EMPTY_CAST_TIMELINE
;
currentTrackGroups
=
TrackGroupArray
.
EMPTY
;
...
...
@@ -464,13 +470,8 @@ public final class CastPlayer extends BasePlayer {
}
@Override
public
void
setPlaybackParameters
(
PlaybackParameters
playbackParameters
)
{
// Unsupported by the RemoteMediaClient API. Do nothing.
}
@Override
public
PlaybackParameters
getPlaybackParameters
()
{
return
PlaybackParameters
.
DEFAULT
;
return
playbackParameters
.
value
;
}
@Override
...
...
@@ -490,6 +491,32 @@ public final class CastPlayer extends BasePlayer {
}
@Override
public
void
setPlaybackParameters
(
PlaybackParameters
playbackParameters
)
{
if
(
remoteMediaClient
==
null
)
{
return
;
}
PlaybackParameters
actualPlaybackParameters
=
new
PlaybackParameters
(
Util
.
constrainValue
(
playbackParameters
.
speed
,
MIN_SPEED_SUPPORTED
,
MAX_SPEED_SUPPORTED
));
setPlaybackParametersAndNotifyIfChanged
(
actualPlaybackParameters
);
listeners
.
flushEvents
();
PendingResult
<
MediaChannelResult
>
pendingResult
=
remoteMediaClient
.
setPlaybackRate
(
actualPlaybackParameters
.
speed
,
/* customData= */
null
);
this
.
playbackParameters
.
pendingResultCallback
=
new
ResultCallback
<
MediaChannelResult
>()
{
@Override
public
void
onResult
(
MediaChannelResult
mediaChannelResult
)
{
if
(
remoteMediaClient
!=
null
)
{
updatePlaybackRateAndNotifyIfChanged
(
this
);
listeners
.
flushEvents
();
}
}
};
pendingResult
.
setResultCallback
(
this
.
playbackParameters
.
pendingResultCallback
);
}
@Override
public
void
setRepeatMode
(
@RepeatMode
int
repeatMode
)
{
if
(
remoteMediaClient
==
null
)
{
return
;
...
...
@@ -761,6 +788,7 @@ public final class CastPlayer extends BasePlayer {
Player
.
EVENT_IS_PLAYING_CHANGED
,
listener
->
listener
.
onIsPlayingChanged
(
isPlaying
));
}
updateRepeatModeAndNotifyIfChanged
(
/* resultCallback= */
null
);
updatePlaybackRateAndNotifyIfChanged
(
/* resultCallback= */
null
);
boolean
playingPeriodChangedByTimelineChange
=
updateTimelineAndNotifyIfChanged
();
Timeline
currentTimeline
=
getCurrentTimeline
();
currentWindowIndex
=
fetchCurrentWindowIndex
(
remoteMediaClient
,
currentTimeline
);
...
...
@@ -845,6 +873,22 @@ public final class CastPlayer extends BasePlayer {
}
@RequiresNonNull
(
"remoteMediaClient"
)
private
void
updatePlaybackRateAndNotifyIfChanged
(
@Nullable
ResultCallback
<?>
resultCallback
)
{
if
(
playbackParameters
.
acceptsUpdate
(
resultCallback
))
{
@Nullable
MediaStatus
mediaStatus
=
remoteMediaClient
.
getMediaStatus
();
float
speed
=
mediaStatus
!=
null
?
(
float
)
mediaStatus
.
getPlaybackRate
()
:
PlaybackParameters
.
DEFAULT
.
speed
;
if
(
speed
>
0.0f
)
{
// Set the speed if not paused.
setPlaybackParametersAndNotifyIfChanged
(
new
PlaybackParameters
(
speed
));
}
playbackParameters
.
clearPendingResultCallback
();
}
}
@RequiresNonNull
(
"remoteMediaClient"
)
private
void
updateRepeatModeAndNotifyIfChanged
(
@Nullable
ResultCallback
<?>
resultCallback
)
{
if
(
repeatMode
.
acceptsUpdate
(
resultCallback
))
{
setRepeatModeAndNotifyIfChanged
(
fetchRepeatMode
(
remoteMediaClient
));
...
...
@@ -1100,6 +1144,17 @@ public final class CastPlayer extends BasePlayer {
}
}
private
void
setPlaybackParametersAndNotifyIfChanged
(
PlaybackParameters
playbackParameters
)
{
if
(
this
.
playbackParameters
.
value
.
equals
(
playbackParameters
))
{
return
;
}
this
.
playbackParameters
.
value
=
playbackParameters
;
listeners
.
queueEvent
(
Player
.
EVENT_PLAYBACK_PARAMETERS_CHANGED
,
listener
->
listener
.
onPlaybackParametersChanged
(
playbackParameters
));
updateAvailableCommandsAndNotifyIfChanged
();
}
@SuppressWarnings
(
"deprecation"
)
private
void
setPlayerStateAndNotifyIfChanged
(
boolean
playWhenReady
,
...
...
extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/CastPlayerTest.java
View file @
d930e07a
...
...
@@ -61,6 +61,7 @@ import android.net.Uri;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.MediaItem
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.util.Assertions
;
...
...
@@ -126,6 +127,7 @@ public class CastPlayerTest {
// Make the remote media client present the same default values as ExoPlayer:
when
(
mockRemoteMediaClient
.
isPaused
()).
thenReturn
(
true
);
when
(
mockMediaStatus
.
getQueueRepeatMode
()).
thenReturn
(
MediaStatus
.
REPEAT_MODE_REPEAT_OFF
);
when
(
mockMediaStatus
.
getPlaybackRate
()).
thenReturn
(
1.0d
);
castPlayer
=
new
CastPlayer
(
mockCastContext
);
castPlayer
.
addListener
(
mockListener
);
verify
(
mockRemoteMediaClient
).
registerCallback
(
callbackArgumentCaptor
.
capture
());
...
...
@@ -209,6 +211,93 @@ public class CastPlayerTest {
}
@Test
public
void
playbackParameters_defaultPlaybackSpeed_isUnitSpeed
()
{
assertThat
(
castPlayer
.
getPlaybackParameters
()).
isEqualTo
(
PlaybackParameters
.
DEFAULT
);
}
@Test
public
void
playbackParameters_onStatusUpdated_setsRemotePlaybackSpeed
()
{
PlaybackParameters
expectedPlaybackParameters
=
new
PlaybackParameters
(
/* speed= */
1.234f
);
when
(
mockMediaStatus
.
getPlaybackRate
()).
thenReturn
(
1.234d
);
remoteMediaClientCallback
.
onStatusUpdated
();
assertThat
(
castPlayer
.
getPlaybackParameters
()).
isEqualTo
(
expectedPlaybackParameters
);
verify
(
mockListener
).
onPlaybackParametersChanged
(
expectedPlaybackParameters
);
}
@Test
public
void
playbackParameters_onStatusUpdated_ignoreInPausedState
()
{
when
(
mockMediaStatus
.
getPlaybackRate
()).
thenReturn
(
0.0d
);
remoteMediaClientCallback
.
onStatusUpdated
();
assertThat
(
castPlayer
.
getPlaybackParameters
()).
isEqualTo
(
PlaybackParameters
.
DEFAULT
);
verifyNoMoreInteractions
(
mockListener
);
}
@Test
public
void
setPlaybackParameters_speedOutOfRange_valueIsConstraintToMinAndMax
()
{
when
(
mockRemoteMediaClient
.
setPlaybackRate
(
eq
(
2
d
),
any
())).
thenReturn
(
mockPendingResult
);
when
(
mockRemoteMediaClient
.
setPlaybackRate
(
eq
(
0.5d
),
any
())).
thenReturn
(
mockPendingResult
);
PlaybackParameters
expectedMaxValuePlaybackParameters
=
new
PlaybackParameters
(
/* speed= */
2
f
);
PlaybackParameters
expectedMinValuePlaybackParameters
=
new
PlaybackParameters
(
/* speed= */
0.5f
);
castPlayer
.
setPlaybackParameters
(
new
PlaybackParameters
(
/* speed= */
2.001f
));
verify
(
mockListener
).
onPlaybackParametersChanged
(
expectedMaxValuePlaybackParameters
);
castPlayer
.
setPlaybackParameters
(
new
PlaybackParameters
(
/* speed= */
0.499f
));
verify
(
mockListener
).
onPlaybackParametersChanged
(
expectedMinValuePlaybackParameters
);
}
@Test
public
void
setPlaybackParameters_masksPendingState
()
{
PlaybackParameters
playbackParameters
=
new
PlaybackParameters
(
/* speed= */
1.234f
);
when
(
mockRemoteMediaClient
.
setPlaybackRate
(
eq
((
double
)
1.234f
),
any
()))
.
thenReturn
(
mockPendingResult
);
castPlayer
.
setPlaybackParameters
(
playbackParameters
);
verify
(
mockPendingResult
).
setResultCallback
(
setResultCallbackArgumentCaptor
.
capture
());
assertThat
(
castPlayer
.
getPlaybackParameters
().
speed
).
isEqualTo
(
1.234f
);
verify
(
mockListener
).
onPlaybackParametersChanged
(
playbackParameters
);
// Simulate a status update while the update is pending that must not override the masked speed.
when
(
mockMediaStatus
.
getPlaybackRate
()).
thenReturn
(
99.0d
);
remoteMediaClientCallback
.
onStatusUpdated
();
assertThat
(
castPlayer
.
getPlaybackParameters
().
speed
).
isEqualTo
(
1.234f
);
// Call the captured result callback when the device responds. The listener must not be called.
when
(
mockMediaStatus
.
getPlaybackRate
()).
thenReturn
(
1.234d
);
setResultCallbackArgumentCaptor
.
getValue
()
.
onResult
(
mock
(
RemoteMediaClient
.
MediaChannelResult
.
class
));
assertThat
(
castPlayer
.
getPlaybackParameters
().
speed
).
isEqualTo
(
1.234f
);
verifyNoMoreInteractions
(
mockListener
);
}
@Test
public
void
setPlaybackParameters_speedChangeNotSupported_resetOnResultCallback
()
{
when
(
mockRemoteMediaClient
.
setPlaybackRate
(
eq
((
double
)
1.234f
),
any
()))
.
thenReturn
(
mockPendingResult
);
PlaybackParameters
playbackParameters
=
new
PlaybackParameters
(
/* speed= */
1.234f
);
// Change the playback speed and and capture the result callback.
castPlayer
.
setPlaybackParameters
(
playbackParameters
);
verify
(
mockPendingResult
).
setResultCallback
(
setResultCallbackArgumentCaptor
.
capture
());
verify
(
mockListener
).
onPlaybackParametersChanged
(
new
PlaybackParameters
(
/* speed= */
1.234f
));
// The device does not support speed changes and returns unit speed to the result callback.
when
(
mockMediaStatus
.
getPlaybackRate
()).
thenReturn
(
1.0d
);
setResultCallbackArgumentCaptor
.
getValue
()
.
onResult
(
mock
(
RemoteMediaClient
.
MediaChannelResult
.
class
));
assertThat
(
castPlayer
.
getPlaybackParameters
()).
isEqualTo
(
PlaybackParameters
.
DEFAULT
);
verify
(
mockListener
).
onPlaybackParametersChanged
(
PlaybackParameters
.
DEFAULT
);
verifyNoMoreInteractions
(
mockListener
);
}
@Test
public
void
setRepeatMode_masksRemoteState
()
{
when
(
mockRemoteMediaClient
.
queueSetRepeatMode
(
anyInt
(),
any
())).
thenReturn
(
mockPendingResult
);
assertThat
(
castPlayer
.
getRepeatMode
()).
isEqualTo
(
Player
.
REPEAT_MODE_OFF
);
...
...
@@ -1215,7 +1304,7 @@ public class CastPlayerTest {
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_SEEK_TO_WINDOW
)).
isTrue
();
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_SEEK_BACK
)).
isTrue
();
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_SEEK_FORWARD
)).
isTrue
();
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_SET_SPEED_AND_PITCH
)).
is
Fals
e
();
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_SET_SPEED_AND_PITCH
)).
is
Tru
e
();
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_SET_SHUFFLE_MODE
)).
isFalse
();
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_SET_REPEAT_MODE
)).
isTrue
();
assertThat
(
castPlayer
.
isCommandAvailable
(
COMMAND_GET_CURRENT_MEDIA_ITEM
)).
isTrue
();
...
...
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