diff options
author | Domingos Lopes <domingos86lopes+github@gmail.com> | 2016-04-30 01:50:35 -0400 |
---|---|---|
committer | Domingos Lopes <domingos86lopes+github@gmail.com> | 2016-07-25 23:16:28 -0400 |
commit | e94219ce26084fba304e7dc87fab074b74d8de1b (patch) | |
tree | 6745723511be262ca02c9c4c7117f1a4ff3f3367 /core/src/main | |
parent | 8e281890dd1a41cbb969e32c16d57f6ecff93953 (diff) | |
download | AntennaPod-e94219ce26084fba304e7dc87fab074b74d8de1b.zip |
change protocol for episode transition on PlaybackService
Diffstat (limited to 'core/src/main')
3 files changed, 159 insertions, 124 deletions
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 8bacac1ef..6fbc722b6 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 @@ -143,7 +143,10 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { setPlayerStatus(PlayerStatus.PAUSED, media); } - smartMarkAsPlayed(media); + if (!media.getIdentifier().equals(playable.getIdentifier())) { + final Playable oldMedia = media; + executor.submit(() -> callback.onPostPlayback(oldMedia, false, true)); + } setPlayerStatus(PlayerStatus.INDETERMINATE, null); } @@ -762,13 +765,47 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { if (playerStatus != PlayerStatus.INDETERMINATE) { setPlayerStatus(PlayerStatus.INDETERMINATE, media); } + // we're relying on the position stored in the Playable object for post-playback processing + if (media != null) { + int position = getPosition(); + if (position >= 0) { + media.setPosition(position); + } + } + if (mediaPlayer != null) { mediaPlayer.reset(); - } audioManager.abandonAudioFocus(audioFocusChangeListener); - callback.endPlayback(media, isPlaying, wasSkipped, switchingPlayers); + // 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); + + 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); + } else { + callback.onPlaybackEnded(null, true); + stop(); + } + executor.submit(() -> callback.onPostPlayback(currentMedia, !wasSkipped, nextMedia != null)); playerLock.unlock(); }); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index e3557f5f8..14fa28eed 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -700,121 +700,138 @@ public class PlaybackService extends MediaBrowserServiceCompat { } @Override - public boolean endPlayback(Playable media, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) { - PlaybackService.this.endPlayback(media, playNextEpisode, wasSkipped, switchingPlayers); - return true; + public void onPostPlayback(Playable media, boolean ended, boolean playingNext) { + PlaybackService.this.onPostPlayback(media, ended, playingNext); } - }; - private void endPlayback(final Playable playable, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) { - Log.d(TAG, "Playback ended" + (switchingPlayers ? " from switching players": "")); + @Override + public Playable getNextInQueue(Playable currentMedia) { + return PlaybackService.this.getNextInQueue(currentMedia); + } - if (playable == null) { - Log.e(TAG, "Cannot end playback: media was null"); - return; + @Override + public void onPlaybackEnded(MediaType mediaType, boolean stopPlaying) { + PlaybackService.this.onPlaybackEnded(mediaType, stopPlaying); } + }; - taskManager.cancelPositionSaver(); + private Playable getNextInQueue(final Playable currentMedia) { + if (!(currentMedia instanceof FeedMedia)) { + Log.d(TAG, "getNextInQueue(), but playable not an instance of FeedMedia, so not proceeding"); + return null; + } + if (!ClientConfig.playbackServiceCallbacks.useQueue()) { + Log.d(TAG, "getNextInQueue(), but queue not in use by this app"); + return null; + } + Log.d(TAG, "getNextInQueue()"); + FeedMedia media = (FeedMedia) currentMedia; + try { + media.loadMetadata(); + } catch (Playable.PlayableException e) { + Log.e(TAG, "Unable to load metadata to get next in queue", e); + return null; + } + FeedItem item = media.getItem(); + if (item == null) { + Log.w(TAG, "getNextInQueue() with FeedMedia object whose FeedItem is null"); + return null; + } + FeedItem nextItem; + try { + final List<FeedItem> queue = taskManager.getQueue(); + nextItem = DBTasks.getQueueSuccessorOfItem(item.getId(), queue); + } catch (InterruptedException e) { + Log.e(TAG, "Error handling the queue in order to retrieve the next item", e); + return null; + } + return (nextItem != null)? nextItem.getMedia() : null; - boolean isInQueue = false; - FeedItem nextItem = null; + } - if (playable instanceof FeedMedia && ((FeedMedia) playable).getItem() != null) { - FeedMedia media = (FeedMedia) playable; - FeedItem item = media.getItem(); + /** + * Set of instructions to be performed when playback ends. + */ + private void onPlaybackEnded(MediaType mediaType, boolean stopPlaying) { + Log.d(TAG, "Playback ended"); + if (stopPlaying) { + taskManager.cancelPositionSaver(); + writePlaybackPreferencesNoMediaPlaying(); + if (!isCasting) { + stopForeground(true); + } + stopWidgetUpdater(); + } + if (mediaType == null) { + sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0); + } else { + sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, + isCasting ? EXTRA_CODE_CAST : + (mediaType == MediaType.VIDEO) ? EXTRA_CODE_VIDEO : EXTRA_CODE_AUDIO); + } + } + + //TODO add javadoc, that is is assumed that the playable object contains info about its position and duration + private void onPostPlayback(final Playable playable, boolean ended, boolean playingNext) { + if (playable == null) { + Log.e(TAG, "Cannot do post-playback processing: media was null"); + return; + } + Log.d(TAG, "onPostPlayback(): media=" + playable.getEpisodeTitle()); - if (!switchingPlayers) { + if (!(playable instanceof FeedMedia)) { + Log.d(TAG, "Not doing post-playback processing: media not of type FeedMedia"); + return; + } + FeedMedia media = (FeedMedia) playable; + FeedItem item = media.getItem(); + boolean smartMarkAsPlayed = playingNext && media.hasAlmostEnded(); + if (!ended && smartMarkAsPlayed) { + Log.d(TAG, "smart mark as played"); + } + + // auto-flattr if enabled + if (isAutoFlattrable(media) && UserPreferences.getAutoFlattrPlayedDurationThreshold() == 1.0f) { + DBTasks.flattrItemIfLoggedIn(PlaybackService.this, item); + } + + // gpodder play action + if (GpodnetPreferences.loggedIn()) { + GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.PLAY) + .currentDeviceId() + .currentTimestamp() + .started(startPosition / 1000) + .position(((ended || smartMarkAsPlayed) ? media.getDuration() : media.getPosition()) / 1000) + .total(media.getDuration() / 1000) + .build(); + GpodnetPreferences.enqueueEpisodeAction(action); + } + + if (item != null) { + if (ended || smartMarkAsPlayed || + !UserPreferences.shouldSkipKeepEpisode()) { + // only mark the item as played if we're not keeping it anyways + DBWriter.markItemPlayed(item, FeedItem.PLAYED, ended); try { final List<FeedItem> queue = taskManager.getQueue(); - isInQueue = QueueAccess.ItemListAccess(queue).contains(item.getId()); - nextItem = DBTasks.getQueueSuccessorOfItem(item.getId(), queue); + if (QueueAccess.ItemListAccess(queue).contains(item.getId())) { + // don't know if it actually matters to not autodownload when smart mark as played is triggered + DBWriter.removeQueueItem(PlaybackService.this, item, ended); + } } catch (InterruptedException e) { e.printStackTrace(); // isInQueue remains false } - - boolean shouldKeep = wasSkipped && UserPreferences.shouldSkipKeepEpisode(); - - if (!shouldKeep) { - // only mark the item as played if we're not keeping it anyways - DBWriter.markItemPlayed(item, FeedItem.PLAYED, true); - - if (isInQueue) { - DBWriter.removeQueueItem(PlaybackService.this, item, true); - } - - // Delete episode if enabled - if (item.getFeed().getPreferences().getCurrentAutoDelete()) { - DBWriter.deleteFeedMediaOfItem(PlaybackService.this, media.getId()); - Log.d(TAG, "Episode Deleted"); - } + // Delete episode if enabled + if (item.getFeed().getPreferences().getCurrentAutoDelete()) { + DBWriter.deleteFeedMediaOfItem(PlaybackService.this, media.getId()); + Log.d(TAG, "Episode Deleted"); } } - - - DBWriter.addItemToPlaybackHistory(media); - - // auto-flattr if enabled - if (isAutoFlattrable(media) && UserPreferences.getAutoFlattrPlayedDurationThreshold() == 1.0f) { - DBTasks.flattrItemIfLoggedIn(PlaybackService.this, item); - } - - // gpodder play action - if(GpodnetPreferences.loggedIn()) { - GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.PLAY) - .currentDeviceId() - .currentTimestamp() - .started(startPosition / 1000) - .position(getDuration() / 1000) - .total(getDuration() / 1000) - .build(); - GpodnetPreferences.enqueueEpisodeAction(action); - } } - if (!switchingPlayers) { - // 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 - Playable nextMedia = null; - boolean loadNextItem = ClientConfig.playbackServiceCallbacks.useQueue() && - isInQueue && - nextItem != null; - - playNextEpisode = playNextEpisode && - loadNextItem && - UserPreferences.isFollowQueue(); - - if (loadNextItem) { - Log.d(TAG, "Loading next item in queue"); - nextMedia = nextItem.getMedia(); - } - final boolean prepareImmediately; - final boolean startWhenPrepared; - final boolean stream; - - if (playNextEpisode) { - Log.d(TAG, "Playback of next episode will start immediately."); - prepareImmediately = startWhenPrepared = true; - } else { - Log.d(TAG, "No more episodes available to play"); - prepareImmediately = startWhenPrepared = false; - stopForeground(true); - stopWidgetUpdater(); - } - - writePlaybackPreferencesNoMediaPlaying(); - if (nextMedia != null) { - stream = !nextMedia.localFileAvailable(); - mediaPlayer.playMediaObject(nextMedia, stream, startWhenPrepared, prepareImmediately); - sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, - isCasting ? EXTRA_CODE_CAST : - (nextMedia.getMediaType() == MediaType.VIDEO) ? EXTRA_CODE_VIDEO : EXTRA_CODE_AUDIO); - } else { - sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0); - mediaPlayer.stop(); - //stopSelf(); - } + if (ended || playingNext) { + DBWriter.addItemToPlaybackHistory(media); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java index e05733135..51742b27e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java @@ -9,10 +9,7 @@ import android.util.Pair; import android.view.SurfaceHolder; import de.danoeh.antennapod.core.feed.Chapter; -import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; -import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.playback.Playable; @@ -291,26 +288,6 @@ public abstract class PlaybackServiceMediaPlayer { callback.statusChanged(new PSMPInfo(playerStatus, getPlayable())); } - protected void smartMarkAsPlayed(Playable media) { - if(media != null && media instanceof FeedMedia) { - FeedMedia oldMedia = (FeedMedia) media; - if(oldMedia.hasAlmostEnded()) { - Log.d(TAG, "smart mark as read"); - FeedItem item = oldMedia.getItem(); - if (item == null) { - return; - } - DBWriter.markItemPlayed(item, FeedItem.PLAYED, false); - DBWriter.removeQueueItem(context, item, false); - DBWriter.addItemToPlaybackHistory(oldMedia); - if (item.getFeed().getPreferences().getCurrentAutoDelete()) { - Log.d(TAG, "Delete " + oldMedia.toString()); - DBWriter.deleteFeedMediaOfItem(context, oldMedia.getId()); - } - } - } - } - public interface PSMPCallback { void statusChanged(PSMPInfo newInfo); @@ -328,7 +305,11 @@ public abstract class PlaybackServiceMediaPlayer { boolean onMediaPlayerError(Object inObj, int what, int extra); - boolean endPlayback(Playable media, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers); + void onPostPlayback(Playable media, boolean ended, boolean playingNext); + + Playable getNextInQueue(Playable currentMedia); + + void onPlaybackEnded(MediaType mediaType, boolean stopPlaying); } /** |