aboutsummaryrefslogtreecommitdiff
path: root/src/github
diff options
context:
space:
mode:
Diffstat (limited to 'src/github')
-rw-r--r--src/github/daneren2005/dsub/service/DLNAController.java109
-rw-r--r--src/github/daneren2005/dsub/service/DownloadService.java4
2 files changed, 92 insertions, 21 deletions
diff --git a/src/github/daneren2005/dsub/service/DLNAController.java b/src/github/daneren2005/dsub/service/DLNAController.java
index b863068b..0a90c2d7 100644
--- a/src/github/daneren2005/dsub/service/DLNAController.java
+++ b/src/github/daneren2005/dsub/service/DLNAController.java
@@ -16,7 +16,9 @@
package github.daneren2005.dsub.service;
import android.content.SharedPreferences;
+import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.util.Log;
import org.fourthline.cling.controlpoint.ControlPoint;
@@ -26,8 +28,10 @@ import org.fourthline.cling.model.gena.CancelReason;
import org.fourthline.cling.model.gena.GENASubscription;
import org.fourthline.cling.model.message.UpnpResponse;
import org.fourthline.cling.model.meta.Device;
+import org.fourthline.cling.model.meta.Service;
import org.fourthline.cling.model.state.StateVariableValue;
import org.fourthline.cling.model.types.ServiceType;
+import org.fourthline.cling.support.avtransport.callback.GetPositionInfo;
import org.fourthline.cling.support.avtransport.callback.Pause;
import org.fourthline.cling.support.avtransport.callback.Play;
import org.fourthline.cling.support.avtransport.callback.Seek;
@@ -38,6 +42,7 @@ import org.fourthline.cling.support.avtransport.lastchange.AVTransportVariable;
import org.fourthline.cling.support.contentdirectory.DIDLParser;
import org.fourthline.cling.support.lastchange.LastChange;
import org.fourthline.cling.support.model.DIDLContent;
+import org.fourthline.cling.support.model.PositionInfo;
import org.fourthline.cling.support.model.SeekMode;
import org.fourthline.cling.support.model.item.Item;
import org.fourthline.cling.support.model.item.MusicTrack;
@@ -48,6 +53,7 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
+import java.util.concurrent.atomic.AtomicLong;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.DLNADevice;
@@ -59,6 +65,7 @@ import github.daneren2005.serverproxy.FileProxy;
public class DLNAController extends RemoteController {
private static final String TAG = DLNAController.class.getSimpleName();
+ private static final long STATUS_UPDATE_INTERVAL_SECONDS = 3L;
DLNADevice device;
ControlPoint controlPoint;
@@ -68,6 +75,11 @@ public class DLNAController extends RemoteController {
String rootLocation = "";
boolean error = false;
+ final AtomicLong lastUpdate = new AtomicLong();
+ int currentPosition = 0;
+ String currentPlayingURI;
+ boolean running = true;
+
public DLNAController(DownloadService downloadService, ControlPoint controlPoint, DLNADevice device) {
this.downloadService = downloadService;
this.controlPoint = controlPoint;
@@ -81,9 +93,7 @@ public class DLNAController extends RemoteController {
public void create(final boolean playing, final int seconds) {
downloadService.setPlayerState(PlayerState.PREPARING);
- Device renderer = device.renderer;
-
- callback = new SubscriptionCallback(renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport")), 600) {
+ callback = new SubscriptionCallback(getTransportService(), 600) {
@Override
protected void failed(GENASubscription genaSubscription, UpnpResponse upnpResponse, Exception e, String msg) {
Log.w(TAG, "Register subscription callback failed: " + msg, e);
@@ -161,7 +171,7 @@ public class DLNAController extends RemoteController {
return;
}
- controlPoint.execute(new Play(device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport"))) {
+ controlPoint.execute(new Play(getTransportService()) {
@Override
public void success(ActionInvocation invocation) {
downloadService.setPlayerState(PlayerState.STARTED);
@@ -177,7 +187,7 @@ public class DLNAController extends RemoteController {
@Override
public void stop() {
- controlPoint.execute(new Pause(device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport"))) {
+ controlPoint.execute(new Pause(getTransportService()) {
@Override
public void success(ActionInvocation invocation) {
downloadService.setPlayerState(PlayerState.PAUSED);
@@ -192,7 +202,7 @@ public class DLNAController extends RemoteController {
@Override
public void shutdown() {
- controlPoint.execute(new Stop(device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport"))) {
+ controlPoint.execute(new Stop(getTransportService()) {
@Override
public void failure(ActionInvocation invocation, org.fourthline.cling.model.message.UpnpResponse operation, String defaultMessage) {
Log.w(TAG, "Stop failed: " + defaultMessage);
@@ -203,6 +213,8 @@ public class DLNAController extends RemoteController {
callback.end();
callback = null;
}
+
+ running = false;
}
@Override
@@ -216,7 +228,7 @@ public class DLNAController extends RemoteController {
public void changePosition(int seconds) {
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
- controlPoint.execute(new Seek(device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport")), SeekMode.REL_TIME, df.format(new Date(seconds * 1000))) {
+ controlPoint.execute(new Seek(getTransportService(), SeekMode.REL_TIME, df.format(new Date(seconds * 1000))) {
@SuppressWarnings("rawtypes")
@Override
public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMessage) {
@@ -261,7 +273,8 @@ public class DLNAController extends RemoteController {
@Override
public int getRemotePosition() {
- return 0;
+ int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - lastUpdate.get()) / 1000L);
+ return currentPosition + secondsSinceLastUpdate;
}
private void startSong(final DownloadFile currentPlaying, final boolean autoStart, final int position) {
@@ -321,25 +334,21 @@ public class DLNAController extends RemoteController {
Log.w(TAG, "Metadata generation failed", e);
}
- controlPoint.execute(new SetAVTransportURI(device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport")), url, metadata) {
+ currentPlayingURI = url;
+ controlPoint.execute(new SetAVTransportURI(getTransportService(), url, metadata) {
@Override
public void success(ActionInvocation invocation) {
- if (autoStart) {
- controlPoint.execute(new Play(device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport"))) {
- @Override
- public void success(ActionInvocation invocation) {
- downloadService.setPlayerState(PlayerState.STARTED);
- }
+ if(position != 0) {
+ changePosition(position);
+ }
- @Override
- public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String msg) {
- Log.w(TAG, "Failed to start playing: " + msg);
- failedLoad();
- }
- });
+ if (autoStart) {
+ start();
} else {
downloadService.setPlayerState(PlayerState.PAUSED);
}
+
+ getUpdatedStatus();
}
@Override
@@ -369,4 +378,62 @@ public class DLNAController extends RemoteController {
Util.toast(downloadService, downloadService.getResources().getString(R.string.download_failed_to_load));
}
}
+
+ private Service getTransportService() {
+ return device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport"));
+ }
+
+ private void getUpdatedStatus() {
+ // Don't care if shutdown in the meantime
+ if(!running) {
+ return;
+ }
+
+ controlPoint.execute(new GetPositionInfo(getTransportService()) {
+ @Override
+ public void received(ActionInvocation actionInvocation, PositionInfo positionInfo) {
+ // Don't care if shutdown in the meantime
+ if(!running) {
+ return;
+ }
+
+ lastUpdate.set(System.currentTimeMillis());
+
+ // Playback was stopped
+ if(positionInfo.getTrackURI() == null) {
+ if(downloadService.getCurrentPlaying() != null && downloadService.getPlayerState() != PlayerState.IDLE) {
+ Log.w(TAG, "Nothing is playing on DLNA device");
+ downloadService.setCurrentPlaying(null, false);
+ }
+ }
+ // End device started playing something else, no idea what
+ else if(!positionInfo.getTrackURI().equals(currentPlayingURI) && downloadService.getPlayerState() != PlayerState.IDLE) {
+ Log.w(TAG, "A different song is playing on the remote device: " + positionInfo.getTrackURI());
+ downloadService.setCurrentPlaying(null, false);
+ } else {
+ // Let's get the updated position
+ currentPosition = (int) positionInfo.getTrackElapsedSeconds();
+ }
+
+ downloadService.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ getUpdatedStatus();
+ }
+ }, STATUS_UPDATE_INTERVAL_SECONDS);
+ }
+
+ @Override
+ public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String s) {
+ Log.w(TAG, "Failed to get an update");
+
+ downloadService.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ getUpdatedStatus();
+ }
+ }, STATUS_UPDATE_INTERVAL_SECONDS);
+ }
+ });
+ }
}
diff --git a/src/github/daneren2005/dsub/service/DownloadService.java b/src/github/daneren2005/dsub/service/DownloadService.java
index 6482cc14..a1bf7b52 100644
--- a/src/github/daneren2005/dsub/service/DownloadService.java
+++ b/src/github/daneren2005/dsub/service/DownloadService.java
@@ -302,6 +302,9 @@ public class DownloadService extends Service {
public void post(Runnable r) {
handler.post(r);
}
+ public void postDelayed(Runnable r, long millis) {
+ handler.postDelayed(r, millis);
+ }
public synchronized void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle) {
download(songs, save, autoplay, playNext, shuffle, 0, 0);
@@ -703,6 +706,7 @@ public class DownloadService extends Service {
this.currentPlaying = currentPlaying;
if(currentPlaying == null) {
currentPlayingIndex = -1;
+ setPlayerState(IDLE);
} else {
currentPlayingIndex = downloadList.indexOf(currentPlaying);
}