fix skipping episodes and unwanted reinits

This commit is contained in:
Domingos Lopes 2016-04-24 02:43:20 -04:00
parent 9981c71bab
commit fab2d05979
7 changed files with 134 additions and 118 deletions

View File

@ -1441,30 +1441,29 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
*/ */
private void onRemoteMediaPlayerStatusUpdated() { private void onRemoteMediaPlayerStatusUpdated() {
Log.d(TAG, "onRemoteMediaPlayerStatusUpdated() reached"); Log.d(TAG, "onRemoteMediaPlayerStatusUpdated() reached");
if (mApiClient == null || remoteMediaPlayer == null if (mApiClient == null || remoteMediaPlayer == null) {
|| remoteMediaPlayer.getMediaStatus() == null) {
Log.d(TAG, "mApiClient or remoteMediaPlayer is null, so will not proceed"); Log.d(TAG, "mApiClient or remoteMediaPlayer is null, so will not proceed");
return; return;
} }
mediaStatus = remoteMediaPlayer.getMediaStatus(); mediaStatus = remoteMediaPlayer.getMediaStatus();
List<MediaQueueItem> queueItems = mediaStatus.getQueueItems(); if (mediaStatus == null) {
if (queueItems != null) { Log.d(TAG, "MediaStatus is null, so will not proceed");
int itemId = mediaStatus.getCurrentItemId();
MediaQueueItem item = mediaStatus.getQueueItemById(itemId);
int repeatMode = mediaStatus.getQueueRepeatMode();
onQueueUpdated(queueItems, item, repeatMode, false);
} else { } else {
onQueueUpdated(null, null, MediaStatus.REPEAT_MODE_REPEAT_OFF, false); List<MediaQueueItem> queueItems = mediaStatus.getQueueItems();
} if (queueItems != null) {
state = mediaStatus.getPlayerState(); int itemId = mediaStatus.getCurrentItemId();
idleReason = mediaStatus.getIdleReason(); MediaQueueItem item = mediaStatus.getQueueItemById(itemId);
int repeatMode = mediaStatus.getQueueRepeatMode();
onQueueUpdated(queueItems, item, repeatMode, false);
} else {
onQueueUpdated(null, null, MediaStatus.REPEAT_MODE_REPEAT_OFF, false);
}
state = mediaStatus.getPlayerState();
idleReason = mediaStatus.getIdleReason();
try {
double volume = getStreamVolume();
boolean isMute = isStreamMute();
if (state == MediaStatus.PLAYER_STATE_PLAYING) { if (state == MediaStatus.PLAYER_STATE_PLAYING) {
Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = playing"); Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = playing");
long mediaDurationLeft = getMediaTimeRemaining(); // long mediaDurationLeft = getMediaTimeRemaining();
//startReconnectionService(mediaDurationLeft); //startReconnectionService(mediaDurationLeft);
} else if (state == MediaStatus.PLAYER_STATE_PAUSED) { } else if (state == MediaStatus.PLAYER_STATE_PAUSED) {
Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = paused"); Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = paused");
@ -1482,14 +1481,17 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
} else { } else {
Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = unknown"); Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = unknown");
} }
}
for (CastConsumer consumer : castConsumers) {
consumer.onRemoteMediaPlayerStatusUpdated();
}
if (mediaStatus != null) {
double volume = mediaStatus.getStreamVolume();
boolean isMute = mediaStatus.isMute();
for (CastConsumer consumer : castConsumers) { for (CastConsumer consumer : castConsumers) {
consumer.onRemoteMediaPlayerStatusUpdated();
consumer.onStreamVolumeChanged(volume, isMute); consumer.onStreamVolumeChanged(volume, isMute);
} }
} catch (TransientNetworkDisconnectionException | NoConnectionException e) {
Log.e(TAG, "Failed to get volume state due to network issues", e);
} }
} }
private void onRemoteMediaPreloadStatusUpdated() { private void onRemoteMediaPreloadStatusUpdated() {

View File

@ -599,6 +599,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
public void shutdown() { public void shutdown() {
executor.shutdown(); executor.shutdown();
if (mediaPlayer != null) { if (mediaPlayer != null) {
removeMediaPlayerListeners(mediaPlayer);
mediaPlayer.release(); mediaPlayer.release();
} }
releaseWifiLockIfNecessary(); releaseWifiLockIfNecessary();
@ -762,7 +763,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
} }
audioManager.abandonAudioFocus(audioFocusChangeListener); audioManager.abandonAudioFocus(audioFocusChangeListener);
callback.endPlayback(isPlaying, wasSkipped, switchingPlayers); callback.endPlayback(media, isPlaying, wasSkipped, switchingPlayers);
playerLock.unlock(); playerLock.unlock();
}); });
@ -821,6 +822,26 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
return mp; return mp;
} }
private void removeMediaPlayerListeners(IPlayer mp) {
if (mp == null) {
return;
}
if (mp instanceof AudioPlayer) {
((AudioPlayer) mp).setOnCompletionListener(null);
((AudioPlayer) mp).setOnSeekCompleteListener(null);
((AudioPlayer) mp).setOnErrorListener(null);
((AudioPlayer) mp).setOnBufferingUpdateListener(null);
((AudioPlayer) mp).setOnInfoListener(null);
((AudioPlayer) mp).setOnSpeedAdjustmentAvailableChangedListener(null);
} else {
((VideoPlayer) mp).setOnCompletionListener(null);
((VideoPlayer) mp).setOnSeekCompleteListener(null);
((VideoPlayer) mp).setOnErrorListener(null);
((VideoPlayer) mp).setOnBufferingUpdateListener(null);
((VideoPlayer) mp).setOnInfoListener(null);
}
}
private final MediaPlayer.OnCompletionListener audioCompletionListener = private final MediaPlayer.OnCompletionListener audioCompletionListener =
mp -> genericOnCompletion(); mp -> genericOnCompletion();

View File

@ -413,11 +413,7 @@ public class PlaybackService extends Service {
case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (status == PlayerStatus.PLAYING) { if (status == PlayerStatus.PLAYING) {
if (UserPreferences.isPersistNotify()) { mediaPlayer.pause(!UserPreferences.isPersistNotify(), true);
mediaPlayer.pause(false, true);
} else {
mediaPlayer.pause(true, true);
}
} else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) { } else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
mediaPlayer.resume(); mediaPlayer.resume();
} else if (status == PlayerStatus.PREPARING) { } else if (status == PlayerStatus.PREPARING) {
@ -437,12 +433,7 @@ public class PlaybackService extends Service {
break; break;
case KeyEvent.KEYCODE_MEDIA_PAUSE: case KeyEvent.KEYCODE_MEDIA_PAUSE:
if (status == PlayerStatus.PLAYING) { if (status == PlayerStatus.PLAYING) {
mediaPlayer.pause(false, true); mediaPlayer.pause(!UserPreferences.isPersistNotify(), true);
}
if (UserPreferences.isPersistNotify()) {
mediaPlayer.pause(false, true);
} else {
mediaPlayer.pause(true, true);
} }
break; break;
@ -674,16 +665,15 @@ public class PlaybackService extends Service {
} }
@Override @Override
public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) { public boolean endPlayback(Playable media, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
PlaybackService.this.endPlayback(playNextEpisode, wasSkipped, switchingPlayers); PlaybackService.this.endPlayback(media, playNextEpisode, wasSkipped, switchingPlayers);
return true; return true;
} }
}; };
private void endPlayback(boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) { private void endPlayback(final Playable playable, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
Log.d(TAG, "Playback ended"); Log.d(TAG, "Playback ended");
final Playable playable = mediaPlayer.getPlayable();
if (playable == null) { if (playable == null) {
Log.e(TAG, "Cannot end playback: media was null"); Log.e(TAG, "Cannot end playback: media was null");
return; return;
@ -698,26 +688,35 @@ public class PlaybackService extends Service {
FeedMedia media = (FeedMedia) playable; FeedMedia media = (FeedMedia) playable;
FeedItem item = media.getItem(); FeedItem item = media.getItem();
try { if (!switchingPlayers) {
final List<FeedItem> queue = taskManager.getQueue(); try {
isInQueue = QueueAccess.ItemListAccess(queue).contains(item.getId()); final List<FeedItem> queue = taskManager.getQueue();
nextItem = DBTasks.getQueueSuccessorOfItem(item.getId(), queue); isInQueue = QueueAccess.ItemListAccess(queue).contains(item.getId());
} catch (InterruptedException e) { nextItem = DBTasks.getQueueSuccessorOfItem(item.getId(), queue);
e.printStackTrace(); } catch (InterruptedException e) {
// isInQueue remains false e.printStackTrace();
} // isInQueue remains false
}
boolean shouldKeep = wasSkipped && UserPreferences.shouldSkipKeepEpisode(); boolean shouldKeep = wasSkipped && UserPreferences.shouldSkipKeepEpisode();
if (!shouldKeep) { if (!shouldKeep) {
// only mark the item as played if we're not keeping it anyways // only mark the item as played if we're not keeping it anyways
DBWriter.markItemPlayed(item, FeedItem.PLAYED, true); DBWriter.markItemPlayed(item, FeedItem.PLAYED, true);
if (isInQueue) { if (isInQueue) {
DBWriter.removeQueueItem(PlaybackService.this, item, true); DBWriter.removeQueueItem(PlaybackService.this, item, true);
}
}
// Delete episode if enabled
if (item.getFeed().getPreferences().getCurrentAutoDelete() && !shouldKeep) {
DBWriter.deleteFeedMediaOfItem(PlaybackService.this, media.getId());
Log.d(TAG, "Episode Deleted");
} }
} }
DBWriter.addItemToPlaybackHistory(media); DBWriter.addItemToPlaybackHistory(media);
// auto-flattr if enabled // auto-flattr if enabled
@ -725,12 +724,6 @@ public class PlaybackService extends Service {
DBTasks.flattrItemIfLoggedIn(PlaybackService.this, item); DBTasks.flattrItemIfLoggedIn(PlaybackService.this, item);
} }
// Delete episode if enabled
if(item.getFeed().getPreferences().getCurrentAutoDelete() && !shouldKeep ) {
DBWriter.deleteFeedMediaOfItem(PlaybackService.this, media.getId());
Log.d(TAG, "Episode Deleted");
}
// gpodder play action // gpodder play action
if(GpodnetPreferences.loggedIn()) { if(GpodnetPreferences.loggedIn()) {
GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.PLAY) GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.PLAY)
@ -744,49 +737,49 @@ public class PlaybackService extends Service {
} }
} }
// Load next episode if previous episode was in the queue and if there if (!switchingPlayers) {
// is an episode in the queue left. // Load next episode if previous episode was in the queue and if there
// Start playback immediately if continuous playback is enabled // is an episode in the queue left.
Playable nextMedia = null; // Start playback immediately if continuous playback is enabled
boolean loadNextItem = ClientConfig.playbackServiceCallbacks.useQueue() && Playable nextMedia = null;
isInQueue && boolean loadNextItem = ClientConfig.playbackServiceCallbacks.useQueue() &&
nextItem != null; isInQueue &&
nextItem != null;
playNextEpisode = playNextEpisode && playNextEpisode = playNextEpisode &&
loadNextItem && loadNextItem &&
UserPreferences.isFollowQueue(); UserPreferences.isFollowQueue();
if (loadNextItem) { if (loadNextItem) {
Log.d(TAG, "Loading next item in queue"); Log.d(TAG, "Loading next item in queue");
nextMedia = nextItem.getMedia(); nextMedia = nextItem.getMedia();
} }
final boolean prepareImmediately; final boolean prepareImmediately;
final boolean startWhenPrepared; final boolean startWhenPrepared;
final boolean stream; final boolean stream;
if (playNextEpisode) { if (playNextEpisode) {
Log.d(TAG, "Playback of next episode will start immediately."); Log.d(TAG, "Playback of next episode will start immediately.");
prepareImmediately = startWhenPrepared = true; prepareImmediately = startWhenPrepared = true;
} else { } else {
Log.d(TAG, "No more episodes available to play"); Log.d(TAG, "No more episodes available to play");
prepareImmediately = startWhenPrepared = false; prepareImmediately = startWhenPrepared = false;
stopForeground(true); stopForeground(true);
stopWidgetUpdater(); stopWidgetUpdater();
} }
writePlaybackPreferencesNoMediaPlaying(); writePlaybackPreferencesNoMediaPlaying();
if (nextMedia != null) { if (nextMedia != null) {
stream = !nextMedia.localFileAvailable(); stream = !nextMedia.localFileAvailable();
mediaPlayer.playMediaObject(nextMedia, stream, startWhenPrepared, prepareImmediately); mediaPlayer.playMediaObject(nextMedia, stream, startWhenPrepared, prepareImmediately);
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD,
isCasting ? EXTRA_CODE_CAST : isCasting ? EXTRA_CODE_CAST :
(nextMedia.getMediaType() == MediaType.VIDEO) ? EXTRA_CODE_VIDEO : EXTRA_CODE_AUDIO); (nextMedia.getMediaType() == MediaType.VIDEO) ? EXTRA_CODE_VIDEO : EXTRA_CODE_AUDIO);
} else { } else {
if (!switchingPlayers) { sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0); mediaPlayer.stop();
//stopSelf();
} }
mediaPlayer.stop();
//stopSelf();
} }
} }
@ -1024,8 +1017,8 @@ public class PlaybackService extends Service {
.centerCrop() .centerCrop()
.into(iconSize, iconSize) .into(iconSize, iconSize)
.get(); .get();
} catch(Throwable tr) { } catch (Throwable tr) {
Log.e(TAG, Log.getStackTraceString(tr)); Log.e(TAG, "Error loading the media icon for the notification", tr);
} }
} }
} }
@ -1300,11 +1293,7 @@ public class PlaybackService extends Service {
if (mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING) { if (mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING) {
transientPause = true; transientPause = true;
} }
if (UserPreferences.isPersistNotify()) { mediaPlayer.pause(!UserPreferences.isPersistNotify(), true);
mediaPlayer.pause(false, true);
} else {
mediaPlayer.pause(true, true);
}
} }
} }

View File

@ -278,7 +278,7 @@ public abstract class PlaybackServiceMediaPlayer {
* @param newMedia The new playable object of the PSMP object. This can be null. * @param newMedia The new playable object of the PSMP object. This can be null.
*/ */
protected synchronized final void setPlayerStatus(@NonNull PlayerStatus newStatus, Playable newMedia) { protected synchronized final void setPlayerStatus(@NonNull PlayerStatus newStatus, Playable newMedia) {
Log.d(TAG, "Setting player status to " + newStatus); Log.d(TAG, this.getClass().getSimpleName() + ": Setting player status to " + newStatus);
this.playerStatus = newStatus; this.playerStatus = newStatus;
setPlayable(newMedia); setPlayable(newMedia);
@ -327,7 +327,7 @@ public abstract class PlaybackServiceMediaPlayer {
boolean onMediaPlayerError(Object inObj, int what, int extra); boolean onMediaPlayerError(Object inObj, int what, int extra);
boolean endPlayback(boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers); boolean endPlayback(Playable media, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers);
} }
/** /**

View File

@ -64,8 +64,8 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
if (castMgr.isConnected() && castMgr.isRemoteMediaLoaded()) { if (castMgr.isConnected() && castMgr.isRemoteMediaLoaded()) {
// updates the state, but does not start playing new media if it was going to // updates the state, but does not start playing new media if it was going to
onRemoteMediaPlayerStatusUpdated( onRemoteMediaPlayerStatusUpdated(
((playNextEpisode, wasSkipped, switchingPlayers) -> ((p, playNextEpisode, wasSkipped, switchingPlayers) ->
this.callback.endPlayback(false, wasSkipped, switchingPlayers))); this.callback.endPlayback(p, false, wasSkipped, switchingPlayers)));
} }
} catch (TransientNetworkDisconnectionException | NoConnectionException e) { } catch (TransientNetworkDisconnectionException | NoConnectionException e) {
Log.e(TAG, "Unable to do initial check for loaded media", e); Log.e(TAG, "Unable to do initial check for loaded media", e);
@ -146,6 +146,7 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
private void onRemoteMediaPlayerStatusUpdated(@NonNull EndPlaybackCall endPlaybackCall) { private void onRemoteMediaPlayerStatusUpdated(@NonNull EndPlaybackCall endPlaybackCall) {
MediaStatus status = castMgr.getMediaStatus(); MediaStatus status = castMgr.getMediaStatus();
if (status == null) { if (status == null) {
Log.d(TAG, "Received null MediaStatus");
setBuffering(false); setBuffering(false);
setPlayerStatus(PlayerStatus.INDETERMINATE, null); setPlayerStatus(PlayerStatus.INDETERMINATE, null);
return; return;
@ -186,12 +187,12 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
case MediaStatus.IDLE_REASON_FINISHED: case MediaStatus.IDLE_REASON_FINISHED:
boolean playing = playerStatus == PlayerStatus.PLAYING; boolean playing = playerStatus == PlayerStatus.PLAYING;
setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia);
endPlaybackCall.endPlayback(playing, false, false); endPlaybackCall.endPlayback(currentMedia,playing, false, false);
break; break;
case MediaStatus.IDLE_REASON_ERROR: case MediaStatus.IDLE_REASON_ERROR:
//Let's assume it's a media format error. Skipping... Log.w(TAG, "Got an error status from the Chromecast. Skipping, if possible, to the next episode...");
setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia);
endPlaybackCall.endPlayback(startWhenPrepared.get(), true, false); endPlaybackCall.endPlayback(currentMedia, startWhenPrepared.get(), true, false);
} }
break; break;
case MediaStatus.PLAYER_STATE_UNKNOWN: case MediaStatus.PLAYER_STATE_UNKNOWN:
@ -286,18 +287,13 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
@Override @Override
public void pause(boolean abandonFocus, boolean reinit) { public void pause(boolean abandonFocus, boolean reinit) {
boolean playing = true;
try { try {
playing = castMgr.isRemoteMediaPlaying(); if (castMgr.isRemoteMediaPlaying()) {
if (playing) {
castMgr.pause(); castMgr.pause();
} }
} catch (CastException | TransientNetworkDisconnectionException | NoConnectionException e) { } catch (CastException | TransientNetworkDisconnectionException | NoConnectionException e) {
Log.e(TAG, "Unable to pause", e); Log.e(TAG, "Unable to pause", e);
} }
if (playing && reinit) {
reinit();
}
} }
@Override @Override
@ -325,6 +321,7 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
@Override @Override
public void reinit() { public void reinit() {
Log.d(TAG, "reinit() called");
if (media != null) { if (media != null) {
playMediaObject(media, true, false, startWhenPrepared.get(), false); playMediaObject(media, true, false, startWhenPrepared.get(), false);
} else { } else {
@ -513,11 +510,12 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
@Override @Override
public void endPlayback(boolean wasSkipped, boolean switchingPlayers) { public void endPlayback(boolean wasSkipped, boolean switchingPlayers) {
Log.d(TAG, "endPlayback() called");
boolean isPlaying = playerStatus == PlayerStatus.PLAYING; boolean isPlaying = playerStatus == PlayerStatus.PLAYING;
if (playerStatus != PlayerStatus.INDETERMINATE) { if (playerStatus != PlayerStatus.INDETERMINATE) {
setPlayerStatus(PlayerStatus.INDETERMINATE, media); setPlayerStatus(PlayerStatus.INDETERMINATE, media);
} }
callback.endPlayback(isPlaying, wasSkipped, switchingPlayers); callback.endPlayback(media, isPlaying, wasSkipped, switchingPlayers);
} }
@Override @Override
@ -535,6 +533,6 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
} }
private interface EndPlaybackCall { private interface EndPlaybackCall {
boolean endPlayback(boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers); boolean endPlayback(Playable media, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers);
} }
} }

View File

@ -0,0 +1,5 @@
package de.danoeh.antennapod.core.util;
public interface Supplier<T> {
T get();
}

View File

@ -750,6 +750,7 @@ public abstract class PlaybackController {
public void reinitServiceIfPaused() { public void reinitServiceIfPaused() {
if (playbackService != null if (playbackService != null
&& playbackService.isStreaming() && playbackService.isStreaming()
&& !PlaybackService.isCasting()
&& (playbackService.getStatus() == PlayerStatus.PAUSED || && (playbackService.getStatus() == PlayerStatus.PAUSED ||
(playbackService.getStatus() == PlayerStatus.PREPARING && (playbackService.getStatus() == PlayerStatus.PREPARING &&
!playbackService.isStartWhenPrepared()))) { !playbackService.isStartWhenPrepared()))) {