From 366c98a3abab425d562b4dba811d04093dfabdba Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 30 Nov 2015 15:34:14 -0800 Subject: Move next setup login into DownloadService, fix some casting UI issues --- .../daneren2005/dsub/service/DLNAController.java | 6 ------ .../daneren2005/dsub/service/DownloadService.java | 23 ++++++++++++++++++---- .../daneren2005/dsub/service/RemoteController.java | 11 +---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java index 64abce8a..a0dc16c1 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java @@ -171,11 +171,6 @@ public class DLNAController extends RemoteController { switch (lastChange.getEventedValue(0, AVTransportVariable.TransportState.class).getValue()) { case PLAYING: downloadService.setPlayerState(PlayerState.STARTED); - - // Try to setup next playing after playback start has been registered - if(supportsSetupNext && downloadService.getNextPlayerState() == PlayerState.IDLE) { - downloadService.setNextPlaying(); - } break; case PAUSED_PLAYBACK: downloadService.setPlayerState(PlayerState.PAUSED); @@ -408,7 +403,6 @@ public class DLNAController extends RemoteController { Pair songInfo = getSongInfo(currentPlaying); currentPlayingURI = songInfo.getFirst(); - downloadService.setNextPlayerState(PlayerState.IDLE); controlPoint.execute(new SetAVTransportURI(getTransportService(), songInfo.getFirst(), songInfo.getSecond()) { @Override public void success(ActionInvocation invocation) { diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index baff1a72..37070903 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -401,7 +401,10 @@ public class DownloadService extends Service { offset++; } } - setNextPlaying(); + + if(remoteState == LOCAL || (remoteController != null && remoteController.isNextSupported())) { + setNextPlaying(); + } } else { int size = size(); int index = getCurrentPlayingIndex(); @@ -881,13 +884,13 @@ public class DownloadService extends Service { if(remoteState == LOCAL) { nextPlayingTask = new CheckCompletionTask(nextPlaying); nextPlayingTask.execute(); - } else if(remoteController != null) { + } else if(remoteController != null && remoteController.isNextSupported()) { remoteController.changeNextTrack(nextPlaying); } } else { if(remoteState == LOCAL) { // resetNext(); - } else if(remoteController != null) { + } else if(remoteController != null && remoteController.isNextSupported()) { remoteController.changeNextTrack(nextPlaying); } nextPlaying = null; @@ -1100,11 +1103,14 @@ public class DownloadService extends Service { } mediaPlayer.seekTo(position); - cachedPosition = position; subtractPosition = 0; } + cachedPosition = position; onSongProgress(); + if(playerState == PAUSED) { + lifecycleSupport.serializeDownloadQueue(); + } } catch (Exception x) { handleError(x); } @@ -1408,6 +1414,15 @@ public class DownloadService extends Service { positionCache.stop(); positionCache = null; } + + if(remoteController != null && remoteController.isNextSupported()) { + if(playerState == STARTED && nextPlayerState == IDLE) { + setNextPlaying(); + } else if(playerState == PREPARING || playerState == IDLE) { + nextPlayerState = IDLE; + } + } + onStateUpdate(); } diff --git a/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java b/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java index cac28c09..99502f5e 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RemoteController.java @@ -19,18 +19,11 @@ package github.daneren2005.dsub.service; -import android.content.Context; import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ProgressBar; -import android.widget.Toast; import java.util.Iterator; import java.util.concurrent.LinkedBlockingQueue; -import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.RemoteStatus; import github.daneren2005.serverproxy.WebProxy; @@ -48,9 +41,7 @@ public abstract class RemoteController { public abstract void changePosition(int seconds); public abstract void changeTrack(int index, DownloadFile song); // Really is abstract, just don't want to require RemoteController's support it - public void changeNextTrack(DownloadFile song) { - - }; + public void changeNextTrack(DownloadFile song) {} public boolean isNextSupported() { return this.nextSupported; } -- cgit v1.2.3 From 32fd7c300851ebd558cd17a7d5c90f8cf7f17530 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 30 Nov 2015 17:19:15 -0800 Subject: #589 Fix case where we are trying to setup the next song before the current one is actually playing --- .../java/github/daneren2005/dsub/service/DLNAController.java | 2 +- .../java/github/daneren2005/dsub/service/DownloadService.java | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java index a0dc16c1..94bf7231 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java @@ -633,7 +633,7 @@ public class DLNAController extends RemoteController { if(positionInfo.getTrackURI() != null && positionInfo.getTrackURI().equals(nextPlayingURI) && downloadService.getNextPlayerState() == PlayerState.PREPARED) { downloadService.setCurrentPlaying(nextPlaying, true); downloadService.setPlayerState(PlayerState.STARTED); - downloadService.setNextPlaying(); + downloadService.setNextPlayerState(PlayerState.IDLE); } downloadService.postDelayed(new Runnable() { diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 37070903..ae619802 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1416,9 +1416,7 @@ public class DownloadService extends Service { } if(remoteController != null && remoteController.isNextSupported()) { - if(playerState == STARTED && nextPlayerState == IDLE) { - setNextPlaying(); - } else if(playerState == PREPARING || playerState == IDLE) { + if(playerState == PREPARING || playerState == IDLE) { nextPlayerState = IDLE; } } @@ -2679,6 +2677,13 @@ public class DownloadService extends Service { } }); } + + // Setup next playing at least a couple of seconds into the song since both Chromecast and some DLNA clients report PLAYING when still PREPARING + if(position > 2000 && remoteController != null && remoteController.isNextSupported()) { + if(playerState == STARTED && nextPlayerState == IDLE) { + setNextPlaying(); + } + } } private void onStateUpdate() { final long atRevision = revision; -- cgit v1.2.3 From cef807002df9adaeabe8937510444f2372a6e784 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 30 Nov 2015 17:54:27 -0800 Subject: Fix gapless playback on DLNA not scrobbling completion --- .../github/daneren2005/dsub/service/ChromeCastController.java | 2 -- .../main/java/github/daneren2005/dsub/service/DLNAController.java | 6 +----- .../java/github/daneren2005/dsub/service/DownloadService.java | 8 ++++++++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java index 7d2b0a07..79312f44 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java @@ -483,8 +483,6 @@ public class ChromeCastController extends RemoteController { break; case MediaStatus.PLAYER_STATE_IDLE: if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_FINISHED) { - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.postPlayCleanup(); downloadService.onSongCompleted(); } else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_INTERRUPTED) { if (downloadService.getPlayerState() != PlayerState.PREPARING) { diff --git a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java index 94bf7231..f978c614 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java @@ -188,8 +188,6 @@ public class DLNAController extends RemoteController { failedLoad(); } else if(downloadService.getPlayerState() == PlayerState.STARTED) { // Played until the end - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.postPlayCleanup(); downloadService.onSongCompleted(); } else { downloadService.setPlayerState(PlayerState.STOPPED); @@ -631,9 +629,7 @@ public class DLNAController extends RemoteController { currentPosition = (int) positionInfo.getTrackElapsedSeconds(); if(positionInfo.getTrackURI() != null && positionInfo.getTrackURI().equals(nextPlayingURI) && downloadService.getNextPlayerState() == PlayerState.PREPARED) { - downloadService.setCurrentPlaying(nextPlaying, true); - downloadService.setPlayerState(PlayerState.STARTED); - downloadService.setNextPlayerState(PlayerState.IDLE); + downloadService.onNextStarted(nextPlaying); } downloadService.postDelayed(new Runnable() { diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index ae619802..788f929e 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1189,8 +1189,16 @@ public class DownloadService extends Service { } public void onSongCompleted() { + setPlayerState(PlayerState.COMPLETED); + postPlayCleanup(); play(getNextPlayingIndex()); } + public void onNextStarted(DownloadFile nextPlaying) { + setPlayerState(COMPLETED); + postPlayCleanup(); + setCurrentPlaying(nextPlaying, true); + setPlayerState(STARTED); + } public synchronized void pause() { pause(false); -- cgit v1.2.3 From c56824f9e6fda0ad3439d55de034afe0fc612084 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 30 Nov 2015 18:12:30 -0800 Subject: DLNA: fix a couple of issues with last commit --- app/src/main/java/github/daneren2005/dsub/service/DLNAController.java | 1 + app/src/main/java/github/daneren2005/dsub/service/DownloadService.java | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java index f978c614..32c03306 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java @@ -630,6 +630,7 @@ public class DLNAController extends RemoteController { if(positionInfo.getTrackURI() != null && positionInfo.getTrackURI().equals(nextPlayingURI) && downloadService.getNextPlayerState() == PlayerState.PREPARED) { downloadService.onNextStarted(nextPlaying); + nextPlayingURI = null; } downloadService.postDelayed(new Runnable() { diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index 788f929e..a271c020 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1198,6 +1198,7 @@ public class DownloadService extends Service { postPlayCleanup(); setCurrentPlaying(nextPlaying, true); setPlayerState(STARTED); + setNextPlayerState(IDLE); } public synchronized void pause() { -- cgit v1.2.3 From d9cf55f61b76d7d6c10fe9aa3a23d5c0b91b99dd Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 8 Dec 2015 17:42:53 -0800 Subject: On settings restore remove cache location since they differ from device to device --- .../java/github/daneren2005/dsub/util/SettingsBackupAgent.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java b/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java index 7eb6d137..9b6a20a5 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java +++ b/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java @@ -19,13 +19,22 @@ package github.daneren2005.dsub.util; import android.app.backup.BackupAgentHelper; +import android.app.backup.BackupDataInput; import android.app.backup.SharedPreferencesBackupHelper; +import android.os.ParcelFileDescriptor; + import github.daneren2005.dsub.util.Constants; public class SettingsBackupAgent extends BackupAgentHelper { + @Override public void onCreate() { super.onCreate(); SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Constants.PREFERENCES_FILE_NAME); addHelper("mypreferences", helper); } + + @Override + public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) { + Util.getPreferences(this).edit().remove(Constants.PREFERENCES_KEY_CACHE_LOCATION).apply(); + } } -- cgit v1.2.3 From ec1a894b950dc4ccf7122487e8fac1e7f3c5ee5f Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 8 Dec 2015 17:43:41 -0800 Subject: Forgot to do super.onRestore --- .../main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java b/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java index 9b6a20a5..def97cac 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java +++ b/app/src/main/java/github/daneren2005/dsub/util/SettingsBackupAgent.java @@ -23,6 +23,9 @@ import android.app.backup.BackupDataInput; import android.app.backup.SharedPreferencesBackupHelper; import android.os.ParcelFileDescriptor; +import java.io.IOError; +import java.io.IOException; + import github.daneren2005.dsub.util.Constants; public class SettingsBackupAgent extends BackupAgentHelper { @@ -34,7 +37,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { } @Override - public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) { + public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException{ + super.onRestore(data, appVersionCode, newState); Util.getPreferences(this).edit().remove(Constants.PREFERENCES_KEY_CACHE_LOCATION).apply(); } } -- cgit v1.2.3 From 7a1f0795d2b362be9bc2778d8ad7a345b3c3b03f Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 8 Dec 2015 17:45:45 -0800 Subject: Don't stop playing just because failed to parse event --- app/src/main/java/github/daneren2005/dsub/service/DLNAController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java index 32c03306..0673cdeb 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DLNAController.java @@ -204,7 +204,6 @@ public class DLNAController extends RemoteController { } catch (Exception e) { Log.w(TAG, "Failed to parse UPNP event", e); - failedLoad(); } } -- cgit v1.2.3 From 546cd362c88850999ddb7274eb51fdd7759c5547 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 11 Dec 2015 11:58:35 -0800 Subject: 6.0 Doze fix: grab and hold a Wifi lock while casting --- .../dsub/service/ChromeCastController.java | 3 +- .../daneren2005/dsub/service/DownloadService.java | 76 ++++++++++++++-------- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java index 79312f44..670ea7d2 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java +++ b/app/src/main/java/github/daneren2005/dsub/service/ChromeCastController.java @@ -490,8 +490,7 @@ public class ChromeCastController extends RemoteController { } } else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_ERROR) { Log.e(TAG, "Idle due to unknown error"); - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.next(); + downloadService.onSongCompleted(); } else { Log.w(TAG, "Idle reason: " + mediaStatus.getIdleReason()); downloadService.setPlayerState(PlayerState.IDLE); diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index a271c020..7c80ca56 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -77,6 +77,7 @@ import android.content.SharedPreferences; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.audiofx.AudioEffect; +import android.net.wifi.WifiManager; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -154,6 +155,7 @@ public class DownloadService extends Service { private String suggestedPlaylistName; private String suggestedPlaylistId; private PowerManager.WakeLock wakeLock; + private WifiManager.WifiLock wifiLock; private boolean keepScreenOn; private int cachedPosition = 0; private boolean downloadOngoing = false; @@ -257,6 +259,9 @@ public class DownloadService extends Service { wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); wakeLock.setReferenceCounted(false); + WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); + wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "downloadServiceLock"); + try { timerDuration = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, "5")); } catch(Throwable e) { @@ -1189,12 +1194,12 @@ public class DownloadService extends Service { } public void onSongCompleted() { - setPlayerState(PlayerState.COMPLETED); + setPlayerStateCompleted(); postPlayCleanup(); play(getNextPlayingIndex()); } public void onNextStarted(DownloadFile nextPlaying) { - setPlayerState(COMPLETED); + setPlayerStateCompleted(); postPlayCleanup(); setCurrentPlaying(nextPlaying, true); setPlayerState(STARTED); @@ -1402,15 +1407,6 @@ public class DownloadService extends Service { scrobbler.scrobble(this, currentPlaying, true); } - if(playerState == STARTED && positionCache == null && remoteState == LOCAL) { - positionCache = new LocalPositionCache(); - Thread thread = new Thread(positionCache, "PositionCache"); - thread.start(); - } else if(playerState != STARTED && positionCache != null) { - positionCache.stop(); - positionCache = null; - } - if(playerState == STARTED && positionCache == null) { if(remoteState == LOCAL) { positionCache = new LocalPositionCache(); @@ -1424,6 +1420,17 @@ public class DownloadService extends Service { positionCache = null; } + + if(remoteState != LOCAL) { + if(playerState == STARTED) { + if (!wifiLock.isHeld()) { + wifiLock.acquire(); + } + } else if(playerState == PAUSED && wifiLock.isHeld()) { + wifiLock.release(); + } + } + if(remoteController != null && remoteController.isNextSupported()) { if(playerState == PREPARING || playerState == IDLE) { nextPlayerState = IDLE; @@ -1433,6 +1440,21 @@ public class DownloadService extends Service { onStateUpdate(); } + public void setPlayerStateCompleted() { + // Acquire a temporary wakelock + acquireWakelock(); + + Log.i(TAG, this.playerState.name() + " -> " + PlayerState.COMPLETED + " (" + currentPlaying + ")"); + this.playerState = PlayerState.COMPLETED; + if(positionCache != null) { + positionCache.stop(); + positionCache = null; + } + scrobbler.scrobble(this, currentPlaying, true); + + onStateUpdate(); + } + private class PositionCache implements Runnable { boolean isRunning = true; @@ -1499,16 +1521,6 @@ public class DownloadService extends Service { } } - private void setPlayerStateCompleted() { - Log.i(TAG, this.playerState.name() + " -> " + PlayerState.COMPLETED + " (" + currentPlaying + ")"); - this.playerState = PlayerState.COMPLETED; - if(positionCache != null) { - positionCache.stop(); - positionCache = null; - } - scrobbler.scrobble(this, currentPlaying, true); - } - public synchronized void setNextPlayerState(PlayerState playerState) { Log.i(TAG, "Next: " + this.nextPlayerState.name() + " -> " + playerState.name() + " (" + nextPlaying + ")"); this.nextPlayerState = playerState; @@ -1650,9 +1662,20 @@ public class DownloadService extends Service { remoteController = (RemoteController) ref; break; case LOCAL: default: + if(wifiLock.isHeld()) { + wifiLock.release(); + } break; } + if(remoteState != LOCAL) { + if(!wifiLock.isHeld()) { + wifiLock.acquire(); + } + } else if(wifiLock.isHeld()) { + wifiLock.release(); + } + if(remoteController != null) { remoteController.create(isPlaying, position / 1000); } else { @@ -1928,11 +1951,6 @@ public class DownloadService extends Service { mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { - // Acquire a temporary wakelock, since when we return from - // this callback the MediaPlayer will release its wakelock - // and allow the device to go to sleep. - wakeLock.acquire(30000); - setPlayerStateCompleted(); int pos = getPlayerPosition(); @@ -2588,6 +2606,12 @@ public class DownloadService extends Service { } }); } + public void acquireWakelock() { + acquireWakelock(30000); + } + public void acquireWakelock(int ms) { + wakeLock.acquire(ms); + } public void addOnSongChangedListener(OnSongChangedListener listener) { addOnSongChangedListener(listener, false); -- cgit v1.2.3