diff options
author | Domingos Lopes <domingos86lopes+github@gmail.com> | 2016-03-28 22:43:22 -0400 |
---|---|---|
committer | Domingos Lopes <domingos86lopes+github@gmail.com> | 2016-04-23 21:39:57 -0400 |
commit | b41eba90bdddfc23f9bf4c7204285ad975442f76 (patch) | |
tree | eff3d53543e18b1d2183967d5399f7b35a47435a /core | |
parent | e70f4d5389fc21fc00e3ecdda0e86f07873883ba (diff) | |
download | AntennaPod-b41eba90bdddfc23f9bf4c7204285ad975442f76.zip |
implement basic cast session join
Diffstat (limited to 'core')
4 files changed, 116 insertions, 74 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 684c54d7f..cd5a2cfd1 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 @@ -609,7 +609,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { * This method is executed on an internal executor service. */ @Override - public void shutdownAsync() { + public void shutdownQuietly() { executor.submit(this::shutdown); executor.shutdown(); } 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 8d43c986b..fe6218767 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 @@ -71,7 +71,7 @@ import de.danoeh.antennapod.core.util.playback.Playable; /** * Controls the MediaPlayer that plays a FeedMedia-file */ -public class PlaybackService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener { +public class PlaybackService extends Service { public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE"; public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE"; /** @@ -277,11 +277,17 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar registerReceiver(pauseResumeCurrentEpisodeReceiver, new IntentFilter( ACTION_RESUME_PLAY_CURRENT_EPISODE)); taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback); + PreferenceManager.getDefaultSharedPreferences(this) + .registerOnSharedPreferenceChangeListener(prefListener); CastManager castMgr = CastManager.getInstance(); castMgr.addCastConsumer(castConsumer); isCasting = castMgr.isConnected(); if (isCasting) { - onCastAppConnected(false); + if (UserPreferences.isCastEnabled()) { + onCastAppConnected(false); + } else { + castMgr.disconnect(); + } } else { mediaPlayer = new LocalPSMP(this, mediaPlayerCallback); } @@ -306,8 +312,6 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar Log.e(TAG, "NullPointerException while setting up MediaSession"); npe.printStackTrace(); } - PreferenceManager.getDefaultSharedPreferences(this) - .registerOnSharedPreferenceChangeListener(this); } @Override @@ -319,7 +323,7 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar currentMediaType = MediaType.UNKNOWN; PreferenceManager.getDefaultSharedPreferences(this) - .unregisterOnSharedPreferenceChangeListener(this); + .unregisterOnSharedPreferenceChangeListener(prefListener); if (mediaSession != null) { mediaSession.release(); } @@ -345,13 +349,6 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar } @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(key.equals(UserPreferences.PREF_LOCKSCREEN_BACKGROUND)) { - updateMediaSessionMetadata(getPlayable()); - } - } - - @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); @@ -1598,7 +1595,7 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar info = new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null); } switchMediaPlayer(new LocalPSMP(PlaybackService.this, mediaPlayerCallback), - info); + info, false); if (info.playable != null) { sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, info.playable.getMediaType() == MediaType.AUDIO ? EXTRA_CODE_AUDIO : EXTRA_CODE_VIDEO); @@ -1611,31 +1608,42 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar }; private void onCastAppConnected(boolean wasLaunched) { - //TODO deal with wasLaunched == false - Log.d(TAG, "A cast device application was connected"); + Log.d(TAG, "A cast device application was " + (wasLaunched ? "launched" : "joined")); isCasting = true; if (mediaPlayer != null) { PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo(); if (info.playerStatus == PlayerStatus.PLAYING) { - // could be pause, but this way we make sure the new player will get the correct position, since pause runs asynchronously + // could be pause, but this way we make sure the new player will get the correct position, + // since pause runs asynchronously and we could be directing the new player to play even before + // the old player gives us back the position. saveCurrentPosition(false, 0); } } switchMediaPlayer(new RemotePSMP(PlaybackService.this, mediaPlayerCallback), (mediaPlayer != null) ? mediaPlayer.getPSMPInfo() : - new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null)); + new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null), + wasLaunched); sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, EXTRA_CODE_CAST); registerWifiBroadcastReceiver(); } private void switchMediaPlayer(@NonNull PlaybackServiceMediaPlayer newPlayer, - @NonNull PlaybackServiceMediaPlayer.PSMPInfo info) { + @NonNull PlaybackServiceMediaPlayer.PSMPInfo info, + boolean wasLaunched) { if (mediaPlayer != null) { mediaPlayer.endPlayback(true, true); - mediaPlayer.shutdownAsync(); + mediaPlayer.shutdownQuietly(); } mediaPlayer = newPlayer; Log.d(TAG, "switched to " + mediaPlayer.getClass().getSimpleName()); + if (!wasLaunched) { + PlaybackServiceMediaPlayer.PSMPInfo candidate = mediaPlayer.getPSMPInfo(); + if (candidate.playable != null && + candidate.playerStatus.isAtLeast(PlayerStatus.PREPARING)) { + // do not automatically send new media to cast device + info.playable = null; + } + } if (info.playable != null) { mediaPlayer.playMediaObject(info.playable, !info.playable.localFileAvailable(), @@ -1676,4 +1684,18 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar mWifiBroadcastReceiver = null; } } + + private SharedPreferences.OnSharedPreferenceChangeListener prefListener = + (sharedPreferences, key) -> { + if (UserPreferences.PREF_CAST_ENABLED.equals(key)) { + if (!UserPreferences.isCastEnabled()) { + CastManager castManager = CastManager.getInstance(); + if (castManager.isConnecting() || castManager.isConnected()) { + castManager.disconnect(); + } + } + } else if(key.equals(UserPreferences.PREF_LOCKSCREEN_BACKGROUND)) { + updateMediaSessionMetadata(getPlayable()); + } + }; } 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 13eedfba2..be6f8f3ed 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 @@ -191,7 +191,7 @@ public abstract class PlaybackServiceMediaPlayer { * Releases internally used resources. This method should only be called when the object is not used anymore. * This method is executed on an internal executor service. */ - public abstract void shutdownAsync(); + public abstract void shutdownQuietly(); public abstract void setVideoSurface(SurfaceHolder surface); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java index 7ca9149fd..645f0fe2d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java @@ -67,6 +67,17 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer { executor = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<>(), (r, executor) -> Log.d(TAG, "Rejected execution of runnable")); + try { + 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))); + } + } catch (TransientNetworkDisconnectionException | NoConnectionException e) { + Log.e(TAG, "Unable to do initial check for loaded media", e); + } + castMgr.addCastConsumer(castConsumer); //TODO } @@ -74,62 +85,12 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer { private CastConsumer castConsumer = new CastConsumerImpl() { @Override public void onRemoteMediaPlayerMetadataUpdated() { - //TODO check this is indeed a correct behavior - onRemoteMediaPlayerStatusUpdated(); + RemotePSMP.this.onRemoteMediaPlayerStatusUpdated(callback::endPlayback); } @Override public void onRemoteMediaPlayerStatusUpdated() { - MediaStatus status = castMgr.getMediaStatus(); - if (status == null) { - setBuffering(false); - setPlayerStatus(PlayerStatus.INDETERMINATE, null); - return; - } - Playable currentMedia = localVersion(status.getMediaInfo()); - long position = status.getStreamPosition(); - if (position > 0 && currentMedia.getPosition()==0) { - currentMedia.setPosition((int) position); - } - int state = status.getPlayerState(); - setBuffering(state == MediaStatus.PLAYER_STATE_BUFFERING); - switch (state) { - case MediaStatus.PLAYER_STATE_PLAYING: - setPlayerStatus(PlayerStatus.PLAYING, currentMedia); - break; - case MediaStatus.PLAYER_STATE_PAUSED: - setPlayerStatus(PlayerStatus.PAUSED, currentMedia); - break; - case MediaStatus.PLAYER_STATE_BUFFERING: - setPlayerStatus(playerStatus, currentMedia); - break; - case MediaStatus.PLAYER_STATE_IDLE: - int reason = status.getIdleReason(); - switch (reason) { - case MediaStatus.IDLE_REASON_CANCELED: - setPlayerStatus(PlayerStatus.STOPPED, currentMedia); - break; - case MediaStatus.IDLE_REASON_INTERRUPTED: - setPlayerStatus(PlayerStatus.PREPARING, currentMedia); - break; - case MediaStatus.IDLE_REASON_NONE: - setPlayerStatus(PlayerStatus.INITIALIZED, currentMedia); - break; - case MediaStatus.IDLE_REASON_FINISHED: - boolean playing = playerStatus == PlayerStatus.PLAYING; - setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); - callback.endPlayback(playing, false, false); - break; - case MediaStatus.IDLE_REASON_ERROR: - //Let's assume it's a media format error. Skipping... - setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); - callback.endPlayback(startWhenPrepared.get(), true, false); - } - break; - case MediaStatus.PLAYER_STATE_UNKNOWN: - //is this right? - setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); - } + RemotePSMP.this.onRemoteMediaPlayerStatusUpdated(callback::endPlayback); } @Override @@ -189,6 +150,61 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer { return null; } + private void onRemoteMediaPlayerStatusUpdated(@NonNull EndPlaybackCall endPlaybackCall) { + MediaStatus status = castMgr.getMediaStatus(); + if (status == null) { + setBuffering(false); + setPlayerStatus(PlayerStatus.INDETERMINATE, null); + return; + } + Playable currentMedia = localVersion(status.getMediaInfo()); + if (currentMedia != null) { + long position = status.getStreamPosition(); + if (position > 0 && currentMedia.getPosition() == 0) { + currentMedia.setPosition((int) position); + } + } + int state = status.getPlayerState(); + setBuffering(state == MediaStatus.PLAYER_STATE_BUFFERING); + switch (state) { + case MediaStatus.PLAYER_STATE_PLAYING: + setPlayerStatus(PlayerStatus.PLAYING, currentMedia); + break; + case MediaStatus.PLAYER_STATE_PAUSED: + setPlayerStatus(PlayerStatus.PAUSED, currentMedia); + break; + case MediaStatus.PLAYER_STATE_BUFFERING: + setPlayerStatus(playerStatus, currentMedia); + break; + case MediaStatus.PLAYER_STATE_IDLE: + int reason = status.getIdleReason(); + switch (reason) { + case MediaStatus.IDLE_REASON_CANCELED: + setPlayerStatus(PlayerStatus.STOPPED, currentMedia); + break; + case MediaStatus.IDLE_REASON_INTERRUPTED: + setPlayerStatus(PlayerStatus.PREPARING, currentMedia); + break; + case MediaStatus.IDLE_REASON_NONE: + setPlayerStatus(PlayerStatus.INITIALIZED, currentMedia); + break; + case MediaStatus.IDLE_REASON_FINISHED: + boolean playing = playerStatus == PlayerStatus.PLAYING; + setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); + endPlaybackCall.endPlayback(playing, false, false); + break; + case MediaStatus.IDLE_REASON_ERROR: + //Let's assume it's a media format error. Skipping... + setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); + endPlaybackCall.endPlayback(startWhenPrepared.get(), true, false); + } + break; + case MediaStatus.PLAYER_STATE_UNKNOWN: + //is this right? + setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); + } + } + @Override public void playMediaObject(@NonNull final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) { Log.d(TAG, "playMediaObject() called"); @@ -461,7 +477,7 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer { } @Override - public void shutdownAsync() { + public void shutdownQuietly() { executor.execute(this::shutdown); executor.shutdown(); } @@ -516,4 +532,8 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer { protected boolean shouldLockWifi() { return false; } + + private interface EndPlaybackCall { + boolean endPlayback(boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers); + } } |