Move offload events to their own listener

Move offload events from Player.EventListener to
ExoPlayer.AudioOffloadListener.

PiperOrigin-RevId: 362472462
This commit is contained in:
krocard 2021-03-12 09:30:47 +00:00 committed by Ian Baker
parent b563b82787
commit 3f4f2f90b5
6 changed files with 102 additions and 44 deletions

View File

@ -612,24 +612,6 @@ public interface Player {
@Deprecated @Deprecated
default void onSeekProcessed() {} default void onSeekProcessed() {}
/**
* Called when the player has started or stopped offload scheduling.
*
* <p>If using ExoPlayer, this is done by calling {@code
* ExoPlayer#experimentalSetOffloadSchedulingEnabled(boolean)}.
*
* <p>This method is experimental, and will be renamed or removed in a future release.
*/
// TODO(b/172315872) Move this method in a new ExoPlayer.EventListener.
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) {}
/** /**
* Called when one or more player states changed. * Called when one or more player states changed.
* *

View File

@ -140,6 +140,28 @@ public interface ExoPlayer extends Player {
*/ */
long DEFAULT_RELEASE_TIMEOUT_MS = 500; long DEFAULT_RELEASE_TIMEOUT_MS = 500;
/**
* A listener for audio offload events.
*
* <p>This class is experimental, and might be renamed, moved or removed in a future release.
*/
interface AudioOffloadListener {
/**
* Called when the player has started or stopped offload scheduling using {@link
* ExoPlayer#experimentalSetOffloadSchedulingEnabled(boolean)}.
*
* <p>This method is experimental, and will be renamed or removed in a future release.
*/
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) {}
}
/** /**
* A builder for {@link ExoPlayer} instances. * A builder for {@link ExoPlayer} instances.
* *
@ -450,6 +472,20 @@ public interface ExoPlayer extends Player {
} }
} }
/**
* Adds a listener to receive audio offload events.
*
* @param listener The listener to register.
*/
void addAudioOffloadListener(AudioOffloadListener listener);
/**
* Removes a listener of audio offload events.
*
* @param listener The listener to unregister.
*/
void removeAudioOffloadListener(AudioOffloadListener listener);
/** Returns the number of renderers. */ /** Returns the number of renderers. */
int getRendererCount(); int getRendererCount();
@ -665,7 +701,7 @@ public interface ExoPlayer extends Player {
* <p>While offload scheduling is enabled, player events may be delivered severely delayed and * <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 * apps should not interact with the player. When returning to the foreground, disable offload
* scheduling and wait for {@link * scheduling and wait for {@link
* Player.EventListener#onExperimentalOffloadSchedulingEnabledChanged(boolean)} to be called with * AudioOffloadListener#onExperimentalOffloadSchedulingEnabledChanged(boolean)} to be called with
* {@code offloadSchedulingEnabled = false} before interacting with the player. * {@code offloadSchedulingEnabled = false} before interacting with the player.
* *
* <p>This mode should save significant power when the phone is playing offload audio with the * <p>This mode should save significant power when the phone is playing offload audio with the
@ -697,7 +733,7 @@ public interface ExoPlayer extends Player {
* Returns whether the player has paused its main loop to save power in offload scheduling mode. * Returns whether the player has paused its main loop to save power in offload scheduling mode.
* *
* @see #experimentalSetOffloadSchedulingEnabled(boolean) * @see #experimentalSetOffloadSchedulingEnabled(boolean)
* @see EventListener#onExperimentalSleepingForOffloadChanged(boolean) * @see AudioOffloadListener#onExperimentalSleepingForOffloadChanged(boolean)
*/ */
boolean experimentalIsSleepingForOffload(); boolean experimentalIsSleepingForOffload();
} }

View File

@ -49,6 +49,7 @@ import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
/** /**
* An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayer.Builder}. * An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayer.Builder}.
@ -72,6 +73,7 @@ import java.util.List;
private final ExoPlayerImplInternal.PlaybackInfoUpdateListener playbackInfoUpdateListener; private final ExoPlayerImplInternal.PlaybackInfoUpdateListener playbackInfoUpdateListener;
private final ExoPlayerImplInternal internalPlayer; private final ExoPlayerImplInternal internalPlayer;
private final ListenerSet<Player.EventListener> listeners; private final ListenerSet<Player.EventListener> listeners;
private final CopyOnWriteArraySet<AudioOffloadListener> audioOffloadListeners;
private final Timeline.Period period; private final Timeline.Period period;
private final List<MediaSourceHolderSnapshot> mediaSourceHolderSnapshots; private final List<MediaSourceHolderSnapshot> mediaSourceHolderSnapshots;
private final boolean useLazyPreparation; private final boolean useLazyPreparation;
@ -166,6 +168,7 @@ import java.util.List;
applicationLooper, applicationLooper,
clock, clock,
(listener, flags) -> listener.onEvents(playerForListeners, new Events(flags))); (listener, flags) -> listener.onEvents(playerForListeners, new Events(flags)));
audioOffloadListeners = new CopyOnWriteArraySet<>();
mediaSourceHolderSnapshots = new ArrayList<>(); mediaSourceHolderSnapshots = new ArrayList<>();
shuffleOrder = new ShuffleOrder.DefaultShuffleOrder(/* length= */ 0); shuffleOrder = new ShuffleOrder.DefaultShuffleOrder(/* length= */ 0);
emptyTrackSelectorResult = emptyTrackSelectorResult =
@ -284,6 +287,16 @@ import java.util.List;
listeners.remove(listener); listeners.remove(listener);
} }
@Override
public void addAudioOffloadListener(AudioOffloadListener listener) {
audioOffloadListeners.add(listener);
}
@Override
public void removeAudioOffloadListener(AudioOffloadListener listener) {
audioOffloadListeners.remove(listener);
}
@Override @Override
public boolean isCommandAvailable(@Command int command) { public boolean isCommandAvailable(@Command int command) {
return availableCommands.contains(command); return availableCommands.contains(command);
@ -1099,21 +1112,20 @@ import java.util.List;
if (seekProcessed) { if (seekProcessed) {
listeners.queueEvent(/* eventFlag= */ C.INDEX_UNSET, EventListener::onSeekProcessed); listeners.queueEvent(/* eventFlag= */ C.INDEX_UNSET, EventListener::onSeekProcessed);
} }
if (previousPlaybackInfo.offloadSchedulingEnabled != newPlaybackInfo.offloadSchedulingEnabled) {
listeners.queueEvent(
/* eventFlag= */ C.INDEX_UNSET,
listener ->
listener.onExperimentalOffloadSchedulingEnabledChanged(
newPlaybackInfo.offloadSchedulingEnabled));
}
if (previousPlaybackInfo.sleepingForOffload != newPlaybackInfo.sleepingForOffload) {
listeners.queueEvent(
/* eventFlag= */ C.INDEX_UNSET,
listener ->
listener.onExperimentalSleepingForOffloadChanged(newPlaybackInfo.sleepingForOffload));
}
updateAvailableCommands(); updateAvailableCommands();
listeners.flushEvents(); listeners.flushEvents();
if (previousPlaybackInfo.offloadSchedulingEnabled != newPlaybackInfo.offloadSchedulingEnabled) {
for (AudioOffloadListener listener : audioOffloadListeners) {
listener.onExperimentalOffloadSchedulingEnabledChanged(
newPlaybackInfo.offloadSchedulingEnabled);
}
}
if (previousPlaybackInfo.sleepingForOffload != newPlaybackInfo.sleepingForOffload) {
for (AudioOffloadListener listener : audioOffloadListeners) {
listener.onExperimentalSleepingForOffloadChanged(newPlaybackInfo.sleepingForOffload);
}
}
} }
private Pair<Boolean, Integer> evaluateMediaItemTransitionReason( private Pair<Boolean, Integer> evaluateMediaItemTransitionReason(

View File

@ -685,6 +685,7 @@ public class SimpleExoPlayer extends BasePlayer
builder.looper, builder.looper,
/* wrappingPlayer= */ this); /* wrappingPlayer= */ this);
player.addListener(componentListener); player.addListener(componentListener);
player.addAudioOffloadListener(componentListener);
audioBecomingNoisyManager = audioBecomingNoisyManager =
new AudioBecomingNoisyManager(builder.context, eventHandler, componentListener); new AudioBecomingNoisyManager(builder.context, eventHandler, componentListener);
@ -894,6 +895,18 @@ public class SimpleExoPlayer extends BasePlayer
} }
} }
@Override
public void addAudioOffloadListener(AudioOffloadListener listener) {
// Don't verify application thread. We allow calls to this method from any thread.
player.addAudioOffloadListener(listener);
}
@Override
public void removeAudioOffloadListener(AudioOffloadListener listener) {
// Don't verify application thread. We allow calls to this method from any thread.
player.removeAudioOffloadListener(listener);
}
@Override @Override
public void addAudioListener(AudioListener listener) { public void addAudioListener(AudioListener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
@ -1973,7 +1986,8 @@ public class SimpleExoPlayer extends BasePlayer
AudioFocusManager.PlayerControl, AudioFocusManager.PlayerControl,
AudioBecomingNoisyManager.EventListener, AudioBecomingNoisyManager.EventListener,
StreamVolumeManager.Listener, StreamVolumeManager.Listener,
Player.EventListener { Player.EventListener,
AudioOffloadListener {
// VideoRendererEventListener implementation // VideoRendererEventListener implementation
@ -2241,6 +2255,8 @@ public class SimpleExoPlayer extends BasePlayer
updateWakeAndWifiLock(); updateWakeAndWifiLock();
} }
// Player.AudioOffloadListener implementation.
@Override @Override
public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) { public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) {
updateWakeAndWifiLock(); updateWakeAndWifiLock();

View File

@ -210,46 +210,48 @@ public class TestPlayerRunHelper {
/** /**
* Runs tasks of the main {@link Looper} until a {@link * Runs tasks of the main {@link Looper} until a {@link
* Player.EventListener#onExperimentalOffloadSchedulingEnabledChanged} callback occurred. * ExoPlayer.AudioOffloadListener#onExperimentalOffloadSchedulingEnabledChanged} callback
* occurred.
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @return The new offloadSchedulingEnabled state. * @return The new offloadSchedulingEnabled state.
* @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static boolean runUntilReceiveOffloadSchedulingEnabledNewState(Player player) public static boolean runUntilReceiveOffloadSchedulingEnabledNewState(ExoPlayer player)
throws TimeoutException { throws TimeoutException {
verifyMainTestThread(player); verifyMainTestThread(player);
AtomicReference<@NullableType Boolean> offloadSchedulingEnabledReceiver = AtomicReference<@NullableType Boolean> offloadSchedulingEnabledReceiver =
new AtomicReference<>(); new AtomicReference<>();
Player.EventListener listener = ExoPlayer.AudioOffloadListener listener =
new Player.EventListener() { new ExoPlayer.AudioOffloadListener() {
@Override @Override
public void onExperimentalOffloadSchedulingEnabledChanged( public void onExperimentalOffloadSchedulingEnabledChanged(
boolean offloadSchedulingEnabled) { boolean offloadSchedulingEnabled) {
offloadSchedulingEnabledReceiver.set(offloadSchedulingEnabled); offloadSchedulingEnabledReceiver.set(offloadSchedulingEnabled);
} }
}; };
player.addListener(listener); player.addAudioOffloadListener(listener);
runMainLooperUntil(() -> offloadSchedulingEnabledReceiver.get() != null); runMainLooperUntil(() -> offloadSchedulingEnabledReceiver.get() != null);
return Assertions.checkNotNull(offloadSchedulingEnabledReceiver.get()); return Assertions.checkNotNull(offloadSchedulingEnabledReceiver.get());
} }
/** /**
* Runs tasks of the main {@link Looper} until a {@link * Runs tasks of the main {@link Looper} until a {@link
* Player.EventListener#onExperimentalSleepingForOffloadChanged(boolean)} callback occurred. * ExoPlayer.AudioOffloadListener#onExperimentalSleepingForOffloadChanged(boolean)} callback
* occurred.
* *
* @param player The {@link Player}. * @param player The {@link Player}.
* @param expectedSleepForOffload The expected sleep of offload state. * @param expectedSleepForOffload The expected sleep of offload state.
* @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded. * exceeded.
*/ */
public static void runUntilSleepingForOffload(Player player, boolean expectedSleepForOffload) public static void runUntilSleepingForOffload(ExoPlayer player, boolean expectedSleepForOffload)
throws TimeoutException { throws TimeoutException {
verifyMainTestThread(player); verifyMainTestThread(player);
AtomicBoolean receiverCallback = new AtomicBoolean(false); AtomicBoolean receiverCallback = new AtomicBoolean(false);
Player.EventListener listener = ExoPlayer.AudioOffloadListener listener =
new Player.EventListener() { new ExoPlayer.AudioOffloadListener() {
@Override @Override
public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) { public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) {
if (sleepingForOffload == expectedSleepForOffload) { if (sleepingForOffload == expectedSleepForOffload) {
@ -257,7 +259,7 @@ public class TestPlayerRunHelper {
} }
} }
}; };
player.addListener(listener); player.addAudioOffloadListener(listener);
runMainLooperUntil( runMainLooperUntil(
() -> { // Make sure progress is being made, see [internal: b/170387438#comment2] () -> { // Make sure progress is being made, see [internal: b/170387438#comment2]
assertThat(player.getPlayerError()).isNull(); assertThat(player.getPlayerError()).isNull();

View File

@ -91,6 +91,16 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void addAudioOffloadListener(AudioOffloadListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void removeAudioOffloadListener(AudioOffloadListener listener) {
throw new UnsupportedOperationException();
}
@Override @Override
@State @State
public int getPlaybackState() { public int getPlaybackState() {