Add ExoPlayer.setPriority
This lets apps update the task manager priority and send the priority message to all renderers so that they can adjust their resources if needed. PiperOrigin-RevId: 629426058
This commit is contained in:
parent
72013446c4
commit
703b9368c3
@ -10,6 +10,9 @@
|
||||
* ExoPlayer:
|
||||
* Add `reset` to `BasePreloadManager` to release all the holding sources
|
||||
while keep the preload manager instance.
|
||||
* Add `ExoPlayer.setPriority` (and `Builder.setPriority`) to define the
|
||||
priority value used in `PriorityTaskManager` and for MediaCodec
|
||||
importance from API 35.
|
||||
* Transformer:
|
||||
* Work around a decoder bug where the number of audio channels was capped
|
||||
at stereo when handling PCM input.
|
||||
|
@ -456,6 +456,7 @@ public interface ExoPlayer extends Player {
|
||||
/* package */ Supplier<BandwidthMeter> bandwidthMeterSupplier;
|
||||
/* package */ Function<Clock, AnalyticsCollector> analyticsCollectorFunction;
|
||||
/* package */ Looper looper;
|
||||
/* package */ @C.Priority int priority;
|
||||
@Nullable /* package */ PriorityTaskManager priorityTaskManager;
|
||||
/* package */ AudioAttributes audioAttributes;
|
||||
/* package */ boolean handleAudioFocus;
|
||||
@ -502,6 +503,7 @@ public interface ExoPlayer extends Player {
|
||||
* Looper} of the application's main thread if the current thread doesn't have a {@link
|
||||
* Looper}
|
||||
* <li>{@link AnalyticsCollector}: {@link AnalyticsCollector} with {@link Clock#DEFAULT}
|
||||
* <li>{@link C.Priority}: {@link C#PRIORITY_PLAYBACK}
|
||||
* <li>{@link PriorityTaskManager}: {@code null} (not used)
|
||||
* <li>{@link AudioAttributes}: {@link AudioAttributes#DEFAULT}, not handling audio focus
|
||||
* <li>{@link C.WakeMode}: {@link C#WAKE_MODE_NONE}
|
||||
@ -679,6 +681,7 @@ public interface ExoPlayer extends Player {
|
||||
detachSurfaceTimeoutMs = DEFAULT_DETACH_SURFACE_TIMEOUT_MS;
|
||||
usePlatformDiagnostics = true;
|
||||
playerName = "";
|
||||
priority = C.PRIORITY_PLAYBACK;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -837,10 +840,30 @@ public interface ExoPlayer extends Player {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link C.Priority} for this player.
|
||||
*
|
||||
* <p>The priority may influence resource allocation between multiple players or other
|
||||
* components running in the same app.
|
||||
*
|
||||
* <p>This priority is used for the {@link PriorityTaskManager}, if {@linkplain
|
||||
* #setPriorityTaskManager set}.
|
||||
*
|
||||
* @param priority The {@link C.Priority}.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
@UnstableApi
|
||||
public Builder setPriority(@C.Priority int priority) {
|
||||
checkState(!buildCalled);
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an {@link PriorityTaskManager} that will be used by the player.
|
||||
*
|
||||
* <p>The priority {@link C#PRIORITY_PLAYBACK} will be set while the player is loading.
|
||||
* <p>The priority set via {@link #setPriority} (or {@link C#PRIORITY_PLAYBACK by default)} will
|
||||
* be set while the player is loading.
|
||||
*
|
||||
* @param priorityTaskManager A {@link PriorityTaskManager}, or null to not use one.
|
||||
* @return This builder.
|
||||
@ -1809,10 +1832,25 @@ public interface ExoPlayer extends Player {
|
||||
*/
|
||||
void setWakeMode(@C.WakeMode int wakeMode);
|
||||
|
||||
/**
|
||||
* Sets the {@link C.Priority} for this player.
|
||||
*
|
||||
* <p>The priority may influence resource allocation between multiple players or other components
|
||||
* running in the same app.
|
||||
*
|
||||
* <p>This priority is used for the {@link PriorityTaskManager}, if {@linkplain
|
||||
* #setPriorityTaskManager set}.
|
||||
*
|
||||
* @param priority The {@link C.Priority}.
|
||||
*/
|
||||
@UnstableApi
|
||||
void setPriority(@C.Priority int priority);
|
||||
|
||||
/**
|
||||
* Sets a {@link PriorityTaskManager}, or null to clear a previously set priority task manager.
|
||||
*
|
||||
* <p>The priority {@link C#PRIORITY_PLAYBACK} will be set while the player is loading.
|
||||
* <p>The priority set via {@link #setPriority} (or {@link C#PRIORITY_PLAYBACK by default)} will
|
||||
* be set while the player is loading.
|
||||
*
|
||||
* @param priorityTaskManager The {@link PriorityTaskManager}, or null to clear a previously set
|
||||
* priority task manager.
|
||||
|
@ -30,6 +30,7 @@ import static androidx.media3.exoplayer.Renderer.MSG_SET_CAMERA_MOTION_LISTENER;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_CHANGE_FRAME_RATE_STRATEGY;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_IMAGE_OUTPUT;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_PREFERRED_AUDIO_DEVICE;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_PRIORITY;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_SCALING_MODE;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_SKIP_SILENCE_ENABLED;
|
||||
import static androidx.media3.exoplayer.Renderer.MSG_SET_VIDEO_EFFECTS;
|
||||
@ -221,6 +222,7 @@ import java.util.concurrent.TimeoutException;
|
||||
@Nullable private CameraMotionListener cameraMotionListener;
|
||||
private boolean throwsWhenUsingWrongThread;
|
||||
private boolean hasNotifiedFullWrongThreadWarning;
|
||||
private @C.Priority int priority;
|
||||
@Nullable private PriorityTaskManager priorityTaskManager;
|
||||
private boolean isPriorityTaskManagerRegistered;
|
||||
private boolean playerReleased;
|
||||
@ -255,6 +257,7 @@ import java.util.concurrent.TimeoutException;
|
||||
+ "]");
|
||||
applicationContext = builder.context.getApplicationContext();
|
||||
analyticsCollector = builder.analyticsCollectorFunction.apply(builder.clock);
|
||||
priority = builder.priority;
|
||||
priorityTaskManager = builder.priorityTaskManager;
|
||||
audioAttributes = builder.audioAttributes;
|
||||
videoScalingMode = builder.videoScalingMode;
|
||||
@ -433,6 +436,7 @@ import java.util.concurrent.TimeoutException;
|
||||
TRACK_TYPE_VIDEO, MSG_SET_VIDEO_FRAME_METADATA_LISTENER, frameMetadataListener);
|
||||
sendRendererMessage(
|
||||
TRACK_TYPE_CAMERA_MOTION, MSG_SET_CAMERA_MOTION_LISTENER, frameMetadataListener);
|
||||
sendRendererMessage(MSG_SET_PRIORITY, priority);
|
||||
} finally {
|
||||
constructorFinished.open();
|
||||
}
|
||||
@ -1075,7 +1079,7 @@ import java.util.concurrent.TimeoutException;
|
||||
ownedSurface = null;
|
||||
}
|
||||
if (isPriorityTaskManagerRegistered) {
|
||||
checkNotNull(priorityTaskManager).remove(C.PRIORITY_PLAYBACK);
|
||||
checkNotNull(priorityTaskManager).remove(priority);
|
||||
isPriorityTaskManagerRegistered = false;
|
||||
}
|
||||
currentCueGroup = CueGroup.EMPTY_TIME_ZERO;
|
||||
@ -1603,6 +1607,21 @@ import java.util.concurrent.TimeoutException;
|
||||
audioBecomingNoisyManager.setEnabled(handleAudioBecomingNoisy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(@C.Priority int priority) {
|
||||
verifyApplicationThread();
|
||||
if (this.priority == priority) {
|
||||
return;
|
||||
}
|
||||
if (isPriorityTaskManagerRegistered) {
|
||||
PriorityTaskManager priorityTaskManager = checkNotNull(this.priorityTaskManager);
|
||||
priorityTaskManager.add(priority);
|
||||
priorityTaskManager.remove(this.priority);
|
||||
}
|
||||
this.priority = priority;
|
||||
sendRendererMessage(MSG_SET_PRIORITY, priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager) {
|
||||
verifyApplicationThread();
|
||||
@ -1610,10 +1629,10 @@ import java.util.concurrent.TimeoutException;
|
||||
return;
|
||||
}
|
||||
if (isPriorityTaskManagerRegistered) {
|
||||
checkNotNull(this.priorityTaskManager).remove(C.PRIORITY_PLAYBACK);
|
||||
checkNotNull(this.priorityTaskManager).remove(priority);
|
||||
}
|
||||
if (priorityTaskManager != null && isLoading()) {
|
||||
priorityTaskManager.add(C.PRIORITY_PLAYBACK);
|
||||
priorityTaskManager.add(priority);
|
||||
isPriorityTaskManagerRegistered = true;
|
||||
} else {
|
||||
isPriorityTaskManagerRegistered = false;
|
||||
@ -2870,10 +2889,14 @@ import java.util.concurrent.TimeoutException;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendRendererMessage(int messageType, @Nullable Object payload) {
|
||||
sendRendererMessage(/* trackType= */ -1, messageType, payload);
|
||||
}
|
||||
|
||||
private void sendRendererMessage(
|
||||
@C.TrackType int trackType, int messageType, @Nullable Object payload) {
|
||||
for (Renderer renderer : renderers) {
|
||||
if (renderer.getTrackType() == trackType) {
|
||||
if (trackType == -1 || renderer.getTrackType() == trackType) {
|
||||
createMessageInternal(renderer).setType(messageType).setPayload(payload).send();
|
||||
}
|
||||
}
|
||||
@ -2916,10 +2939,10 @@ import java.util.concurrent.TimeoutException;
|
||||
private void updatePriorityTaskManagerForIsLoadingChange(boolean isLoading) {
|
||||
if (priorityTaskManager != null) {
|
||||
if (isLoading && !isPriorityTaskManagerRegistered) {
|
||||
priorityTaskManager.add(C.PRIORITY_PLAYBACK);
|
||||
priorityTaskManager.add(priority);
|
||||
isPriorityTaskManagerRegistered = true;
|
||||
} else if (!isLoading && isPriorityTaskManagerRegistered) {
|
||||
priorityTaskManager.remove(C.PRIORITY_PLAYBACK);
|
||||
priorityTaskManager.remove(priority);
|
||||
isPriorityTaskManagerRegistered = false;
|
||||
}
|
||||
}
|
||||
|
@ -697,6 +697,12 @@ public class SimpleExoPlayer extends BasePlayer
|
||||
player.setHandleAudioBecomingNoisy(handleAudioBecomingNoisy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(@C.Priority int priority) {
|
||||
blockUntilConstructorFinished();
|
||||
player.setPriority(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager) {
|
||||
blockUntilConstructorFinished();
|
||||
|
@ -121,6 +121,7 @@ import androidx.media3.common.Player.DiscontinuityReason;
|
||||
import androidx.media3.common.Player.Listener;
|
||||
import androidx.media3.common.Player.PlayWhenReadyChangeReason;
|
||||
import androidx.media3.common.Player.PositionInfo;
|
||||
import androidx.media3.common.PriorityTaskManager;
|
||||
import androidx.media3.common.StreamKey;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.Timeline.Window;
|
||||
@ -14485,6 +14486,94 @@ public final class ExoPlayerTest {
|
||||
assertThat(expected).hasMessageThat().contains("lib-effect dependencies");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPriority_blocksOtherLowPriorityTasksInPriorityTaskManager() throws Exception {
|
||||
PriorityTaskManager priorityTaskManager = new PriorityTaskManager();
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
player.setPriorityTaskManager(priorityTaskManager);
|
||||
player.setPriority(C.PRIORITY_PLAYBACK);
|
||||
// Add a source without EOS so it loads indefinitely.
|
||||
player.setMediaSource(
|
||||
new FakeMediaSource(
|
||||
new FakeTimeline(),
|
||||
DrmSessionManager.DRM_UNSUPPORTED,
|
||||
(format, mediaPeriodId) -> ImmutableList.of(),
|
||||
ExoPlayerTestRunner.VIDEO_FORMAT));
|
||||
player.prepare();
|
||||
run(player).untilPendingCommandsAreFullyHandled();
|
||||
priorityTaskManager.add(C.PRIORITY_PLAYBACK + 1); // Higher priority than playback.
|
||||
|
||||
boolean canProcessOtherTask = priorityTaskManager.proceedNonBlocking(C.PRIORITY_PLAYBACK + 1);
|
||||
player.setPriority(C.PRIORITY_PLAYBACK + 2);
|
||||
boolean canProcessOtherTaskAfterUpdate =
|
||||
priorityTaskManager.proceedNonBlocking(C.PRIORITY_PLAYBACK + 1);
|
||||
player.release();
|
||||
boolean canProcessOtherTaskAfterRelease =
|
||||
priorityTaskManager.proceedNonBlocking(C.PRIORITY_PLAYBACK + 1);
|
||||
|
||||
assertThat(canProcessOtherTask).isTrue();
|
||||
assertThat(canProcessOtherTaskAfterUpdate).isFalse();
|
||||
assertThat(canProcessOtherTaskAfterRelease).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPriority_allowsOtherHighPriorityTasksInPriorityTaskManager() throws Exception {
|
||||
PriorityTaskManager priorityTaskManager = new PriorityTaskManager();
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
player.setPriorityTaskManager(priorityTaskManager);
|
||||
player.setPriority(C.PRIORITY_PLAYBACK);
|
||||
// Add a source without EOS so it loads indefinitely.
|
||||
player.setMediaSource(
|
||||
new FakeMediaSource(
|
||||
new FakeTimeline(),
|
||||
DrmSessionManager.DRM_UNSUPPORTED,
|
||||
(format, mediaPeriodId) -> ImmutableList.of(),
|
||||
ExoPlayerTestRunner.VIDEO_FORMAT));
|
||||
player.prepare();
|
||||
run(player).untilPendingCommandsAreFullyHandled();
|
||||
priorityTaskManager.add(C.PRIORITY_PLAYBACK - 1); // Lower priority than playback.
|
||||
|
||||
boolean canProcessOtherTask = priorityTaskManager.proceedNonBlocking(C.PRIORITY_PLAYBACK + 1);
|
||||
player.setPriority(C.PRIORITY_PLAYBACK - 2);
|
||||
boolean canProcessOtherTaskAfterUpdate =
|
||||
priorityTaskManager.proceedNonBlocking(C.PRIORITY_PLAYBACK - 1);
|
||||
player.release();
|
||||
boolean canProcessOtherTaskAfterRelease =
|
||||
priorityTaskManager.proceedNonBlocking(C.PRIORITY_PLAYBACK - 1);
|
||||
|
||||
assertThat(canProcessOtherTask).isFalse();
|
||||
assertThat(canProcessOtherTaskAfterUpdate).isTrue();
|
||||
assertThat(canProcessOtherTaskAfterRelease).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPriority_sendsSetPriorityMessageToRenderers() throws Exception {
|
||||
ArrayList<Pair<Integer, Object>> receivedMessages = new ArrayList<>();
|
||||
ExoPlayer player =
|
||||
new TestExoPlayerBuilder(context)
|
||||
.setRenderers(
|
||||
new FakeRenderer(C.TRACK_TYPE_VIDEO) {
|
||||
@Override
|
||||
public void handleMessage(@MessageType int messageType, @Nullable Object message)
|
||||
throws ExoPlaybackException {
|
||||
receivedMessages.add(Pair.create(messageType, message));
|
||||
super.handleMessage(messageType, message);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
player.setPriority(C.PRIORITY_DOWNLOAD);
|
||||
run(player).untilPendingCommandsAreFullyHandled();
|
||||
player.release();
|
||||
|
||||
// Assert default setting and updated setting arrived in the renderer.
|
||||
assertThat(receivedMessages)
|
||||
.containsAtLeast(
|
||||
Pair.create(Renderer.MSG_SET_PRIORITY, C.PRIORITY_PLAYBACK),
|
||||
Pair.create(Renderer.MSG_SET_PRIORITY, C.PRIORITY_DOWNLOAD))
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
||||
private void addWatchAsSystemFeature() {
|
||||
|
@ -20,6 +20,7 @@ import android.os.Looper;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.AuxEffectInfo;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Effect;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.Player;
|
||||
@ -397,6 +398,11 @@ public class StubExoPlayer extends StubPlayer implements ExoPlayer {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(@C.Priority int priority) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
Loading…
x
Reference in New Issue
Block a user