Use experimental release timeout in setForgroundMode(false).

The setForeground mode method blocks in the same way as release
and should use the same timeout if configured.

In case the method runs into the timeout, a player error is reported.

PiperOrigin-RevId: 317283808
This commit is contained in:
tonihei 2020-06-19 12:18:04 +01:00 committed by Andrew Lewis
parent 63ae4cc54b
commit 457b215565
2 changed files with 46 additions and 53 deletions

View file

@ -659,7 +659,14 @@ import java.util.concurrent.TimeoutException;
public void setForegroundMode(boolean foregroundMode) {
if (this.foregroundMode != foregroundMode) {
this.foregroundMode = foregroundMode;
internalPlayer.setForegroundMode(foregroundMode);
if (!internalPlayer.setForegroundMode(foregroundMode)) {
notifyListeners(
listener ->
listener.onPlayerError(
ExoPlaybackException.createForUnexpected(
new RuntimeException(
new TimeoutException("Setting foreground mode timed out.")))));
}
}
}

View file

@ -43,6 +43,7 @@ import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.HandlerWrapper;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Supplier;
import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
@ -296,29 +297,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
handler.obtainMessage(MSG_SEND_MESSAGE, message).sendToTarget();
}
public synchronized void setForegroundMode(boolean foregroundMode) {
public synchronized boolean setForegroundMode(boolean foregroundMode) {
if (released || !internalPlaybackThread.isAlive()) {
return;
return true;
}
if (foregroundMode) {
handler.obtainMessage(MSG_SET_FOREGROUND_MODE, /* foregroundMode */ 1, 0).sendToTarget();
return true;
} else {
AtomicBoolean processedFlag = new AtomicBoolean();
handler
.obtainMessage(MSG_SET_FOREGROUND_MODE, /* foregroundMode */ 0, 0, processedFlag)
.sendToTarget();
boolean wasInterrupted = false;
while (!processedFlag.get()) {
try {
wait();
} catch (InterruptedException e) {
wasInterrupted = true;
}
}
if (wasInterrupted) {
// Restore the interrupted status.
Thread.currentThread().interrupt();
if (releaseTimeoutMs > 0) {
waitUninterruptibly(/* condition= */ processedFlag::get, releaseTimeoutMs);
} else {
waitUninterruptibly(/* condition= */ processedFlag::get);
}
return processedFlag.get();
}
}
@ -328,16 +324,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
handler.sendEmptyMessage(MSG_RELEASE);
try {
if (releaseTimeoutMs > 0) {
waitUntilReleased(releaseTimeoutMs);
} else {
waitUntilReleased();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
if (releaseTimeoutMs > 0) {
waitUninterruptibly(/* condition= */ () -> released, releaseTimeoutMs);
} else {
waitUninterruptibly(/* condition= */ () -> released);
}
return released;
}
@ -505,59 +496,54 @@ import java.util.concurrent.atomic.AtomicBoolean;
// Private methods.
/**
* Blocks the current thread until {@link #releaseInternal()} is executed on the playback Thread.
* Blocks the current thread until a condition becomes true.
*
* <p>If the current thread is interrupted while waiting for {@link #releaseInternal()} to
* complete, this method will delay throwing the {@link InterruptedException} to ensure that the
* underlying resources have been released, and will an {@link InterruptedException} <b>after</b>
* {@link #releaseInternal()} is complete.
* <p>If the current thread is interrupted while waiting for the condition to become true, this
* method will restore the interrupt <b>after</b> the condition became true.
*
* @throws {@link InterruptedException} if the current Thread was interrupted while waiting for
* {@link #releaseInternal()} to complete.
* @param condition The condition.
*/
private synchronized void waitUntilReleased() throws InterruptedException {
InterruptedException interruptedException = null;
while (!released) {
private synchronized void waitUninterruptibly(Supplier<Boolean> condition) {
boolean wasInterrupted = false;
while (!condition.get()) {
try {
wait();
} catch (InterruptedException e) {
interruptedException = e;
wasInterrupted = true;
}
}
if (interruptedException != null) {
throw interruptedException;
if (wasInterrupted) {
// Restore the interrupted status.
Thread.currentThread().interrupt();
}
}
/**
* Blocks the current thread until {@link #releaseInternal()} is performed on the playback Thread
* or the specified amount of time has elapsed.
* Blocks the current thread until a condition becomes true or the specified amount of time has
* elapsed.
*
* <p>If the current thread is interrupted while waiting for {@link #releaseInternal()} to
* complete, this method will delay throwing the {@link InterruptedException} to ensure that the
* underlying resources have been released or the operation timed out, and will throw an {@link
* InterruptedException} afterwards.
* <p>If the current thread is interrupted while waiting for the condition to become true, this
* method will restore the interrupt <b>after</b> the condition became true or the operation times
* out.
*
* @param timeoutMs the time in milliseconds to wait for {@link #releaseInternal()} to complete.
* @throws {@link InterruptedException} if the current Thread was interrupted while waiting for
* {@link #releaseInternal()} to complete.
* @param condition The condition.
* @param timeoutMs The time in milliseconds to wait for the condition to become true.
*/
private synchronized void waitUntilReleased(long timeoutMs) throws InterruptedException {
private synchronized void waitUninterruptibly(Supplier<Boolean> condition, long timeoutMs) {
long deadlineMs = clock.elapsedRealtime() + timeoutMs;
long remainingMs = timeoutMs;
InterruptedException interruptedException = null;
while (!released && remainingMs > 0) {
boolean wasInterrupted = false;
while (!condition.get() && remainingMs > 0) {
try {
wait(remainingMs);
} catch (InterruptedException e) {
interruptedException = e;
wasInterrupted = true;
}
remainingMs = deadlineMs - clock.elapsedRealtime();
}
if (interruptedException != null) {
throw interruptedException;
if (wasInterrupted) {
// Restore the interrupted status.
Thread.currentThread().interrupt();
}
}