From 01412f4a57086bec3c10be474c04ca500427e9f2 Mon Sep 17 00:00:00 2001 From: bachinger Date: Fri, 27 May 2022 13:42:44 +0000 Subject: [PATCH] Unconditionally sleep for offload Unconditionally sleep for offload, if the audio buffer is full. Previously ExoPlayer would not sleep if the expected wake-up was in 2s. This was to prevent underrun if the wake-up was delayed. Experiments have shown that the wakup audio buffer is far more than 2s (around 1min). Additionally, the metric was incorrect because it measured both, AudioTrack + DSP. Finally, this metric was erroneous after a gapless transition, when the head position would reset to 0 and thus the computed delay until next wakeup was too large. PiperOrigin-RevId: 451383701 --- .../media3/exoplayer/ExoPlayerImplInternal.java | 16 ++-------------- .../java/androidx/media3/exoplayer/Renderer.java | 5 +---- .../media3/exoplayer/audio/AudioSink.java | 9 ++------- .../audio/AudioTrackPositionTracker.java | 5 ----- .../media3/exoplayer/audio/DefaultAudioSink.java | 4 +--- .../exoplayer/audio/MediaCodecAudioRenderer.java | 4 ++-- .../androidx/media3/exoplayer/ExoPlayerTest.java | 7 ++----- 7 files changed, 10 insertions(+), 40 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java index ba32561c63..6eba41d01e 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java @@ -168,15 +168,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; /** * Duration for which the player needs to appear stuck before the playback is failed on the * assumption that no further progress will be made. To appear stuck, the player's renderers must @@ -2486,11 +2477,8 @@ import java.util.concurrent.atomic.AtomicBoolean; 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; - } + public void onSleep() { + requestForRendererSleep = true; } @Override diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java index 850421e315..b66921faad 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java @@ -66,11 +66,8 @@ public interface Renderer extends PlayerMessage.Target { * The renderer no longer needs to render until the next wakeup. * *

Must be called from the thread ExoPlayer invokes the renderer from. - * - * @param wakeupDeadlineMs Maximum time in milliseconds until {@link #onWakeup()} will be - * called. */ - void onSleep(long wakeupDeadlineMs); + void onSleep(); /** * The renderer needs to render some frames. The client should call {@link #render(long, long)} diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java index 04d91a3d05..b90f5a6a98 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java @@ -108,13 +108,8 @@ public interface AudioSink { /** 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) {} + /** Called when the offload buffer has been filled completely. */ + default void onOffloadBufferFull() {} /** * Called when {@link AudioSink} has encountered an error. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java index 2844cace37..952c5fb8b6 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioTrackPositionTracker.java @@ -386,11 +386,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 Util.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/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index 25b531ef78..3defbe3015 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -1202,9 +1202,7 @@ public final class DefaultAudioSink implements AudioSink { && listener != null && bytesWritten < bytesRemaining && !isWaitingForOffloadEndOfStreamHandled) { - long pendingDurationMs = - audioTrackPositionTracker.getPendingBufferDurationMs(writtenEncodedFrames); - listener.onOffloadBufferFull(pendingDurationMs); + listener.onOffloadBufferFull(); } } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/MediaCodecAudioRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/MediaCodecAudioRenderer.java index 5baab56bcb..d6305fd56f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/MediaCodecAudioRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/MediaCodecAudioRenderer.java @@ -930,9 +930,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media } @Override - public void onOffloadBufferFull(long bufferEmptyingDeadlineMs) { + public void onOffloadBufferFull() { if (wakeupListener != null) { - wakeupListener.onSleep(bufferEmptyingDeadlineMs); + wakeupListener.onSleep(); } } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java index 8a9d13e237..4b6ce27fc9 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -12154,7 +12154,6 @@ public final class ExoPlayerTest { /** {@link FakeRenderer} that can sleep and be woken-up. */ private static class FakeSleepRenderer extends FakeRenderer { - private static final long WAKEUP_DEADLINE_MS = 60 * C.MICROS_PER_SECOND; private final AtomicBoolean sleepOnNextRender; private final AtomicReference wakeupListenerReceiver; @@ -12168,9 +12167,7 @@ public final class ExoPlayerTest { wakeupListenerReceiver.get().onWakeup(); } - /** - * Call {@link Renderer.WakeupListener#onSleep(long)} on the next {@link #render(long, long)} - */ + /** Call {@link Renderer.WakeupListener#onSleep()} on the next {@link #render(long, long)} */ public FakeSleepRenderer sleepOnNextRender() { sleepOnNextRender.set(true); return this; @@ -12190,7 +12187,7 @@ public final class ExoPlayerTest { public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { super.render(positionUs, elapsedRealtimeUs); if (sleepOnNextRender.compareAndSet(/* expectedValue= */ true, /* newValue= */ false)) { - wakeupListenerReceiver.get().onSleep(WAKEUP_DEADLINE_MS); + wakeupListenerReceiver.get().onSleep(); } } }