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
f37d79a4
authored
Sep 24, 2020
by
krocard
Committed by
kim-vde
Sep 25, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Callback when sleeping for offload and existing from it
#exo-offload PiperOrigin-RevId: 333497538
parent
294ae10e
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
115 additions
and
48 deletions
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/PlaybackInfo.java
library/core/src/main/java/com/google/android/exoplayer2/Player.java
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/TestExoPlayer.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
View file @
f37d79a4
...
...
@@ -1353,6 +1353,7 @@ import java.util.concurrent.TimeoutException;
private
final
boolean
isPlayingChanged
;
private
final
boolean
playbackParametersChanged
;
private
final
boolean
offloadSchedulingEnabledChanged
;
private
final
boolean
sleepingForOffloadChanged
;
public
PlaybackInfoUpdate
(
PlaybackInfo
playbackInfo
,
...
...
@@ -1394,6 +1395,8 @@ import java.util.concurrent.TimeoutException;
!
previousPlaybackInfo
.
playbackParameters
.
equals
(
playbackInfo
.
playbackParameters
);
offloadSchedulingEnabledChanged
=
previousPlaybackInfo
.
offloadSchedulingEnabled
!=
playbackInfo
.
offloadSchedulingEnabled
;
sleepingForOffloadChanged
=
previousPlaybackInfo
.
sleepingForOffload
!=
playbackInfo
.
sleepingForOffload
;
}
@SuppressWarnings
(
"deprecation"
)
...
...
@@ -1476,6 +1479,12 @@ import java.util.concurrent.TimeoutException;
listener
.
onExperimentalOffloadSchedulingEnabledChanged
(
playbackInfo
.
offloadSchedulingEnabled
));
}
if
(
sleepingForOffloadChanged
)
{
invokeAll
(
listenerSnapshot
,
listener
->
listener
.
onExperimentalSleepingForOffloadChanged
(
playbackInfo
.
sleepingForOffload
));
}
}
private
static
boolean
isPlaying
(
PlaybackInfo
playbackInfo
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
View file @
f37d79a4
...
...
@@ -960,14 +960,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
playbackInfo
=
playbackInfo
.
copyWithOffloadSchedulingEnabled
(
offloadSchedulingEnabled
);
}
boolean
sleepingForOffload
=
false
;
if
((
shouldPlayWhenReady
()
&&
playbackInfo
.
playbackState
==
Player
.
STATE_READY
)
||
playbackInfo
.
playbackState
==
Player
.
STATE_BUFFERING
)
{
maybeScheduleWakeup
(
operationStartTimeMs
,
ACTIVE_INTERVAL_MS
);
sleepingForOffload
=
!
maybeScheduleWakeup
(
operationStartTimeMs
,
ACTIVE_INTERVAL_MS
);
}
else
if
(
enabledRendererCount
!=
0
&&
playbackInfo
.
playbackState
!=
Player
.
STATE_ENDED
)
{
scheduleNextWork
(
operationStartTimeMs
,
IDLE_INTERVAL_MS
);
}
else
{
handler
.
removeMessages
(
MSG_DO_SOME_WORK
);
}
if
(
playbackInfo
.
sleepingForOffload
!=
sleepingForOffload
)
{
playbackInfo
=
playbackInfo
.
copyWithSleepingForOffload
(
sleepingForOffload
);
}
requestForRendererSleep
=
false
;
// A sleep request is only valid for the current doSomeWork.
TraceUtil
.
endSection
();
...
...
@@ -978,12 +982,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
handler
.
sendEmptyMessageAtTime
(
MSG_DO_SOME_WORK
,
thisOperationStartTimeMs
+
intervalMs
);
}
private
void
maybeScheduleWakeup
(
long
operationStartTimeMs
,
long
intervalMs
)
{
private
boolean
maybeScheduleWakeup
(
long
operationStartTimeMs
,
long
intervalMs
)
{
if
(
offloadSchedulingEnabled
&&
requestForRendererSleep
)
{
return
;
return
false
;
}
scheduleNextWork
(
operationStartTimeMs
,
intervalMs
);
return
true
;
}
private
void
seekToInternal
(
SeekPosition
seekPosition
)
throws
ExoPlaybackException
{
...
...
@@ -1308,7 +1313,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
startPositionUs
,
/* totalBufferedDurationUs= */
0
,
startPositionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
/* sleepingForOffload= */
false
);
if
(
releaseMediaSourceList
)
{
mediaSourceList
.
release
();
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/PlaybackInfo.java
View file @
f37d79a4
...
...
@@ -67,6 +67,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
public
final
PlaybackParameters
playbackParameters
;
/** Whether offload scheduling is enabled for the main player loop. */
public
final
boolean
offloadSchedulingEnabled
;
/** Whether the main player loop is sleeping, while using offload scheduling. */
public
final
boolean
sleepingForOffload
;
/**
* Position up to which media is buffered in {@link #loadingMediaPeriodId) relative to the start
...
...
@@ -109,7 +111,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
/* bufferedPositionUs= */
0
,
/* totalBufferedDurationUs= */
0
,
/* positionUs= */
0
,
/* offloadSchedulingEnabled= */
false
);
/* offloadSchedulingEnabled= */
false
,
/* sleepingForOffload= */
false
);
}
/**
...
...
@@ -131,6 +134,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
* @param totalBufferedDurationUs See {@link #totalBufferedDurationUs}.
* @param positionUs See {@link #positionUs}.
* @param offloadSchedulingEnabled See {@link #offloadSchedulingEnabled}.
* @param sleepingForOffload See {@link #sleepingForOffload}.
*/
public
PlaybackInfo
(
Timeline
timeline
,
...
...
@@ -148,7 +152,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
long
bufferedPositionUs
,
long
totalBufferedDurationUs
,
long
positionUs
,
boolean
offloadSchedulingEnabled
)
{
boolean
offloadSchedulingEnabled
,
boolean
sleepingForOffload
)
{
this
.
timeline
=
timeline
;
this
.
periodId
=
periodId
;
this
.
requestedContentPositionUs
=
requestedContentPositionUs
;
...
...
@@ -165,6 +170,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
this
.
totalBufferedDurationUs
=
totalBufferedDurationUs
;
this
.
positionUs
=
positionUs
;
this
.
offloadSchedulingEnabled
=
offloadSchedulingEnabled
;
this
.
sleepingForOffload
=
sleepingForOffload
;
}
/** Returns a placeholder period id for an empty timeline. */
...
...
@@ -209,7 +215,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -236,7 +243,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -263,7 +271,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -290,7 +299,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -317,7 +327,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -344,7 +355,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -375,7 +387,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -402,7 +415,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
...
...
@@ -430,6 +444,35 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
);
offloadSchedulingEnabled
,
sleepingForOffload
);
}
/**
* Copies playback info with new sleepingForOffload.
*
* @param sleepingForOffload New main player loop sleeping state. See {@link #sleepingForOffload}.
* @return Copied playback info with new main player loop sleeping state.
*/
@CheckResult
public
PlaybackInfo
copyWithSleepingForOffload
(
boolean
sleepingForOffload
)
{
return
new
PlaybackInfo
(
timeline
,
periodId
,
requestedContentPositionUs
,
playbackState
,
playbackError
,
isLoading
,
trackGroups
,
trackSelectorResult
,
loadingMediaPeriodId
,
playWhenReady
,
playbackSuppressionReason
,
playbackParameters
,
bufferedPositionUs
,
totalBufferedDurationUs
,
positionUs
,
offloadSchedulingEnabled
,
sleepingForOffload
);
}
}
library/core/src/main/java/com/google/android/exoplayer2/Player.java
View file @
f37d79a4
...
...
@@ -604,6 +604,12 @@ public interface Player {
* <p>This method is experimental, and will be renamed or removed in a future release.
*/
default
void
onExperimentalOffloadSchedulingEnabledChanged
(
boolean
offloadSchedulingEnabled
)
{}
/**
* Called when the player has started or finished sleeping for offload.
*
* <p>This method is experimental, and will be renamed or removed in a future release.
*/
default
void
onExperimentalSleepingForOffloadChanged
(
boolean
sleepingForOffload
)
{}
}
/**
...
...
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
View file @
f37d79a4
...
...
@@ -20,6 +20,7 @@ import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSample
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
TestExoPlayer
.
playUntilStartOfWindow
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
TestExoPlayer
.
runUntilPlaybackState
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
TestExoPlayer
.
runUntilReceiveOffloadSchedulingEnabledNewState
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
TestExoPlayer
.
runUntilSleepingForOffload
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
TestExoPlayer
.
runUntilTimelineChanged
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
TestUtil
.
runMainLooperUntil
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
...
...
@@ -111,7 +112,6 @@ import java.util.Collections;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.TimeoutException
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicLong
;
...
...
@@ -8249,16 +8249,14 @@ public final class ExoPlayerTest {
Timeline
timeline
=
new
FakeTimeline
(
/* windowCount= */
1
);
player
.
setMediaSource
(
new
FakeMediaSource
(
timeline
,
ExoPlayerTestRunner
.
AUDIO_FORMAT
));
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
);
player
.
prepare
();
player
.
play
();
run
MainLooperUntil
(
sleepRenderer:
:
isSleeping
);
run
UntilSleepingForOffload
(
player
,
/* expectedSleepForOffload= */
true
);
player
.
experimentalSetOffloadSchedulingEnabled
(
false
);
assertThat
(
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
)).
isFalse
();
}
@Test
public
void
enableOffloadScheduling_isEnable_playerSleeps
()
throws
Exception
{
FakeSleepRenderer
sleepRenderer
=
new
FakeSleepRenderer
(
C
.
TRACK_TYPE_AUDIO
);
...
...
@@ -8271,14 +8269,7 @@ public final class ExoPlayerTest {
sleepRenderer
.
sleepOnNextRender
();
runMainLooperUntil
(
sleepRenderer:
:
isSleeping
);
// TODO(b/163303129): There is currently no way to check that the player is sleeping for
// offload, for now use a timeout to check that the renderer is never woken up.
final
int
renderTimeoutMs
=
500
;
assertThrows
(
TimeoutException
.
class
,
()
->
runMainLooperUntil
(()
->
!
sleepRenderer
.
isSleeping
(),
renderTimeoutMs
,
Clock
.
DEFAULT
));
runUntilSleepingForOffload
(
player
,
/* expectedSleepForOffload= */
true
);
}
@Test
...
...
@@ -8292,11 +8283,11 @@ public final class ExoPlayerTest {
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
player
.
prepare
();
player
.
play
();
run
MainLooperUntil
(
sleepRenderer:
:
isSleeping
);
run
UntilSleepingForOffload
(
player
,
/* expectedSleepForOffload= */
true
);
player
.
experimentalSetOffloadSchedulingEnabled
(
false
);
// Force the player to exit offload sleep
run
MainLooperUntil
(()
->
!
sleepRenderer
.
isSleeping
()
);
run
UntilSleepingForOffload
(
player
,
/* expectedSleepForOffload= */
false
);
runUntilPlaybackState
(
player
,
Player
.
STATE_ENDED
);
}
...
...
@@ -8309,11 +8300,11 @@ public final class ExoPlayerTest {
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
player
.
prepare
();
player
.
play
();
run
MainLooperUntil
(
sleepRenderer:
:
isSleeping
);
run
UntilSleepingForOffload
(
player
,
/* expectedSleepForOffload= */
true
);
sleepRenderer
.
wakeup
();
run
MainLooperUntil
(()
->
!
sleepRenderer
.
isSleeping
()
);
run
UntilSleepingForOffload
(
player
,
/* expectedSleepForOffload= */
false
);
runUntilPlaybackState
(
player
,
Player
.
STATE_ENDED
);
}
...
...
@@ -8350,13 +8341,11 @@ public final class ExoPlayerTest {
private
static
class
FakeSleepRenderer
extends
FakeRenderer
{
private
static
final
long
WAKEUP_DEADLINE_MS
=
60
*
C
.
MICROS_PER_SECOND
;
private
final
AtomicBoolean
sleepOnNextRender
;
private
final
AtomicBoolean
isSleeping
;
private
final
AtomicReference
<
Renderer
.
WakeupListener
>
wakeupListenerReceiver
;
public
FakeSleepRenderer
(
int
trackType
)
{
super
(
trackType
);
sleepOnNextRender
=
new
AtomicBoolean
(
false
);
isSleeping
=
new
AtomicBoolean
(
false
);
wakeupListenerReceiver
=
new
AtomicReference
<>();
}
...
...
@@ -8372,14 +8361,6 @@ public final class ExoPlayerTest {
return
this
;
}
/**
* Returns whether {@link Renderer.WakeupListener#onSleep(long)} was called on the last {@link
* #render(long, long)}
*/
public
boolean
isSleeping
()
{
return
isSleeping
.
get
();
}
@Override
public
void
handleMessage
(
int
what
,
@Nullable
Object
object
)
throws
ExoPlaybackException
{
if
(
what
==
MSG_SET_WAKEUP_LISTENER
)
{
...
...
@@ -8394,11 +8375,6 @@ public final class ExoPlayerTest {
super
.
render
(
positionUs
,
elapsedRealtimeUs
);
if
(
sleepOnNextRender
.
compareAndSet
(
/* expect= */
true
,
/* update= */
false
))
{
wakeupListenerReceiver
.
get
().
onSleep
(
WAKEUP_DEADLINE_MS
);
// TODO(b/163303129): Use an actual message from the player instead of guessing that the
// player will always sleep for offload after calling `onSleep`.
isSleeping
.
set
(
true
);
}
else
{
isSleeping
.
set
(
false
);
}
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
View file @
f37d79a4
...
...
@@ -439,7 +439,8 @@ public final class MediaPeriodQueueTest {
/* bufferedPositionUs= */
0
,
/* totalBufferedDurationUs= */
0
,
/* positionUs= */
0
,
/* offloadSchedulingEnabled= */
false
);
/* offloadSchedulingEnabled= */
false
,
/* sleepingForOffload= */
false
);
}
private
void
advance
()
{
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/TestExoPlayer.java
View file @
f37d79a4
...
...
@@ -467,6 +467,32 @@ public class TestExoPlayer {
}
/**
* Runs tasks of the main {@link Looper} until a {@link
* Player.EventListener#onExperimentalSleepingForOffloadChanged(boolean)} callback occurred.
*
* @param player The {@link Player}.
* @param expectedSleepForOffload The expected sleep of offload state.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded.
*/
public
static
void
runUntilSleepingForOffload
(
Player
player
,
boolean
expectedSleepForOffload
)
throws
TimeoutException
{
verifyMainTestThread
(
player
);
AtomicBoolean
receiverCallback
=
new
AtomicBoolean
(
false
);
Player
.
EventListener
listener
=
new
Player
.
EventListener
()
{
@Override
public
void
onExperimentalSleepingForOffloadChanged
(
boolean
sleepingForOffload
)
{
if
(
sleepingForOffload
==
expectedSleepForOffload
)
{
receiverCallback
.
set
(
true
);
}
}
};
player
.
addListener
(
listener
);
runMainLooperUntil
(
receiverCallback:
:
get
);
}
/**
* Runs tasks of the main {@link Looper} until the {@link VideoListener#onRenderedFirstFrame}
* callback has been called.
*
...
...
@@ -504,7 +530,7 @@ public class TestExoPlayer {
verifyMainTestThread
(
player
);
Handler
testHandler
=
Util
.
createHandlerForCurrentOrMainLooper
();
AtomicBoolean
messageHandled
=
new
AtomicBoolean
();
AtomicBoolean
messageHandled
=
new
AtomicBoolean
(
false
);
player
.
createMessage
(
(
messageType
,
payload
)
->
{
...
...
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