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

View File

@ -599,6 +599,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
public void shutdown() {
executor.shutdown();
if (mediaPlayer != null) {
removeMediaPlayerListeners(mediaPlayer);
mediaPlayer.release();
}
releaseWifiLockIfNecessary();
@ -762,7 +763,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
}
audioManager.abandonAudioFocus(audioFocusChangeListener);
callback.endPlayback(isPlaying, wasSkipped, switchingPlayers);
callback.endPlayback(media, isPlaying, wasSkipped, switchingPlayers);
playerLock.unlock();
});
@ -821,6 +822,26 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
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 =
mp -> genericOnCompletion();

View File

@ -413,11 +413,7 @@ public class PlaybackService extends Service {
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (status == PlayerStatus.PLAYING) {
if (UserPreferences.isPersistNotify()) {
mediaPlayer.pause(false, true);
} else {
mediaPlayer.pause(true, true);
}
mediaPlayer.pause(!UserPreferences.isPersistNotify(), true);
} else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
mediaPlayer.resume();
} else if (status == PlayerStatus.PREPARING) {
@ -437,12 +433,7 @@ public class PlaybackService extends Service {
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
if (status == PlayerStatus.PLAYING) {
mediaPlayer.pause(false, true);
}
if (UserPreferences.isPersistNotify()) {
mediaPlayer.pause(false, true);
} else {
mediaPlayer.pause(true, true);
mediaPlayer.pause(!UserPreferences.isPersistNotify(), true);
}
break;
@ -674,16 +665,15 @@ public class PlaybackService extends Service {
}
@Override
public boolean endPlayback(boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
PlaybackService.this.endPlayback(playNextEpisode, wasSkipped, switchingPlayers);
public boolean endPlayback(Playable media, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
PlaybackService.this.endPlayback(media, playNextEpisode, wasSkipped, switchingPlayers);
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");
final Playable playable = mediaPlayer.getPlayable();
if (playable == null) {
Log.e(TAG, "Cannot end playback: media was null");
return;
@ -698,26 +688,35 @@ public class PlaybackService extends Service {
FeedMedia media = (FeedMedia) playable;
FeedItem item = media.getItem();
try {
final List<FeedItem> queue = taskManager.getQueue();
isInQueue = QueueAccess.ItemListAccess(queue).contains(item.getId());
nextItem = DBTasks.getQueueSuccessorOfItem(item.getId(), queue);
} catch (InterruptedException e) {
e.printStackTrace();
// isInQueue remains false
}
if (!switchingPlayers) {
try {
final List<FeedItem> queue = taskManager.getQueue();
isInQueue = QueueAccess.ItemListAccess(queue).contains(item.getId());
nextItem = DBTasks.getQueueSuccessorOfItem(item.getId(), queue);
} catch (InterruptedException e) {
e.printStackTrace();
// isInQueue remains false
}
boolean shouldKeep = wasSkipped && UserPreferences.shouldSkipKeepEpisode();
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 (!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);
if (isInQueue) {
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);
// auto-flattr if enabled
@ -725,12 +724,6 @@ public class PlaybackService extends Service {
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
if(GpodnetPreferences.loggedIn()) {
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
// 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;
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();
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 {
if (!switchingPlayers) {
sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
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();
}
mediaPlayer.stop();
//stopSelf();
}
}
@ -1024,8 +1017,8 @@ public class PlaybackService extends Service {
.centerCrop()
.into(iconSize, iconSize)
.get();
} catch(Throwable tr) {
Log.e(TAG, Log.getStackTraceString(tr));
} catch (Throwable 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) {
transientPause = true;
}
if (UserPreferences.isPersistNotify()) {
mediaPlayer.pause(false, true);
} else {
mediaPlayer.pause(true, true);
}
mediaPlayer.pause(!UserPreferences.isPersistNotify(), 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.
*/
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;
setPlayable(newMedia);
@ -327,7 +327,7 @@ public abstract class PlaybackServiceMediaPlayer {
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()) {
// updates the state, but does not start playing new media if it was going to
onRemoteMediaPlayerStatusUpdated(
((playNextEpisode, wasSkipped, switchingPlayers) ->
this.callback.endPlayback(false, wasSkipped, switchingPlayers)));
((p, playNextEpisode, wasSkipped, switchingPlayers) ->
this.callback.endPlayback(p, false, wasSkipped, switchingPlayers)));
}
} catch (TransientNetworkDisconnectionException | NoConnectionException 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) {
MediaStatus status = castMgr.getMediaStatus();
if (status == null) {
Log.d(TAG, "Received null MediaStatus");
setBuffering(false);
setPlayerStatus(PlayerStatus.INDETERMINATE, null);
return;
@ -186,12 +187,12 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
case MediaStatus.IDLE_REASON_FINISHED:
boolean playing = playerStatus == PlayerStatus.PLAYING;
setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia);
endPlaybackCall.endPlayback(playing, false, false);
endPlaybackCall.endPlayback(currentMedia,playing, false, false);
break;
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);
endPlaybackCall.endPlayback(startWhenPrepared.get(), true, false);
endPlaybackCall.endPlayback(currentMedia, startWhenPrepared.get(), true, false);
}
break;
case MediaStatus.PLAYER_STATE_UNKNOWN:
@ -286,18 +287,13 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
@Override
public void pause(boolean abandonFocus, boolean reinit) {
boolean playing = true;
try {
playing = castMgr.isRemoteMediaPlaying();
if (playing) {
if (castMgr.isRemoteMediaPlaying()) {
castMgr.pause();
}
} catch (CastException | TransientNetworkDisconnectionException | NoConnectionException e) {
Log.e(TAG, "Unable to pause", e);
}
if (playing && reinit) {
reinit();
}
}
@Override
@ -325,6 +321,7 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
@Override
public void reinit() {
Log.d(TAG, "reinit() called");
if (media != null) {
playMediaObject(media, true, false, startWhenPrepared.get(), false);
} else {
@ -513,11 +510,12 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
@Override
public void endPlayback(boolean wasSkipped, boolean switchingPlayers) {
Log.d(TAG, "endPlayback() called");
boolean isPlaying = playerStatus == PlayerStatus.PLAYING;
if (playerStatus != PlayerStatus.INDETERMINATE) {
setPlayerStatus(PlayerStatus.INDETERMINATE, media);
}
callback.endPlayback(isPlaying, wasSkipped, switchingPlayers);
callback.endPlayback(media, isPlaying, wasSkipped, switchingPlayers);
}
@Override
@ -535,6 +533,6 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
}
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() {
if (playbackService != null
&& playbackService.isStreaming()
&& !PlaybackService.isCasting()
&& (playbackService.getStatus() == PlayerStatus.PAUSED ||
(playbackService.getStatus() == PlayerStatus.PREPARING &&
!playbackService.isStartWhenPrepared()))) {