add a general callback method for reporting media updates

This commit is contained in:
Domingos Lopes 2016-04-26 01:10:08 -04:00
parent 86cc2233d3
commit b1f62b56cd
5 changed files with 139 additions and 91 deletions

View File

@ -176,7 +176,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -255,7 +255,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -337,7 +337,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -420,7 +420,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -497,7 +497,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -575,7 +575,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -655,7 +655,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -738,7 +738,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -796,7 +796,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -874,7 +874,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -989,7 +989,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -1081,7 +1081,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}
@ -1185,7 +1185,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
public void reloadUI() {
}

View File

@ -158,7 +158,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
setPlayerStatus(PlayerStatus.INITIALIZING, media);
try {
media.loadMetadata();
executor.submit(() -> callback.updateMediaSessionMetadata(media));
callback.reloadUI();
if (stream) {
mediaPlayer.setDataSource(media.getStreamUrl());
} else {
@ -599,7 +599,6 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
public void shutdown() {
executor.shutdown();
if (mediaPlayer != null) {
removeMediaPlayerListeners(mediaPlayer);
mediaPlayer.release();
}
releaseWifiLockIfNecessary();
@ -822,26 +821,6 @@ 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

@ -22,10 +22,10 @@ import android.os.Build;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.support.annotation.NonNull;
import android.support.v7.app.NotificationCompat;
import android.support.v7.media.MediaRouter;
import android.text.TextUtils;
@ -39,6 +39,7 @@ import android.view.WindowManager;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.Target;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager;
@ -633,8 +634,9 @@ public class PlaybackService extends Service {
}
@Override
public void updateMediaSessionMetadata(Playable p) {
PlaybackService.this.updateMediaSessionMetadata(p);
public void reloadUI() {
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
PlaybackService.this.updateMediaSessionMetadata(getPlayable());
}
@Override
@ -672,7 +674,7 @@ public class PlaybackService extends Service {
};
private void endPlayback(final Playable playable, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers) {
Log.d(TAG, "Playback ended");
Log.d(TAG, "Playback ended" + (switchingPlayers ? " from switching players": ""));
if (playable == null) {
Log.e(TAG, "Cannot end playback: media was null");
@ -707,12 +709,12 @@ public class PlaybackService extends Service {
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");
// Delete episode if enabled
if (item.getFeed().getPreferences().getCurrentAutoDelete()) {
DBWriter.deleteFeedMediaOfItem(PlaybackService.this, media.getId());
Log.d(TAG, "Episode Deleted");
}
}
}
@ -903,11 +905,6 @@ public class PlaybackService extends Service {
sendBroadcast(intent);
}
/**
* Used by setupNotification to load notification data in another thread.
*/
private Thread notificationSetupThread;
/**
* Updates the Media Session for the corresponding status.
* @param playerStatus the current {@link PlayerStatus}
@ -957,37 +954,68 @@ public class PlaybackService extends Service {
mediaSession.setPlaybackState(sessionState.build());
}
private void updateMediaSessionMetadata(Playable p) {
/**
* Used by updateMediaSessionMetadata to load notification data in another thread.
*/
private Thread mediaSessionSetupThread;
private void updateMediaSessionMetadata(final Playable p) {
if (p == null || mediaSession == null) {
return;
}
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
try {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Bitmap art = Glide.with(this)
.load(p.getImageUri())
.asBitmap()
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.centerCrop()
.into(display.getWidth(), display.getHeight())
.get();
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
} catch (Throwable tr) {
Log.e(TAG, Log.getStackTraceString(tr));
}
if (mediaSessionSetupThread != null) {
mediaSessionSetupThread.interrupt();
}
mediaSession.setMetadata(builder.build());
Runnable mediaSessionSetupTask = () -> {
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
try {
if (isCasting) {
Bitmap art = Glide.with(this)
.load(p.getImageUri())
.asBitmap()
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
} else {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Bitmap art = Glide.with(this)
.load(p.getImageUri())
.asBitmap()
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.centerCrop()
.into(display.getWidth(), display.getHeight())
.get();
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
}
} catch (Throwable tr) {
Log.e(TAG, Log.getStackTraceString(tr));
}
}
if (!Thread.currentThread().isInterrupted() && started) {
mediaSession.setMetadata(builder.build());
}
};
mediaSessionSetupThread = new Thread(mediaSessionSetupTask);
mediaSessionSetupThread.start();
}
/**
* Used by setupNotification to load notification data in another thread.
*/
private Thread notificationSetupThread;
/**
* Prepares notification and starts the service in the foreground.
*/

View File

@ -321,7 +321,7 @@ public abstract class PlaybackServiceMediaPlayer {
void onBufferingUpdate(int percent);
void updateMediaSessionMetadata(Playable p);
void reloadUI();
boolean onMediaPlayerInfo(int code);

View File

@ -7,6 +7,7 @@ import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
import com.google.android.gms.cast.Cast;
import com.google.android.gms.cast.CastStatusCodes;
import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaStatus;
@ -14,9 +15,6 @@ import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastEx
import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException;
import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import de.danoeh.antennapod.core.cast.CastConsumer;
@ -46,8 +44,6 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
private final AtomicBoolean startWhenPrepared;
private final ThreadPoolExecutor executor;
public RemotePSMP(@NonNull Context context, @NonNull PSMPCallback callback) {
super(context, callback);
@ -57,9 +53,6 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
startWhenPrepared = new AtomicBoolean(false);
isBuffering = new AtomicBoolean(false);
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
@ -107,6 +100,26 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
Log.d(TAG, "onMediaLoadResult called, but Player Status wasn't in preparing state, so we ignore the result");
}
}
@Override
public void onApplicationStatusChanged(String appStatus) {
if (playerStatus != PlayerStatus.PLAYING) {
Log.d(TAG, "onApplicationStatusChanged, but no media was playing");
return;
}
boolean playbackEnded = false;
try {
int standbyState = castMgr.getApplicationStandbyState();
Log.d(TAG, "standbyState: " + standbyState);
playbackEnded = standbyState == Cast.STANDBY_STATE_YES;
} catch (IllegalStateException e) {
Log.d(TAG, "unable to get standbyState on onApplicationStatusChanged()");
}
if (playbackEnded) {
setPlayerStatus(PlayerStatus.INDETERMINATE, media);
callback.endPlayback(media, true, false, false);
}
}
};
private void setBuffering(boolean buffering) {
@ -147,13 +160,14 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
MediaStatus status = castMgr.getMediaStatus();
if (status == null) {
Log.d(TAG, "Received null MediaStatus");
setBuffering(false);
setPlayerStatus(PlayerStatus.INDETERMINATE, null);
//setBuffering(false);
//setPlayerStatus(PlayerStatus.INDETERMINATE, null);
return;
} else {
Log.d(TAG, "Received remote status/media update. New state=" + status.getPlayerState());
}
Playable currentMedia = localVersion(status.getMediaInfo());
boolean updateUI = currentMedia != media;
if (currentMedia != null) {
long position = status.getStreamPosition();
if (position > 0 && currentMedia.getPosition() == 0) {
@ -176,10 +190,20 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
int reason = status.getIdleReason();
switch (reason) {
case MediaStatus.IDLE_REASON_CANCELED:
setPlayerStatus(PlayerStatus.STOPPED, currentMedia);
// check if we're already loading something else
if (!updateUI || media == null) {
setPlayerStatus(PlayerStatus.STOPPED, currentMedia);
} else {
updateUI = false;
}
break;
case MediaStatus.IDLE_REASON_INTERRUPTED:
setPlayerStatus(PlayerStatus.PREPARING, currentMedia);
// check if we're already loading something else
if (!updateUI || media == null) {
setPlayerStatus(PlayerStatus.PREPARING, currentMedia);
} else {
updateUI = false;
}
break;
case MediaStatus.IDLE_REASON_NONE:
setPlayerStatus(PlayerStatus.INITIALIZED, currentMedia);
@ -188,11 +212,15 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
boolean playing = playerStatus == PlayerStatus.PLAYING;
setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia);
endPlaybackCall.endPlayback(currentMedia,playing, false, false);
// endPlayback already updates the UI, so no need to trigger it ourselves
updateUI = false;
break;
case MediaStatus.IDLE_REASON_ERROR:
Log.w(TAG, "Got an error status from the Chromecast. Skipping, if possible, to the next episode...");
setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia);
endPlaybackCall.endPlayback(currentMedia, startWhenPrepared.get(), true, false);
// endPlayback already updates the UI, so no need to trigger it ourselves
updateUI = false;
}
break;
case MediaStatus.PLAYER_STATE_UNKNOWN:
@ -203,6 +231,9 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
Log.e(TAG, "Remote media state undetermined!");
setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia);
}
if (updateUI) {
callback.reloadUI();
}
}
@Override
@ -257,7 +288,7 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
setPlayerStatus(PlayerStatus.INITIALIZING, media);
try {
media.loadMetadata();
executor.execute(() -> callback.updateMediaSessionMetadata(media));
callback.reloadUI();
setPlayerStatus(PlayerStatus.INITIALIZED, media);
if (prepareImmediately) {
prepare();
@ -471,13 +502,11 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
@Override
public void shutdown() {
castMgr.removeCastConsumer(castConsumer);
executor.shutdown();
}
@Override
public void shutdownQuietly() {
executor.execute(this::shutdown);
executor.shutdown();
shutdown();
}
@Override
@ -512,6 +541,18 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
public void endPlayback(boolean wasSkipped, boolean switchingPlayers) {
Log.d(TAG, "endPlayback() called");
boolean isPlaying = playerStatus == PlayerStatus.PLAYING;
try {
isPlaying = castMgr.isRemoteMediaPlaying();
} catch (TransientNetworkDisconnectionException | NoConnectionException e) {
Log.e(TAG, "Could not determine if media is playing", e);
}
if (wasSkipped) {
try {
castMgr.stop();
} catch (CastException | TransientNetworkDisconnectionException | NoConnectionException e) {
Log.e(TAG, "Could not stop remote playback when skipping", e);
}
}
if (playerStatus != PlayerStatus.INDETERMINATE) {
setPlayerStatus(PlayerStatus.INDETERMINATE, media);
}