Do not enable offload scheduling while preparing next media

ExoPlayer disables sleeping for offload when the reading period advances and re-evaluates turning it back on when the playing period advances. For playlists of short items where the reading period could advance much further than the playing period, sleeping should still be disabled until the playing period advances to match the current reading period.

Issue: androidx/media#1920
PiperOrigin-RevId: 743503063
(cherry picked from commit 8327a2a52dd72a98d4abc123f33cfe1250898318)
This commit is contained in:
michaelkatz 2025-04-03 04:13:23 -07:00 committed by tonihei
parent cb80fe4c7c
commit 9cfaf78994
3 changed files with 55 additions and 0 deletions

View File

@ -39,6 +39,9 @@
* DataSource: * DataSource:
* Audio: * Audio:
* Allow constant power upmixing/downmixing in DefaultAudioMixer. * Allow constant power upmixing/downmixing in DefaultAudioMixer.
* Fix offload issue where position might get stuck when playing a playlist
of short content
([#1920](https://github.com/androidx/media/issues/1920)).
* Video: * Video:
* Add experimental `ExoPlayer` API to include the * Add experimental `ExoPlayer` API to include the
`MediaCodec.BUFFER_FLAG_DECODE_ONLY` flag when queuing decode-only input `MediaCodec.BUFFER_FLAG_DECODE_ONLY` flag when queuing decode-only input

View File

@ -2783,6 +2783,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void maybeUpdateOffloadScheduling() { private void maybeUpdateOffloadScheduling() {
// If playing period is audio-only with offload mode preference to enable, then offload // If playing period is audio-only with offload mode preference to enable, then offload
// scheduling should be enabled. // scheduling should be enabled.
if (queue.getPlayingPeriod() != queue.getReadingPeriod()) {
// Do not enable offload scheduling when starting to process the next media item.
return;
}
@Nullable MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod(); @Nullable MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
if (playingPeriodHolder != null) { if (playingPeriodHolder != null) {
TrackSelectorResult trackSelectorResult = playingPeriodHolder.getTrackSelectorResult(); TrackSelectorResult trackSelectorResult = playingPeriodHolder.getTrackSelectorResult();

View File

@ -11786,6 +11786,54 @@ public class ExoPlayerTest {
player.release(); player.release();
} }
@Test
public void enablingOffload_withFastReadingPeriodAdvancement_playerDoesNotSleep()
throws Exception {
FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO);
AtomicInteger sleepingForOffloadCounter = new AtomicInteger();
ExoPlayer player =
parameterizeTestExoPlayerBuilder(
new TestExoPlayerBuilder(context).setRenderers(sleepRenderer))
.build();
ExoPlayer.AudioOffloadListener listener =
new ExoPlayer.AudioOffloadListener() {
@Override
public void onSleepingForOffloadChanged(boolean sleepingForOffload) {
if (sleepingForOffload) {
sleepingForOffloadCounter.getAndIncrement();
}
}
};
player.addAudioOffloadListener(listener);
// Set a playlist of multiple, short audio-only items such that the reading period quickly
// advances past the playing period.
Timeline timeline = new FakeTimeline();
player.setMediaSources(
ImmutableList.of(
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT),
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT),
new FakeMediaSource(timeline, ExoPlayerTestRunner.AUDIO_FORMAT)));
player.setTrackSelectionParameters(
player
.getTrackSelectionParameters()
.buildUpon()
.setAudioOffloadPreferences(
new AudioOffloadPreferences.Builder()
.setAudioOffloadMode(AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_REQUIRED)
.build())
.build());
player.prepare();
player.play();
advance(player).untilStartOfMediaItem(/* mediaItemIndex= */ 1);
sleepRenderer.sleepOnNextRender();
runUntilPlaybackState(player, Player.STATE_ENDED);
assertThat(sleepingForOffloadCounter.get()).isEqualTo(0);
player.release();
}
@Test @Test
public void wakeupListenerWhileSleepingForOffload_isWokenUp_renderingResumes() throws Exception { public void wakeupListenerWhileSleepingForOffload_isWokenUp_renderingResumes() throws Exception {
FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO).sleepOnNextRender(); FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO).sleepOnNextRender();