Commit 457b2155 by tonihei Committed by Andrew Lewis

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