Commit 74c68b37 by bachinger Committed by Marc Baechinger

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
parent 6b521b29
......@@ -161,15 +161,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.
*
* <p>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
* not be ready, there must be more media available to load, and the LoadControl must be refusing
......@@ -2478,11 +2469,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
......
......@@ -62,11 +62,8 @@ public interface Renderer extends PlayerMessage.Target {
* The renderer no longer needs to render until the next wakeup.
*
* <p>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)}
......
......@@ -104,13 +104,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.
......
......@@ -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
......
......@@ -1193,9 +1193,7 @@ public final class DefaultAudioSink implements AudioSink {
&& listener != null
&& bytesWritten < bytesRemaining
&& !isWaitingForOffloadEndOfStreamHandled) {
long pendingDurationMs =
audioTrackPositionTracker.getPendingBufferDurationMs(writtenEncodedFrames);
listener.onOffloadBufferFull(pendingDurationMs);
listener.onOffloadBufferFull();
}
}
......
......@@ -926,9 +926,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();
}
}
......
......@@ -12144,7 +12144,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<Renderer.WakeupListener> wakeupListenerReceiver;
......@@ -12158,9 +12157,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;
......@@ -12180,7 +12177,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();
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment