adapt media player switch into the new protocol
This commit is contained in:
parent
385079d168
commit
c17723816b
|
@ -13,6 +13,7 @@ import org.antennapod.audio.MediaPlayer;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -754,8 +755,8 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
|
|||
|
||||
|
||||
@Override
|
||||
protected void endPlayback(final boolean wasSkipped) {
|
||||
executor.submit(() -> {
|
||||
protected Future<?> endPlayback(final boolean wasSkipped, final boolean shouldContinue, final boolean toStoppedState) {
|
||||
return executor.submit(() -> {
|
||||
playerLock.lock();
|
||||
releaseWifiLockIfNecessary();
|
||||
|
||||
|
@ -776,35 +777,46 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
|
|||
mediaPlayer.reset();
|
||||
}
|
||||
audioManager.abandonAudioFocus(audioFocusChangeListener);
|
||||
// Load next episode if previous episode was in the queue and if there
|
||||
// is an episode in the queue left.
|
||||
// Start playback immediately if continuous playback is enabled
|
||||
|
||||
final Playable currentMedia = media;
|
||||
Playable nextMedia = callback.getNextInQueue(currentMedia);
|
||||
Playable nextMedia = null;
|
||||
|
||||
boolean playNextEpisode = isPlaying &&
|
||||
nextMedia != null &&
|
||||
UserPreferences.isFollowQueue();
|
||||
if (shouldContinue) {
|
||||
// Load next episode if previous episode was in the queue and if there
|
||||
// is an episode in the queue left.
|
||||
// Start playback immediately if continuous playback is enabled
|
||||
nextMedia = callback.getNextInQueue(currentMedia);
|
||||
|
||||
if (playNextEpisode) {
|
||||
Log.d(TAG, "Playback of next episode will start immediately.");
|
||||
} else if (nextMedia == null){
|
||||
Log.d(TAG, "No more episodes available to play");
|
||||
} else {
|
||||
Log.d(TAG, "Loading next episode, but not playing automatically.");
|
||||
boolean playNextEpisode = isPlaying &&
|
||||
nextMedia != null &&
|
||||
UserPreferences.isFollowQueue();
|
||||
|
||||
if (playNextEpisode) {
|
||||
Log.d(TAG, "Playback of next episode will start immediately.");
|
||||
} else if (nextMedia == null){
|
||||
Log.d(TAG, "No more episodes available to play");
|
||||
} else {
|
||||
Log.d(TAG, "Loading next episode, but not playing automatically.");
|
||||
}
|
||||
|
||||
if (nextMedia != null) {
|
||||
callback.onPlaybackEnded(nextMedia.getMediaType(), !playNextEpisode);
|
||||
// setting media to null signals to playMediaObject() that we're taking care of post-playback processing
|
||||
media = null;
|
||||
playMediaObject(nextMedia, false, !nextMedia.localFileAvailable(), playNextEpisode, playNextEpisode);
|
||||
}
|
||||
}
|
||||
if (shouldContinue || toStoppedState) {
|
||||
if (nextMedia == null) {
|
||||
callback.onPlaybackEnded(null, true);
|
||||
stop();
|
||||
}
|
||||
final boolean hasNext = nextMedia != null;
|
||||
|
||||
if (nextMedia != null) {
|
||||
callback.onPlaybackEnded(nextMedia.getMediaType(), !playNextEpisode);
|
||||
// setting media to null signals to playMediaObject() that we're taking care of post-playback processing
|
||||
media = null;
|
||||
playMediaObject(nextMedia, false, !nextMedia.localFileAvailable(), playNextEpisode, playNextEpisode);
|
||||
} else {
|
||||
callback.onPlaybackEnded(null, true);
|
||||
stop();
|
||||
executor.submit(() -> callback.onPostPlayback(currentMedia, !wasSkipped, hasNext));
|
||||
} else if (isPlaying) {
|
||||
callback.onPlaybackPause(currentMedia, currentMedia.getPosition());
|
||||
}
|
||||
|
||||
executor.submit(() -> callback.onPostPlayback(currentMedia, !wasSkipped, nextMedia != null));
|
||||
playerLock.unlock();
|
||||
});
|
||||
}
|
||||
|
@ -815,8 +827,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
|
|||
* This method will only take care of changing the PlayerStatus of this object! Other tasks like
|
||||
* abandoning audio focus have to be done with other methods.
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
private void stop() {
|
||||
executor.submit(() -> {
|
||||
playerLock.lock();
|
||||
releaseWifiLockIfNecessary();
|
||||
|
@ -869,7 +880,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
|
|||
mp -> genericOnCompletion();
|
||||
|
||||
private void genericOnCompletion() {
|
||||
endPlayback(false);
|
||||
endPlayback(false, true, true);
|
||||
}
|
||||
|
||||
private final MediaPlayer.OnBufferingUpdateListener audioBufferingUpdateListener =
|
||||
|
|
|
@ -786,6 +786,11 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
|||
|
||||
if (!(playable instanceof FeedMedia)) {
|
||||
Log.d(TAG, "Not doing post-playback processing: media not of type FeedMedia");
|
||||
if (ended) {
|
||||
playable.onPlaybackCompleted(getApplicationContext());
|
||||
} else {
|
||||
playable.onPlaybackPause(getApplicationContext());
|
||||
}
|
||||
return;
|
||||
}
|
||||
FeedMedia media = (FeedMedia) playable;
|
||||
|
@ -1587,7 +1592,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
|||
@Override
|
||||
public void onStop() {
|
||||
Log.d(TAG, "onStop()");
|
||||
mediaPlayer.stop();
|
||||
mediaPlayer.stopPlayback(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,8 @@ import android.util.Log;
|
|||
import android.util.Pair;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
|
||||
|
@ -226,18 +228,43 @@ public abstract class PlaybackServiceMediaPlayer {
|
|||
protected abstract void setPlayable(Playable playable);
|
||||
|
||||
public void skip() {
|
||||
endPlayback(true);
|
||||
endPlayback(true, true, true);
|
||||
}
|
||||
|
||||
protected abstract void endPlayback(boolean wasSkipped);
|
||||
/**
|
||||
* Ends playback of current media (if any) and moves into INDETERMINATE state, unless
|
||||
* {@param toStoppedState} is set to true, in which case it moves into STOPPED state.
|
||||
*
|
||||
* @see #endPlayback(boolean, boolean, boolean)
|
||||
*/
|
||||
public Future<?> stopPlayback(boolean toStoppedState) {
|
||||
return endPlayback(true, false, toStoppedState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the PSMP into STOPPED state. This call is only valid if the player is currently in
|
||||
* INDETERMINATE state, for example after a call to endPlayback.
|
||||
* This method will only take care of changing the PlayerStatus of this object! Other tasks like
|
||||
* abandoning audio focus have to be done with other methods.
|
||||
* Internal method that handles end of playback.
|
||||
*
|
||||
* Currently, it has 4 use cases:
|
||||
* <ul>
|
||||
* <li>Media playback has completed: call with (false, true, true)</li>
|
||||
* <li>User asks to skip to next episode: call with (true, true, true)</li>
|
||||
* <li>Stopping the media player: call with (true, false, true)</li>
|
||||
* <li>We want to change the media player implementation: call with (true, false, false)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param wasSkipped If true, we assume the current media's playback has ended, for
|
||||
* purposes of post playback processing.
|
||||
* @param shouldContinue If true, the media player should try to load, and possibly play,
|
||||
* the next item, based on the user preferences and whether such item
|
||||
* exists.
|
||||
* @param toStoppedState If true, the playback state gets set to STOPPED if the media player
|
||||
* is not loading/playing after this call, and the UI will reflect that.
|
||||
* Only relevant if {@param shouldContinue} is set to false, otherwise
|
||||
* this method's behavior defaults as if this parameter was true.
|
||||
*
|
||||
* @return a Future, just for the purpose of tracking its execution.
|
||||
*/
|
||||
public abstract void stop();
|
||||
protected abstract Future<?> endPlayback(boolean wasSkipped, boolean shouldContinue, boolean toStoppedState);
|
||||
|
||||
/**
|
||||
* @return {@code true} if the WifiLock feature should be used, {@code false} otherwise.
|
||||
|
|
|
@ -15,6 +15,8 @@ import android.widget.Toast;
|
|||
import com.google.android.gms.cast.ApplicationMetadata;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import de.danoeh.antennapod.core.cast.CastConsumer;
|
||||
import de.danoeh.antennapod.core.cast.CastManager;
|
||||
import de.danoeh.antennapod.core.cast.DefaultCastConsumer;
|
||||
|
@ -182,8 +184,11 @@ public class PlaybackServiceFlavorHelper {
|
|||
boolean wasLaunched) {
|
||||
PlaybackServiceMediaPlayer mediaPlayer = callback.getMediaPlayer();
|
||||
if (mediaPlayer != null) {
|
||||
//TODO change implementation to new protocol
|
||||
// mediaPlayer.endPlayback(true, true);
|
||||
try {
|
||||
mediaPlayer.stopPlayback(false).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Log.e(TAG, "There was a problem stopping playback while switching media players", e);
|
||||
}
|
||||
mediaPlayer.shutdownQuietly();
|
||||
}
|
||||
mediaPlayer = newPlayer;
|
||||
|
|
|
@ -15,6 +15,8 @@ import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastEx
|
|||
import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import de.danoeh.antennapod.core.R;
|
||||
|
@ -121,7 +123,7 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
|
|||
}
|
||||
if (playbackEnded) {
|
||||
// This is an unconventional thing to occur...
|
||||
endPlayback(true);
|
||||
endPlayback(true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,13 +261,13 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
|
|||
if (mediaChanged && currentMedia != null) {
|
||||
media = currentMedia;
|
||||
}
|
||||
endPlayback(false);
|
||||
endPlayback(false, true, true);
|
||||
return;
|
||||
case MediaStatus.IDLE_REASON_ERROR:
|
||||
Log.w(TAG, "Got an error status from the Chromecast. Skipping, if possible, to the next episode...");
|
||||
callback.onMediaPlayerInfo(CAST_ERROR_PRIORITY_HIGH,
|
||||
R.string.cast_failed_media_error_skipping);
|
||||
endPlayback(true);
|
||||
endPlayback(true, true, true);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -597,7 +599,7 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void endPlayback(boolean wasSkipped) {
|
||||
protected Future<?> endPlayback(boolean wasSkipped, boolean shouldContinue, boolean toStoppedState) {
|
||||
Log.d(TAG, "endPlayback() called");
|
||||
boolean isPlaying = playerStatus == PlayerStatus.PLAYING;
|
||||
if (playerStatus != PlayerStatus.INDETERMINATE) {
|
||||
|
@ -611,32 +613,43 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
|
|||
}
|
||||
}
|
||||
final Playable currentMedia = media;
|
||||
Playable nextMedia = callback.getNextInQueue(currentMedia);
|
||||
Playable nextMedia = null;
|
||||
if (shouldContinue) {
|
||||
nextMedia = callback.getNextInQueue(currentMedia);
|
||||
|
||||
boolean playNextEpisode = isPlaying && nextMedia != null && UserPreferences.isFollowQueue();
|
||||
if (playNextEpisode) {
|
||||
Log.d(TAG, "Playback of next episode will start immediately.");
|
||||
} else if (nextMedia == null){
|
||||
Log.d(TAG, "No more episodes available to play");
|
||||
} else {
|
||||
Log.d(TAG, "Loading next episode, but not playing automatically.");
|
||||
boolean playNextEpisode = isPlaying && nextMedia != null && UserPreferences.isFollowQueue();
|
||||
if (playNextEpisode) {
|
||||
Log.d(TAG, "Playback of next episode will start immediately.");
|
||||
} else if (nextMedia == null){
|
||||
Log.d(TAG, "No more episodes available to play");
|
||||
} else {
|
||||
Log.d(TAG, "Loading next episode, but not playing automatically.");
|
||||
}
|
||||
|
||||
if (nextMedia != null) {
|
||||
callback.onPlaybackEnded(nextMedia.getMediaType(), !playNextEpisode);
|
||||
// setting media to null signals to playMediaObject() that we're taking care of post-playback processing
|
||||
media = null;
|
||||
playMediaObject(nextMedia, false, true /*TODO for now we always stream*/, playNextEpisode, playNextEpisode);
|
||||
}
|
||||
}
|
||||
if (shouldContinue || toStoppedState) {
|
||||
if (nextMedia != null) {
|
||||
callback.onPlaybackEnded(null, true);
|
||||
stop();
|
||||
}
|
||||
callback.onPostPlayback(currentMedia, !wasSkipped, nextMedia != null);
|
||||
} else if (isPlaying) {
|
||||
callback.onPlaybackPause(currentMedia,
|
||||
currentMedia != null ? currentMedia.getPosition() : INVALID_TIME);
|
||||
}
|
||||
|
||||
if (nextMedia != null) {
|
||||
callback.onPlaybackEnded(nextMedia.getMediaType(), !playNextEpisode);
|
||||
// setting media to null signals to playMediaObject() that we're taking care of post-playback processing
|
||||
media = null;
|
||||
playMediaObject(nextMedia, false, true /*TODO for now we always stream*/, playNextEpisode, playNextEpisode);
|
||||
} else {
|
||||
callback.onPlaybackEnded(null, true);
|
||||
stop();
|
||||
}
|
||||
|
||||
callback.onPostPlayback(currentMedia, !wasSkipped, nextMedia != null);
|
||||
FutureTask<?> future = new FutureTask<>(() -> {}, null);
|
||||
future.run();
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
private void stop() {
|
||||
if (playerStatus == PlayerStatus.INDETERMINATE) {
|
||||
setPlayerStatus(PlayerStatus.STOPPED, null);
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue