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
This commit is contained in:
michaelkatz 2025-04-03 04:13:23 -07:00 committed by Copybara-Service
parent 18e9a3fe36
commit 8327a2a52d
3 changed files with 55 additions and 0 deletions

View File

@ -36,6 +36,9 @@
* DataSource:
* Audio:
* 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:
* Add experimental `ExoPlayer` API to include the
`MediaCodec.BUFFER_FLAG_DECODE_ONLY` flag when queuing decode-only input

View File

@ -2820,6 +2820,10 @@ import java.util.Objects;
private void maybeUpdateOffloadScheduling() {
// If playing period is audio-only with offload mode preference to enable, then offload
// 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();
if (playingPeriodHolder != null) {
TrackSelectorResult trackSelectorResult = playingPeriodHolder.getTrackSelectorResult();

View File

@ -11787,6 +11787,54 @@ public final class ExoPlayerTest {
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
public void wakeupListenerWhileSleepingForOffload_isWokenUp_renderingResumes() throws Exception {
FakeSleepRenderer sleepRenderer = new FakeSleepRenderer(C.TRACK_TYPE_AUDIO).sleepOnNextRender();