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
19e6de77
authored
Sep 10, 2020
by
krocard
Committed by
Oliver Woodman
Sep 11, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Introduce audio offload scheduling tests
PiperOrigin-RevId: 330918396
parent
362d4f5b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
190 additions
and
0 deletions
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/TestExoPlayer.java
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
View file @
19e6de77
...
...
@@ -19,6 +19,7 @@ import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSample
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
FakeSampleStream
.
FakeSampleStreamItem
.
oneByteSample
;
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
.
runUntilTimelineChanged
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
TestUtil
.
runMainLooperUntil
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
...
...
@@ -110,6 +111,7 @@ 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
;
...
...
@@ -8208,6 +8210,109 @@ public final class ExoPlayerTest {
assertThat
(
player
.
getCurrentWindowIndex
()).
isEqualTo
(
0
);
}
@Test
public
void
enableOffloadSchedulingWhileIdle_isToggled_isReported
()
throws
Exception
{
SimpleExoPlayer
player
=
new
TestExoPlayer
.
Builder
(
context
).
build
();
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
assertThat
(
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
)).
isTrue
();
player
.
experimentalSetOffloadSchedulingEnabled
(
false
);
assertThat
(
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
)).
isFalse
();
}
@Test
public
void
enableOffloadSchedulingWhilePlaying_isToggled_isReported
()
throws
Exception
{
FakeSleepRenderer
sleepRenderer
=
new
FakeSleepRenderer
(
C
.
TRACK_TYPE_AUDIO
).
sleepOnNextRender
();
SimpleExoPlayer
player
=
new
TestExoPlayer
.
Builder
(
context
).
setRenderers
(
sleepRenderer
).
build
();
Timeline
timeline
=
new
FakeTimeline
(
/* windowCount= */
1
);
player
.
setMediaSource
(
new
FakeMediaSource
(
timeline
,
ExoPlayerTestRunner
.
AUDIO_FORMAT
));
player
.
prepare
();
player
.
play
();
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
assertThat
(
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
)).
isTrue
();
player
.
experimentalSetOffloadSchedulingEnabled
(
false
);
assertThat
(
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
)).
isFalse
();
}
@Test
public
void
enableOffloadSchedulingWhileSleepingForOffload_isDisabled_isReported
()
throws
Exception
{
FakeSleepRenderer
sleepRenderer
=
new
FakeSleepRenderer
(
C
.
TRACK_TYPE_AUDIO
).
sleepOnNextRender
();
SimpleExoPlayer
player
=
new
TestExoPlayer
.
Builder
(
context
).
setRenderers
(
sleepRenderer
).
build
();
Timeline
timeline
=
new
FakeTimeline
(
/* windowCount= */
1
);
player
.
setMediaSource
(
new
FakeMediaSource
(
timeline
,
ExoPlayerTestRunner
.
AUDIO_FORMAT
));
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
);
player
.
prepare
();
player
.
play
();
runMainLooperUntil
(
sleepRenderer:
:
isSleeping
);
player
.
experimentalSetOffloadSchedulingEnabled
(
false
);
assertThat
(
runUntilReceiveOffloadSchedulingEnabledNewState
(
player
)).
isFalse
();
}
@Test
public
void
enableOffloadScheduling_isEnable_playerSleeps
()
throws
Exception
{
FakeSleepRenderer
sleepRenderer
=
new
FakeSleepRenderer
(
C
.
TRACK_TYPE_AUDIO
);
SimpleExoPlayer
player
=
new
TestExoPlayer
.
Builder
(
context
).
setRenderers
(
sleepRenderer
).
build
();
Timeline
timeline
=
new
FakeTimeline
(
/* windowCount= */
1
);
player
.
setMediaSource
(
new
FakeMediaSource
(
timeline
,
ExoPlayerTestRunner
.
AUDIO_FORMAT
));
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
player
.
prepare
();
player
.
play
();
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
));
}
@Test
public
void
experimentalEnableOffloadSchedulingWhileSleepingForOffload_isDisabled_renderingResumes
()
throws
Exception
{
FakeSleepRenderer
sleepRenderer
=
new
FakeSleepRenderer
(
C
.
TRACK_TYPE_AUDIO
).
sleepOnNextRender
();
SimpleExoPlayer
player
=
new
TestExoPlayer
.
Builder
(
context
).
setRenderers
(
sleepRenderer
).
build
();
Timeline
timeline
=
new
FakeTimeline
(
/* windowCount= */
1
);
player
.
setMediaSource
(
new
FakeMediaSource
(
timeline
,
ExoPlayerTestRunner
.
AUDIO_FORMAT
));
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
player
.
prepare
();
player
.
play
();
runMainLooperUntil
(
sleepRenderer:
:
isSleeping
);
player
.
experimentalSetOffloadSchedulingEnabled
(
false
);
// Force the player to exit offload sleep
runMainLooperUntil
(()
->
!
sleepRenderer
.
isSleeping
());
runUntilPlaybackState
(
player
,
Player
.
STATE_ENDED
);
}
@Test
public
void
wakeupListenerWhileSleepingForOffload_isWokenUp_renderingResumes
()
throws
Exception
{
FakeSleepRenderer
sleepRenderer
=
new
FakeSleepRenderer
(
C
.
TRACK_TYPE_AUDIO
).
sleepOnNextRender
();
SimpleExoPlayer
player
=
new
TestExoPlayer
.
Builder
(
context
).
setRenderers
(
sleepRenderer
).
build
();
Timeline
timeline
=
new
FakeTimeline
(
/* windowCount= */
1
);
player
.
setMediaSource
(
new
FakeMediaSource
(
timeline
,
ExoPlayerTestRunner
.
AUDIO_FORMAT
));
player
.
experimentalSetOffloadSchedulingEnabled
(
true
);
player
.
prepare
();
player
.
play
();
runMainLooperUntil
(
sleepRenderer:
:
isSleeping
);
sleepRenderer
.
wakeup
();
runMainLooperUntil
(()
->
!
sleepRenderer
.
isSleeping
());
runUntilPlaybackState
(
player
,
Player
.
STATE_ENDED
);
}
// Internal methods.
private
static
ActionSchedule
.
Builder
addSurfaceSwitch
(
ActionSchedule
.
Builder
builder
)
{
...
...
@@ -8237,6 +8342,63 @@ public final class ExoPlayerTest {
// Internal classes.
/* {@link FakeRenderer} that can sleep and be woken-up. */
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
<>();
}
public
void
wakeup
()
{
wakeupListenerReceiver
.
get
().
onWakeup
();
}
/**
* Call {@link Renderer.WakeupListener#onSleep(long)} on the next {@link #render(long, long)}
*/
public
FakeSleepRenderer
sleepOnNextRender
()
{
sleepOnNextRender
.
set
(
true
);
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
)
{
assertThat
(
object
).
isNotNull
();
wakeupListenerReceiver
.
set
((
WakeupListener
)
object
);
}
super
.
handleMessage
(
what
,
object
);
}
@Override
public
void
render
(
long
positionUs
,
long
elapsedRealtimeUs
)
throws
ExoPlaybackException
{
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
);
}
}
}
private
static
final
class
CountingMessageTarget
implements
PlayerMessage
.
Target
{
public
int
messageCount
;
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/TestExoPlayer.java
View file @
19e6de77
...
...
@@ -44,6 +44,7 @@ import com.google.android.exoplayer2.video.VideoListener;
import
java.util.concurrent.TimeoutException
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
java.util.concurrent.atomic.AtomicReference
;
import
org.checkerframework.checker.nullness.compatqual.NullableType
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
...
...
@@ -439,6 +440,33 @@ public class TestExoPlayer {
}
/**
* Runs tasks of the main {@link Looper} until a {@link
* Player.EventListener#onExperimentalOffloadSchedulingEnabledChanged} callback occurred.
*
* @param player The {@link Player}.
* @return The new offloadSchedulingEnabled state.
* @throws TimeoutException If the {@link TestUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded.
*/
public
static
boolean
runUntilReceiveOffloadSchedulingEnabledNewState
(
Player
player
)
throws
TimeoutException
{
verifyMainTestThread
(
player
);
AtomicReference
<
@NullableType
Boolean
>
offloadSchedulingEnabledReceiver
=
new
AtomicReference
<>();
Player
.
EventListener
listener
=
new
Player
.
EventListener
()
{
@Override
public
void
onExperimentalOffloadSchedulingEnabledChanged
(
boolean
offloadSchedulingEnabled
)
{
offloadSchedulingEnabledReceiver
.
set
(
offloadSchedulingEnabled
);
}
};
player
.
addListener
(
listener
);
runMainLooperUntil
(()
->
offloadSchedulingEnabledReceiver
.
get
()
!=
null
);
return
Assertions
.
checkNotNull
(
offloadSchedulingEnabledReceiver
.
get
());
}
/**
* Runs tasks of the main {@link Looper} until the {@link VideoListener#onRenderedFirstFrame}
* callback has been called.
*
...
...
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