Enable offload scheduling by default for audio-only offload playback
Removed `ExoPlayer.experimentalSetOffloadSchedulingEnabled` as scheduling will be enabled by default when offload is enabled for audio-only playback. In addition, the `experimental` key word was taken out of the following method signatures: * `ExoPlayer.experimentalIsSleepingForOffload` * `AudioOffloadListener.onExperimentalSleepingForOffloadChanged` * `AudioOffloadListener.onExperimentalOffloadedPlayback` PiperOrigin-RevId: 565035289
This commit is contained in:
parent
abaf3e7aa1
commit
85c944b955
@ -35,6 +35,12 @@
|
||||
* Add support for Opus gapless metadata during offload playback.
|
||||
* Allow renderer recovery by disabling offload if failed at first write
|
||||
([#627](https://github.com/androidx/media/issues/627)).
|
||||
* Enable Offload Scheduling by default for audio-only offloaded playback.
|
||||
* Delete `ExoPlayer.experimentalSetOffloadSchedulingEnabled` and
|
||||
`AudioOffloadListener.onExperimentalOffloadSchedulingEnabledChanged`.
|
||||
* Renamed `onExperimentalSleepingForOffloadChanged` as
|
||||
`onSleepingForOffloadChanged` and `onExperimentalOffloadedPlayback` as
|
||||
`onOffloadedPlayback`.
|
||||
* Video:
|
||||
* Text:
|
||||
* Metadata:
|
||||
|
@ -421,37 +421,24 @@ public interface ExoPlayer extends Player {
|
||||
void setDeviceMuted(boolean muted);
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener for audio offload events.
|
||||
*
|
||||
* <p>This class is experimental, and might be renamed, moved or removed in a future release.
|
||||
*/
|
||||
/** A listener for audio offload events. */
|
||||
@UnstableApi
|
||||
interface AudioOffloadListener {
|
||||
/**
|
||||
* Called when the player has started or stopped offload scheduling using {@link
|
||||
* #experimentalSetOffloadSchedulingEnabled(boolean)}.
|
||||
* Called when the value of {@link #isSleepingForOffload} changes.
|
||||
*
|
||||
* <p>This method is experimental, and will be renamed or removed in a future release.
|
||||
* <p>When {@code isSleepingForOffload} is {@code true} then, the player has paused its main
|
||||
* loop to save power in offload scheduling mode.
|
||||
*/
|
||||
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) {}
|
||||
default void onSleepingForOffloadChanged(boolean isSleepingForOffload) {}
|
||||
|
||||
/**
|
||||
* Called when the value of {@link AudioTrack#isOffloadedPlayback} changes.
|
||||
*
|
||||
* <p>This should not be generally required to be acted upon. But when offload is critical for
|
||||
* efficiency, or audio features (gapless, playback speed), this will let the app know.
|
||||
*
|
||||
* <p>This method is experimental, and will be renamed or removed in a future release.
|
||||
*/
|
||||
default void onExperimentalOffloadedPlayback(boolean offloadedPlayback) {}
|
||||
default void onOffloadedPlayback(boolean isOffloadedPlayback) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1827,24 +1814,13 @@ public interface ExoPlayer extends Player {
|
||||
void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager);
|
||||
|
||||
/**
|
||||
* Sets whether audio offload scheduling is enabled. If enabled, ExoPlayer's main loop will run as
|
||||
* rarely as possible when playing an audio stream using audio offload.
|
||||
* Returns whether the player has paused its main loop to save power in offload scheduling mode.
|
||||
*
|
||||
* <p>Only use this scheduling mode if the player is not displaying anything to the user. For
|
||||
* example when the application is in the background, or the screen is off. The player state
|
||||
* (including position) is rarely updated (roughly between every 10 seconds and 1 minute).
|
||||
* <p>Offload scheduling mode should save significant power when the phone is playing offload
|
||||
* audio with the screen off.
|
||||
*
|
||||
* <p>While offload scheduling is enabled, player events may be delivered severely delayed and
|
||||
* apps should not interact with the player. When returning to the foreground, disable offload
|
||||
* scheduling and wait for {@link
|
||||
* AudioOffloadListener#onExperimentalOffloadSchedulingEnabledChanged(boolean)} to be called with
|
||||
* {@code offloadSchedulingEnabled = false} before interacting with the player.
|
||||
*
|
||||
* <p>This mode should save significant power when the phone is playing offload audio with the
|
||||
* screen off.
|
||||
*
|
||||
* <p>This mode only has an effect when playing an audio track in offload mode, which requires all
|
||||
* the following:
|
||||
* <p>Offload scheduling is only enabled when playing an audio track in offload mode, which
|
||||
* requires all the following:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Audio offload rendering is enabled through {@link
|
||||
@ -1854,24 +1830,10 @@ public interface ExoPlayer extends Player {
|
||||
* <li>The {@link AudioSink} is playing with an offload {@link AudioTrack}.
|
||||
* </ul>
|
||||
*
|
||||
* <p>The state where ExoPlayer main loop has been paused to save power during offload playback
|
||||
* can be queried with {@link #experimentalIsSleepingForOffload()}.
|
||||
*
|
||||
* <p>This method is experimental, and will be renamed or removed in a future release.
|
||||
*
|
||||
* @param offloadSchedulingEnabled Whether to enable offload scheduling.
|
||||
* @see AudioOffloadListener#onSleepingForOffloadChanged(boolean)
|
||||
*/
|
||||
@UnstableApi
|
||||
void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled);
|
||||
|
||||
/**
|
||||
* Returns whether the player has paused its main loop to save power in offload scheduling mode.
|
||||
*
|
||||
* @see #experimentalSetOffloadSchedulingEnabled(boolean)
|
||||
* @see AudioOffloadListener#onExperimentalSleepingForOffloadChanged(boolean)
|
||||
*/
|
||||
@UnstableApi
|
||||
boolean experimentalIsSleepingForOffload();
|
||||
boolean isSleepingForOffload();
|
||||
|
||||
/**
|
||||
* Returns whether <a
|
||||
|
@ -466,16 +466,7 @@ import java.util.concurrent.TimeoutException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) {
|
||||
verifyApplicationThread();
|
||||
internalPlayer.experimentalSetOffloadSchedulingEnabled(offloadSchedulingEnabled);
|
||||
for (AudioOffloadListener listener : audioOffloadListeners) {
|
||||
listener.onExperimentalOffloadSchedulingEnabledChanged(offloadSchedulingEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean experimentalIsSleepingForOffload() {
|
||||
public boolean isSleepingForOffload() {
|
||||
verifyApplicationThread();
|
||||
return playbackInfo.sleepingForOffload;
|
||||
}
|
||||
@ -2135,7 +2126,7 @@ import java.util.concurrent.TimeoutException;
|
||||
|
||||
if (previousPlaybackInfo.sleepingForOffload != newPlaybackInfo.sleepingForOffload) {
|
||||
for (AudioOffloadListener listener : audioOffloadListeners) {
|
||||
listener.onExperimentalSleepingForOffloadChanged(newPlaybackInfo.sleepingForOffload);
|
||||
listener.onSleepingForOffloadChanged(newPlaybackInfo.sleepingForOffload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2817,7 +2808,7 @@ import java.util.concurrent.TimeoutException;
|
||||
switch (playbackState) {
|
||||
case Player.STATE_READY:
|
||||
case Player.STATE_BUFFERING:
|
||||
boolean isSleeping = experimentalIsSleepingForOffload();
|
||||
boolean isSleeping = isSleepingForOffload();
|
||||
wakeLockManager.setStayAwake(getPlayWhenReady() && !isSleeping);
|
||||
// The wifi lock is not released while sleeping to avoid interrupting downloads.
|
||||
wifiLockManager.setStayAwake(getPlayWhenReady());
|
||||
@ -3262,7 +3253,7 @@ import java.util.concurrent.TimeoutException;
|
||||
// Player.AudioOffloadListener implementation.
|
||||
|
||||
@Override
|
||||
public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) {
|
||||
public void onSleepingForOffloadChanged(boolean sleepingForOffload) {
|
||||
updateWakeAndWifiLock();
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package androidx.media3.exoplayer;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Util.castNonNull;
|
||||
import static androidx.media3.common.util.Util.msToUs;
|
||||
import static androidx.media3.exoplayer.audio.AudioSink.OFFLOAD_MODE_DISABLED;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
@ -164,7 +165,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
private static final int MSG_SET_SHUFFLE_ORDER = 21;
|
||||
private static final int MSG_PLAYLIST_UPDATE_REQUESTED = 22;
|
||||
private static final int MSG_SET_PAUSE_AT_END_OF_WINDOW = 23;
|
||||
private static final int MSG_SET_OFFLOAD_SCHEDULING_ENABLED = 24;
|
||||
private static final int MSG_ATTEMPT_RENDERER_ERROR_RECOVERY = 25;
|
||||
private static final int MSG_RENDERER_CAPABILITIES_CHANGED = 26;
|
||||
private static final int MSG_UPDATE_MEDIA_SOURCES_WITH_MEDIA_ITEMS = 27;
|
||||
@ -317,13 +317,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
this.setForegroundModeTimeoutMs = setForegroundModeTimeoutMs;
|
||||
}
|
||||
|
||||
public void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) {
|
||||
handler
|
||||
.obtainMessage(
|
||||
MSG_SET_OFFLOAD_SCHEDULING_ENABLED, offloadSchedulingEnabled ? 1 : 0, /* unused */ 0)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
public void prepare() {
|
||||
handler.obtainMessage(MSG_PREPARE).sendToTarget();
|
||||
}
|
||||
@ -590,9 +583,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
case MSG_SET_PAUSE_AT_END_OF_WINDOW:
|
||||
setPauseAtEndOfWindowInternal(msg.arg1 != 0);
|
||||
break;
|
||||
case MSG_SET_OFFLOAD_SCHEDULING_ENABLED:
|
||||
setOffloadSchedulingEnabledInternal(msg.arg1 == 1);
|
||||
break;
|
||||
case MSG_ATTEMPT_RENDERER_ERROR_RECOVERY:
|
||||
attemptRendererErrorRecovery();
|
||||
break;
|
||||
@ -891,7 +881,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
}
|
||||
|
||||
private void setOffloadSchedulingEnabledInternal(boolean offloadSchedulingEnabled) {
|
||||
private void setOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) {
|
||||
if (offloadSchedulingEnabled == this.offloadSchedulingEnabled) {
|
||||
return;
|
||||
}
|
||||
@ -2301,6 +2291,30 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeUpdateOffloadScheduling() {
|
||||
// If playing period is audio-only with offload mode preference to enable, then offload
|
||||
// scheduling should be enabled.
|
||||
@Nullable MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
||||
if (playingPeriodHolder != null) {
|
||||
TrackSelectorResult trackSelectorResult = playingPeriodHolder.getTrackSelectorResult();
|
||||
boolean isAudioRendererEnabledAndOffloadPreferred = false;
|
||||
boolean isAudioOnly = true;
|
||||
for (int i = 0; i < renderers.length; i++) {
|
||||
if (trackSelectorResult.isRendererEnabled(i)) {
|
||||
if (renderers[i].getTrackType() != C.TRACK_TYPE_AUDIO) {
|
||||
isAudioOnly = false;
|
||||
break;
|
||||
}
|
||||
if (trackSelectorResult.rendererConfigurations[i].offloadModePreferred
|
||||
!= OFFLOAD_MODE_DISABLED) {
|
||||
isAudioRendererEnabledAndOffloadPreferred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
setOffloadSchedulingEnabled(isAudioRendererEnabledAndOffloadPreferred && isAudioOnly);
|
||||
}
|
||||
}
|
||||
|
||||
private void allowRenderersToRenderStartOfStreams() {
|
||||
TrackSelectorResult playingTracks = queue.getPlayingPeriod().getTrackSelectorResult();
|
||||
for (int i = 0; i < renderers.length; i++) {
|
||||
@ -2546,6 +2560,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
playingPeriodHolder.info =
|
||||
playingPeriodHolder.info.copyWithRequestedContentPositionUs(requestedContentPositionUs);
|
||||
}
|
||||
maybeUpdateOffloadScheduling();
|
||||
} else if (!mediaPeriodId.equals(playbackInfo.periodId)) {
|
||||
// Reset previously kept track info if unprepared and the period changes.
|
||||
trackGroupArray = TrackGroupArray.EMPTY;
|
||||
|
@ -446,15 +446,9 @@ public class SimpleExoPlayer extends BasePlayer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) {
|
||||
public boolean isSleepingForOffload() {
|
||||
blockUntilConstructorFinished();
|
||||
player.experimentalSetOffloadSchedulingEnabled(offloadSchedulingEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean experimentalIsSleepingForOffload() {
|
||||
blockUntilConstructorFinished();
|
||||
return player.experimentalIsSleepingForOffload();
|
||||
return player.isSleepingForOffload();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1024,7 +1024,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
AudioTrack audioTrack =
|
||||
configuration.buildAudioTrack(tunneling, audioAttributes, audioSessionId);
|
||||
if (audioOffloadListener != null) {
|
||||
audioOffloadListener.onExperimentalOffloadedPlayback(isOffloadedPlayback(audioTrack));
|
||||
audioOffloadListener.onOffloadedPlayback(isOffloadedPlayback(audioTrack));
|
||||
}
|
||||
return audioTrack;
|
||||
} catch (InitializationException e) {
|
||||
|
@ -121,6 +121,7 @@ import androidx.media3.common.Player.PositionInfo;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.Timeline.Window;
|
||||
import androidx.media3.common.TrackGroup;
|
||||
import androidx.media3.common.TrackSelectionParameters;
|
||||
import androidx.media3.common.Tracks;
|
||||
import androidx.media3.common.VideoSize;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
@ -10198,53 +10199,118 @@ public final class ExoPlayerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableOffloadScheduling_isReported() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
ExoPlayer.AudioOffloadListener mockListener = mock(ExoPlayer.AudioOffloadListener.class);
|
||||
player.addAudioOffloadListener(mockListener);
|
||||
|
||||
player.experimentalSetOffloadSchedulingEnabled(true);
|
||||
verify(mockListener).onExperimentalOffloadSchedulingEnabledChanged(true);
|
||||
|
||||
player.experimentalSetOffloadSchedulingEnabled(false);
|
||||
verify(mockListener).onExperimentalOffloadSchedulingEnabledChanged(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableOffloadScheduling_isEnable_playerSleeps() throws Exception {
|
||||
public void enablingOffload_withAudioOnly_playerSleeps() throws Exception {
|
||||
FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO);
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(sleepRenderer).build();
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.experimentalSetOffloadSchedulingEnabled(true);
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
player.prepare();
|
||||
player.play();
|
||||
|
||||
sleepRenderer.sleepOnNextRender();
|
||||
|
||||
runUntilSleepingForOffload(player, /* expectedSleepForOffload= */ true);
|
||||
assertThat(player.experimentalIsSleepingForOffload()).isTrue();
|
||||
|
||||
assertThat(player.isSleepingForOffload()).isTrue();
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
experimentalEnableOffloadSchedulingWhileSleepingForOffload_isDisabled_renderingResumes()
|
||||
throws Exception {
|
||||
public void enablingOffloadDuringPlayback_withAudioOnly_playerSleeps() throws Exception {
|
||||
FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO);
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(sleepRenderer).build();
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.prepare();
|
||||
player.play();
|
||||
runUntilPlaybackState(player, Player.STATE_READY);
|
||||
sleepRenderer.sleepOnNextRender();
|
||||
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
runUntilSleepingForOffload(player, /* expectedSleepForOffload= */ true);
|
||||
|
||||
assertThat(player.isSleepingForOffload()).isTrue();
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableOffloadScheduling_whenPlayerSleeps_callsOnSleepingForOffloadChanged()
|
||||
throws Exception {
|
||||
FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO);
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(sleepRenderer).build();
|
||||
ExoPlayer.AudioOffloadListener mockListener = mock(ExoPlayer.AudioOffloadListener.class);
|
||||
player.addAudioOffloadListener(mockListener);
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
player.prepare();
|
||||
player.play();
|
||||
|
||||
sleepRenderer.sleepOnNextRender();
|
||||
runUntilSleepingForOffload(player, /* expectedSleepForOffload= */ true);
|
||||
|
||||
verify(mockListener).onSleepingForOffloadChanged(true);
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableOffloadScheduling_whenOffloadIsDisabled_renderingResumes() throws Exception {
|
||||
FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO).sleepOnNextRender();
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(sleepRenderer).build();
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.experimentalSetOffloadSchedulingEnabled(true);
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
player.prepare();
|
||||
player.play();
|
||||
runUntilSleepingForOffload(player, /* expectedSleepForOffload= */ true);
|
||||
|
||||
player.experimentalSetOffloadSchedulingEnabled(false); // Force the player to exit offload sleep
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_DISABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
|
||||
runUntilSleepingForOffload(player, /* expectedSleepForOffload= */ false);
|
||||
assertThat(player.experimentalIsSleepingForOffload()).isFalse();
|
||||
assertThat(player.isSleepingForOffload()).isFalse();
|
||||
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
|
||||
player.release();
|
||||
@ -10256,22 +10322,29 @@ public final class ExoPlayerTest {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(sleepRenderer).build();
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.experimentalSetOffloadSchedulingEnabled(true);
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
player.prepare();
|
||||
player.play();
|
||||
runUntilSleepingForOffload(player, /* expectedSleepForOffload= */ true);
|
||||
|
||||
sleepRenderer.wakeup();
|
||||
|
||||
runUntilSleepingForOffload(player, /* expectedSleepForOffload= */ false);
|
||||
assertThat(player.experimentalIsSleepingForOffload()).isFalse();
|
||||
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
assertThat(player.isSleepingForOffload()).isFalse();
|
||||
|
||||
runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableOffloadScheduling_duringSleepGetCurrentPosition_returnsEstimatedPosition()
|
||||
public void enableOffload_duringSleepGetCurrentPosition_returnsEstimatedPosition()
|
||||
throws Exception {
|
||||
FakeClock fakeClock =
|
||||
new FakeClock(/* initialTimeMs= */ 987_654_321L, /* isAutoAdvancing= */ true);
|
||||
@ -10280,7 +10353,15 @@ public final class ExoPlayerTest {
|
||||
new TestExoPlayerBuilder(context).setClock(fakeClock).setRenderers(sleepRenderer).build();
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.experimentalSetOffloadSchedulingEnabled(true);
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
player.prepare();
|
||||
player.play();
|
||||
sleepRenderer.sleepOnNextRender();
|
||||
@ -10297,7 +10378,7 @@ public final class ExoPlayerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableOffloadScheduling_pauseAndSeekDuringSleep_currentPositionIsSeekedPosition()
|
||||
public void enableOffload_pauseAndSeekDuringSleep_currentPositionIsSeekedPosition()
|
||||
throws Exception {
|
||||
FakeClock fakeClock =
|
||||
new FakeClock(/* initialTimeMs= */ 987_654_321L, /* isAutoAdvancing= */ true);
|
||||
@ -10306,7 +10387,15 @@ public final class ExoPlayerTest {
|
||||
new TestExoPlayerBuilder(context).setClock(fakeClock).setRenderers(sleepRenderer).build();
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.experimentalSetOffloadSchedulingEnabled(true);
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
player.prepare();
|
||||
player.play();
|
||||
sleepRenderer.sleepOnNextRender();
|
||||
@ -10324,7 +10413,7 @@ public final class ExoPlayerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableOffloadScheduling_seekThenPauseDuringSleep_returnsEstimatePositionByPauseTime()
|
||||
public void enableOffload_seekThenPauseDuringSleep_returnsEstimatePositionByPauseTime()
|
||||
throws Exception {
|
||||
FakeClock fakeClock =
|
||||
new FakeClock(/* initialTimeMs= */ 987_654_321L, /* isAutoAdvancing= */ true);
|
||||
@ -10333,7 +10422,15 @@ public final class ExoPlayerTest {
|
||||
new TestExoPlayerBuilder(context).setClock(fakeClock).setRenderers(sleepRenderer).build();
|
||||
Timeline timeline = new FakeTimeline();
|
||||
player.setMediaSource(new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT));
|
||||
player.experimentalSetOffloadSchedulingEnabled(true);
|
||||
player.setTrackSelectionParameters(
|
||||
player
|
||||
.getTrackSelectionParameters()
|
||||
.buildUpon()
|
||||
.setAudioOffloadPreference(
|
||||
TrackSelectionParameters.AUDIO_OFFLOAD_MODE_PREFERENCE_ENABLED,
|
||||
/* isGaplessSupportRequired= */ false,
|
||||
/* isSpeedChangeSupportRequired= */ false)
|
||||
.build());
|
||||
player.prepare();
|
||||
player.play();
|
||||
sleepRenderer.sleepOnNextRender();
|
||||
@ -14098,6 +14195,16 @@ public final class ExoPlayerTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Capabilities int supportsFormat(Format format) throws ExoPlaybackException {
|
||||
@Capabilities int rendererCapabilities = super.supportsFormat(format);
|
||||
if (RendererCapabilities.getFormatSupport(rendererCapabilities) == C.FORMAT_HANDLED
|
||||
&& getTrackType() == C.TRACK_TYPE_AUDIO) {
|
||||
rendererCapabilities |= AUDIO_OFFLOAD_SUPPORTED;
|
||||
}
|
||||
return rendererCapabilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(@MessageType int messageType, @Nullable Object message)
|
||||
throws ExoPlaybackException {
|
||||
|
@ -398,12 +398,7 @@ public class StubExoPlayer extends StubPlayer implements ExoPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean experimentalIsSleepingForOffload() {
|
||||
public boolean isSleepingForOffload() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -225,8 +225,8 @@ public class TestPlayerRunHelper {
|
||||
|
||||
/**
|
||||
* Runs tasks of the main {@link Looper} until {@link
|
||||
* ExoPlayer.AudioOffloadListener#onExperimentalSleepingForOffloadChanged(boolean)} is called or a
|
||||
* playback error occurs.
|
||||
* ExoPlayer.AudioOffloadListener#onSleepingForOffloadChanged(boolean)} is called or a playback
|
||||
* error occurs.
|
||||
*
|
||||
* <p>If a playback error occurs it will be thrown wrapped in an {@link IllegalStateException}.
|
||||
*
|
||||
@ -244,7 +244,7 @@ public class TestPlayerRunHelper {
|
||||
ExoPlayer.AudioOffloadListener listener =
|
||||
new ExoPlayer.AudioOffloadListener() {
|
||||
@Override
|
||||
public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) {
|
||||
public void onSleepingForOffloadChanged(boolean sleepingForOffload) {
|
||||
if (sleepingForOffload == expectedSleepForOffload) {
|
||||
receiverCallback.set(true);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user