diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Player.java b/library/common/src/main/java/com/google/android/exoplayer2/Player.java
index fc9a3c800e..4ec99cf010 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/Player.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/Player.java
@@ -612,24 +612,6 @@ public interface Player {
@Deprecated
default void onSeekProcessed() {}
- /**
- * Called when the player has started or stopped offload scheduling.
- *
- *
If using ExoPlayer, this is done by calling {@code
- * ExoPlayer#experimentalSetOffloadSchedulingEnabled(boolean)}.
- *
- *
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.
- *
- *
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.
*
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
index 7536fd65b9..f02ba4d6ff 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
@@ -140,6 +140,28 @@ public interface ExoPlayer extends Player {
*/
long DEFAULT_RELEASE_TIMEOUT_MS = 500;
+ /**
+ * A listener for audio offload events.
+ *
+ *
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)}.
+ *
+ *
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.
+ *
+ *
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.
*
@@ -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. */
int getRendererCount();
@@ -665,7 +701,7 @@ public interface ExoPlayer extends Player {
*
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
- * Player.EventListener#onExperimentalOffloadSchedulingEnabledChanged(boolean)} to be called with
+ * AudioOffloadListener#onExperimentalOffloadSchedulingEnabledChanged(boolean)} to be called with
* {@code offloadSchedulingEnabled = false} before interacting with the player.
*
*
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.
*
* @see #experimentalSetOffloadSchedulingEnabled(boolean)
- * @see EventListener#onExperimentalSleepingForOffloadChanged(boolean)
+ * @see AudioOffloadListener#onExperimentalSleepingForOffloadChanged(boolean)
*/
boolean experimentalIsSleepingForOffload();
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
index d823975595..32b341b437 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
@@ -49,6 +49,7 @@ import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
/**
* 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 internalPlayer;
private final ListenerSet listeners;
+ private final CopyOnWriteArraySet audioOffloadListeners;
private final Timeline.Period period;
private final List mediaSourceHolderSnapshots;
private final boolean useLazyPreparation;
@@ -166,6 +168,7 @@ import java.util.List;
applicationLooper,
clock,
(listener, flags) -> listener.onEvents(playerForListeners, new Events(flags)));
+ audioOffloadListeners = new CopyOnWriteArraySet<>();
mediaSourceHolderSnapshots = new ArrayList<>();
shuffleOrder = new ShuffleOrder.DefaultShuffleOrder(/* length= */ 0);
emptyTrackSelectorResult =
@@ -284,6 +287,16 @@ import java.util.List;
listeners.remove(listener);
}
+ @Override
+ public void addAudioOffloadListener(AudioOffloadListener listener) {
+ audioOffloadListeners.add(listener);
+ }
+
+ @Override
+ public void removeAudioOffloadListener(AudioOffloadListener listener) {
+ audioOffloadListeners.remove(listener);
+ }
+
@Override
public boolean isCommandAvailable(@Command int command) {
return availableCommands.contains(command);
@@ -1099,21 +1112,20 @@ import java.util.List;
if (seekProcessed) {
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();
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 evaluateMediaItemTransitionReason(
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
index ea4d8f05bc..13a284ff7f 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
@@ -685,6 +685,7 @@ public class SimpleExoPlayer extends BasePlayer
builder.looper,
/* wrappingPlayer= */ this);
player.addListener(componentListener);
+ player.addAudioOffloadListener(componentListener);
audioBecomingNoisyManager =
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
public void addAudioListener(AudioListener listener) {
// 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,
AudioBecomingNoisyManager.EventListener,
StreamVolumeManager.Listener,
- Player.EventListener {
+ Player.EventListener,
+ AudioOffloadListener {
// VideoRendererEventListener implementation
@@ -2241,6 +2255,8 @@ public class SimpleExoPlayer extends BasePlayer
updateWakeAndWifiLock();
}
+ // Player.AudioOffloadListener implementation.
+
@Override
public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) {
updateWakeAndWifiLock();
diff --git a/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java
index bd203de5c6..1eaf1ee36a 100644
--- a/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java
+++ b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/TestPlayerRunHelper.java
@@ -210,46 +210,48 @@ public class TestPlayerRunHelper {
/**
* 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}.
* @return The new offloadSchedulingEnabled state.
* @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded.
*/
- public static boolean runUntilReceiveOffloadSchedulingEnabledNewState(Player player)
+ public static boolean runUntilReceiveOffloadSchedulingEnabledNewState(ExoPlayer player)
throws TimeoutException {
verifyMainTestThread(player);
AtomicReference<@NullableType Boolean> offloadSchedulingEnabledReceiver =
new AtomicReference<>();
- Player.EventListener listener =
- new Player.EventListener() {
+ ExoPlayer.AudioOffloadListener listener =
+ new ExoPlayer.AudioOffloadListener() {
@Override
public void onExperimentalOffloadSchedulingEnabledChanged(
boolean offloadSchedulingEnabled) {
offloadSchedulingEnabledReceiver.set(offloadSchedulingEnabled);
}
};
- player.addListener(listener);
+ player.addAudioOffloadListener(listener);
runMainLooperUntil(() -> offloadSchedulingEnabledReceiver.get() != null);
return Assertions.checkNotNull(offloadSchedulingEnabledReceiver.get());
}
/**
* 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 expectedSleepForOffload The expected sleep of offload state.
* @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
* exceeded.
*/
- public static void runUntilSleepingForOffload(Player player, boolean expectedSleepForOffload)
+ public static void runUntilSleepingForOffload(ExoPlayer player, boolean expectedSleepForOffload)
throws TimeoutException {
verifyMainTestThread(player);
AtomicBoolean receiverCallback = new AtomicBoolean(false);
- Player.EventListener listener =
- new Player.EventListener() {
+ ExoPlayer.AudioOffloadListener listener =
+ new ExoPlayer.AudioOffloadListener() {
@Override
public void onExperimentalSleepingForOffloadChanged(boolean sleepingForOffload) {
if (sleepingForOffload == expectedSleepForOffload) {
@@ -257,7 +259,7 @@ public class TestPlayerRunHelper {
}
}
};
- player.addListener(listener);
+ player.addAudioOffloadListener(listener);
runMainLooperUntil(
() -> { // Make sure progress is being made, see [internal: b/170387438#comment2]
assertThat(player.getPlayerError()).isNull();
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
index af68d4f8e1..d99a28f325 100644
--- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
@@ -91,6 +91,16 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
throw new UnsupportedOperationException();
}
+ @Override
+ public void addAudioOffloadListener(AudioOffloadListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeAudioOffloadListener(AudioOffloadListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
@State
public int getPlaybackState() {