diff options
author | H. Lehmann <ByteHamster@users.noreply.github.com> | 2019-04-11 20:50:56 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-11 20:50:56 +0200 |
commit | 97d08f3b00f864d421608ac52e42beafc37e323d (patch) | |
tree | a5f2061613f6a1f8fd73128f6d9f157d54abfe9b /core/src/main | |
parent | be6eb1c738beb7d5671647211d39d15c2edb235e (diff) | |
parent | 1d0e22135e57c7bcff8988c388d7f0f813ad7061 (diff) | |
download | AntennaPod-97d08f3b00f864d421608ac52e42beafc37e323d.zip |
Merge pull request #3097 from ByteHamster/exoplayer-main-thread
Executing all ExoPlayer methods on main thread
Diffstat (limited to 'core/src/main')
3 files changed, 60 insertions, 7 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index 281bd064b..f20525f73 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -165,6 +165,7 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void seekTo(int i) throws IllegalStateException { mExoPlayer.seekTo(i); + audioSeekCompleteListener.onSeekComplete(null); } @Override diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java index 9274b9a49..649082f6e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java @@ -18,6 +18,7 @@ import java.io.File; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -57,16 +58,42 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { private final ReentrantLock playerLock; private CountDownLatch seekLatch; - private final ThreadPoolExecutor executor; + private final PlayerExecutor executor; + + /** + * All ExoPlayer methods must be executed on the same thread. + * We use the main application thread. This class allows to + * "fake" an executor that just calls the methods on the + * calling thread instead of submitting to an executor. + * Other players are still executed in a background thread. + */ + private class PlayerExecutor { + private boolean useCallerThread = true; + private ThreadPoolExecutor threadPool; + + public Future<?> submit(Runnable r) { + if (useCallerThread) { + r.run(); + return new FutureTask<Void>(() -> {}, null); + } else { + return threadPool.submit(r); + } + } + + public void shutdown() { + threadPool.shutdown(); + } + } public LocalPSMP(@NonNull Context context, @NonNull PSMPCallback callback) { super(context, callback); - this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); this.playerLock = new ReentrantLock(); this.startWhenPrepared = new AtomicBoolean(false); - executor = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<>(), + + executor = new PlayerExecutor(); + executor.threadPool = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<>(), (r, executor) -> Log.d(TAG, "Rejected execution of runnable")); mediaPlayer = null; @@ -105,6 +132,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { @Override public void playMediaObject(@NonNull final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) { Log.d(TAG, "playMediaObject(...)"); + executor.useCallerThread = UserPreferences.useExoplayer(); executor.submit(() -> { playerLock.lock(); try { @@ -372,6 +400,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { */ @Override public void reinit() { + executor.useCallerThread = UserPreferences.useExoplayer(); executor.submit(() -> { playerLock.lock(); Log.d(TAG, "reinit()"); @@ -821,6 +850,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { @Override protected Future<?> endPlayback(final boolean hasEnded, final boolean wasSkipped, final boolean shouldContinue, final boolean toStoppedState) { + executor.useCallerThread = UserPreferences.useExoplayer(); return executor.submit(() -> { playerLock.lock(); releaseWifiLockIfNecessary(); @@ -1012,7 +1042,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { mp -> genericSeekCompleteListener(); private void genericSeekCompleteListener() { - Thread t = new Thread(() -> { + Runnable r = () -> { Log.d(TAG, "genericSeekCompleteListener"); if(seekLatch != null) { seekLatch.countDown(); @@ -1025,7 +1055,12 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { setPlayerStatus(statusBeforeSeeking, media, getPosition()); } playerLock.unlock(); - }); - t.start(); + }; + + if (executor.useCallerThread) { + r.run(); + } else { + new Thread(r).start(); + } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java index 3d97e862a..bfc75a902 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java @@ -1,6 +1,8 @@ package de.danoeh.antennapod.core.service.playback; import android.content.Context; +import android.os.Handler; +import android.os.Looper; import android.os.Vibrator; import android.support.annotation.NonNull; import android.util.Log; @@ -126,6 +128,7 @@ public class PlaybackServiceTaskManager { public synchronized void startPositionSaver() { if (!isPositionSaverActive()) { Runnable positionSaver = callback::positionSaverTick; + positionSaver = useMainThreadIfNecessary(positionSaver); positionSaverFuture = schedExecutor.scheduleWithFixedDelay(positionSaver, POSITION_SAVER_WAITING_INTERVAL, POSITION_SAVER_WAITING_INTERVAL, TimeUnit.MILLISECONDS); @@ -158,6 +161,7 @@ public class PlaybackServiceTaskManager { public synchronized void startWidgetUpdater() { if (!isWidgetUpdaterActive()) { Runnable widgetUpdater = callback::onWidgetUpdaterTick; + widgetUpdater = useMainThreadIfNecessary(widgetUpdater); widgetUpdaterFuture = schedExecutor.scheduleWithFixedDelay(widgetUpdater, WIDGET_UPDATER_NOTIFICATION_INTERVAL, WIDGET_UPDATER_NOTIFICATION_INTERVAL, TimeUnit.MILLISECONDS); @@ -184,7 +188,8 @@ public class PlaybackServiceTaskManager { sleepTimerFuture.cancel(true); } sleepTimer = new SleepTimer(waitingTime, shakeToReset, vibrate); - sleepTimerFuture = schedExecutor.schedule(sleepTimer, 0, TimeUnit.MILLISECONDS); + Runnable runnable = useMainThreadIfNecessary(sleepTimer); + sleepTimerFuture = schedExecutor.schedule(runnable, 0, TimeUnit.MILLISECONDS); } /** @@ -267,6 +272,7 @@ public class PlaybackServiceTaskManager { } Log.d(TAG, "Chapter loader stopped"); }; + chapterLoader = useMainThreadIfNecessary(chapterLoader); chapterLoaderFuture = schedExecutor.submit(chapterLoader); } @@ -292,6 +298,17 @@ public class PlaybackServiceTaskManager { schedExecutor.shutdown(); } + private Runnable useMainThreadIfNecessary(Runnable runnable) { + if (Looper.myLooper() == Looper.getMainLooper()) { + // Called in main thread => ExoPlayer is used + // Run on ui thread even if called from schedExecutor + Handler handler = new Handler(); + return () -> handler.post(runnable); + } else { + return runnable; + } + } + /** * Sleeps for a given time and then pauses playback. */ |