summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDomingos Lopes <domingos86lopes+github@gmail.com>2016-03-28 22:43:22 -0400
committerDomingos Lopes <domingos86lopes+github@gmail.com>2016-04-23 21:39:57 -0400
commitb41eba90bdddfc23f9bf4c7204285ad975442f76 (patch)
treeeff3d53543e18b1d2183967d5399f7b35a47435a
parente70f4d5389fc21fc00e3ecdda0e86f07873883ba (diff)
downloadAntennaPod-b41eba90bdddfc23f9bf4c7204285ad975442f76.zip
implement basic cast session join
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java60
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java126
5 files changed, 117 insertions, 75 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
index 82cf0eed1..9177a1f1c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/CastEnabledActivity.java
@@ -82,7 +82,7 @@ public abstract class CastEnabledActivity extends AppCompatActivity
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (key.equals(UserPreferences.PREF_CAST_ENABLED)) {
+ if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
isCastEnabled = UserPreferences.isCastEnabled();
Log.d(TAG, "onSharedPreferenceChanged(), isCastEnabled set to " + isCastEnabled);
mMediaRouteActionProvider.setEnabled(isCastEnabled);
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);
+ }
}