diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 196074485a..0073540f1c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -164,7 +164,6 @@ * No longer use a `MediaCodec` in audio passthrough mode. * Check `DefaultAudioSink` supports passthrough, in addition to checking the `AudioCapabilities` - * Add an experimental scheduling mode to save power in offload. ([#7404](https://github.com/google/ExoPlayer/issues/7404)). * Adjust input timestamps in `MediaCodecRenderer` to account for the Codec2 MP3 decoder having lower timestamps on the output side. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java index 3913922c3c..bd56974b32 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java @@ -219,20 +219,12 @@ public class DefaultRenderersFactory implements RenderersFactory { } /** - * Sets whether audio should be played using the offload path. - * - *
Audio offload disables ExoPlayer audio processing, but significantly reduces the energy - * consumption of the playback when {@link - * ExoPlayer#experimental_enableOffloadScheduling(boolean)} is enabled. - * - *
Most Android devices can only support one offload {@link android.media.AudioTrack} at a time - * and can invalidate it at any time. Thus an app can never be guaranteed that it will be able to - * play in offload. + * Sets whether audio should be played using the offload path. Audio offload disables audio + * processors (for example speed adjustment). * *
The default value is {@code false}. * - * @param enableOffload Whether to enable use of audio offload for supported formats, if - * available. + * @param enableOffload If audio offload should be used. * @return This factory, for convenience. */ public DefaultRenderersFactory setEnableAudioOffload(boolean enableOffload) { @@ -431,8 +423,7 @@ public class DefaultRenderersFactory implements RenderersFactory { * before output. May be empty. * @param eventHandler A handler to use when invoking event listeners and outputs. * @param eventListener An event listener. - * @param enableOffload Whether to enable use of audio offload for supported formats, if - * available. + * @param enableOffload If the renderer should use audio offload for all supported formats. * @param out An array to which the built renderers should be appended. */ protected void buildAudioRenderers( 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 b3b369b68e..b4cd9a399d 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 @@ -20,8 +20,6 @@ import android.os.Looper; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.analytics.AnalyticsCollector; -import com.google.android.exoplayer2.audio.AudioCapabilities; -import com.google.android.exoplayer2.audio.DefaultAudioSink; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.source.ClippingMediaSource; @@ -599,39 +597,4 @@ public interface ExoPlayer extends Player { * @see #setPauseAtEndOfMediaItems(boolean) */ boolean getPauseAtEndOfMediaItems(); - - /** - * Enables audio offload scheduling, which runs ExoPlayer's main loop as rarely as possible when - * playing an audio stream using audio offload. - * - *
Only use this scheduling mode if the player is not displaying anything to the user. For - * example when the application is in the background, or the screen is off. The player state - * (including position) is rarely updated (between 10s and 1min). - * - *
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 before interacting with the player - * - *
This mode should save significant power when the phone is playing offload audio with the - * screen off. - * - *
This mode only has an effect when playing an audio track in offload mode, which requires all - * the following: - * - *
This method is experimental, and will be renamed or removed in a future release. - * - * @param enableOffloadScheduling Whether to enable offload scheduling. - */ - void experimental_enableOffloadScheduling(boolean enableOffloadScheduling); } 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 51c8a9ea60..26357a18dc 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 @@ -202,11 +202,6 @@ import java.util.concurrent.TimeoutException; internalPlayer.experimental_throwWhenStuckBuffering(); } - @Override - public void experimental_enableOffloadScheduling(boolean enableOffloadScheduling) { - internalPlayer.experimental_enableOffloadScheduling(enableOffloadScheduling); - } - @Override @Nullable public AudioComponent getAudioComponent() { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index c5e6b06c19..53c8a5d080 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -94,15 +94,6 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int ACTIVE_INTERVAL_MS = 10; private static final int IDLE_INTERVAL_MS = 1000; - /** - * Duration under which pausing the main DO_SOME_WORK loop is not expected to yield significant - * power saving. - * - *
This value is probably too high, power measurements are needed adjust it, but as renderer - * sleep is currently only implemented for audio offload, which uses buffer much bigger than 2s, - * this does not matter for now. - */ - private static final long MIN_RENDERER_SLEEP_DURATION_MS = 2000; private final Renderer[] renderers; private final RendererCapabilities[] rendererCapabilities; @@ -136,8 +127,6 @@ import java.util.concurrent.atomic.AtomicBoolean; @Player.RepeatMode private int repeatMode; private boolean shuffleModeEnabled; private boolean foregroundMode; - private boolean requestForRendererSleep; - private boolean offloadSchedulingEnabled; private int enabledRendererCount; @Nullable private SeekPosition pendingInitialSeekPosition; @@ -210,13 +199,6 @@ import java.util.concurrent.atomic.AtomicBoolean; throwWhenStuckBuffering = true; } - public void experimental_enableOffloadScheduling(boolean enableOffloadScheduling) { - offloadSchedulingEnabled = enableOffloadScheduling; - if (!enableOffloadScheduling) { - handler.sendEmptyMessage(MSG_DO_SOME_WORK); - } - } - public void prepare() { handler.obtainMessage(MSG_PREPARE).sendToTarget(); } @@ -903,13 +885,12 @@ import java.util.concurrent.atomic.AtomicBoolean; if ((shouldPlayWhenReady() && playbackInfo.playbackState == Player.STATE_READY) || playbackInfo.playbackState == Player.STATE_BUFFERING) { - maybeScheduleWakeup(operationStartTimeMs, ACTIVE_INTERVAL_MS); + scheduleNextWork(operationStartTimeMs, ACTIVE_INTERVAL_MS); } else if (enabledRendererCount != 0 && playbackInfo.playbackState != Player.STATE_ENDED) { scheduleNextWork(operationStartTimeMs, IDLE_INTERVAL_MS); } else { handler.removeMessages(MSG_DO_SOME_WORK); } - requestForRendererSleep = false; // A sleep request is only valid for the current doSomeWork. TraceUtil.endSection(); } @@ -919,14 +900,6 @@ import java.util.concurrent.atomic.AtomicBoolean; handler.sendEmptyMessageAtTime(MSG_DO_SOME_WORK, thisOperationStartTimeMs + intervalMs); } - private void maybeScheduleWakeup(long operationStartTimeMs, long intervalMs) { - if (offloadSchedulingEnabled && requestForRendererSleep) { - return; - } - - scheduleNextWork(operationStartTimeMs, intervalMs); - } - private void seekToInternal(SeekPosition seekPosition) throws ExoPlaybackException { playbackInfoUpdate.incrementPendingOperationAcks(/* operationAcks= */ 1); @@ -2095,24 +2068,6 @@ import java.util.concurrent.atomic.AtomicBoolean; joining, mayRenderStartOfStream, periodHolder.getRendererOffset()); - - renderer.handleMessage( - Renderer.MSG_SET_WAKEUP_LISTENER, - new Renderer.WakeupListener() { - @Override - public void onSleep(long wakeupDeadlineMs) { - // Do not sleep if the expected sleep time is not long enough to save significant power. - if (wakeupDeadlineMs >= MIN_RENDERER_SLEEP_DURATION_MS) { - requestForRendererSleep = true; - } - } - - @Override - public void onWakeup() { - handler.sendEmptyMessage(MSG_DO_SOME_WORK); - } - }); - mediaClock.onRendererEnabled(renderer); // Start the renderer if playing. if (playing) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java b/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java index 8620c2d752..fa73f9257d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java @@ -46,30 +46,6 @@ import java.lang.annotation.RetentionPolicy; */ public interface Renderer extends PlayerMessage.Target { - /** - * Some renderers can signal when {@link #render(long, long)} should be called. - * - *
That allows the player to sleep until the next wakeup, instead of calling {@link - * #render(long, long)} in a tight loop. The aim of this interrupt based scheduling is to save - * power. - */ - interface WakeupListener { - - /** - * The renderer no longer needs to render until the next wakeup. - * - * @param wakeupDeadlineMs Maximum time in milliseconds until {@link #onWakeup()} will be - * called. - */ - void onSleep(long wakeupDeadlineMs); - - /** - * The renderer needs to render some frames. The client should call {@link #render(long, long)} - * at its earliest convenience. - */ - void onWakeup(); - } - /** * The type of a message that can be passed to a video renderer via {@link * ExoPlayer#createMessage(Target)}. The message payload should be the target {@link Surface}, or @@ -161,14 +137,6 @@ public interface Renderer extends PlayerMessage.Target { * representing the audio session ID that will be attached to the underlying audio track. */ int MSG_SET_AUDIO_SESSION_ID = 102; - /** - * A type of a message that can be passed to a {@link Renderer} via {@link - * ExoPlayer#createMessage(Target)}, to inform the renderer that it can schedule waking up another - * component. - * - *
The message payload must be a {@link WakeupListener} instance.
- */
- int MSG_SET_WAKEUP_LISTENER = 103;
/**
* Applications or extensions may define custom {@code MSG_*} constants that can be passed to
* renderers. These custom constants must be greater than or equal to this value.
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 4c36f9fc99..d1f0cfc798 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
@@ -633,11 +633,6 @@ public class SimpleExoPlayer extends BasePlayer
C.TRACK_TYPE_AUDIO, Renderer.MSG_SET_SKIP_SILENCE_ENABLED, skipSilenceEnabled);
}
- @Override
- public void experimental_enableOffloadScheduling(boolean enableOffloadScheduling) {
- player.experimental_enableOffloadScheduling(enableOffloadScheduling);
- }
-
@Override
@Nullable
public AudioComponent getAudioComponent() {
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
index 8bebd97a67..c4fa25d6bf 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
@@ -90,17 +90,6 @@ public interface AudioSink {
* @param skipSilenceEnabled Whether skipping silences is enabled.
*/
void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled);
-
- /** Called when the offload buffer has been partially emptied. */
- default void onOffloadBufferEmptying() {}
-
- /**
- * Called when the offload buffer has been filled completely.
- *
- * @param bufferEmptyingDeadlineMs Maximum time in milliseconds until {@link
- * #onOffloadBufferEmptying()} will be called.
- */
- default void onOffloadBufferFull(long bufferEmptyingDeadlineMs) {}
}
/**
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java
index ae2eb92044..d15fe44fc0 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java
@@ -335,11 +335,6 @@ import java.lang.reflect.Method;
return bufferSize - bytesPending;
}
- /** Returns the duration of audio that is buffered but unplayed. */
- public long getPendingBufferDurationMs(long writtenFrames) {
- return C.usToMs(framesToDurationUs(writtenFrames - getPlaybackHeadPosition()));
- }
-
/** Returns whether the track is in an invalid state and must be recreated. */
public boolean isStalled(long writtenFrames) {
return forceResetWorkaroundTimeMs != C.TIME_UNSET
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
index fdd684a269..bc3c321cac 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
@@ -20,7 +20,6 @@ import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.ConditionVariable;
-import android.os.Handler;
import android.os.SystemClock;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
@@ -275,7 +274,6 @@ public final class DefaultAudioSink implements AudioSink {
private final AudioTrackPositionTracker audioTrackPositionTracker;
private final ArrayDeque