From 457b21556557f93540cd7ab43384d8a55eb61fd7 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 19 Jun 2020 12:18:04 +0100 Subject: [PATCH] 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 --- .../android/exoplayer2/ExoPlayerImpl.java | 9 +- .../exoplayer2/ExoPlayerImplInternal.java | 90 ++++++++----------- 2 files changed, 46 insertions(+), 53 deletions(-) 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 26357a18dc..47ee6b062c 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 @@ -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."))))); + } } } 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 53c8a5d080..f7abd4dd9d 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 @@ -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. * - *

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} after - * {@link #releaseInternal()} is complete. + *

If the current thread is interrupted while waiting for the condition to become true, this + * method will restore the interrupt after 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 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. * - *

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. + *

If the current thread is interrupted while waiting for the condition to become true, this + * method will restore the interrupt after 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 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(); } }